@decaf-ts/core
Version:
Core persistence module for the decaf framework
151 lines • 6.17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.pkOnCreate = pkOnCreate;
exports.pkDec = pkDec;
exports.pk = pk;
const decorator_validation_1 = require("@decaf-ts/decorator-validation");
const SequenceOptions_1 = require("./../interfaces/SequenceOptions.cjs");
const db_decorators_1 = require("@decaf-ts/db-decorators");
const decorators_1 = require("./../model/decorators.cjs");
const constants_1 = require("./../repository/constants.cjs");
const decoration_1 = require("@decaf-ts/decoration");
const defaultPkPriority = 60; // Default priority for primary key to run latter than other properties
/**
* @description Callback function for primary key creation
* @summary Handles the creation of primary key values for models using sequences
* @template M - Type that extends Model
* @template R - Type that extends Repo<M, F, C>
* @template V - Type that extends SequenceOptions
* @template F - Type that extends RepositoryFlags
* @template C - Type that extends Context<F>
* @param {Context<F>} context - The execution context
* @param {V} data - The sequence options
* @param key - The property key to set as primary key
* @param {M} model - The model instance
* @return {Promise<void>} A promise that resolves when the primary key is set
* @function pkOnCreate
* @category Property Decorators
* @mermaid
* sequenceDiagram
* participant Model
* participant pkOnCreate
* participant Adapter
* participant Sequence
*
* Model->>pkOnCreate: Call with model instance
* Note over pkOnCreate: Check if key already exists
* alt Key exists or no type specified
* pkOnCreate-->>Model: Return early
* else Key needs to be created
* pkOnCreate->>pkOnCreate: Generate sequence name if not provided
* pkOnCreate->>Adapter: Request Sequence(data)
* Adapter->>Sequence: Create sequence
* Sequence-->>pkOnCreate: Return sequence
* pkOnCreate->>Sequence: Call next()
* Sequence-->>pkOnCreate: Return next value
* pkOnCreate->>Model: Set primary key value
* end
*/
async function pkOnCreate(context, data, key, model) {
if (!data.type || !data.generated || model[key]) {
return;
}
const setPrimaryKeyValue = function (target, propertyKey, value) {
Reflect.set(target, propertyKey, value);
};
if (!data.name)
data.name = decorator_validation_1.Model.sequenceName(model, "pk");
let sequence;
try {
sequence = await this.adapter.Sequence(data);
}
catch (e) {
throw new db_decorators_1.InternalError(`Failed to instantiate Sequence ${data.name}: ${e}`);
}
const next = await sequence.next(context);
setPrimaryKeyValue(model, key, next);
}
function pkDec(options, groupsort) {
return function pkDec(obj, attr) {
(0, decoration_1.prop)()(obj, attr);
switch (options.type) {
case undefined: {
const metaType = decoration_1.Metadata.type(obj.constructor, attr);
if (![Number.name, String.name, BigInt.name].includes(metaType?.name || metaType))
throw new Error("Incorrrect option type");
options.type = metaType;
break;
}
case String.name || String.name.toLowerCase():
console.warn(`Deprecated "${options.type}" type in options`);
// eslint-disable-next-line no-fallthrough
case String:
options.generated = false;
options.type = String;
break;
case Number.name || String.name.toLowerCase():
console.warn(`Deprecated "${options.type}" type in options`);
// eslint-disable-next-line no-fallthrough
case Number:
options.generated = true;
options.type = Number;
break;
case BigInt.name || BigInt.name.toLowerCase():
console.warn(`Deprecated "${options.type}" type in options`);
// eslint-disable-next-line no-fallthrough
case BigInt:
options.type = BigInt;
options.generated = true;
break;
case "uuid":
case "serial":
options.generated = true;
break;
default:
throw new Error("Unsupported type");
}
if (typeof options.generated === "undefined") {
options.generated = true;
}
const decs = [
(0, decorators_1.index)([constants_1.OrderDirection.ASC, constants_1.OrderDirection.DSC]),
(0, decorator_validation_1.required)(),
(0, db_decorators_1.readonly)(),
(0, decoration_1.propMetadata)(decoration_1.Metadata.key(db_decorators_1.DBKeys.ID, attr), options),
(0, db_decorators_1.onCreate)(pkOnCreate, options, groupsort),
];
if (options.generated)
decs.push((0, decorators_1.generated)());
return (0, decoration_1.apply)(...decs)(obj, attr);
};
}
/**
* @description Primary Key Decorator
* @summary Marks a property as the model's primary key with automatic sequence generation
* This decorator combines multiple behaviors: it marks the property as unique, required,
* and ensures the index is created properly according to the provided sequence options.
* @param {Omit<SequenceOptions, "cycle" | "startWith" | "incrementBy">} opts - Options for the sequence generation
* @return {PropertyDecorator} A property decorator that can be applied to model properties
* @function pk
* @category Property Decorators
* @example
* ```typescript
* class User extends BaseModel {
* @pk()
* id!: string;
*
* @required()
* username!: string;
* }
* ```
*/
function pk(opts = SequenceOptions_1.DefaultSequenceOptions) {
opts = Object.assign({}, SequenceOptions_1.DefaultSequenceOptions, opts);
return decoration_1.Decoration.for(db_decorators_1.DBKeys.ID)
.define({
decorator: pkDec,
args: [opts, { priority: defaultPkPriority }],
})
.apply();
}
//# sourceMappingURL=decorators.js.map