database/src/decorators/Field.ts
2026-10-23 08:53:07 -04:00

40 lines
1.3 KiB
TypeScript

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<Value = any>(
options: FieldOptions<Value>,
): 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<string, FieldDescriptor> {
const existing = getMetadata(FIELD_METADATA_KEY, target) as
| Map<string, FieldDescriptor>
| undefined;
if (existing) return existing;
const fields = new Map<string, FieldDescriptor>();
defineMetadata(FIELD_METADATA_KEY, fields, target);
return fields;
}