import type { Keyof } from "@fabric/core"; import type { FieldToType } from "./fields/field-to-type.ts"; import { Field, type FieldDefinition } from "./fields/index.ts"; /** * A model is a schema definition for some type of structured data. */ export class Model< TName extends string = string, TFields extends ModelFields = ModelFields, > { static from( name: TName, fields: TFields, ) { return new Model(name, fields); } static aggregateFrom( name: TName, fields: TFields, ): Model { return new Model(name, { ...fields, ...DefaultAggregateFields }); } static entityFrom( name: TName, fields: TFields, ): Model { return new Model(name, { ...fields, ...DefaultEntityFields }); } private constructor(readonly name: TName, readonly fields: TFields) {} } export type EntityModel = Model< string, typeof DefaultEntityFields & ModelFields >; export type AggregateModel = Model< string, typeof DefaultAggregateFields & ModelFields >; 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]; type ModelFields = Record; const DefaultEntityFields = { id: Field.uuid({ isPrimaryKey: true }), } as const; const DefaultAggregateFields = { ...DefaultEntityFields, streamId: Field.uuid({ isIndexed: true }), streamVersion: Field.integer({ isUnsigned: true, hasArbitraryPrecision: true, }), deletedAt: Field.timestamp({ isOptional: true }), } as const;