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

42 lines
1.3 KiB
TypeScript

import { defineMetadata, getMetadata } from "muddle/metadata";
export const HYDRATE_METADATA_KEY = "muddle:orm:hydrated";
export interface HydrateOptions<Value = any> {
/** Computes the value from the raw database row. */
decode?: (row: Record<string, unknown>) => Value;
/** Column the value is derived from, handed to `decode` as second argument. */
column?: string;
}
export interface HydrateDescriptor {
property: string;
options: HydrateOptions;
}
/** Declares a hydrated (computed) property. */
export function Hydrate<Value = any>(
options: HydrateOptions<Value> = {},
): PropertyDecorator {
return (target, propertyKey) => {
const constructor = target.constructor as object;
const hydrated = getHydratedProperties(constructor);
hydrated.set(String(propertyKey), {
property: String(propertyKey),
options: options as HydrateOptions,
});
};
}
/** Reads the hydrated properties declared on a model class. */
export function getHydratedProperties(
target: object,
): Map<string, HydrateDescriptor> {
const existing = getMetadata(HYDRATE_METADATA_KEY, target) as
| Map<string, HydrateDescriptor>
| undefined;
if (existing) return existing;
const hydrated = new Map<string, HydrateDescriptor>();
defineMetadata(HYDRATE_METADATA_KEY, hydrated, target);
return hydrated;
}