import { AppError, castTo, type Class, getClass } from '@travetto/runtime'; import { SchemaRegistryIndex } from '@travetto/schema'; import type { ModelType } from '../types/model.ts'; import type { DataHandler, IndexConfig, ModelConfig, PrePersistScope } from './types.ts'; import { ModelRegistryIndex } from './registry-index.ts'; /** * Model decorator, extends `@Schema` * * @augments `@travetto/schema:Schema` * @kind decorator */ export function Model(config: Partial> | string = {}) { return function >(cls: U): U { if (typeof config === 'string') { config = { store: config }; } ModelRegistryIndex.getForRegister(cls).register(config); if (SchemaRegistryIndex.getForRegister(cls).get().fields.id) { SchemaRegistryIndex.getForRegister(cls).registerField('id', { required: { active: false } }); } return cls; }; } /** * Defines an index on a model * @kind decorator */ export function Index(...indices: IndexConfig[]) { if (indices.some(config => config.fields.some(field => field === 'id'))) { throw new AppError('Cannot create an index with the id field'); } return function (cls: Class): void { ModelRegistryIndex.getForRegister(cls).register({ indices }); }; } /** * Model field decorator for denoting expiry date/time * @augments `@travetto/schema:Field` * @kind decorator */ export function ExpiresAt() { return >>(instance: T, property: K): void => { ModelRegistryIndex.getForRegister(getClass(instance)).register({ expiresAt: property }); }; } /** * Model class decorator for pre-persist behavior * @augments `@travetto/schema:Schema` * @kind decorator */ export function PrePersist(handler: DataHandler, scope: PrePersistScope = 'all') { return function (cls: Class): void { ModelRegistryIndex.getForRegister(cls).register({ prePersist: [{ scope, handler: castTo(handler) }] }); }; } /** * Model field decorator for pre-persist value setting * @augments `@travetto/schema:Field` * @kind decorator */ export function PersistValue(handler: (current: T | undefined) => T, scope: PrePersistScope = 'all') { return function >>(instance: C, property: K): void { ModelRegistryIndex.getForRegister(getClass(instance)).register({ prePersist: [{ scope, handler: (inst): void => { const cInst: Record = castTo(inst); cInst[property] = handler(cInst[property]); } }] }); }; } /** * Prevent a field from being persisted * @augments `@travetto/schema:Field` * @kind decorator */ export function Transient() { return function >>(instance: C, property: K): void { ModelRegistryIndex.getForRegister(getClass(instance)).register({ prePersist: [{ scope: 'all', handler: (inst): void => { const cInst: Record = castTo(inst); delete cInst[property]; } }] }); }; } /** * Model class decorator for post-load behavior * @augments `@travetto/schema:Schema` * @kind decorator */ export function PostLoad(handler: DataHandler) { return function (cls: Class): void { ModelRegistryIndex.getForRegister(cls).register({ postLoad: [castTo(handler)] }); }; }