@palmares/databases
Version:
Add support for working with databases with palmares framework
541 lines (535 loc) • 20.1 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/models/fields/boolean.ts
var boolean_exports = {};
__export(boolean_exports, {
BooleanField: () => BooleanField,
bool: () => bool
});
module.exports = __toCommonJS(boolean_exports);
// src/models/fields/field.ts
var import_core = require("@palmares/core");
// src/models/fields/utils.ts
async function defaultToStringCallback(engine, field, _, customParams = void 0) {
let customImports = [];
let stringifiedCustomAttributes = "{}";
if (engine.fields.fieldToString) {
const stringifiedField = engine.fields.fieldToString(field["__customAttributes"]);
customImports = stringifiedField.imports;
stringifiedCustomAttributes = stringifiedField.result;
}
const stringfieldDefaultValue = field["__defaultValue"] === void 0 ? void 0 : JSON.stringify(field["__defaultValue"]);
return {
stringfied: `models.fields.${field["__typeName"]}.new(${customParams?.constructorParams ? `${customParams.constructorParams}` : ""})${typeof field["__primaryKey"] === "boolean" ? `.primaryKey(${field["__primaryKey"]})` : ""}${stringfieldDefaultValue !== void 0 ? `.default(${typeof field["__defaultValue"] === "string" ? `"${stringfieldDefaultValue}"` : stringfieldDefaultValue})` : ""}${typeof field["__allowNull"] === "boolean" ? `.allowNull(${field["__allowNull"]})` : ""}${typeof field["__unique"] === "boolean" ? `.unique(${field["__unique"]})` : ""}${typeof field["__dbIndex"] === "boolean" ? `.dbIndex(${field["__dbIndex"]})` : ""}${typeof field["__databaseName"] === "string" ? `.databaseName("${field["__databaseName"]}")` : ""}${typeof field["__underscored"] === "boolean" ? `.underscored(${field["__underscored"]})` : ""}${typeof stringifiedCustomAttributes === "string" ? `.setCustomAttributes(${stringifiedCustomAttributes})` : ""}${customParams?.builderParams ? `${customParams.builderParams}` : ""}`,
customImports
};
}
__name(defaultToStringCallback, "defaultToStringCallback");
function defaultCompareCallback(engine, existingField, newField, _) {
let isCustomAttributesEqual = true;
if (engine.fields.compare) {
const areCustomAttributesEqual = engine.fields.compare(existingField["__customAttributes"], newField["__customAttributes"]);
isCustomAttributesEqual = areCustomAttributesEqual;
}
const isTypeNameEqual = existingField["__typeName"] === newField["__typeName"];
const isAllowNullEqual = existingField["__allowNull"] === newField["__allowNull"];
const isPrimaryKeyEqual = existingField["__primaryKey"] === newField["__primaryKey"];
const isDefaultValueEqual = existingField["__defaultValue"] === newField["__defaultValue"];
const isUniqueEqual = existingField["__unique"] === newField["__unique"];
const isDbIndexEqual = existingField["__dbIndex"] === newField["__dbIndex"];
const isDatabaseNameEqual = existingField["__databaseName"] === newField["__databaseName"];
const isUnderscoredEqual = existingField["__underscored"] === newField["__underscored"];
const changedAttributes = [
!isTypeNameEqual && "typeName",
!isAllowNullEqual && "allowNull",
!isCustomAttributesEqual && "customAttributes",
!isPrimaryKeyEqual && "primaryKey",
!isDefaultValueEqual && "defaultValue",
!isUniqueEqual && "unique",
!isDbIndexEqual && "dbIndex",
!isDatabaseNameEqual && "databaseName",
!isUnderscoredEqual && "underscored"
].filter((attr) => typeof attr === "string");
return [
changedAttributes.length === 0,
changedAttributes
];
}
__name(defaultCompareCallback, "defaultCompareCallback");
function defaultOptionsCallback(setFieldValue, oldField, _) {
setFieldValue("__allowNull", "allowNull", oldField["__allowNull"]);
setFieldValue("__customAttributes", "customAttributes", oldField["__customAttributes"]);
setFieldValue("__defaultValue", "defaultValue", oldField["__defaultValue"]);
setFieldValue("__dbIndex", "dbIndex", oldField["__dbIndex"]);
setFieldValue("__databaseName", "databaseName", oldField["__databaseName"]);
setFieldValue("__primaryKey", "primaryKey", oldField["__primaryKey"]);
setFieldValue("__underscored", "underscored", oldField["__underscored"]);
setFieldValue("__unique", "unique", oldField["__unique"]);
setFieldValue("__isAuto", "isAuto", oldField["__isAuto"]);
setFieldValue("__fieldName", "fieldName", oldField["__fieldName"]);
setFieldValue("__model", void 0, oldField["__model"]);
}
__name(defaultOptionsCallback, "defaultOptionsCallback");
function defaultNewInstanceArgumentsCallback(_field, _defaultNewInstanceArgumentsCallback) {
return [];
}
__name(defaultNewInstanceArgumentsCallback, "defaultNewInstanceArgumentsCallback");
function defaultGetArgumentsCallback(field, _) {
return {
$field: field,
$model: field["__model"],
typeName: field["__typeName"],
fieldName: field["__fieldName"],
modelName: field["__model"]?.["__getName"]?.() || "",
isAuto: field["__isAuto"],
primaryKey: field["__primaryKey"],
defaultValue: field["__defaultValue"],
allowNull: field["__allowNull"],
unique: field["__unique"],
dbIndex: field["__dbIndex"],
databaseName: field["__databaseName"],
underscored: field["__underscored"],
customAttributes: field["__customAttributes"]
};
}
__name(defaultGetArgumentsCallback, "defaultGetArgumentsCallback");
// src/models/fields/field.ts
var Field = class {
static {
__name(this, "Field");
}
$$type = "$PField";
__typeName = "Field";
__isAuto = false;
__hasDefaultValue = false;
__primaryKey = false;
__defaultValue = void 0;
__allowNull = false;
__unique = false;
__dbIndex = false;
__databaseName = void 0;
__underscored = true;
__customAttributes;
__allowedQueryOperations = /* @__PURE__ */ new Set([
"eq",
"is",
"greaterThan",
"lessThan",
"like",
"between",
"and",
"or"
]);
// eslint-disable-next-line ts/require-await
__toStringCallback = defaultToStringCallback;
// eslint-disable-next-line ts/require-await
__compareCallback = defaultCompareCallback;
__optionsCallback = defaultOptionsCallback;
__newInstanceCallback = defaultNewInstanceArgumentsCallback;
__customImports = [];
__getArgumentsCallback = defaultGetArgumentsCallback;
__inputParsers = /* @__PURE__ */ new Map();
__outputParsers = /* @__PURE__ */ new Map();
__model;
__fieldName;
constructor(..._args) {
}
/**
* Supposed to be used by library maintainers.
*
* When you custom create a field, you might want to take advantage of the builder pattern we already support.
* This let's you create functions that can be chained together to create a new field. It should be used
* alongside the `_setPartialAttributes` method like
*
* @example
* ```ts
* const customBigInt = TextField.overrideType<
* { create: bigint; read: bigint; update: bigint },
* {
* customAttributes: { name: string };
* unique: boolean;
* auto: boolean;
* allowNull: true;
* dbIndex: boolean;
* isPrimaryKey: boolean;
* defaultValue: any;
* typeName: string;
* engineInstance: DatabaseAdapter;
* }
* >({
* typeName: 'CustomBigInt'
* });
*
* const customBuilder = <TParams extends { name: string }>(params: TParams) => {
* const field = customBigInt.new(params);
* return field._setNewBuilderMethods({
* test: <TTest extends { age: number }>(param: TTest) =>
* // This will union the type `string` with what already exists in the field 'create' type
* field._setPartialAttributes<{ create: string }, { create: 'union' }>(param)
* });
* };
*
* // Then your user can use it like:
*
* const field = customBuilder({ name: 'test' }).test({ age: 2 });
* ```
*
* **Important**: `customBuilder` will be used by the end user and you are responsible for documenting it.
*/
_setNewBuilderMethods(functions) {
if (functions === void 0) return this;
const propertiesOfBase = Object.getOwnPropertyNames(Object.getPrototypeOf(functions));
for (const key of propertiesOfBase) {
if (key === "constructor") continue;
this[key] = functions[key].bind(this);
}
return this;
}
/**
* FOR LIBRARY MAINTAINERS ONLY
*
* Focused for library maintainers that want to support a custom field type not supported by palmares.
* This let's them partially update the custom attributes of the field. By default setCustomAttributes
* will override the custom attributes entirely.
*/
_setPartialAttributes() {
return (partialCustomAttributes) => {
if (partialCustomAttributes !== void 0) {
if (this.__customAttributes === void 0) this.__customAttributes = {};
this.__customAttributes = {
...this.__customAttributes,
...partialCustomAttributes
};
}
return this;
};
}
setCustomAttributes(customAttributes) {
this.__customAttributes = customAttributes;
return this;
}
unique(isUnique) {
if (typeof isUnique !== "boolean") isUnique = true;
this.__unique = isUnique;
return this;
}
allowNull(isNull) {
if (typeof isNull !== "boolean") isNull = true;
this.__allowNull = isNull;
return this;
}
/**
* This method is used to create an index on the database for this field.
*/
dbIndex(dbIndex) {
if (typeof dbIndex !== "boolean") dbIndex = true;
this.__dbIndex = dbIndex;
return this;
}
underscored(isUnderscored) {
if (typeof isUnderscored !== "boolean") isUnderscored = true;
this.__underscored = isUnderscored;
return this;
}
primaryKey(isPrimaryKey) {
if (typeof isPrimaryKey !== "boolean") isPrimaryKey = true;
this.__primaryKey = isPrimaryKey;
return this;
}
auto(isAuto) {
if (typeof isAuto !== "boolean") isAuto = true;
this.__isAuto = isAuto;
return this;
}
default(defaultValue) {
this.__defaultValue = defaultValue;
return this;
}
databaseName(databaseName) {
this.__databaseName = databaseName;
return this;
}
/**
* This method can be used to override the type of a field. This is useful for library
* maintainers that want to support the field type but the default type provided by palmares
* is not the one that the user want to use.
*
* @example
* ```ts
* const MyCustomDatabaseAutoField = AutoField.overrideType<{ input: string; output: string }>();
*
* // then the user can use as normal:
*
* const autoField = MyCustomDatabaseAutoField.new();
*
* // now the type inferred for the field will be a string instead of a number.
* ```
*
* ### Note
*
* Your library should provide documentation of the fields that are supported.
*/
static _overrideType(args) {
this.new = (params) => {
const newInstance = new this(params);
newInstance.__customImports = args.customImports || [];
newInstance.__toStringCallback = args.toStringCallback || defaultToStringCallback;
newInstance.__compareCallback = args.compareCallback || defaultCompareCallback;
newInstance.__optionsCallback = args.optionsCallback || defaultOptionsCallback;
newInstance.__newInstanceCallback = args.newInstanceCallback || defaultNewInstanceArgumentsCallback;
newInstance.__typeName = args.typeName;
newInstance.__allowedQueryOperations = /* @__PURE__ */ new Set([
"is",
"eq",
"greaterThan",
"lessThan",
"like",
"between"
]);
newInstance["__customAttributes"] = params;
return newInstance;
};
return this;
}
/**
* This method enables the framework to automatically import the files when generating the migrations.
*
* This is generally useful for custom field types.
*
* @return - Returns a list of packages that we want to import in the migration file.
*/
// eslint-disable-next-line ts/require-await
async __getCustomImports() {
return this["__customImports"];
}
__init(fieldName, model) {
const isAlreadyInitialized = this.__model !== void 0 && typeof this.__fieldName === "string";
if (isAlreadyInitialized) return;
const isUnderscored = (this.__underscored || model.__cachedOptions?.underscored) === true;
this.__fieldName = fieldName;
this.__model = model;
if (this.__primaryKey) model["__primaryKeys"].push(this.__fieldName);
if (isUnderscored) this.__databaseName = import_core.utils.camelCaseToHyphenOrSnakeCase(this.__fieldName);
else this.__databaseName = this.__fieldName;
}
/**
* Gets all of the arguments to pass to the field during migration, translation, etc.
*
* Everything in the field is protected, this way end users don't access the internal implementation.
*/
__getArguments() {
return this.__getArgumentsCallback(this, defaultGetArgumentsCallback);
}
// eslint-disable-next-line ts/require-await
async __toString(engine) {
return this.__toStringCallback(engine, this, defaultToStringCallback, void 0);
}
/**
* Used for comparing one field with the other so we are able to tell if they are different or not.
*
* This is obligatory to add if you create any custom fields.
*
* For custom fields you will call this super method before continuing, we first check if they are the same type.
*
* @param field - The field to compare to.
*
* @return - Returns true if the fields are equal and false otherwise
*/
// eslint-disable-next-line ts/require-await
__compare(engine, field) {
return this.__compareCallback(engine, this, field, defaultCompareCallback);
}
/**
* Used for cloning the field to a new field.
*
* @param oldField - The field to clone. If not provided it will use the current field.
*
* @returns - Returns the cloned field.
*/
__clone(oldField, args) {
const argumentsToPass = oldField.__newInstanceCallback(oldField, defaultNewInstanceArgumentsCallback);
const overridenArguments = args?.newInstanceOverrideCallback?.(argumentsToPass) || argumentsToPass;
const newInstanceOfField = oldField.constructor.new(...Array.isArray(overridenArguments) ? overridenArguments : []);
oldField.__optionsCallback((hiddenAttributeName, getAttributesAttributeName, value) => {
let actualValueToSet = value;
if (getAttributesAttributeName && args?.optionsOverrideCallback?.[getAttributesAttributeName] !== void 0) actualValueToSet = (args?.optionsOverrideCallback)[getAttributesAttributeName](value);
newInstanceOfField[hiddenAttributeName] = actualValueToSet;
}, oldField, defaultOptionsCallback);
return newInstanceOfField;
}
/**
* You should not use this method directly, it is used internally by the framework.
*
* This method is used to create a new instance of the field with the same options as the old field.
*/
static new(..._args) {
return new this(..._args);
}
};
// src/models/fields/boolean.ts
function bool() {
return BooleanField.new();
}
__name(bool, "bool");
var BooleanField = class extends Field {
static {
__name(this, "BooleanField");
}
$$type = "$PBooleanField";
__typeName = "BooleanField";
__allowedQueryOperations = /* @__PURE__ */ new Set([
"and",
"in",
"or",
"eq",
"is"
]);
__inputParsers = /* @__PURE__ */ new Map();
__outputParsers = /* @__PURE__ */ new Map();
/**
* Supposed to be used by library maintainers.
*
* When you custom create a field, you might want to take advantage of the builder pattern we already support.
* This let's you create functions that can be chained together to create a new field. It should be used
* alongside the `_setPartialAttributes` method like
*
* @example
* ```ts
* const customBigInt = TextField._overrideType<
* { create: bigint; read: bigint; update: bigint },
* {
* customAttributes: { name: string };
* unique: boolean;
* auto: boolean;
* allowNull: true;
* dbIndex: boolean;
* isPrimaryKey: boolean;
* defaultValue: any;
* typeName: string;
* engineInstance: DatabaseAdapter;
* }
* >({
* typeName: 'CustomBigInt'
* });
*
* const customBuilder = () => {
* const field = textField.new();
* class Builder {
* test<TTest extends { age: number }>(param: TTest) {
* return field
* ._setPartialAttributes<{ create: TTest }, { create: 'union' }>()(param)
* ._setNewBuilderMethods<Builder>();
* }
* value<const TValue extends string>(value: TValue) {
* return field
* ._setPartialAttributes<{ create: TValue }, { create: 'replace' }>()(value)
* ._setNewBuilderMethods<Builder>();
* }
* }
*
* const builder = new Builder();
* return field._setNewBuilderMethods(builder);
* };
*
* // Then your user can use it like:
*
* const field = customBuilder({ name: 'test' }).test({ age: 2 });
* ```
*
* **Important**: `customBuilder` will be used by the end user and you are responsible for documenting it.
*/
_setNewBuilderMethods(functions) {
if (functions === void 0) return this;
const propertiesOfBase = Object.getOwnPropertyNames(Object.getPrototypeOf(functions));
for (const key of propertiesOfBase) {
if (key === "constructor") continue;
this[key] = functions[key].bind(this);
}
return this;
}
/**
* FOR LIBRARY MAINTAINERS ONLY
*
* Focused for library maintainers that want to support a custom field type not supported by palmares.
* This let's them partially update the custom attributes of the field. By default setCustomAttributes
* will override the custom attributes entirely.
*/
_setPartialAttributes() {
return (partialCustomAttributes) => {
if (partialCustomAttributes !== void 0) {
if (this.__customAttributes === void 0) this.__customAttributes = {};
this.__customAttributes = {
...this.__customAttributes,
...partialCustomAttributes
};
}
return this;
};
}
setCustomAttributes(customAttributes) {
this.__customAttributes = customAttributes;
return this;
}
unique(isUnique) {
return super.unique(isUnique);
}
allowNull(isNull) {
return super.allowNull(isNull);
}
/**
* This method is used to create an index on the database for this field.
*/
dbIndex(isDbIndex) {
return super.dbIndex(isDbIndex);
}
underscored(isUnderscored) {
return super.underscored(isUnderscored);
}
primaryKey(isPrimaryKey) {
return super.primaryKey(isPrimaryKey);
}
auto(isAuto) {
return super.auto(isAuto);
}
default(defaultValue) {
return super.default(defaultValue);
}
databaseName(databaseName) {
return super.databaseName(databaseName);
}
/**
* This method can be used to override the type of a field. This is useful for library
* maintainers that want to support a custom field type not supported by palmares.
*
* ### Note
* Your library should provide documentation of the fields that are supported.
*/
static _overrideType(args) {
return super._overrideType(args);
}
static new(..._args) {
return new this(..._args);
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BooleanField,
bool
});