123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371 |
- 'use strict';
- const url = require('url');
- const path = require('path');
- const retry = require('retry-as-promised');
- const _ = require('lodash');
- const Utils = require('./utils');
- const Model = require('./model');
- const DataTypes = require('./data-types');
- const Deferrable = require('./deferrable');
- const ModelManager = require('./model-manager');
- const Transaction = require('./transaction');
- const QueryTypes = require('./query-types');
- const TableHints = require('./table-hints');
- const IndexHints = require('./index-hints');
- const sequelizeErrors = require('./errors');
- const Hooks = require('./hooks');
- const Association = require('./associations/index');
- const Validator = require('./utils/validator-extras').validator;
- const Op = require('./operators');
- const deprecations = require('./utils/deprecations');
- class Sequelize {
-
- constructor(database, username, password, options) {
- let config;
- if (arguments.length === 1 && typeof database === 'object') {
-
- options = database;
- config = _.pick(options, 'host', 'port', 'database', 'username', 'password');
- } else if (arguments.length === 1 && typeof database === 'string' || arguments.length === 2 && typeof username === 'object') {
-
- config = {};
- options = username || {};
- const urlParts = url.parse(arguments[0], true);
- options.dialect = urlParts.protocol.replace(/:$/, '');
- options.host = urlParts.hostname;
- if (options.dialect === 'sqlite' && urlParts.pathname && !urlParts.pathname.startsWith('/:memory')) {
- const storagePath = path.join(options.host, urlParts.pathname);
- options.storage = path.resolve(options.storage || storagePath);
- }
- if (urlParts.pathname) {
- config.database = urlParts.pathname.replace(/^\//, '');
- }
- if (urlParts.port) {
- options.port = urlParts.port;
- }
- if (urlParts.auth) {
- const authParts = urlParts.auth.split(':');
- config.username = authParts[0];
- if (authParts.length > 1)
- config.password = authParts.slice(1).join(':');
- }
- if (urlParts.query) {
-
-
-
- if (urlParts.query.host) {
- options.host = urlParts.query.host;
- }
- if (options.dialectOptions) {
- Object.assign(options.dialectOptions, urlParts.query);
- } else {
- options.dialectOptions = urlParts.query;
- if (urlParts.query.options) {
- try {
- const o = JSON.parse(urlParts.query.options);
- options.dialectOptions.options = o;
- } catch (e) {
-
-
- }
- }
- }
- }
- } else {
-
- options = options || {};
- config = { database, username, password };
- }
- Sequelize.runHooks('beforeInit', config, options);
- this.options = {
- dialect: null,
- dialectModule: null,
- dialectModulePath: null,
- host: 'localhost',
- protocol: 'tcp',
- define: {},
- query: {},
- sync: {},
- timezone: '+00:00',
- clientMinMessages: 'warning',
- standardConformingStrings: true,
-
- logging: console.log,
- omitNull: false,
- native: false,
- replication: false,
- ssl: undefined,
- pool: {},
- quoteIdentifiers: true,
- hooks: {},
- retry: {
- max: 5,
- match: [
- 'SQLITE_BUSY: database is locked'
- ]
- },
- transactionType: Transaction.TYPES.DEFERRED,
- isolationLevel: null,
- databaseVersion: 0,
- typeValidation: false,
- benchmark: false,
- minifyAliases: false,
- logQueryParameters: false,
- ...options
- };
- if (!this.options.dialect) {
- throw new Error('Dialect needs to be explicitly supplied as of v4.0.0');
- }
- if (this.options.dialect === 'postgresql') {
- this.options.dialect = 'postgres';
- }
- if (this.options.dialect === 'sqlite' && this.options.timezone !== '+00:00') {
- throw new Error('Setting a custom timezone is not supported by SQLite, dates are always returned as UTC. Please remove the custom timezone parameter.');
- }
- if (this.options.logging === true) {
- deprecations.noTrueLogging();
-
- this.options.logging = console.log;
- }
- this._setupHooks(options.hooks);
- this.config = {
- database: config.database || this.options.database,
- username: config.username || this.options.username,
- password: config.password || this.options.password || null,
- host: config.host || this.options.host,
- port: config.port || this.options.port,
- pool: this.options.pool,
- protocol: this.options.protocol,
- native: this.options.native,
- ssl: this.options.ssl,
- replication: this.options.replication,
- dialectModule: this.options.dialectModule,
- dialectModulePath: this.options.dialectModulePath,
- keepDefaultTimezone: this.options.keepDefaultTimezone,
- dialectOptions: this.options.dialectOptions
- };
- let Dialect;
-
-
- switch (this.getDialect()) {
- case 'mariadb':
- Dialect = require('./dialects/mariadb');
- break;
- case 'mssql':
- Dialect = require('./dialects/mssql');
- break;
- case 'mysql':
- Dialect = require('./dialects/mysql');
- break;
- case 'postgres':
- Dialect = require('./dialects/postgres');
- break;
- case 'sqlite':
- Dialect = require('./dialects/sqlite');
- break;
- default:
- throw new Error(`The dialect ${this.getDialect()} is not supported. Supported dialects: mssql, mariadb, mysql, postgres, and sqlite.`);
- }
- this.dialect = new Dialect(this);
- this.dialect.queryGenerator.typeValidation = options.typeValidation;
- if (_.isPlainObject(this.options.operatorsAliases)) {
- deprecations.noStringOperators();
- this.dialect.queryGenerator.setOperatorsAliases(this.options.operatorsAliases);
- } else if (typeof this.options.operatorsAliases === 'boolean') {
- deprecations.noBoolOperatorAliases();
- }
- this.queryInterface = this.dialect.queryInterface;
-
- this.models = {};
- this.modelManager = new ModelManager(this);
- this.connectionManager = this.dialect.connectionManager;
- Sequelize.runHooks('afterInit', this);
- }
-
- refreshTypes() {
- this.connectionManager.refreshTypeParser(DataTypes);
- }
-
- getDialect() {
- return this.options.dialect;
- }
-
- getDatabaseName() {
- return this.config.database;
- }
-
- getQueryInterface() {
- return this.queryInterface;
- }
-
- define(modelName, attributes, options = {}) {
- options.modelName = modelName;
- options.sequelize = this;
- const model = class extends Model {};
- model.init(attributes, options);
- return model;
- }
-
- model(modelName) {
- if (!this.isDefined(modelName)) {
- throw new Error(`${modelName} has not been defined`);
- }
- return this.modelManager.getModel(modelName);
- }
-
- isDefined(modelName) {
- return !!this.modelManager.models.find(model => model.name === modelName);
- }
-
- async query(sql, options) {
- options = { ...this.options.query, ...options };
- if (options.instance && !options.model) {
- options.model = options.instance.constructor;
- }
- if (!options.instance && !options.model) {
- options.raw = true;
- }
-
- if (options.mapToModel) {
- options.fieldMap = _.get(options, 'model.fieldAttributeMap', {});
- }
- options = _.defaults(options, {
-
- logging: Object.prototype.hasOwnProperty.call(this.options, 'logging') ? this.options.logging : console.log,
- searchPath: Object.prototype.hasOwnProperty.call(this.options, 'searchPath') ? this.options.searchPath : 'DEFAULT'
- });
- if (!options.type) {
- if (options.model || options.nest || options.plain) {
- options.type = QueryTypes.SELECT;
- } else {
- options.type = QueryTypes.RAW;
- }
- }
-
-
- if (
- !this.dialect.supports.searchPath ||
- !this.options.dialectOptions ||
- !this.options.dialectOptions.prependSearchPath ||
- options.supportsSearchPath === false
- ) {
- delete options.searchPath;
- } else if (!options.searchPath) {
-
-
- options.searchPath = 'DEFAULT';
- }
- if (typeof sql === 'object') {
- if (sql.values !== undefined) {
- if (options.replacements !== undefined) {
- throw new Error('Both `sql.values` and `options.replacements` cannot be set at the same time');
- }
- options.replacements = sql.values;
- }
- if (sql.bind !== undefined) {
- if (options.bind !== undefined) {
- throw new Error('Both `sql.bind` and `options.bind` cannot be set at the same time');
- }
- options.bind = sql.bind;
- }
- if (sql.query !== undefined) {
- sql = sql.query;
- }
- }
- sql = sql.trim();
- if (options.replacements && options.bind) {
- throw new Error('Both `replacements` and `bind` cannot be set at the same time');
- }
- if (options.replacements) {
- if (Array.isArray(options.replacements)) {
- sql = Utils.format([sql].concat(options.replacements), this.options.dialect);
- } else {
- sql = Utils.formatNamedParameters(sql, options.replacements, this.options.dialect);
- }
- }
- let bindParameters;
- if (options.bind) {
- [sql, bindParameters] = this.dialect.Query.formatBindParameters(sql, options.bind, this.options.dialect);
- }
- const checkTransaction = () => {
- if (options.transaction && options.transaction.finished && !options.completesTransaction) {
- const error = new Error(`${options.transaction.finished} has been called on this transaction(${options.transaction.id}), you can no longer use it. (The rejected query is attached as the 'sql' property of this error)`);
- error.sql = sql;
- throw error;
- }
- };
- const retryOptions = { ...this.options.retry, ...options.retry };
- return retry(async () => {
- if (options.transaction === undefined && Sequelize._cls) {
- options.transaction = Sequelize._cls.get('transaction');
- }
- checkTransaction();
- const connection = await (options.transaction ? options.transaction.connection : this.connectionManager.getConnection(options));
- const query = new this.dialect.Query(connection, this, options);
- try {
- await this.runHooks('beforeQuery', options, query);
- checkTransaction();
- return await query.run(sql, bindParameters);
- } finally {
- await this.runHooks('afterQuery', options, query);
- if (!options.transaction) {
- await this.connectionManager.releaseConnection(connection);
- }
- }
- }, retryOptions);
- }
-
- async set(variables, options) {
-
- options = { ...this.options.set, ...typeof options === 'object' && options };
- if (this.options.dialect !== 'mysql') {
- throw new Error('sequelize.set is only supported for mysql');
- }
- if (!options.transaction || !(options.transaction instanceof Transaction) ) {
- throw new TypeError('options.transaction is required');
- }
-
- options.raw = true;
- options.plain = true;
- options.type = 'SET';
-
- const query =
- `SET ${
- _.map(variables, (v, k) => `@${k} := ${typeof v === 'string' ? `"${v}"` : v}`).join(', ')}`;
- return await this.query(query, options);
- }
-
- escape(value) {
- return this.dialect.queryGenerator.escape(value);
- }
-
- async createSchema(schema, options) {
- return await this.getQueryInterface().createSchema(schema, options);
- }
-
- async showAllSchemas(options) {
- return await this.getQueryInterface().showAllSchemas(options);
- }
-
- async dropSchema(schema, options) {
- return await this.getQueryInterface().dropSchema(schema, options);
- }
-
- async dropAllSchemas(options) {
- return await this.getQueryInterface().dropAllSchemas(options);
- }
-
- async sync(options) {
- options = {
- ...this.options,
- ...this.options.sync,
- ...options,
- hooks: options ? options.hooks !== false : true
- };
- if (options.match) {
- if (!options.match.test(this.config.database)) {
- throw new Error(`Database "${this.config.database}" does not match sync match parameter "${options.match}"`);
- }
- }
- if (options.hooks) {
- await this.runHooks('beforeBulkSync', options);
- }
- if (options.force) {
- await this.drop(options);
- }
- const models = [];
-
-
- this.modelManager.forEachModel(model => {
- if (model) {
- models.push(model);
- } else {
-
- }
- });
-
- if (!models.length) {
- await this.authenticate(options);
- } else {
- for (const model of models) await model.sync(options);
- }
- if (options.hooks) {
- await this.runHooks('afterBulkSync', options);
- }
- return this;
- }
-
- async truncate(options) {
- const models = [];
- this.modelManager.forEachModel(model => {
- if (model) {
- models.push(model);
- }
- }, { reverse: false });
- if (options && options.cascade) {
- for (const model of models) await model.truncate(options);
- } else {
- await Promise.all(models.map(model => model.truncate(options)));
- }
- }
-
- async drop(options) {
- const models = [];
- this.modelManager.forEachModel(model => {
- if (model) {
- models.push(model);
- }
- }, { reverse: false });
- for (const model of models) await model.drop(options);
- }
-
- async authenticate(options) {
- options = {
- raw: true,
- plain: true,
- type: QueryTypes.SELECT,
- ...options
- };
- await this.query('SELECT 1+1 AS result', options);
- return;
- }
- async databaseVersion(options) {
- return await this.getQueryInterface().databaseVersion(options);
- }
-
- random() {
- const dia = this.getDialect();
- if (dia === 'postgres' || dia === 'sqlite') {
- return this.fn('RANDOM');
- }
- return this.fn('RAND');
- }
-
- static fn(fn, ...args) {
- return new Utils.Fn(fn, args);
- }
-
- static col(col) {
- return new Utils.Col(col);
- }
-
- static cast(val, type) {
- return new Utils.Cast(val, type);
- }
-
- static literal(val) {
- return new Utils.Literal(val);
- }
-
- static and(...args) {
- return { [Op.and]: args };
- }
-
- static or(...args) {
- return { [Op.or]: args };
- }
-
- static json(conditionsOrPath, value) {
- return new Utils.Json(conditionsOrPath, value);
- }
-
- static where(attr, comparator, logic) {
- return new Utils.Where(attr, comparator, logic);
- }
-
- async transaction(options, autoCallback) {
- if (typeof options === 'function') {
- autoCallback = options;
- options = undefined;
- }
- const transaction = new Transaction(this, options);
- if (!autoCallback) {
- await transaction.prepareEnvironment(false);
- return transaction;
- }
-
- return Sequelize._clsRun(async () => {
- try {
- await transaction.prepareEnvironment();
- const result = await autoCallback(transaction);
- await transaction.commit();
- return await result;
- } catch (err) {
- try {
- if (!transaction.finished) {
- await transaction.rollback();
- } else {
-
- await transaction.cleanup();
- }
- } catch (err0) {
-
- }
- throw err;
- }
- });
- }
-
- static useCLS(ns) {
-
- if (!ns || typeof ns !== 'object' || typeof ns.bind !== 'function' || typeof ns.run !== 'function') throw new Error('Must provide CLS namespace');
-
- this._cls = ns;
-
- return this;
- }
-
- static _clsRun(fn) {
- const ns = Sequelize._cls;
- if (!ns) return fn();
- let res;
- ns.run(context => res = fn(context));
- return res;
- }
- log(...args) {
- let options;
- const last = _.last(args);
- if (last && _.isPlainObject(last) && Object.prototype.hasOwnProperty.call(last, 'logging')) {
- options = last;
-
-
- if (options.logging === console.log) {
- args.splice(args.length - 1, 1);
- }
- } else {
- options = this.options;
- }
- if (options.logging) {
- if (options.logging === true) {
- deprecations.noTrueLogging();
-
- options.logging = console.log;
- }
-
-
- if ((this.options.benchmark || options.benchmark) && options.logging === console.log) {
- args = [`${args[0]} Elapsed time: ${args[1]}ms`];
- }
- options.logging(...args);
- }
- }
-
- close() {
- return this.connectionManager.close();
- }
- normalizeDataType(Type) {
- let type = typeof Type === 'function' ? new Type() : Type;
- const dialectTypes = this.dialect.DataTypes || {};
- if (dialectTypes[type.key]) {
- type = dialectTypes[type.key].extend(type);
- }
- if (type instanceof DataTypes.ARRAY) {
- if (!type.type) {
- throw new Error('ARRAY is missing type definition for its values.');
- }
- if (dialectTypes[type.type.key]) {
- type.type = dialectTypes[type.type.key].extend(type.type);
- }
- }
- return type;
- }
- normalizeAttribute(attribute) {
- if (!_.isPlainObject(attribute)) {
- attribute = { type: attribute };
- }
- if (!attribute.type) return attribute;
- attribute.type = this.normalizeDataType(attribute.type);
- if (Object.prototype.hasOwnProperty.call(attribute, 'defaultValue')) {
- if (typeof attribute.defaultValue === 'function' && (
- attribute.defaultValue === DataTypes.NOW ||
- attribute.defaultValue === DataTypes.UUIDV1 ||
- attribute.defaultValue === DataTypes.UUIDV4
- )) {
- attribute.defaultValue = new attribute.defaultValue();
- }
- }
- if (attribute.type instanceof DataTypes.ENUM) {
-
- if (attribute.values) {
- attribute.type.values = attribute.type.options.values = attribute.values;
- } else {
- attribute.values = attribute.type.values;
- }
- if (!attribute.values.length) {
- throw new Error('Values for ENUM have not been defined.');
- }
- }
- return attribute;
- }
- }
- Sequelize.prototype.fn = Sequelize.fn;
- Sequelize.prototype.col = Sequelize.col;
- Sequelize.prototype.cast = Sequelize.cast;
- Sequelize.prototype.literal = Sequelize.literal;
- Sequelize.prototype.and = Sequelize.and;
- Sequelize.prototype.or = Sequelize.or;
- Sequelize.prototype.json = Sequelize.json;
- Sequelize.prototype.where = Sequelize.where;
- Sequelize.prototype.validate = Sequelize.prototype.authenticate;
- Sequelize.version = require('../package.json').version;
- Sequelize.options = { hooks: {} };
- Sequelize.Utils = Utils;
- Sequelize.Op = Op;
- Sequelize.TableHints = TableHints;
- Sequelize.IndexHints = IndexHints;
- Sequelize.Transaction = Transaction;
- Sequelize.prototype.Sequelize = Sequelize;
- Sequelize.prototype.QueryTypes = Sequelize.QueryTypes = QueryTypes;
- Sequelize.prototype.Validator = Sequelize.Validator = Validator;
- Sequelize.Model = Model;
- Sequelize.DataTypes = DataTypes;
- for (const dataType in DataTypes) {
- Sequelize[dataType] = DataTypes[dataType];
- }
- Sequelize.Deferrable = Deferrable;
- Sequelize.prototype.Association = Sequelize.Association = Association;
- Sequelize.useInflection = Utils.useInflection;
- Hooks.applyTo(Sequelize);
- Hooks.applyTo(Sequelize.prototype);
- Sequelize.Error = sequelizeErrors.BaseError;
- for (const error of Object.keys(sequelizeErrors)) {
- Sequelize[error] = sequelizeErrors[error];
- }
- module.exports = Sequelize;
- module.exports.Sequelize = Sequelize;
- module.exports.default = Sequelize;
|