@typegoose/typegoose
Version:
Define Mongoose models using TypeScript classes
681 lines • 51.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isCachingEnabled = exports.isGlobalCachingEnabled = exports.mapModelOptionsToNaming = exports.toStringNoFail = exports.warnNotMatchingExisting = exports.warnNotCorrectTypeOptions = exports.isConstructor = exports.getType = exports.assertionIsClass = exports.assertion = exports.createArrayFromDimensions = exports.getMergedModelOptions = exports.assignGlobalModelOptions = exports.isNullOrUndefined = exports.warnMixed = exports.isTypeMeantToBeArray = exports.mapOptions = exports.mapArrayOptions = exports.isNotDefined = exports.getName = exports.getRightTarget = exports.mergeSchemaOptions = exports.mergeMetadata = exports.assignMetadata = exports.includesAllVirtualPOP = exports.allVirtualoptions = exports.isWithVirtualPOP = exports.isWithEnumValidate = exports.isWithNumberValidate = exports.isWithStringTransform = exports.isWithStringValidate = exports.getClass = exports.getCachedSchema = exports.isString = exports.isNumber = exports.isObject = exports.isAnRefType = exports.isPrimitive = void 0;
const lodash_1 = require("lodash");
const mongoose = require("mongoose");
const logSettings_1 = require("../logSettings");
const constants_1 = require("./constants");
const data_1 = require("./data");
const errors_1 = require("./errors");
/**
* Returns true, if the type is included in mongoose.Schema.Types
* @param Type The Type to test
* @returns true, if it includes it
*/
function isPrimitive(Type) {
if (typeof Type?.name === 'string') {
// try to match "Type.name" with all the Property Names of "mongoose.Schema.Types"
// (like "String" with "mongoose.Schema.Types.String")
return (Object.getOwnPropertyNames(mongoose.Schema.Types).includes(Type.name) ||
// try to match "Type.name" with all "mongoose.Schema.Types.*.name"
// (like "SchemaString" with "mongoose.Schema.Types.String.name")
Object.values(mongoose.Schema.Types).findIndex((v) => v.name === Type.name) >= 0);
}
return false;
}
exports.isPrimitive = isPrimitive;
/**
* Returns true, if the type is included in mongoose.Schema.Types except the aliases
* @param Type The Type to test
* @returns true, if it includes it
*/
function isAnRefType(Type) {
if (typeof Type?.name === 'string') {
// Note: this is not done "once" because types can be added as custom types
const tmp = Object.getOwnPropertyNames(mongoose.Schema.Types).filter((x) => {
switch (x) {
case 'Oid':
case 'Bool':
case 'Object':
case 'Boolean':
return false;
default:
return true;
}
});
// try to match "Type.name" with all the Property Names of "mongoose.Schema.Types" except the ones with aliases
// (like "String" with "mongoose.Schema.Types.String")
return (tmp.includes(Type.name) ||
// try to match "Type.name" with all "mongoose.Schema.Types.*.name"
// (like "SchemaString" with "mongoose.Schema.Types.String.name")
Object.values(mongoose.Schema.Types).findIndex((v) => v.name === Type.name) >= 0);
}
return false;
}
exports.isAnRefType = isAnRefType;
/**
* Returns true, if it is an Object
* Looks down the prototype chain, unless "once" is set to "true"
* @param Type The Type to test
* @param once Set to not loop down the prototype chain, default "false"
* @returns true, if it is an Object
*/
function isObject(Type, once = false) {
if (typeof Type?.name === 'string') {
let prototype = Type.prototype;
// schemaName is "Mixed", whereas name for ".Types.Mixed" is since mongoose 8.0 "SchemaMixed"
// so use "schemaName" if it exists and use ".name" as a fallback
let name = Type?.schemaName ?? Type.name;
while (name) {
if (name === 'Object' || name === 'Mixed') {
return true;
}
if (once) {
break;
}
prototype = Object.getPrototypeOf(prototype);
name = prototype?.constructor.name;
}
}
return false;
}
exports.isObject = isObject;
/**
* Returns true, if it is an Number
* @param Type The Type to test
* @returns true, if it is an Number
*/
function isNumber(Type) {
const name = Type?.name ?? '';
return name === 'Number' || name === mongoose.Schema.Types.Number.name;
}
exports.isNumber = isNumber;
/**
* Returns true, if it is an String
* @param Type The Type to test
* @returns true, if it is an String
*/
function isString(Type) {
const name = Type?.name ?? '';
return name === 'String' || name === mongoose.Schema.Types.String.name;
}
exports.isString = isString;
/**
* Get or init the Cached Schema
* @param target The Target to get / init the cached schema
* @returns The Schema to use
*/
function getCachedSchema(target) {
let schemaReflectTarget = Reflect.getMetadata(constants_1.DecoratorKeys.CachedSchema, target);
if (isNullOrUndefined(schemaReflectTarget)) {
Reflect.defineMetadata(constants_1.DecoratorKeys.CachedSchema, {}, target);
schemaReflectTarget = Reflect.getMetadata(constants_1.DecoratorKeys.CachedSchema, target);
}
else if (isNullOrUndefined(Reflect.getOwnMetadata(constants_1.DecoratorKeys.CachedSchema, target))) {
// set own metadata and clone object, because otherwise on inheritance it would just modify the base class's object, not its own object
schemaReflectTarget = { ...schemaReflectTarget };
Reflect.defineMetadata(constants_1.DecoratorKeys.CachedSchema, schemaReflectTarget, target);
}
return schemaReflectTarget;
}
exports.getCachedSchema = getCachedSchema;
/**
* Get the Class for a number of inputs
* @param input The Input to fetch the class from
*/
function getClass(input) {
assertion(isGlobalCachingEnabled(), () => new errors_1.CacheDisabledError('getClass'));
if (typeof input === 'string') {
return data_1.constructors.get(input);
}
if (typeof input?.typegooseName === 'string') {
return data_1.constructors.get(input.typegooseName);
}
if (typeof input?.typegooseName === 'function') {
return data_1.constructors.get(input.typegooseName());
}
if (typeof input?.constructor?.modelName === 'string') {
return data_1.constructors.get(input.constructor.modelName);
}
throw new errors_1.ResolveTypegooseNameError(input);
}
exports.getClass = getClass;
/**
* Returns all options found in "options" that are String-validate related
* @param options The raw Options that may contain the wanted options
*/
function isWithStringValidate(options) {
return (0, lodash_1.intersection)(Object.keys(options), ['match', 'minlength', 'maxlength']);
}
exports.isWithStringValidate = isWithStringValidate;
/**
* Returns all options found in "options" that are String-transform related
* @param options The raw Options
*/
function isWithStringTransform(options) {
return (0, lodash_1.intersection)(Object.keys(options), ['lowercase', 'uppercase', 'trim']);
}
exports.isWithStringTransform = isWithStringTransform;
/**
* Returns all options found in "options" that are Number-Validate related
* @param options The raw Options
*/
function isWithNumberValidate(options) {
return (0, lodash_1.intersection)(Object.keys(options), ['min', 'max']);
}
exports.isWithNumberValidate = isWithNumberValidate;
/**
* Returns all options found in "options" that are Enum Related
* @param options The raw Options
*/
function isWithEnumValidate(options) {
return (0, lodash_1.intersection)(Object.keys(options), ['enum']);
}
exports.isWithEnumValidate = isWithEnumValidate;
const virtualOptions = ['localField', 'foreignField'];
/**
* Check if the "options" contain any Virtual-Populate related options (excluding "ref" by it self)
* @param options The raw Options
*/
function isWithVirtualPOP(options) {
return Object.keys(options).some((v) => virtualOptions.includes(v));
}
exports.isWithVirtualPOP = isWithVirtualPOP;
exports.allVirtualoptions = virtualOptions.slice(0); // copy "virtualOptions" array
exports.allVirtualoptions.push('ref');
/**
* Check if all Required options for Virtual-Populate are included in "options"
* @param options The raw Options
*/
function includesAllVirtualPOP(options) {
return exports.allVirtualoptions.every((v) => Object.keys(options).includes(v));
}
exports.includesAllVirtualPOP = includesAllVirtualPOP;
/**
* Merge "value" with existing Metadata and save it to the class
* Difference with "mergeMetadata" is that this one DOES save it to the class
* Overwrites any existing Metadata that is new in "value"
* @param key Metadata key to read from and assign the new value to
* @param value Options to merge with
* @param cl The Class to read and assign the new metadata to
* @internal
*/
function assignMetadata(key, value, cl) {
if (isNullOrUndefined(value)) {
return value;
}
const newValue = mergeMetadata(key, value, cl);
Reflect.defineMetadata(key, newValue, cl);
return newValue;
}
exports.assignMetadata = assignMetadata;
/**
* Merge "value" with existing Metadata
* Difference with "assignMetadata" is that this one DOES NOT save it to the class
* Overwrites any existing Metadata that is new in "value"
* @param key Metadata key to read existing metadata from
* @param value Option to merge with
* @param cl The Class to read the metadata from
* @param getOwn Use "getOwnMetadata" isntead of "getMetadata"
* @returns Returns the merged output, where "value" overwrites existing Metadata values
* @internal
*/
function mergeMetadata(key, value, cl, getOwn = false) {
assertion(typeof key === 'string' && key.length > 0, () => new errors_1.StringLengthExpectedError(1, key, getName(cl), 'key'));
assertionIsClass(cl);
let classMetadata = (getOwn ? Reflect.getOwnMetadata(key, cl) : Reflect.getMetadata(key, cl)) ?? {};
// dont inherit some options if the current class does not have its own metadata
// this is somewhat hacky
if (key === constants_1.DecoratorKeys.ModelOptions && !Reflect.hasOwnMetadata(key, cl) && 'options' in classMetadata) {
// this has to be done, because otherwise it will be deleted on the original
classMetadata = { ...classMetadata };
classMetadata.options = { ...classMetadata.options };
// dont inherit "disableLowerIndexes" because that would otherwise be inherited and so disable all indexes if inherited, not just from where it was set
delete classMetadata?.options?.disableLowerIndexes;
}
// Please don't remove the other values from the function, even when unused - it is made to be clear what is what
return (0, lodash_1.mergeWith)({}, classMetadata, value, (_objValue, srcValue, ckey) => customMerger(ckey, srcValue));
}
exports.mergeMetadata = mergeMetadata;
/**
* Used for lodash customizers (cloneWith, cloneDeepWith, mergeWith)
* @param key the key of the current object
* @param val the value of the object that should get returned for "existingMongoose" & "existingConnection"
*/
function customMerger(key, val) {
if (typeof key !== 'string') {
return undefined;
}
if (/^(existingMongoose|existingConnection)$/.test(key)) {
return val;
}
return undefined;
}
/**
* Merge only schemaOptions from ModelOptions of the class
* @param value The value to use
* @param cl The Class to get the values from
*/
function mergeSchemaOptions(value, cl) {
return mergeMetadata(constants_1.DecoratorKeys.ModelOptions, { schemaOptions: value }, cl).schemaOptions;
}
exports.mergeSchemaOptions = mergeSchemaOptions;
/**
* Tries to return the right target
* if target.constructor.name is "Function", return "target", otherwise "target.constructor"
* @param target The target to determine
*/
function getRightTarget(target) {
return target.constructor?.name === 'Function' ? target : target.constructor;
}
exports.getRightTarget = getRightTarget;
/**
* Get the Class's final name
* (combines all available options to generate a name)
* @param cl The Class to get the name for
* @param overwriteNaming Overwrite naming options used for generating the name
*/
function getName(cl, overwriteNaming) {
// this case (cl being undefined / null) can happen when type casting (or type being "any") happened and wanting to throw a Error (and there using "getName" to help)
// check if input variable is undefined, if it is throw a error (cannot be combined with the error below because of "getRightTarget")
assertion(!isNullOrUndefined(cl), () => new errors_1.NoValidClassError(cl));
const ctor = getRightTarget(cl);
assertion(isConstructor(ctor), () => new errors_1.NoValidClassError(ctor));
const options = Reflect.getMetadata(constants_1.DecoratorKeys.ModelOptions, ctor) ?? {};
const baseName = ctor.name;
const customName = overwriteNaming?.customName ?? options.options?.customName;
if (typeof customName === 'function') {
const name = customName(options);
assertion(typeof name === 'string' && name.length > 0, () => new errors_1.StringLengthExpectedError(1, name, baseName, 'options.customName(function)'));
return name;
}
const automaticName = overwriteNaming?.automaticName ?? options.options?.automaticName;
if (automaticName) {
const suffix = customName ?? overwriteNaming?.schemaCollection ?? options.schemaOptions?.collection;
return !isNullOrUndefined(suffix) ? `${baseName}_${suffix}` : baseName;
}
if (isNullOrUndefined(customName)) {
return baseName;
}
assertion(typeof customName === 'string' && customName.length > 0, () => new errors_1.StringLengthExpectedError(1, customName, baseName, 'options.customName'));
return customName;
}
exports.getName = getName;
/**
* Check if "Type" is a class and if it is already in "schemas"
* @param Type The Type to check
*/
function isNotDefined(Type) {
return (typeof Type === 'function' &&
!isPrimitive(Type) &&
Type !== Object &&
isNullOrUndefined(Reflect.getMetadata(constants_1.DecoratorKeys.CachedSchema, Type)));
}
exports.isNotDefined = isNotDefined;
/**
* Map Options to "inner" & "outer"
* -> inner: means inner of "type: [{here})"
* -> outer: means outer of "type: [{}], here"
*
* Specific to Arrays
* @param rawOptions The raw options
* @param Type The Type of the array
* @param target The Target class
* @param pkey Key of the Property
* @param loggerType Type to use for logging
* @param extraInner Extra Options to Mad explicitly to "inner"
*/
function mapArrayOptions(rawOptions, Type, target, pkey, loggerType, extraInner) {
logSettings_1.logger.debug('mapArrayOptions called');
loggerType = loggerType ?? Type;
if (!(Type instanceof mongoose.Schema)) {
loggerType = Type;
}
const dim = rawOptions.dim; // needed, otherwise it will be included (and not removed) in the returnObject
delete rawOptions.dim;
const mapped = mapOptions(rawOptions, Type, target, pkey, loggerType);
/** The Object that gets returned */
const returnObject = {
...mapped.outer,
type: [
{
type: Type,
...mapped.inner,
...extraInner,
},
],
};
rawOptions.dim = dim; // re-add for "createArrayFromDimensions"
returnObject.type = createArrayFromDimensions(rawOptions, returnObject.type, getName(target), pkey);
if (loggerType) {
logSettings_1.logger.debug('(Array) Final mapped Options for Type "%s"', getName(loggerType), returnObject);
}
return returnObject;
}
exports.mapArrayOptions = mapArrayOptions;
/**
* Map Options to "inner" & "outer"
* @param rawOptions The raw options
* @param Type The Type of the array
* @param target The Target class
* @param pkey Key of the Property
* @param loggerType Type to use for logging
*/
function mapOptions(rawOptions, Type, target, pkey, loggerType) {
logSettings_1.logger.debug('mapOptions called');
loggerType = loggerType ?? Type;
/** The Object that gets returned */
const ret = {
inner: {},
outer: {},
};
// if Type is not a Schema, try to convert js type to mongoose type (Object => Mixed)
if (!(Type instanceof mongoose.Schema)) {
// set the loggerType to the js type
loggerType = Type;
const loggerTypeName = getName(loggerType);
if (loggerTypeName in mongoose.Schema.Types) {
logSettings_1.logger.info('Converting "%s" to mongoose Type', loggerTypeName);
Type = mongoose.Schema.Types[loggerTypeName];
if (Type === mongoose.Schema.Types.Mixed) {
warnMixed(target, pkey);
}
}
}
if (isNullOrUndefined(loggerType)) {
logSettings_1.logger.info('mapOptions loggerType is undefined!');
}
/** The OptionsConstructor to use */
let OptionsCTOR = Type?.prototype?.OptionsConstructor;
if (Type instanceof mongoose.Schema) {
OptionsCTOR = mongoose.Schema.Types.Subdocument.prototype.OptionsConstructor;
}
assertion(!isNullOrUndefined(OptionsCTOR), () => new errors_1.InvalidOptionsConstructorError(getName(target), pkey, loggerType));
const options = Object.assign({}, rawOptions); // for sanity
if (OptionsCTOR.prototype instanceof mongoose.SchemaTypeOptions) {
for (const [key, value] of Object.entries(options)) {
if (Object.getOwnPropertyNames(OptionsCTOR.prototype).includes(key)) {
ret.inner[key] = value;
}
else {
ret.outer[key] = value;
}
}
}
else {
if (loggerType) {
logSettings_1.logger.info('The Type "%s" has a property "OptionsConstructor" but it does not extend "SchemaTypeOptions"', getName(loggerType));
}
ret.outer = options;
}
if (typeof options?.innerOptions === 'object') {
delete ret.outer.innerOptions;
for (const [key, value] of Object.entries(options.innerOptions)) {
ret.inner[key] = value;
}
}
if (typeof options?.outerOptions === 'object') {
delete ret.outer.outerOptions;
for (const [key, value] of Object.entries(options.outerOptions)) {
ret.outer[key] = value;
}
}
if (loggerType) {
logSettings_1.logger.debug('Final mapped Options for Type "%s"', getName(loggerType), ret);
}
return ret;
}
exports.mapOptions = mapOptions;
/**
* Check if the current Type is meant to be a Array
* @param rawOptions The raw options
*/
function isTypeMeantToBeArray(rawOptions) {
// check if the "dim" option exists, if yes the type is meant to be a array in the end
return !isNullOrUndefined(rawOptions) && !isNullOrUndefined(rawOptions.dim) && typeof rawOptions.dim === 'number' && rawOptions.dim > 0;
}
exports.isTypeMeantToBeArray = isTypeMeantToBeArray;
/**
* Warn, Error or Allow if an mixed type is set
* -> this function exists for de-duplication
* @param target Target Class
* @param key Property key
*/
function warnMixed(target, key) {
const name = getName(target);
const modelOptions = Reflect.getMetadata(constants_1.DecoratorKeys.ModelOptions, getRightTarget(target)) ?? {};
const rawOptions = Reflect.getMetadata(constants_1.DecoratorKeys.PropCache, target);
const setSeverity = rawOptions?.get(key)?.options?.allowMixed ?? modelOptions.options?.allowMixed ?? constants_1.Severity.WARN;
logSettings_1.logger.debug(`setSeverity for "${name}.${key}" is "${setSeverity}"`);
switch (setSeverity) {
default:
case constants_1.Severity.WARN:
logSettings_1.logger.warn('Setting "Mixed" for property "%s.%s"\nLook here for how to disable this message: https://typegoose.github.io/typegoose/docs/api/decorators/model-options/#allowmixed', name, key);
break;
case constants_1.Severity.ALLOW:
break;
case constants_1.Severity.ERROR:
throw new TypeError(`Setting "Mixed" is not allowed! (${name}, ${key}) [E017]`);
}
return; // always return, if "allowMixed" is not "ERROR"
}
exports.warnMixed = warnMixed;
/**
* Check if "val" is "null" to "undefined"
* This Function exists because since node 4.0.0 the internal util.is* functions got deprecated
* @param val Any value to test if null or undefined
*/
function isNullOrUndefined(val) {
return val === null || val === undefined;
}
exports.isNullOrUndefined = isNullOrUndefined;
/**
* Assign Global ModelOptions if not already existing
* @param target Target Class
* @returns "true" when it assigned options
*/
function assignGlobalModelOptions(target) {
if (isNullOrUndefined(Reflect.getMetadata(constants_1.DecoratorKeys.ModelOptions, target))) {
logSettings_1.logger.info('Assigning global Schema Options to "%s"', getName(target));
assignMetadata(constants_1.DecoratorKeys.ModelOptions, (0, lodash_1.omit)(data_1.globalOptions, 'globalOptions'), target);
return true;
}
return false;
}
exports.assignGlobalModelOptions = assignGlobalModelOptions;
/**
* Consistently get the "ModelOptions", merged with (the following is the order in which options are applied):
* 1. globalOptions if unset
* 2. decorator ModelOptions
* 3. input "rawOptions"
*
* Note: applies global options to the decorator options if unset, but does not set the final options
* @param rawOptions Options to merge(-overwrite) all previous options
* @param cl The Class to get / set the ModelOptions on
* @param getOwn use "getOwnMetadata" instead of "getMetadata"
* @returns A ModelOptions object
*/
function getMergedModelOptions(rawOptions, cl, getOwn = false) {
const opt = typeof rawOptions === 'object' ? rawOptions : {};
if (assignGlobalModelOptions(cl)) {
opt[constants_1.AlreadyMerged] = false;
}
// dont skip merging if "getOwn" is "true"
const mergedOptions = opt?.[constants_1.AlreadyMerged] && !getOwn ? opt : mergeMetadata(constants_1.DecoratorKeys.ModelOptions, rawOptions, cl, getOwn);
mergedOptions[constants_1.AlreadyMerged] = true;
return mergedOptions;
}
exports.getMergedModelOptions = getMergedModelOptions;
/**
* Loop over "dimensions" and create an array from that
* @param rawOptions baseProp's rawOptions
* @param extra What is actually in the deepest array
* @param name name of the target for better error logging
* @param key key of target-key for better error logging
*/
function createArrayFromDimensions(rawOptions, extra, name, key) {
// dimensions start at 1 (not 0)
const dim = typeof rawOptions.dim === 'number' ? rawOptions.dim : 1;
if (dim < 1) {
throw new RangeError(`"dim" needs to be higher than 0 (${name}.${key}) [E018]`);
}
delete rawOptions.dim; // delete this property to not actually put it as an option
logSettings_1.logger.info('createArrayFromDimensions called with %d dimensions', dim);
let retArray = Array.isArray(extra) ? extra : [extra];
// index starts at 1 because "retArray" is already once wrapped in an array
for (let index = 1; index < dim; index++) {
retArray = [retArray];
}
return retArray;
}
exports.createArrayFromDimensions = createArrayFromDimensions;
/**
* Assert a condition, if "false" throw error
* Note: it is not named "assert" to differentiate between node and jest types
*
* Note: "error" can be a function to not execute the constructor when not needed
* @param cond The Condition to check
* @param error A Custom Error to throw or a function that returns a Error
*/
function assertion(cond, error) {
if (!cond) {
throw typeof error === 'function' ? error() : error ?? new errors_1.AssertionFallbackError();
}
}
exports.assertion = assertion;
/**
* Assert if "val" is an function (constructor for classes)
* @param val Value to test
*/
function assertionIsClass(val) {
assertion(isConstructor(val), () => new errors_1.NoValidClassError(val));
}
exports.assertionIsClass = assertionIsClass;
/**
* Get Type, if input is an arrow-function, execute it and return the result
* @param typeOrFunc Function or Type
* @param returnLastFoundArray Return the last found array (used for something like PropOptions.discriminators)
*/
function getType(typeOrFunc, returnLastFoundArray = false) {
const returnObject = {
type: typeOrFunc,
dim: 0,
};
if (typeof returnObject.type === 'function' && !isConstructor(returnObject.type)) {
returnObject.type = returnObject.type();
}
function getDepth() {
if (returnObject.dim > 100) {
// this is arbitrary, but why would anyone have more than 10 nested arrays anyway?
throw new Error('getDepth recursed too much (dim > 100)');
}
if (Array.isArray(returnObject.type)) {
returnObject.dim++;
if (returnLastFoundArray && !Array.isArray(returnObject.type[0])) {
return;
}
returnObject.type = returnObject.type[0];
getDepth();
}
}
getDepth();
logSettings_1.logger.debug('Final getType: dim: %s, type:', returnObject.dim, returnObject.type);
return returnObject;
}
exports.getType = getType;
/**
* Is the provided input an class with an constructor?
* @param obj The Value to test
*/
function isConstructor(obj) {
return (typeof obj === 'function' && !isNullOrUndefined(obj.prototype?.constructor?.name)
// TODO: maybe change to the following implementation, because it would be more correct, but would involve some refactoring
// if the js environment is spec-compliant, then the following should always work
// /^class\s/.test(Function.prototype.toString.call(obj))
);
}
exports.isConstructor = isConstructor;
// /**
// * Execute util.deprecate or when "process" does not exist use "console.log"
// * (if "process" does not exist, the codes are not cached, and are always logged again)
// * This Function is here to try to make typegoose compatible with the browser (see https://github.com/typegoose/typegoose/issues/33)
// */
// eslint-disable-next-line @typescript-eslint/ban-types
// export function deprecate<T extends Function>(fn: T, message: string, code: string): T {
// if (!isNullOrUndefined(process)) {
// // eslint-disable-next-line @typescript-eslint/no-var-requires
// return require('util').deprecate(fn, message, code);
// }
// console.log(`[${code}] DeprecationWarning: ${message}`);
// return fn;
// }
/**
* Logs an warning if "included > 0" that the options of not the current type are included
* @param name Name of the Class
* @param key Name of the Currently Processed key
* @param type Name of the Expected Type
* @param extra Extra string to be included
* @param included Included Options to be listed
*/
function warnNotCorrectTypeOptions(name, key, type, extra, included) {
// this "if" is in this function to de-duplicate code
if (included.length > 0) {
logSettings_1.logger.warn(`Type of "${name}.${key}" is not ${type}, but includes the following ${extra} options [W001]:\n` + ` [${included.join(', ')}]`);
}
}
exports.warnNotCorrectTypeOptions = warnNotCorrectTypeOptions;
/**
* Logs a warning for Discriminator setting a different "existing*" property than the base
* @param fromName Name of the Base Model
* @param clName Name of the Discriminator's class
* @param property The property defined that does not match
*/
function warnNotMatchingExisting(fromName, clName, property) {
logSettings_1.logger.warn(`Property "${property}" was defined on "${clName}", but is different from discriminator base "${fromName}", which is not supported! [W002]`);
}
exports.warnNotMatchingExisting = warnNotMatchingExisting;
/**
* Try to convert input "value" to a String, without it failing
* @param value The Value to convert to String
* @returns A String, either "value.toString" or a placeholder
*/
function toStringNoFail(value) {
try {
return String(value);
}
catch (_) {
return '(Error: Converting value to String failed)';
}
}
exports.toStringNoFail = toStringNoFail;
/**
* Map options from {@link IModelOptions} to {@link INamingOptions}
* @param options The options to map
* @returns Always a object, contains mapped options from {@link IModelOptions}
*/
function mapModelOptionsToNaming(options) {
const mappedNaming = { ...options?.options }; // this copies more than necessary, but works because most of the options are from there
if (!isNullOrUndefined(options?.schemaOptions?.collection)) {
mappedNaming.schemaCollection = options?.schemaOptions?.collection;
}
return mappedNaming;
}
exports.mapModelOptionsToNaming = mapModelOptionsToNaming;
/**
* Helper function to check if caching is enabled globally
* @returns "true" if caching is enabled or "false" if disabled
*/
function isGlobalCachingEnabled() {
return !(data_1.globalOptions.globalOptions?.disableGlobalCaching === true);
}
exports.isGlobalCachingEnabled = isGlobalCachingEnabled;
/**
* Helper function to check if caching is enabled globally AND by options
* @param opt The caching option (from IModelOptions)
* @returns "true" if caching is enabled or "false" if disabled
*/
function isCachingEnabled(opt) {
return isGlobalCachingEnabled() && !(opt === true);
}
exports.isCachingEnabled = isCachingEnabled;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW50ZXJuYWwvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbUNBQXVEO0FBQ3ZELHFDQUFxQztBQUNyQyxnREFBd0M7QUFpQnhDLDJDQUFxRTtBQUNyRSxpQ0FBcUQ7QUFDckQscUNBT2tCO0FBRWxCOzs7O0dBSUc7QUFDSCxTQUFnQixXQUFXLENBQUMsSUFBUztJQUNuQyxJQUFJLE9BQU8sSUFBSSxFQUFFLElBQUksS0FBSyxRQUFRLEVBQUU7UUFDbEMsa0ZBQWtGO1FBQ2xGLHNEQUFzRDtRQUN0RCxPQUFPLENBQ0wsTUFBTSxDQUFDLG1CQUFtQixDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7WUFDckUsbUVBQW1FO1lBQ25FLGlFQUFpRTtZQUNqRSxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQ2pGLENBQUM7S0FDSDtJQUVELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQWJELGtDQWFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLFdBQVcsQ0FBQyxJQUFTO0lBQ25DLElBQUksT0FBTyxJQUFJLEVBQUUsSUFBSSxLQUFLLFFBQVEsRUFBRTtRQUNsQywyRUFBMkU7UUFDM0UsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLG1CQUFtQixDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7WUFDekUsUUFBUSxDQUFDLEVBQUU7Z0JBQ1QsS0FBSyxLQUFLLENBQUM7Z0JBQ1gsS0FBSyxNQUFN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