import type { Schema } from 'effect'; import type { DeltaSchema, Evolution, ForbidIdField, ForbidOptionalFields, ForbidUnderscorePrefix, MergeSchemas, NextVersion, StructFieldsDecoded, StructFieldsSchema, } from '../domain/schema-model/index.js'; import { mergeDelta } from '../domain/schema-model/index.js'; import type { EntityESchema } from './entity-eschema.js'; import { DraftedEntityESchemaBuilder } from './drafted-entity-eschema-builder.js'; export class EntityESchemaBuilder< TName extends string, TIdField extends string, TVersion extends string, TLatest extends StructFieldsSchema, > { constructor( private readonly name: TName, private readonly idField: TIdField, private readonly idSchema: Schema.Codec, private readonly evolutions: readonly Evolution[], readonly version: TVersion, private readonly finish: ( version: V, evolutions: readonly Evolution[], ) => EntityESchema, ) {} evolve, D extends DeltaSchema>( version: V, delta: D & ForbidUnderscorePrefix & ForbidIdField & ForbidOptionalFields, migration: ( previous: StructFieldsDecoded, ) => StructFieldsDecoded>, ) { const previous = this.evolutions.at(-1)?.schema ?? {}; const schema = mergeDelta(previous, delta); schema[this.idField] = this.idSchema; const evolutions = [...this.evolutions, { version, schema, migration }]; return new EntityESchemaBuilder< TName, TIdField, V, MergeSchemas & Record> >(this.name, this.idField, this.idSchema, evolutions, version, this.finish); } draft( delta: D & ForbidUnderscorePrefix & ForbidIdField & ForbidOptionalFields, migrations: { readonly forward: ( previous: StructFieldsDecoded, ) => StructFieldsDecoded>; readonly backward: ( draft: StructFieldsDecoded>, ) => StructFieldsDecoded; }, ): DraftedEntityESchemaBuilder< TName, TIdField, TVersion, TLatest, MergeSchemas & Record> > { const previous = this.evolutions.at(-1)?.schema ?? {}; const schema = mergeDelta(previous, delta); schema[this.idField] = this.idSchema; return new DraftedEntityESchemaBuilder< TName, TIdField, TVersion, TLatest, MergeSchemas & Record> >(this.name, this.idField, this.evolutions, this.version, { schema, forward: migrations.forward, backward: migrations.backward, }); } build(): EntityESchema { return this.finish(this.version, this.evolutions); } }