import { it, describe, expect } from 'vitest'; const itEffect = (name: string, fn: () => Effect.Effect) => it(name, () => Effect.runPromise(fn())); import { Effect, Schema } from 'effect'; import { EntityESchema } from '../index.js'; describe('ESchema', () => { describe('Evolution', () => { describe('Multiple evolutions', () => { itEffect('chains v1 → v2 → v3 migrations', () => Effect.gen(function* () { const schema = EntityESchema.make('Test', 'id', { a: Schema.String, }) .evolve('v2', { b: Schema.String }, (v) => ({ ...v, b: 'from-v1' })) .evolve('v3', { c: Schema.Number }, (v) => ({ ...v, c: 100 })) .build(); const fromV1 = yield* schema.decode({ _v: 'v1', id: 't1', a: 'hello', }); expect(fromV1).toEqual({ id: 't1', a: 'hello', b: 'from-v1', c: 100, }); const fromV2 = yield* schema.decode({ _v: 'v2', id: 't1', a: 'hello', b: 'existing', }); expect(fromV2).toEqual({ id: 't1', a: 'hello', b: 'existing', c: 100, }); const fromV3 = yield* schema.decode({ _v: 'v3', id: 't1', a: 'hello', b: 'existing', c: 999, }); expect(fromV3).toEqual({ id: 't1', a: 'hello', b: 'existing', c: 999, }); }), ); itEffect('handles field removal in migrations', () => Effect.gen(function* () { const schema = EntityESchema.make('Test', 'id', { a: Schema.String, b: Schema.String, }) .evolve('v2', { b: null }, (v) => ({ id: v.id, a: v.a })) .build(); const decoded = yield* schema.decode({ _v: 'v1', id: 't1', a: 'keep', b: 'drop', }); expect(decoded).toEqual({ id: 't1', a: 'keep' }); }), ); itEffect('handles field transformation in migrations', () => Effect.gen(function* () { const schema = EntityESchema.make('Test', 'id', { firstName: Schema.String, lastName: Schema.String, }) .evolve( 'v2', { firstName: null, lastName: null, fullName: Schema.String }, (v) => ({ id: v.id, fullName: `${v.firstName} ${v.lastName}` }), ) .build(); const decoded = yield* schema.decode({ _v: 'v1', id: 't1', firstName: 'John', lastName: 'Doe', }); expect(decoded).toEqual({ id: 't1', fullName: 'John Doe' }); }), ); }); }); });