[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 { 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 }),
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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 }),
|
||||
|
||||
@ -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<string, FieldDefinition>;
|
||||
|
||||
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<TName, TFields> {
|
||||
fields: typeof DefaultModelFields & TFields;
|
||||
}
|
||||
|
||||
export function defineModel<
|
||||
TName extends string,
|
||||
TFields extends CustomModelFields,
|
||||
>(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 {
|
||||
name,
|
||||
fields,
|
||||
} as const;
|
||||
}
|
||||
|
||||
export type ModelToType<TModel extends Collection> = {
|
||||
export type ModelToType<TModel extends Model> = {
|
||||
[K in Keyof<TModel["fields"]>]: FieldToType<TModel["fields"][K]>;
|
||||
};
|
||||
|
||||
export type ModelFieldNames<TModel extends CustomModelFields> = Keyof<
|
||||
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 { 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<TModel extends Model, TEvents extends Event> {
|
||||
export interface Projection<
|
||||
TModel extends AggregateModel,
|
||||
TEvents extends Event,
|
||||
> {
|
||||
model: TModel;
|
||||
events: TEvents[VariantTag][];
|
||||
projection: (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user