import {Collection} from '../../util' import {FieldType} from '../types' /** The reflection metadata key containing information about the model's fields. */ export const EXTOLLO_ORM_MODEL_FIELDS_METADATA_KEY = 'extollo:orm:Field.ts' /** * Abstract representation of a field on a model. */ export interface ModelField { databaseKey: string, modelKey: string | symbol, type: any, } /** * Retrieve a collection of ModelField metadata from the given model. * @param model */ export function getFieldsMeta(model: unknown): Collection { const fields = Reflect.getMetadata(EXTOLLO_ORM_MODEL_FIELDS_METADATA_KEY, (model as any).constructor) if ( !(fields instanceof Collection) ) { return new Collection() } return fields as Collection } /** * Set the collection of ModelField metadata as the field data for the given model. * @param model * @param fields */ export function setFieldsMeta(model: unknown, fields: Collection): void { Reflect.defineMetadata(EXTOLLO_ORM_MODEL_FIELDS_METADATA_KEY, fields, (model as any).constructor) } /** * Decorator that maps the given property to a database column of the specified FieldType. * * @example * ```typescript * class MyModel extends Model { * // Maps the 'name' VARCHAR column in the database to this property * @Field(FieldType.Varchar) * public name!: string * * // Maps the 'first_name' VARCHAR column in the database to this property * @Field(FieldType.Varchar, 'first_name') * public firstName!: string * } * ``` * * @param type * @param databaseKey * @constructor */ export function Field(type: FieldType, databaseKey?: string): PropertyDecorator { return (target, modelKey) => { if ( !databaseKey ) { databaseKey = String(modelKey) } const fields = getFieldsMeta(target) const existingField = fields.firstWhere('modelKey', '=', modelKey) if ( existingField ) { existingField.databaseKey = databaseKey existingField.type = type return setFieldsMeta(target, fields) } fields.push({ databaseKey, modelKey, type, }) setFieldsMeta(target, fields) } }