[fabric/domain] Refactor aggregate model implementation and related types
This commit is contained in:
parent
2ed9291c4d
commit
3c3ce276c0
37
packages/fabric/domain/models/aggregate-model.ts
Normal file
37
packages/fabric/domain/models/aggregate-model.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import type { Keyof } from "../../core/index.ts";
|
||||||
|
import type { CustomModelFields } from "./custom-model-fields.ts";
|
||||||
|
import { DefaultEntityFields, type EntityModel } from "./entity-model.ts";
|
||||||
|
import { Field } from "./fields/index.ts";
|
||||||
|
|
||||||
|
export const DefaultAggregateFields = {
|
||||||
|
...DefaultEntityFields,
|
||||||
|
streamId: Field.uuid({ isIndexed: true }),
|
||||||
|
streamVersion: Field.integer({
|
||||||
|
isUnsigned: true,
|
||||||
|
hasArbitraryPrecision: true,
|
||||||
|
}),
|
||||||
|
deletedAt: Field.timestamp({ isOptional: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface AggregateModel<
|
||||||
|
TName extends string = string,
|
||||||
|
TFields extends CustomModelFields = CustomModelFields,
|
||||||
|
> extends EntityModel<TName, TFields> {
|
||||||
|
fields: typeof DefaultAggregateFields & TFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function defineAggregateModel<
|
||||||
|
TName extends string,
|
||||||
|
TFields extends CustomModelFields,
|
||||||
|
>(name: TName, fields: TFields): AggregateModel<TName, TFields> {
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
fields: { ...DefaultAggregateFields, ...fields },
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ModelAddressableFields<TModel extends AggregateModel> = {
|
||||||
|
[K in Keyof<TModel["fields"]>]: TModel["fields"][K] extends { isUnique: true }
|
||||||
|
? K
|
||||||
|
: never;
|
||||||
|
}[Keyof<TModel["fields"]>];
|
||||||
3
packages/fabric/domain/models/custom-model-fields.ts
Normal file
3
packages/fabric/domain/models/custom-model-fields.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import type { FieldDefinition } from "./fields/index.ts";
|
||||||
|
|
||||||
|
export type CustomModelFields = Record<string, FieldDefinition>;
|
||||||
14
packages/fabric/domain/models/entity-model.ts
Normal file
14
packages/fabric/domain/models/entity-model.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import type { CustomModelFields } from "./custom-model-fields.ts";
|
||||||
|
import { Field } from "./fields/index.ts";
|
||||||
|
import type { Model } from "./model.ts";
|
||||||
|
|
||||||
|
export const DefaultEntityFields = {
|
||||||
|
id: Field.uuid({ isPrimaryKey: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface EntityModel<
|
||||||
|
TName extends string = string,
|
||||||
|
TFields extends CustomModelFields = CustomModelFields,
|
||||||
|
> extends Model<TName, TFields> {
|
||||||
|
fields: typeof DefaultEntityFields & TFields;
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { isError } from "@fabric/core";
|
import { isError } from "@fabric/core";
|
||||||
import { describe, expect, test } from "@fabric/testing";
|
import { describe, expect, test } from "@fabric/testing";
|
||||||
import { defineModel } from "../model.ts";
|
import { defineAggregateModel } from "../aggregate-model.ts";
|
||||||
import { Field } from "./index.ts";
|
import { Field } from "./index.ts";
|
||||||
import {
|
import {
|
||||||
InvalidReferenceFieldError,
|
InvalidReferenceFieldError,
|
||||||
@ -9,7 +9,7 @@ import {
|
|||||||
|
|
||||||
describe("Validate Reference Field", () => {
|
describe("Validate Reference Field", () => {
|
||||||
const schema = {
|
const schema = {
|
||||||
User: defineModel("User", {
|
User: defineAggregateModel("User", {
|
||||||
name: Field.string(),
|
name: Field.string(),
|
||||||
password: Field.string(),
|
password: Field.string(),
|
||||||
otherUnique: Field.integer({ isUnique: true }),
|
otherUnique: Field.integer({ isUnique: true }),
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
export * from "./aggregate-model.ts";
|
||||||
|
export * from "./custom-model-fields.ts";
|
||||||
export * from "./fields/index.ts";
|
export * from "./fields/index.ts";
|
||||||
export * from "./model-schema.ts";
|
export * from "./model-schema.ts";
|
||||||
export * from "./model.ts";
|
export * from "./model.ts";
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import type { PosixDate } from "@fabric/core";
|
|
||||||
import { describe, expectTypeOf, test } from "@fabric/testing";
|
import { describe, expectTypeOf, test } from "@fabric/testing";
|
||||||
|
import type { PosixDate } from "../../core/index.ts";
|
||||||
import type { UUID } from "../types/uuid.ts";
|
import type { UUID } from "../types/uuid.ts";
|
||||||
|
import { defineAggregateModel } from "./aggregate-model.ts";
|
||||||
import { Field } from "./fields/index.ts";
|
import { Field } from "./fields/index.ts";
|
||||||
import { defineModel, type ModelToType } from "./model.ts";
|
import type { ModelToType } from "./model.ts";
|
||||||
|
|
||||||
describe("CreateModel", () => {
|
describe("CreateModel", () => {
|
||||||
test("should create a model and it's interface type", () => {
|
test("should create a model and it's interface type", () => {
|
||||||
const User = defineModel("User", {
|
const User = defineAggregateModel("User", {
|
||||||
name: Field.string(),
|
name: Field.string(),
|
||||||
password: Field.string(),
|
password: Field.string(),
|
||||||
phone: Field.string({ isOptional: true }),
|
phone: Field.string({ isOptional: true }),
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import type { Keyof } from "@fabric/core";
|
import type { Keyof } from "@fabric/core";
|
||||||
|
import type { CustomModelFields } from "./custom-model-fields.ts";
|
||||||
import type { FieldToType } from "./fields/field-to-type.ts";
|
import type { FieldToType } from "./fields/field-to-type.ts";
|
||||||
import { Field, type FieldDefinition } from "./fields/index.ts";
|
|
||||||
|
|
||||||
export type CustomModelFields = Record<string, FieldDefinition>;
|
export interface Model<
|
||||||
|
|
||||||
export interface Collection<
|
|
||||||
TName extends string = string,
|
TName extends string = string,
|
||||||
TFields extends CustomModelFields = CustomModelFields,
|
TFields extends CustomModelFields = CustomModelFields,
|
||||||
> {
|
> {
|
||||||
@ -12,53 +10,20 @@ export interface Collection<
|
|||||||
fields: TFields;
|
fields: TFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DefaultModelFields = {
|
|
||||||
id: Field.uuid({ isPrimaryKey: true }),
|
|
||||||
streamId: Field.uuid({ isIndexed: true }),
|
|
||||||
streamVersion: Field.integer({
|
|
||||||
isUnsigned: true,
|
|
||||||
hasArbitraryPrecision: true,
|
|
||||||
}),
|
|
||||||
deletedAt: Field.timestamp({ isOptional: true }),
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface Model<
|
|
||||||
TName extends string = string,
|
|
||||||
TFields extends CustomModelFields = CustomModelFields,
|
|
||||||
> extends Collection<TName, TFields> {
|
|
||||||
fields: typeof DefaultModelFields & TFields;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function defineModel<
|
export function defineModel<
|
||||||
TName extends string,
|
TName extends string,
|
||||||
TFields extends CustomModelFields,
|
TFields extends CustomModelFields,
|
||||||
>(name: TName, fields: TFields): Model<TName, TFields> {
|
>(name: TName, fields: TFields): Model<TName, TFields> {
|
||||||
return {
|
|
||||||
name,
|
|
||||||
fields: { ...DefaultModelFields, ...fields },
|
|
||||||
} as const;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function defineCollection<
|
|
||||||
TName extends string,
|
|
||||||
TFields extends CustomModelFields,
|
|
||||||
>(name: TName, fields: TFields): Collection<TName, TFields> {
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
fields,
|
fields,
|
||||||
} as const;
|
} as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ModelToType<TModel extends Collection> = {
|
export type ModelToType<TModel extends Model> = {
|
||||||
[K in Keyof<TModel["fields"]>]: FieldToType<TModel["fields"][K]>;
|
[K in Keyof<TModel["fields"]>]: FieldToType<TModel["fields"][K]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ModelFieldNames<TModel extends CustomModelFields> = Keyof<
|
export type ModelFieldNames<TModel extends CustomModelFields> = Keyof<
|
||||||
TModel["fields"]
|
TModel["fields"]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type ModelAddressableFields<TModel extends Model> = {
|
|
||||||
[K in Keyof<TModel["fields"]>]: TModel["fields"][K] extends { isUnique: true }
|
|
||||||
? K
|
|
||||||
: never;
|
|
||||||
}[Keyof<TModel["fields"]>];
|
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
import type { VariantTag } from "@fabric/core";
|
import type { VariantTag } from "@fabric/core";
|
||||||
import type { Event } from "../events/event.ts";
|
import type { Event } from "../events/event.ts";
|
||||||
import type { StoredEvent } from "../events/stored-event.ts";
|
import type { StoredEvent } from "../events/stored-event.ts";
|
||||||
import type { Model, ModelToType } from "../models/model.ts";
|
import type { AggregateModel } from "../models/aggregate-model.ts";
|
||||||
|
import type { ModelToType } from "../models/model.ts";
|
||||||
|
|
||||||
export interface Projection<TModel extends Model, TEvents extends Event> {
|
export interface Projection<
|
||||||
|
TModel extends AggregateModel,
|
||||||
|
TEvents extends Event,
|
||||||
|
> {
|
||||||
model: TModel;
|
model: TModel;
|
||||||
events: TEvents[VariantTag][];
|
events: TEvents[VariantTag][];
|
||||||
projection: (
|
projection: (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user