diff --git a/packages/fabric/domain/models/aggregate-model.ts b/packages/fabric/domain/models/aggregate-model.ts new file mode 100644 index 0000000..6eda9b7 --- /dev/null +++ b/packages/fabric/domain/models/aggregate-model.ts @@ -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 { + fields: typeof DefaultAggregateFields & TFields; +} + +export function defineAggregateModel< + TName extends string, + TFields extends CustomModelFields, +>(name: TName, fields: TFields): AggregateModel { + return { + name, + fields: { ...DefaultAggregateFields, ...fields }, + } as const; +} + +export type ModelAddressableFields = { + [K in Keyof]: TModel["fields"][K] extends { isUnique: true } + ? K + : never; +}[Keyof]; diff --git a/packages/fabric/domain/models/custom-model-fields.ts b/packages/fabric/domain/models/custom-model-fields.ts new file mode 100644 index 0000000..09c2000 --- /dev/null +++ b/packages/fabric/domain/models/custom-model-fields.ts @@ -0,0 +1,3 @@ +import type { FieldDefinition } from "./fields/index.ts"; + +export type CustomModelFields = Record; diff --git a/packages/fabric/domain/models/entity-model.ts b/packages/fabric/domain/models/entity-model.ts new file mode 100644 index 0000000..7d9f870 --- /dev/null +++ b/packages/fabric/domain/models/entity-model.ts @@ -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 { + fields: typeof DefaultEntityFields & TFields; +} diff --git a/packages/fabric/domain/models/fields/reference-field.test.ts b/packages/fabric/domain/models/fields/reference-field.test.ts index 54b99eb..c6dea22 100644 --- a/packages/fabric/domain/models/fields/reference-field.test.ts +++ b/packages/fabric/domain/models/fields/reference-field.test.ts @@ -1,6 +1,6 @@ import { isError } from "@fabric/core"; import { describe, expect, test } from "@fabric/testing"; -import { defineModel } from "../model.ts"; +import { defineAggregateModel } from "../aggregate-model.ts"; import { Field } from "./index.ts"; import { InvalidReferenceFieldError, @@ -9,7 +9,7 @@ import { describe("Validate Reference Field", () => { const schema = { - User: defineModel("User", { + User: defineAggregateModel("User", { name: Field.string(), password: Field.string(), otherUnique: Field.integer({ isUnique: true }), diff --git a/packages/fabric/domain/models/index.ts b/packages/fabric/domain/models/index.ts index 1a39e2b..067e8f5 100644 --- a/packages/fabric/domain/models/index.ts +++ b/packages/fabric/domain/models/index.ts @@ -1,3 +1,5 @@ +export * from "./aggregate-model.ts"; +export * from "./custom-model-fields.ts"; export * from "./fields/index.ts"; export * from "./model-schema.ts"; export * from "./model.ts"; diff --git a/packages/fabric/domain/models/model.test.ts b/packages/fabric/domain/models/model.test.ts index 272a7d4..c4df9d8 100644 --- a/packages/fabric/domain/models/model.test.ts +++ b/packages/fabric/domain/models/model.test.ts @@ -1,12 +1,13 @@ -import type { PosixDate } from "@fabric/core"; import { describe, expectTypeOf, test } from "@fabric/testing"; +import type { PosixDate } from "../../core/index.ts"; import type { UUID } from "../types/uuid.ts"; +import { defineAggregateModel } from "./aggregate-model.ts"; import { Field } from "./fields/index.ts"; -import { defineModel, type ModelToType } from "./model.ts"; +import type { ModelToType } from "./model.ts"; describe("CreateModel", () => { test("should create a model and it's interface type", () => { - const User = defineModel("User", { + const User = defineAggregateModel("User", { name: Field.string(), password: Field.string(), phone: Field.string({ isOptional: true }), diff --git a/packages/fabric/domain/models/model.ts b/packages/fabric/domain/models/model.ts index ab800ee..2f9705d 100644 --- a/packages/fabric/domain/models/model.ts +++ b/packages/fabric/domain/models/model.ts @@ -1,10 +1,8 @@ import type { Keyof } from "@fabric/core"; +import type { CustomModelFields } from "./custom-model-fields.ts"; import type { FieldToType } from "./fields/field-to-type.ts"; -import { Field, type FieldDefinition } from "./fields/index.ts"; -export type CustomModelFields = Record; - -export interface Collection< +export interface Model< TName extends string = string, TFields extends CustomModelFields = CustomModelFields, > { @@ -12,53 +10,20 @@ export interface Collection< 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 { - fields: typeof DefaultModelFields & TFields; -} - export function defineModel< TName extends string, TFields extends CustomModelFields, >(name: TName, fields: TFields): Model { - return { - name, - fields: { ...DefaultModelFields, ...fields }, - } as const; -} - -export function defineCollection< - TName extends string, - TFields extends CustomModelFields, ->(name: TName, fields: TFields): Collection { return { name, fields, } as const; } -export type ModelToType = { +export type ModelToType = { [K in Keyof]: FieldToType; }; export type ModelFieldNames = Keyof< TModel["fields"] >; - -export type ModelAddressableFields = { - [K in Keyof]: TModel["fields"][K] extends { isUnique: true } - ? K - : never; -}[Keyof]; diff --git a/packages/fabric/domain/projections/projection.ts b/packages/fabric/domain/projections/projection.ts index 75e85b6..3f8bff4 100644 --- a/packages/fabric/domain/projections/projection.ts +++ b/packages/fabric/domain/projections/projection.ts @@ -1,9 +1,13 @@ import type { VariantTag } from "@fabric/core"; import type { Event } from "../events/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 { +export interface Projection< + TModel extends AggregateModel, + TEvents extends Event, +> { model: TModel; events: TEvents[VariantTag][]; projection: (