import { defineMetadata, getMetadata } from "muddle/metadata"; import type { FieldOptions } from "muddle/contracts/typegen/orm/field.ts"; import type { FieldDescriptor } from "muddle/contracts/typegen/orm/field.ts"; export const FIELD_METADATA_KEY = "muddle:orm:fields"; /** Converts a property name into the default column name. */ export function toColumnName(property: string): string { return property .replace(/([a-z0-9])([A-Z])/g, "$1_$2") .replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2") .toLowerCase(); } /** Declares the column backing a property. */ export function Field( options: FieldOptions, ): PropertyDecorator { return (target, propertyKey) => { const constructor = target.constructor as object; const fields = getFields(constructor); const property = String(propertyKey); fields.set(property, { property, column: options.column ?? toColumnName(property), options, }); }; } /** Reads the fields declared on a model class. */ export function getFields(target: object): Map { const existing = getMetadata(FIELD_METADATA_KEY, target) as | Map | undefined; if (existing) return existing; const fields = new Map(); defineMetadata(FIELD_METADATA_KEY, fields, target); return fields; }