typed-wx-api
Version:
Typed Wechat API
1,224 lines • 110 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
const assert = require("assert");
const _ = require("lodash");
const Dottie = require("dottie");
const Utils = require("./utils");
const { logger } = require("./utils/logger");
const BelongsTo = require("./associations/belongs-to");
const BelongsToMany = require("./associations/belongs-to-many");
const InstanceValidator = require("./instance-validator");
const QueryTypes = require("./query-types");
const sequelizeErrors = require("./errors");
const Association = require("./associations/base");
const HasMany = require("./associations/has-many");
const DataTypes = require("./data-types");
const Hooks = require("./hooks");
const associationsMixin = require("./associations/mixin");
const Op = require("./operators");
const { noDoubleNestedGroup } = require("./utils/deprecations");
const validQueryKeywords = /* @__PURE__ */ new Set([
"where",
"attributes",
"paranoid",
"include",
"order",
"limit",
"offset",
"transaction",
"lock",
"raw",
"logging",
"benchmark",
"having",
"searchPath",
"rejectOnEmpty",
"plain",
"scope",
"group",
"through",
"defaults",
"distinct",
"primary",
"exception",
"type",
"hooks",
"force",
"name"
]);
const nonCascadingOptions = ["include", "attributes", "originalAttributes", "order", "where", "limit", "offset", "plain", "group", "having"];
class Model {
static get queryInterface() {
return this.sequelize.getQueryInterface();
}
static get queryGenerator() {
return this.queryInterface.queryGenerator;
}
get sequelize() {
return this.constructor.sequelize;
}
constructor(values = {}, options = {}) {
if (!this.constructor._overwrittenAttributesChecked) {
this.constructor._overwrittenAttributesChecked = true;
setTimeout(() => {
const overwrittenAttributes = [];
for (const key of Object.keys(this.constructor._attributeManipulation)) {
if (Object.prototype.hasOwnProperty.call(this, key)) {
overwrittenAttributes.push(key);
}
}
if (overwrittenAttributes.length > 0) {
logger.warn(`Model ${JSON.stringify(this.constructor.name)} is declaring public class fields for attribute(s): ${overwrittenAttributes.map((attr) => JSON.stringify(attr)).join(", ")}.
These class fields are shadowing Sequelize's attribute getters & setters.
See https://sequelize.org/main/manual/model-basics.html#caveat-with-public-class-fields`);
}
}, 0);
}
options = __spreadValues({
isNewRecord: true,
_schema: this.constructor._schema,
_schemaDelimiter: this.constructor._schemaDelimiter
}, options);
if (options.attributes) {
options.attributes = options.attributes.map((attribute) => Array.isArray(attribute) ? attribute[1] : attribute);
}
if (!options.includeValidated) {
this.constructor._conformIncludes(options, this.constructor);
if (options.include) {
this.constructor._expandIncludeAll(options);
this.constructor._validateIncludedElements(options);
}
}
this.dataValues = {};
this._previousDataValues = {};
this.uniqno = 1;
this._changed = /* @__PURE__ */ new Set();
this._options = options;
this.isNewRecord = options.isNewRecord;
this._initValues(values, options);
}
_initValues(values, options) {
let defaults;
let key;
values = __spreadValues({}, values);
if (options.isNewRecord) {
defaults = {};
if (this.constructor._hasDefaultValues) {
defaults = _.mapValues(this.constructor._defaultValues, (valueFn) => {
const value = valueFn();
return value && value instanceof Utils.SequelizeMethod ? value : _.cloneDeep(value);
});
}
if (this.constructor.primaryKeyAttributes.length) {
this.constructor.primaryKeyAttributes.forEach((primaryKeyAttribute) => {
if (!Object.prototype.hasOwnProperty.call(defaults, primaryKeyAttribute)) {
defaults[primaryKeyAttribute] = null;
}
});
}
if (this.constructor._timestampAttributes.createdAt && defaults[this.constructor._timestampAttributes.createdAt]) {
this.dataValues[this.constructor._timestampAttributes.createdAt] = Utils.toDefaultValue(defaults[this.constructor._timestampAttributes.createdAt], this.sequelize.options.dialect);
delete defaults[this.constructor._timestampAttributes.createdAt];
}
if (this.constructor._timestampAttributes.updatedAt && defaults[this.constructor._timestampAttributes.updatedAt]) {
this.dataValues[this.constructor._timestampAttributes.updatedAt] = Utils.toDefaultValue(defaults[this.constructor._timestampAttributes.updatedAt], this.sequelize.options.dialect);
delete defaults[this.constructor._timestampAttributes.updatedAt];
}
if (this.constructor._timestampAttributes.deletedAt && defaults[this.constructor._timestampAttributes.deletedAt]) {
this.dataValues[this.constructor._timestampAttributes.deletedAt] = Utils.toDefaultValue(defaults[this.constructor._timestampAttributes.deletedAt], this.sequelize.options.dialect);
delete defaults[this.constructor._timestampAttributes.deletedAt];
}
for (key in defaults) {
if (values[key] === void 0) {
this.set(key, Utils.toDefaultValue(defaults[key], this.sequelize.options.dialect), { raw: true });
delete values[key];
}
}
}
this.set(values, options);
}
static _paranoidClause(model, options = {}) {
if (options.include) {
for (const include of options.include) {
this._paranoidClause(include.model, include);
}
}
if (_.get(options, "groupedLimit.on.options.paranoid")) {
const throughModel = _.get(options, "groupedLimit.on.through.model");
if (throughModel) {
options.groupedLimit.through = this._paranoidClause(throughModel, options.groupedLimit.through);
}
}
if (!model.options.timestamps || !model.options.paranoid || options.paranoid === false) {
return options;
}
const deletedAtCol = model._timestampAttributes.deletedAt;
const deletedAtAttribute = model.rawAttributes[deletedAtCol];
const deletedAtObject = {};
let deletedAtDefaultValue = Object.prototype.hasOwnProperty.call(deletedAtAttribute, "defaultValue") ? deletedAtAttribute.defaultValue : null;
deletedAtDefaultValue = deletedAtDefaultValue || {
[Op.eq]: null
};
deletedAtObject[deletedAtAttribute.field || deletedAtCol] = deletedAtDefaultValue;
if (Utils.isWhereEmpty(options.where)) {
options.where = deletedAtObject;
} else {
options.where = { [Op.and]: [deletedAtObject, options.where] };
}
return options;
}
static _addDefaultAttributes() {
const tail = {};
let head = {};
if (!_.some(this.rawAttributes, "primaryKey")) {
if ("id" in this.rawAttributes) {
throw new Error(`A column called 'id' was added to the attributes of '${this.tableName}' but not marked with 'primaryKey: true'`);
}
head = {
id: {
type: new DataTypes.INTEGER(),
allowNull: false,
primaryKey: true,
autoIncrement: true,
_autoGenerated: true
}
};
}
if (this._timestampAttributes.createdAt) {
tail[this._timestampAttributes.createdAt] = {
type: DataTypes.DATE,
allowNull: false,
_autoGenerated: true
};
}
if (this._timestampAttributes.updatedAt) {
tail[this._timestampAttributes.updatedAt] = {
type: DataTypes.DATE,
allowNull: false,
_autoGenerated: true
};
}
if (this._timestampAttributes.deletedAt) {
tail[this._timestampAttributes.deletedAt] = {
type: DataTypes.DATE,
_autoGenerated: true
};
}
if (this._versionAttribute) {
tail[this._versionAttribute] = {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
_autoGenerated: true
};
}
const newRawAttributes = __spreadValues(__spreadValues({}, head), this.rawAttributes);
_.each(tail, (value, attr) => {
if (newRawAttributes[attr] === void 0) {
newRawAttributes[attr] = value;
}
});
this.rawAttributes = newRawAttributes;
if (!Object.keys(this.primaryKeys).length) {
this.primaryKeys.id = this.rawAttributes.id;
}
}
static getAttributes() {
return this.rawAttributes;
}
static _findAutoIncrementAttribute() {
this.autoIncrementAttribute = null;
for (const name in this.rawAttributes) {
if (Object.prototype.hasOwnProperty.call(this.rawAttributes, name)) {
const definition = this.rawAttributes[name];
if (definition && definition.autoIncrement) {
if (this.autoIncrementAttribute) {
throw new Error("Invalid Instance definition. Only one autoincrement field allowed.");
}
this.autoIncrementAttribute = name;
}
}
}
}
static _conformIncludes(options, self) {
if (!options.include)
return;
if (!Array.isArray(options.include)) {
options.include = [options.include];
} else if (!options.include.length) {
delete options.include;
return;
}
options.include = options.include.map((include) => this._conformInclude(include, self));
}
static _transformStringAssociation(include, self) {
if (self && typeof include === "string") {
if (!Object.prototype.hasOwnProperty.call(self.associations, include)) {
throw new Error(`Association with alias "${include}" does not exist on ${self.name}`);
}
return self.associations[include];
}
return include;
}
static _conformInclude(include, self) {
if (include) {
let model;
if (include._pseudo)
return include;
include = this._transformStringAssociation(include, self);
if (include instanceof Association) {
if (self && include.target.name === self.name) {
model = include.source;
} else {
model = include.target;
}
return { model, association: include, as: include.as };
}
if (include.prototype && include.prototype instanceof Model) {
return { model: include };
}
if (_.isPlainObject(include)) {
if (include.association) {
include.association = this._transformStringAssociation(include.association, self);
if (self && include.association.target.name === self.name) {
model = include.association.source;
} else {
model = include.association.target;
}
if (!include.model)
include.model = model;
if (!include.as)
include.as = include.association.as;
this._conformIncludes(include, model);
return include;
}
if (include.model) {
this._conformIncludes(include, include.model);
return include;
}
if (include.all) {
this._conformIncludes(include);
return include;
}
}
}
throw new Error("Include unexpected. Element has to be either a Model, an Association or an object.");
}
static _expandIncludeAllElement(includes, include) {
let all = include.all;
delete include.all;
if (all !== true) {
if (!Array.isArray(all)) {
all = [all];
}
const validTypes = {
BelongsTo: true,
HasOne: true,
HasMany: true,
One: ["BelongsTo", "HasOne"],
Has: ["HasOne", "HasMany"],
Many: ["HasMany"]
};
for (let i = 0; i < all.length; i++) {
const type = all[i];
if (type === "All") {
all = true;
break;
}
const types = validTypes[type];
if (!types) {
throw new sequelizeErrors.EagerLoadingError(`include all '${type}' is not valid - must be BelongsTo, HasOne, HasMany, One, Has, Many or All`);
}
if (types !== true) {
all.splice(i, 1);
i--;
for (let j = 0; j < types.length; j++) {
if (!all.includes(types[j])) {
all.unshift(types[j]);
i++;
}
}
}
}
}
const nested = include.nested;
if (nested) {
delete include.nested;
if (!include.include) {
include.include = [];
} else if (!Array.isArray(include.include)) {
include.include = [include.include];
}
}
const used = [];
(function addAllIncludes(parent, includes2) {
_.forEach(parent.associations, (association) => {
if (all !== true && !all.includes(association.associationType)) {
return;
}
const model = association.target;
const as = association.options.as;
const predicate = { model };
if (as) {
predicate.as = as;
}
if (_.some(includes2, predicate)) {
return;
}
if (nested && used.includes(model)) {
return;
}
used.push(parent);
const thisInclude = Utils.cloneDeep(include);
thisInclude.model = model;
if (as) {
thisInclude.as = as;
}
includes2.push(thisInclude);
if (nested) {
addAllIncludes(model, thisInclude.include);
if (thisInclude.include.length === 0)
delete thisInclude.include;
}
});
used.pop();
})(this, includes);
}
static _validateIncludedElements(options, tableNames) {
if (!options.model)
options.model = this;
tableNames = tableNames || {};
options.includeNames = [];
options.includeMap = {};
options.hasSingleAssociation = false;
options.hasMultiAssociation = false;
if (!options.parent) {
options.topModel = options.model;
options.topLimit = options.limit;
}
options.include = options.include.map((include) => {
include = this._conformInclude(include);
include.parent = options;
include.topLimit = options.topLimit;
this._validateIncludedElement.call(options.model, include, tableNames, options);
if (include.duplicating === void 0) {
include.duplicating = include.association.isMultiAssociation;
}
include.hasDuplicating = include.hasDuplicating || include.duplicating;
include.hasRequired = include.hasRequired || include.required;
options.hasDuplicating = options.hasDuplicating || include.hasDuplicating;
options.hasRequired = options.hasRequired || include.required;
options.hasWhere = options.hasWhere || include.hasWhere || !!include.where;
return include;
});
for (const include of options.include) {
include.hasParentWhere = options.hasParentWhere || !!options.where;
include.hasParentRequired = options.hasParentRequired || !!options.required;
if (include.subQuery !== false && options.hasDuplicating && options.topLimit) {
if (include.duplicating) {
include.subQuery = include.subQuery || false;
include.subQueryFilter = include.hasRequired;
} else {
include.subQuery = include.hasRequired;
include.subQueryFilter = false;
}
} else {
include.subQuery = include.subQuery || false;
if (include.duplicating) {
include.subQueryFilter = include.subQuery;
} else {
include.subQueryFilter = false;
include.subQuery = include.subQuery || include.hasParentRequired && include.hasRequired && !include.separate;
}
}
options.includeMap[include.as] = include;
options.includeNames.push(include.as);
if (options.topModel === options.model && options.subQuery === void 0 && options.topLimit) {
if (include.subQuery) {
options.subQuery = include.subQuery;
} else if (include.hasDuplicating) {
options.subQuery = true;
}
}
options.hasIncludeWhere = options.hasIncludeWhere || include.hasIncludeWhere || !!include.where;
options.hasIncludeRequired = options.hasIncludeRequired || include.hasIncludeRequired || !!include.required;
if (include.association.isMultiAssociation || include.hasMultiAssociation) {
options.hasMultiAssociation = true;
}
if (include.association.isSingleAssociation || include.hasSingleAssociation) {
options.hasSingleAssociation = true;
}
}
if (options.topModel === options.model && options.subQuery === void 0) {
options.subQuery = false;
}
return options;
}
static _validateIncludedElement(include, tableNames, options) {
tableNames[include.model.getTableName()] = true;
if (include.attributes && !options.raw) {
include.model._expandAttributes(include);
include.originalAttributes = include.model._injectDependentVirtualAttributes(include.attributes);
include = Utils.mapFinderOptions(include, include.model);
if (include.attributes.length) {
_.each(include.model.primaryKeys, (attr, key) => {
if (!include.attributes.some((includeAttr) => {
if (attr.field !== key) {
return Array.isArray(includeAttr) && includeAttr[0] === attr.field && includeAttr[1] === key;
}
return includeAttr === key;
})) {
include.attributes.unshift(key);
}
});
}
} else {
include = Utils.mapFinderOptions(include, include.model);
}
if (include._pseudo) {
if (!include.attributes) {
include.attributes = Object.keys(include.model.tableAttributes);
}
return Utils.mapFinderOptions(include, include.model);
}
const association = include.association || this._getIncludedAssociation(include.model, include.as);
include.association = association;
include.as = association.as;
if (include.association.through && Object(include.association.through.model) === include.association.through.model) {
if (!include.include)
include.include = [];
const through = include.association.through;
include.through = _.defaults(include.through || {}, {
model: through.model,
as: through.model.name,
association: {
isSingleAssociation: true
},
_pseudo: true,
parent: include
});
if (through.scope) {
include.through.where = include.through.where ? { [Op.and]: [include.through.where, through.scope] } : through.scope;
}
include.include.push(include.through);
tableNames[through.tableName] = true;
}
let model;
if (include.model.scoped === true) {
model = include.model;
} else {
model = include.association.target.name === include.model.name ? include.association.target : include.association.source;
}
model._injectScope(include);
if (!include.attributes) {
include.attributes = Object.keys(include.model.tableAttributes);
}
include = Utils.mapFinderOptions(include, include.model);
if (include.required === void 0) {
include.required = !!include.where;
}
if (include.association.scope) {
include.where = include.where ? { [Op.and]: [include.where, include.association.scope] } : include.association.scope;
}
if (include.limit && include.separate === void 0) {
include.separate = true;
}
if (include.separate === true) {
if (!(include.association instanceof HasMany)) {
throw new Error("Only HasMany associations support include.separate");
}
include.duplicating = false;
if (options.attributes && options.attributes.length && !_.flattenDepth(options.attributes, 2).includes(association.sourceKey)) {
options.attributes.push(association.sourceKey);
}
if (include.attributes && include.attributes.length && !_.flattenDepth(include.attributes, 2).includes(association.foreignKey)) {
include.attributes.push(association.foreignKey);
}
}
if (Object.prototype.hasOwnProperty.call(include, "include")) {
this._validateIncludedElements.call(include.model, include, tableNames);
}
return include;
}
static _getIncludedAssociation(targetModel, targetAlias) {
const associations = this.getAssociations(targetModel);
let association = null;
if (associations.length === 0) {
throw new sequelizeErrors.EagerLoadingError(`${targetModel.name} is not associated to ${this.name}!`);
}
if (associations.length === 1) {
association = this.getAssociationForAlias(targetModel, targetAlias);
if (association) {
return association;
}
if (targetAlias) {
const existingAliases = this.getAssociations(targetModel).map((association2) => association2.as);
throw new sequelizeErrors.EagerLoadingError(`${targetModel.name} is associated to ${this.name} using an alias. You've included an alias (${targetAlias}), but it does not match the alias(es) defined in your association (${existingAliases.join(", ")}).`);
}
throw new sequelizeErrors.EagerLoadingError(`${targetModel.name} is associated to ${this.name} using an alias. You must use the 'as' keyword to specify the alias within your include statement.`);
}
association = this.getAssociationForAlias(targetModel, targetAlias);
if (!association) {
throw new sequelizeErrors.EagerLoadingError(`${targetModel.name} is associated to ${this.name} multiple times. To identify the correct association, you must use the 'as' keyword to specify the alias of the association you want to include.`);
}
return association;
}
static _expandIncludeAll(options) {
const includes = options.include;
if (!includes) {
return;
}
for (let index = 0; index < includes.length; index++) {
const include = includes[index];
if (include.all) {
includes.splice(index, 1);
index--;
this._expandIncludeAllElement(includes, include);
}
}
includes.forEach((include) => {
this._expandIncludeAll.call(include.model, include);
});
}
static _conformIndex(index) {
if (!index.fields) {
throw new Error('Missing "fields" property for index definition');
}
index = _.defaults(index, {
type: "",
parser: null
});
if (index.type && index.type.toLowerCase() === "unique") {
index.unique = true;
delete index.type;
}
return index;
}
static _uniqIncludes(options) {
if (!options.include)
return;
options.include = _(options.include).groupBy((include) => `${include.model && include.model.name}-${include.as}`).map((includes) => this._assignOptions(...includes)).value();
}
static _baseMerge(...args) {
_.assignWith(...args);
this._conformIncludes(args[0], this);
this._uniqIncludes(args[0]);
return args[0];
}
static _mergeFunction(objValue, srcValue, key) {
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
return _.union(objValue, srcValue);
}
if (["where", "having"].includes(key)) {
if (this.options && this.options.whereMergeStrategy === "and") {
return combineWheresWithAnd(objValue, srcValue);
}
if (srcValue instanceof Utils.SequelizeMethod) {
srcValue = { [Op.and]: srcValue };
}
if (_.isPlainObject(objValue) && _.isPlainObject(srcValue)) {
return Object.assign(objValue, srcValue);
}
} else if (key === "attributes" && _.isPlainObject(objValue) && _.isPlainObject(srcValue)) {
return _.assignWith(objValue, srcValue, (objValue2, srcValue2) => {
if (Array.isArray(objValue2) && Array.isArray(srcValue2)) {
return _.union(objValue2, srcValue2);
}
});
}
if (srcValue) {
return Utils.cloneDeep(srcValue, true);
}
return srcValue === void 0 ? objValue : srcValue;
}
static _assignOptions(...args) {
return this._baseMerge(...args, this._mergeFunction.bind(this));
}
static _defaultsOptions(target, opts) {
return this._baseMerge(target, opts, (srcValue, objValue, key) => {
return this._mergeFunction(objValue, srcValue, key);
});
}
static init(attributes, options = {}) {
if (!options.sequelize) {
throw new Error("No Sequelize instance passed");
}
this.sequelize = options.sequelize;
const globalOptions = this.sequelize.options;
options = Utils.merge(_.cloneDeep(globalOptions.define), options);
if (!options.modelName) {
options.modelName = this.name;
}
options = Utils.merge({
name: {
plural: Utils.pluralize(options.modelName),
singular: Utils.singularize(options.modelName)
},
indexes: [],
omitNull: globalOptions.omitNull,
schema: globalOptions.schema
}, options);
this.sequelize.runHooks("beforeDefine", attributes, options);
if (options.modelName !== this.name) {
Object.defineProperty(this, "name", { value: options.modelName });
}
delete options.modelName;
this.options = __spreadValues({
timestamps: true,
validate: {},
freezeTableName: false,
underscored: false,
paranoid: false,
rejectOnEmpty: false,
whereCollection: null,
schema: null,
schemaDelimiter: "",
defaultScope: {},
scopes: {},
indexes: [],
whereMergeStrategy: "overwrite"
}, options);
if (this.sequelize.isDefined(this.name)) {
this.sequelize.modelManager.removeModel(this.sequelize.modelManager.getModel(this.name));
}
this.associations = {};
this._setupHooks(options.hooks);
this.underscored = this.options.underscored;
if (!this.options.tableName) {
this.tableName = this.options.freezeTableName ? this.name : Utils.underscoredIf(Utils.pluralize(this.name), this.underscored);
} else {
this.tableName = this.options.tableName;
}
this._schema = this.options.schema;
this._schemaDelimiter = this.options.schemaDelimiter;
_.each(options.validate, (validator, validatorType) => {
if (Object.prototype.hasOwnProperty.call(attributes, validatorType)) {
throw new Error(`A model validator function must not have the same name as a field. Model: ${this.name}, field/validation name: ${validatorType}`);
}
if (typeof validator !== "function") {
throw new Error(`Members of the validate option must be functions. Model: ${this.name}, error with validate member ${validatorType}`);
}
});
if (!_.includes(["and", "overwrite"], this.options && this.options.whereMergeStrategy)) {
throw new Error(`Invalid value ${this.options && this.options.whereMergeStrategy} for whereMergeStrategy. Allowed values are 'and' and 'overwrite'.`);
}
this.rawAttributes = _.mapValues(attributes, (attribute, name) => {
attribute = this.sequelize.normalizeAttribute(attribute);
if (attribute.type === void 0) {
throw new Error(`Unrecognized datatype for attribute "${this.name}.${name}"`);
}
if (attribute.allowNull !== false && _.get(attribute, "validate.notNull")) {
throw new Error(`Invalid definition for "${this.name}.${name}", "notNull" validator is only allowed with "allowNull:false"`);
}
if (_.get(attribute, "references.model.prototype") instanceof Model) {
attribute.references.model = attribute.references.model.getTableName();
}
return attribute;
});
const tableName = this.getTableName();
this._indexes = this.options.indexes.map((index) => Utils.nameIndex(this._conformIndex(index), tableName));
this.primaryKeys = {};
this._readOnlyAttributes = /* @__PURE__ */ new Set();
this._timestampAttributes = {};
if (this.options.timestamps) {
for (const key of ["createdAt", "updatedAt", "deletedAt"]) {
if (!["undefined", "string", "boolean"].includes(typeof this.options[key])) {
throw new Error(`Value for "${key}" option must be a string or a boolean, got ${typeof this.options[key]}`);
}
if (this.options[key] === "") {
throw new Error(`Value for "${key}" option cannot be an empty string`);
}
}
if (this.options.createdAt !== false) {
this._timestampAttributes.createdAt = typeof this.options.createdAt === "string" ? this.options.createdAt : "createdAt";
this._readOnlyAttributes.add(this._timestampAttributes.createdAt);
}
if (this.options.updatedAt !== false) {
this._timestampAttributes.updatedAt = typeof this.options.updatedAt === "string" ? this.options.updatedAt : "updatedAt";
this._readOnlyAttributes.add(this._timestampAttributes.updatedAt);
}
if (this.options.paranoid && this.options.deletedAt !== false) {
this._timestampAttributes.deletedAt = typeof this.options.deletedAt === "string" ? this.options.deletedAt : "deletedAt";
this._readOnlyAttributes.add(this._timestampAttributes.deletedAt);
}
}
if (this.options.version) {
this._versionAttribute = typeof this.options.version === "string" ? this.options.version : "version";
this._readOnlyAttributes.add(this._versionAttribute);
}
this._hasReadOnlyAttributes = this._readOnlyAttributes.size > 0;
this._addDefaultAttributes();
this.refreshAttributes();
this._findAutoIncrementAttribute();
this._scope = this.options.defaultScope;
this._scopeNames = ["defaultScope"];
this.sequelize.modelManager.addModel(this);
this.sequelize.runHooks("afterDefine", this);
return this;
}
static refreshAttributes() {
const attributeManipulation = {};
this.prototype._customGetters = {};
this.prototype._customSetters = {};
["get", "set"].forEach((type) => {
const opt = `${type}terMethods`;
const funcs = __spreadValues({}, this.options[opt]);
const _custom = type === "get" ? this.prototype._customGetters : this.prototype._customSetters;
_.each(funcs, (method, attribute) => {
_custom[attribute] = method;
if (type === "get") {
funcs[attribute] = function() {
return this.get(attribute);
};
}
if (type === "set") {
funcs[attribute] = function(value) {
return this.set(attribute, value);
};
}
});
_.each(this.rawAttributes, (options, attribute) => {
if (Object.prototype.hasOwnProperty.call(options, type)) {
_custom[attribute] = options[type];
}
if (type === "get") {
funcs[attribute] = function() {
return this.get(attribute);
};
}
if (type === "set") {
funcs[attribute] = function(value) {
return this.set(attribute, value);
};
}
});
_.each(funcs, (fct, name) => {
if (!attributeManipulation[name]) {
attributeManipulation[name] = {
configurable: true
};
}
attributeManipulation[name][type] = fct;
});
});
this._dataTypeChanges = {};
this._dataTypeSanitizers = {};
this._hasBooleanAttributes = false;
this._hasDateAttributes = false;
this._jsonAttributes = /* @__PURE__ */ new Set();
this._virtualAttributes = /* @__PURE__ */ new Set();
this._defaultValues = {};
this.prototype.validators = {};
this.fieldRawAttributesMap = {};
this.primaryKeys = {};
this.uniqueKeys = {};
_.each(this.rawAttributes, (definition, name) => {
definition.type = this.sequelize.normalizeDataType(definition.type);
definition.Model = this;
definition.fieldName = name;
definition._modelAttribute = true;
if (definition.field === void 0) {
definition.field = Utils.underscoredIf(name, this.underscored);
}
if (definition.primaryKey === true) {
this.primaryKeys[name] = definition;
}
this.fieldRawAttributesMap[definition.field] = definition;
if (definition.type._sanitize) {
this._dataTypeSanitizers[name] = definition.type._sanitize;
}
if (definition.type._isChanged) {
this._dataTypeChanges[name] = definition.type._isChanged;
}
if (definition.type instanceof DataTypes.BOOLEAN) {
this._hasBooleanAttributes = true;
} else if (definition.type instanceof DataTypes.DATE || definition.type instanceof DataTypes.DATEONLY) {
this._hasDateAttributes = true;
} else if (definition.type instanceof DataTypes.JSON) {
this._jsonAttributes.add(name);
} else if (definition.type instanceof DataTypes.VIRTUAL) {
this._virtualAttributes.add(name);
}
if (Object.prototype.hasOwnProperty.call(definition, "defaultValue")) {
this._defaultValues[name] = () => Utils.toDefaultValue(definition.defaultValue, this.sequelize.options.dialect);
}
if (Object.prototype.hasOwnProperty.call(definition, "unique") && definition.unique) {
let idxName;
if (typeof definition.unique === "object" && Object.prototype.hasOwnProperty.call(definition.unique, "name")) {
idxName = definition.unique.name;
} else if (typeof definition.unique === "string") {
idxName = definition.unique;
} else {
idxName = `${this.tableName}_${name}_unique`;
}
const idx = this.uniqueKeys[idxName] || { fields: [] };
idx.fields.push(definition.field);
idx.msg = idx.msg || definition.unique.msg || null;
idx.name = idxName || false;
idx.column = name;
idx.customIndex = definition.unique !== true;
this.uniqueKeys[idxName] = idx;
}
if (Object.prototype.hasOwnProperty.call(definition, "validate")) {
this.prototype.validators[name] = definition.validate;
}
if (definition.index === true && definition.type instanceof DataTypes.JSONB) {
this._indexes.push(Utils.nameIndex(this._conformIndex({
fields: [definition.field || name],
using: "gin"
}), this.getTableName()));
delete definition.index;
}
});
this.fieldAttributeMap = _.reduce(this.fieldRawAttributesMap, (map, value, key) => {
if (key !== value.fieldName) {
map[key] = value.fieldName;
}
return map;
}, {});
this._hasJsonAttributes = !!this._jsonAttributes.size;
this._hasVirtualAttributes = !!this._virtualAttributes.size;
this._hasDefaultValues = !_.isEmpty(this._defaultValues);
this.tableAttributes = _.omitBy(this.rawAttributes, (_a, key) => this._virtualAttributes.has(key));
this.prototype._hasCustomGetters = Object.keys(this.prototype._customGetters).length;
this.prototype._hasCustomSetters = Object.keys(this.prototype._customSetters).length;
for (const key of Object.keys(attributeManipulation)) {
if (Object.prototype.hasOwnProperty.call(Model.prototype, key)) {
this.sequelize.log(`Not overriding built-in method from model attribute: ${key}`);
continue;
}
Object.defineProperty(this.prototype, key, attributeManipulation[key]);
}
this.prototype.rawAttributes = this.rawAttributes;
this.prototype._isAttribute = (key) => Object.prototype.hasOwnProperty.call(this.prototype.rawAttributes, key);
this.primaryKeyAttributes = Object.keys(this.primaryKeys);
this.primaryKeyAttribute = this.primaryKeyAttributes[0];
if (this.primaryKeyAttribute) {
this.primaryKeyField = this.rawAttributes[this.primaryKeyAttribute].field || this.primaryKeyAttribute;
}
this._hasPrimaryKeys = this.primaryKeyAttributes.length > 0;
this._isPrimaryKey = (key) => this.primaryKeyAttributes.includes(key);
this._attributeManipulation = attributeManipulation;
}
static removeAttribute(attribute) {
delete this.rawAttributes[attribute];
this.refreshAttributes();
}
static async sync(options) {
options = __spreadValues(__spreadValues({}, this.options), options);
options.hooks = options.hooks === void 0 ? true : !!options.hooks;
const attributes = this.tableAttributes;
const rawAttributes = this.fieldRawAttributesMap;
if (options.hooks) {
await this.runHooks("beforeSync", options);
}
const tableName = this.getTableName(options);
let tableExists;
if (options.force) {
await this.drop(options);
tableExists = false;
} else {
tableExists = await this.queryInterface.tableExists(tableName, options);
}
if (!tableExists) {
await this.queryInterface.createTable(tableName, attributes, options, this);
} else {
await this.queryInterface.ensureEnums(tableName, attributes, options, this);
}
if (tableExists && options.alter) {
const tableInfos = await Promise.all([
this.queryInterface.describeTable(tableName, options),
this.queryInterface.getForeignKeyReferencesForTable(tableName, options)
]);
const columns = tableInfos[0];
const foreignKeyReferences = tableInfos[1];
const removedConstraints = {};
for (const columnName in attributes) {
if (!Object.prototype.hasOwnProperty.call(attributes, columnName))
continue;
if (!columns[columnName] && !columns[attributes[columnName].field]) {
await this.queryInterface.addColumn(tableName, attributes[columnName].field || columnName, attributes[columnName], options);
}
}
if (options.alter === true || typeof options.alter === "object" && options.alter.drop !== false) {
for (const columnName in columns) {
if (!Object.prototype.hasOwnProperty.call(columns, columnName))
continue;
const currentAttribute = rawAttributes[columnName];
if (!currentAttribute) {
await this.queryInterface.removeColumn(tableName, columnName, options);
continue;
}
if (currentAttribute.primaryKey)
continue;
const references = currentAttribute.references;
if (currentAttribute.references) {
const database = this.sequelize.config.database;
const schema = this.sequelize.config.schema;
for (const foreignKeyReference of foreignKeyReferences) {
const constraintName = foreignKeyReference.constraintName;
if (!!constraintName && foreignKeyReference.tableCatalog === database && (schema ? foreignKeyReference.tableSchema === schema : true) && foreignKeyReference.referencedTableName === references.model && foreignKeyReference.referencedColumnName === references.key && (schema ? foreignKeyReference.referencedTableSchema === schema : true) && !removedConstraints[constraintName]) {
await this.queryInterface.removeConstraint(tableName, constraintName, options);
removedConstraints[constraintName] = true;
}
}
}
await this.queryInterface.changeColumn(tableName, columnName, currentAttribute, options);
}
}
}
const existingIndexes = await this.queryInterface.showIndex(tableName, options);
const missingIndexes = this._indexes.filter((item1) => !existingIndexes.some((item2) => item1.name === item2.name)).sort((index1, index2) => {
if (this.sequelize.options.dialect === "postgres") {
if (index1.concurrently === true)
return 1;
if (index2.concurrently === true)
return -1;
}
return 0;
});
for (const index of missingIndexes) {
await this.queryInterface.addIndex(tableName, __spreadValues(__spreadValues({}, options), index));
}
if (options.hooks) {
await this.runHooks("afterSync", options);
}
return this;
}
static async drop(options) {
return await this.queryInterface.dropTable(this.getTableName(options), options);
}
static async dropSchema(schema) {
return await this.queryInterface.dropSchema(schema);
}
static schema(schema, options) {
const clone = class extends this {
};
Object.defineProperty(clone, "name", { value: this.name });
clone._schema = schema;
if (options) {
if (typeof options === "string") {
clone._schemaDelimiter = options;
} else if (options.schemaDelimiter) {
clone._schemaDelimiter = options.schemaDelimiter;
}
}
return clone;
}
static getTableName() {
return this.queryGenerator.addSchema(this);
}
static unscoped() {
return this.scope();
}
static addScope(name, scope, options) {
options = __spreadValues({ override: false }, options);
if ((name === "defaultScope" && Object.keys(this.options.defaultScope).length > 0 || name in this.options.scopes) && options.override === false) {
throw new Error(`The scope ${name} already exists. Pass { override: true } as options to silence this error`);
}
if (name === "defaultScope") {
this.options.defaultScope = this._scope = scope;
} else {
this.options.scopes[name] = scope;
}
}
static scope(option) {
const self = class extends this {
};
let scope;
let scopeName;
Object.defineProperty(self, "name", { value: this.name });
self._scope = {};
self._scopeNames = [];
self.scoped = true;
if (!option) {
return self;
}
const options = _.flatten(arguments);
for (const option2 of options) {
scope = null;
scopeName = null;
if (_.isPlainObject(option2)) {
if (option2.method) {
if (Array.isArray(option2.method) && !!self.options.scopes[option2.method[0]]) {
scopeName = option2.method[0];
scope = self.options.scopes[scopeName].apply(self, option2.method.slice(1));
} else if (self.options.scopes[option2.method]) {
scopeName = option2.method;
scope = self.options.scopes[scopeName].apply(self);
}
} else {
scope = option2;
}
} else if (option2 === "defaultScope" && _.isPlainObject(self.options.defaultScope)) {
scope = self.options.defaultScope;
} else {
scopeName = option2;
scope = self.options.scopes[scopeName];
if (typeof scope === "function") {
scope = scope();
}
}
if (scope) {
this._conformIncludes(scope, this);
this._assignOptions(self._scope, Utils.cloneDeep(scope));
self._scopeNames.push(scopeName ? scopeName : "defaultScope");
} else {
throw new sequelizeErrors.SequelizeScopeError(`Invalid scope ${scopeName} called.`);
}
}
return self;
}
static async findAll(options) {
if (options !== void 0 && !_.isPlainObject(options)) {
throw new sequelizeErrors.QueryError("The argument passed to findAll must be an options object, use findByPk if you wish to pass a single primary key value");
}
if (options !== void 0 && options.attributes) {
if (!Array.isArray(options.attributes) && !_.isPlainObject(options.attributes)) {
throw new sequelizeErrors.QueryError("The attributes option must be an array of column names or an object");
}
}
this.warnOnInvalidOptions(options, Object.keys(this.rawAttributes));
const tableNames = {};
tableNames[this.getTableName(options)] = true;
options = Utils.cloneDeep(options);
_.defaults(options, { hooks: true });
options.rejectOnEmpty = Object.prototype.hasOwnProperty.call(options, "rejectOnEmpty") ? options.rejectOnEmpty : this.options.rejectOnEmpty;
this._injectScope(options);
if (options.hooks) {
await this.runHooks("beforeFind", options);
}
this._conformIncludes(options, this);
this._expandAttributes(options);
this._expandIncludeAll(options);
if (options.hooks) {
await this.runHooks("beforeFindAfterExpandIncludeAll", options);
}
options.originalAttributes = this._injectDependentVirtualAttributes(options.attributes);
if (options.include) {
options.hasJoin = true;
this._validateIncludedElements(options, tableNames);
if (options.attributes && !options.raw && this.primaryKeyAttribute && !options.attributes.includes(this.primaryKeyAttribute) && (!options.group || !options.hasSingleAssociation || options.hasMultiAssociation)) {
options.attributes = [this.primaryKeyAttribute].concat(options.attributes);
}
}
if (!options.attributes) {
options.attributes = Object.keys(this.rawAttributes);
options.originalAttributes = this._injectDependentVirtualAttributes(options.attributes);
}
this.options.whereCollection = options.where || null;
Utils.mapFinderOptions(options, this);
options = this._paranoidClause(this, options);
if (options.hooks) {
await this.runHooks("beforeFindAfterOptions", options);
}
const selectOptions = __spreadProps(__spreadValues({}, options), { tableNames: Object.keys(tableNames) });
const results = await this.queryInterface.select(this, this.getTableName(selectOptions), selectOptions);
if (options.hooks) {
await this.runHooks("afterFind", results, options);
}
if (_.isEmpty(results) && options.rejectOnEmpty) {
if (typeof options.rejectOnEmpty === "function") {
throw new options.rejectOnEmpty();
}
if (typeof options.rejectOnEmpty === "object") {
throw options.rejectOnEmpty;
}
throw new sequelizeErrors.EmptyResultError();
}
return await Model._findSeparate(results, options);
}
static warnOnInvalidOptions(options, validColumnNames) {
if (!_.isPlainObject(options)) {
return;
}
const unrecognizedOptions = Object.keys(options).filter((k) => !validQueryKeywords.has(k));
const unexpectedModelAttributes = _.intersection(unrecognizedOptions, validColumnNames);
if (!options.where && unexpectedModelAttributes.length > 0) {
logger.warn(`Model attributes (${unexpectedModelAttributes.join(", ")}) passed into finder method options of model ${this.name}, but the options.where object is empty. Did you forget to use options.where?`);
}
}
static _injectDependentVirtualAttributes(attributes) {
if (!this._hasVirtualAttributes)
return attributes;
if (!attributes || !Array.isArray(attributes))
return attributes;
for (const attribute of attributes) {
if (this._virtualAttributes.has(attribute) && this.rawAttributes[attribute].type.fields) {
attributes = attributes.concat(this.rawAttributes[attribute].type.fields);
}
}
attributes = _.uniq(attributes);
return attributes;
}
static async _findSeparate(results, options) {
if (!options.include || options.raw || !results)
return results;
const original = results;
if (options.plain)
results = [results];
if (!results.length)
return original;
await Promise.all(options.include.map(async (include) => {
if (!include.separate) {
return await Model._findSeparate(results.reduce((memo, result) => {
let associations = result.get(include.association.as);
if (!associations)
return memo;
if (!Array.isArray(associations))
associations = [associations];
for (let i = 0, len = associations.length; i !== len; ++i) {
memo.push(associations[i]);
}
return memo;
}, []), __spreadProps(__spreadValues({}, _.omit(options, "include", "attributes", "order", "where", "limit", "offset", "plain", "scope")), {
include: include.include || []
}));
}
const map = await include.association.get(results, __spreadValues(__spreadValues({}, _.omit(options, nonCascadingOptions)), _.omit(include, ["parent", "association", "as", "originalAttributes"])));
for (const result of results) {
result.set(include.association.as, map[result.get(include.association.sourceKey)], { raw: true });
}
}));
return original;
}
static async findByPk(param, options) {
if ([null, void 0].includes(param)) {
return null;
}
options = Utils.cloneDeep(options) || {};
if (typeof param === "number" || typeof param === "bigint" || typeof param === "string" || Buffer.isBuffer(param)) {
options.where = {
[this.primaryKeyAttribute]: param
};
} else {
throw new Error(`Argument passed to findByPk is invalid: ${param}`);
}
return await this.findOne(options);
}
static async findOne(options) {
if (options !== void 0 && !_.isPlainObject(options)) {
throw new Error("The argument passed to findOne must be an options object, use findByPk if you wish to pass a single primary key value");
}
options = Utils.cloneDeep(options);
if (options.limit === void 0) {
const uniqueSingleColumns = _.chain(this.uniqueKeys).values().filter((c) => c.fields.length === 1).map("column").value();
if (!options.where || !_.some(options.where, (value, key) => (key === this.primaryKeyAttribu