sequelize.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. 'use strict';
  2. import { EMPTY_OBJECT, shallowClonePojo } from '@sequelize/utils';
  3. import defaults from 'lodash/defaults';
  4. import isPlainObject from 'lodash/isPlainObject';
  5. import map from 'lodash/map';
  6. import retry from 'retry-as-promised';
  7. import { AbstractConnectionManager } from './abstract-dialect/connection-manager.js';
  8. import { AbstractDialect } from './abstract-dialect/dialect.js';
  9. import { AbstractQueryGenerator } from './abstract-dialect/query-generator.js';
  10. import { AbstractQueryInterface } from './abstract-dialect/query-interface';
  11. import { AbstractQuery } from './abstract-dialect/query.js';
  12. import { Association } from './associations/base.js';
  13. import { BelongsToAssociation } from './associations/belongs-to';
  14. import { BelongsToManyAssociation } from './associations/belongs-to-many';
  15. import { HasManyAssociation } from './associations/has-many';
  16. import { HasOneAssociation } from './associations/has-one';
  17. import * as DataTypes from './data-types';
  18. import { ConstraintChecking, Deferrable } from './deferrable';
  19. import * as SequelizeErrors from './errors';
  20. import { AssociationPath } from './expression-builders/association-path';
  21. import { Attribute } from './expression-builders/attribute';
  22. import { BaseSqlExpression } from './expression-builders/base-sql-expression.js';
  23. import { Cast, cast } from './expression-builders/cast.js';
  24. import { Col, col } from './expression-builders/col.js';
  25. import { Fn, fn } from './expression-builders/fn.js';
  26. import { Identifier } from './expression-builders/identifier';
  27. import { JsonPath } from './expression-builders/json-path';
  28. import { JSON_NULL, SQL_NULL } from './expression-builders/json-sql-null.js';
  29. import { json } from './expression-builders/json.js';
  30. import { List } from './expression-builders/list';
  31. import { Literal, literal } from './expression-builders/literal.js';
  32. import { sql } from './expression-builders/sql';
  33. import { Value } from './expression-builders/value';
  34. import { Where, where } from './expression-builders/where.js';
  35. import { importModels } from './import-models.js';
  36. import { IndexHints } from './index-hints';
  37. import { Model } from './model';
  38. import { setTransactionFromCls } from './model-internals.js';
  39. import { ManualOnDelete } from './model-repository.types.js';
  40. import { Op } from './operators';
  41. import { QueryTypes } from './query-types';
  42. import { SequelizeTypeScript } from './sequelize-typescript';
  43. import { TableHints } from './table-hints';
  44. import {
  45. COMPLETES_TRANSACTION,
  46. IsolationLevel,
  47. Lock,
  48. Transaction,
  49. TransactionNestMode,
  50. TransactionType,
  51. } from './transaction.js';
  52. import * as Deprecations from './utils/deprecations';
  53. import {
  54. noGetDialect,
  55. noGetQueryInterface,
  56. noSequelizeDataType,
  57. noSequelizeIsDefined,
  58. noSequelizeModel,
  59. } from './utils/deprecations';
  60. import { isModelStatic, isSameInitialModel } from './utils/model-utils';
  61. import { injectReplacements, mapBindParameters } from './utils/sql';
  62. import { withSqliteForeignKeysOff } from './utils/sql.js';
  63. import { useInflection } from './utils/string';
  64. import { validator as Validator } from './utils/validator-extras';
  65. /**
  66. * This is the main class, the entry point to sequelize.
  67. */
  68. export class Sequelize extends SequelizeTypeScript {
  69. /**
  70. * Returns the specified dialect.
  71. *
  72. * @returns {string} The specified dialect.
  73. */
  74. getDialect() {
  75. noGetDialect();
  76. return this.dialect.name;
  77. }
  78. /**
  79. * Returns the database name.
  80. *
  81. * @returns {string} The database name.
  82. */
  83. getDatabaseName() {
  84. throw new Error(
  85. 'getDatabaseName has been removed as it does not make sense in every dialect. Please use the values available in sequelize.options.replication.write for an equivalent option.',
  86. );
  87. }
  88. /**
  89. * Returns an instance of AbstractQueryInterface.
  90. *
  91. * @returns {AbstractQueryInterface} An instance (singleton) of AbstractQueryInterface.
  92. */
  93. getQueryInterface() {
  94. noGetQueryInterface();
  95. return this.queryInterface;
  96. }
  97. /**
  98. * Define a new model, representing a table in the database.
  99. *
  100. * The table columns are defined by the object that is given as the second argument. Each key of the object represents a column
  101. *
  102. * @param {string} modelName The name of the model. The model will be stored in `sequelize.models` under this name
  103. * @param {object} attributes An object, where each attribute is a column of the table. See {@link Model.init}
  104. * @param {object} [options] These options are merged with the default define options provided to the Sequelize constructor and passed to Model.init()
  105. *
  106. * @see
  107. * {@link Model.init} for a more comprehensive specification of the `options` and `attributes` objects.
  108. * @see
  109. * <a href="/master/manual/model-basics.html">Model Basics</a> guide
  110. *
  111. * @returns {Model} Newly defined model
  112. *
  113. * @example
  114. * sequelize.define('modelName', {
  115. * columnA: {
  116. * type: DataTypes.BOOLEAN,
  117. * validate: {
  118. * is: ["[a-z]",'i'], // will only allow letters
  119. * max: 23, // only allow values <= 23
  120. * isIn: {
  121. * args: [['en', 'zh']],
  122. * msg: "Must be English or Chinese"
  123. * }
  124. * },
  125. * field: 'column_a'
  126. * },
  127. * columnB: DataTypes.STRING,
  128. * columnC: 'MY VERY OWN COLUMN TYPE'
  129. * });
  130. *
  131. * sequelize.models.modelName // The model will now be available in models under the name given to define
  132. */
  133. define(modelName, attributes = EMPTY_OBJECT, options = EMPTY_OBJECT) {
  134. options = shallowClonePojo(options);
  135. options.modelName = modelName;
  136. options.sequelize = this;
  137. const model = class extends Model {};
  138. model.init(attributes, options);
  139. return model;
  140. }
  141. /**
  142. * Fetch a Model which is already defined
  143. *
  144. * @param {string} modelName The name of a model defined with Sequelize.define
  145. *
  146. * @throws Will throw an error if the model is not defined (that is, if sequelize#isDefined returns false)
  147. * @returns {Model} Specified model
  148. */
  149. model(modelName) {
  150. noSequelizeModel();
  151. return this.models.getOrThrow(modelName);
  152. }
  153. /**
  154. * Checks whether a model with the given name is defined
  155. *
  156. * @param {string} modelName The name of a model defined with Sequelize.define
  157. *
  158. * @returns {boolean} Returns true if model is already defined, otherwise false
  159. */
  160. isDefined(modelName) {
  161. noSequelizeIsDefined();
  162. return this.models.hasByName(modelName);
  163. }
  164. /**
  165. * Execute a query on the DB, optionally bypassing all the Sequelize goodness.
  166. *
  167. * By default, the function will return two arguments: an array of results, and a metadata object, containing number of affected rows etc.
  168. *
  169. * If you are running a type of query where you don't need the metadata, for example a `SELECT` query, you can pass in a query type to make sequelize format the results:
  170. *
  171. * ```js
  172. * const [results, metadata] = await sequelize.query('SELECT...'); // Raw query - use array destructuring
  173. *
  174. * const results = await sequelize.query('SELECT...', { type: sequelize.QueryTypes.SELECT }); // SELECT query - no destructuring
  175. * ```
  176. *
  177. * @param {string} sql
  178. * @param {object} [options={}] Query options.
  179. * @param {boolean} [options.raw] If true, sequelize will not try to format the results of the query, or build an instance of a model from the result
  180. * @param {Transaction} [options.transaction=null] The transaction that the query should be executed under
  181. * @param {QueryTypes} [options.type='RAW'] The type of query you are executing. The query type affects how results are formatted before they are passed back. The type is a string, but `Sequelize.QueryTypes` is provided as convenience shortcuts.
  182. * @param {boolean} [options.nest=false] If true, transforms objects with `.` separated property names into nested objects using [dottie.js](https://github.com/mickhansen/dottie.js). For example { 'user.username': 'john' } becomes { user: { username: 'john' }}. When `nest` is true, the query type is assumed to be `'SELECT'`, unless otherwise specified
  183. * @param {boolean} [options.plain=false] Sets the query type to `SELECT` and return a single row
  184. * @param {object|Array} [options.replacements] Either an object of named parameter replacements in the format `:param` or an array of unnamed replacements to replace `?` in your SQL.
  185. * @param {object|Array} [options.bind] Either an object of named bind parameter in the format `_param` or an array of unnamed bind parameter to replace `$1, $2, ...` in your SQL.
  186. * @param {boolean} [options.useMaster=false] Force the query to use the write pool, regardless of the query type.
  187. * @param {Function} [options.logging=false] A function that gets executed while running the query to log the sql.
  188. * @param {Model} [options.instance] A sequelize model instance whose Model is to be used to build the query result
  189. * @param {ModelStatic<Model>} [options.model] A sequelize model used to build the returned model instances
  190. * @param {object} [options.retry] Set of flags that control when a query is automatically retried. Accepts all options for [`retry-as-promised`](https://github.com/mickhansen/retry-as-promised).
  191. * @param {Array} [options.retry.match] Only retry a query if the error matches one of these strings.
  192. * @param {Integer} [options.retry.max] How many times a failing query is automatically retried.
  193. * @param {number} [options.retry.timeout] Maximum duration, in milliseconds, to retry until an error is thrown.
  194. * @param {number} [options.retry.backoffBase=100] Initial backoff duration, in milliseconds.
  195. * @param {number} [options.retry.backoffExponent=1.1] Exponent to increase backoff duration after each retry.
  196. * @param {Function} [options.retry.report] Function that is executed after each retry, called with a message and the current retry options.
  197. * @param {string} [options.retry.name='unknown'] Name used when composing error/reporting messages.
  198. * @param {string} [options.searchPath=DEFAULT] An optional parameter to specify the schema search_path (Postgres only)
  199. * @param {boolean} [options.supportsSearchPath] If false do not prepend the query with the search_path (Postgres only)
  200. * @param {boolean} [options.mapToModel=false] Map returned fields to model's fields if `options.model` or `options.instance` is present. Mapping will occur before building the model instance.
  201. * @param {object} [options.fieldMap] Map returned fields to arbitrary names for `SELECT` query type.
  202. * @param {boolean} [options.rawErrors=false] Set to `true` to cause errors coming from the underlying connection/database library to be propagated unmodified and unformatted. Else, the default behavior (=false) is to reinterpret errors as sequelize.errors.BaseError objects.
  203. *
  204. * @returns {Promise}
  205. *
  206. * @see {@link Model.build} for more information about instance option.
  207. */
  208. async query(sql, options) {
  209. options = { ...this.options.query, ...options };
  210. if (sql instanceof BaseSqlExpression) {
  211. sql = this.queryGenerator.formatSqlExpression(sql, options);
  212. }
  213. if (typeof sql === 'object') {
  214. throw new TypeError(
  215. '"sql" cannot be an object. Pass a string instead, and pass bind and replacement parameters through the "options" parameter',
  216. );
  217. }
  218. sql = sql.trim();
  219. if (options.replacements) {
  220. sql = injectReplacements(sql, this.dialect, options.replacements);
  221. }
  222. // queryRaw will throw if 'replacements' is specified, as a way to warn users that they are miusing the method.
  223. delete options.replacements;
  224. return this.queryRaw(sql, options);
  225. }
  226. async queryRaw(sql, options) {
  227. if (typeof sql !== 'string') {
  228. throw new TypeError('Sequelize#rawQuery requires a string as the first parameter.');
  229. }
  230. if (options != null && 'replacements' in options) {
  231. throw new TypeError(`Sequelize#rawQuery does not accept the "replacements" options.
  232. Only bind parameters can be provided, in the dialect-specific syntax.
  233. Use Sequelize#query if you wish to use replacements.`);
  234. }
  235. options = { ...this.options.query, ...options, bindParameterOrder: null };
  236. let bindParameters;
  237. if (options.bind != null) {
  238. const isBindArray = Array.isArray(options.bind);
  239. if (!isPlainObject(options.bind) && !isBindArray) {
  240. throw new TypeError(
  241. 'options.bind must be either a plain object (for named parameters) or an array (for numeric parameters)',
  242. );
  243. }
  244. const mappedResult = mapBindParameters(sql, this.dialect);
  245. for (const parameterName of mappedResult.parameterSet) {
  246. if (isBindArray) {
  247. if (!/[1-9][0-9]*/.test(parameterName) || options.bind.length < Number(parameterName)) {
  248. throw new Error(
  249. `Query includes bind parameter "$${parameterName}", but no value has been provided for that bind parameter.`,
  250. );
  251. }
  252. } else if (!(parameterName in options.bind)) {
  253. throw new Error(
  254. `Query includes bind parameter "$${parameterName}", but no value has been provided for that bind parameter.`,
  255. );
  256. }
  257. }
  258. sql = mappedResult.sql;
  259. // used by dialects that support "INOUT" parameters to map the OUT parameters back the the name the dev used.
  260. options.bindParameterOrder = mappedResult.bindOrder;
  261. if (mappedResult.bindOrder == null) {
  262. bindParameters = options.bind;
  263. } else {
  264. bindParameters = mappedResult.bindOrder.map(key => {
  265. if (isBindArray) {
  266. return options.bind[key - 1];
  267. }
  268. return options.bind[key];
  269. });
  270. }
  271. }
  272. if (options.instance && !options.model) {
  273. options.model = options.instance.constructor;
  274. }
  275. if (!options.instance && !options.model) {
  276. options.raw = true;
  277. }
  278. // map raw fields to model attributes
  279. if (options.mapToModel) {
  280. // TODO: throw if model is not specified
  281. options.fieldMap = options.model?.fieldAttributeMap;
  282. }
  283. options = defaults(options, {
  284. logging: Object.hasOwn(this.options, 'logging') ? this.options.logging : console.debug,
  285. searchPath: Object.hasOwn(this.options, 'searchPath') ? this.options.searchPath : 'DEFAULT',
  286. });
  287. if (!options.type) {
  288. if (options.model || options.nest || options.plain) {
  289. options.type = QueryTypes.SELECT;
  290. } else {
  291. options.type = QueryTypes.RAW;
  292. }
  293. }
  294. // if dialect doesn't support search_path or dialect option
  295. // to prepend searchPath is not true delete the searchPath option
  296. if (
  297. !this.dialect.supports.searchPath ||
  298. !this.options.prependSearchPath ||
  299. options.supportsSearchPath === false
  300. ) {
  301. delete options.searchPath;
  302. } else if (!options.searchPath) {
  303. // if user wants to always prepend searchPath (preprendSearchPath = true)
  304. // then set to DEFAULT if none is provided
  305. options.searchPath = 'DEFAULT';
  306. }
  307. const checkTransaction = () => {
  308. if (options.transaction && options.transaction.finished && !options[COMPLETES_TRANSACTION]) {
  309. const error = new Error(
  310. `${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)`,
  311. );
  312. error.sql = sql;
  313. throw error;
  314. }
  315. };
  316. setTransactionFromCls(options, this);
  317. const retryOptions = { ...this.options.retry, ...options.retry };
  318. return await retry(async () => {
  319. checkTransaction();
  320. const connection = options.transaction
  321. ? options.transaction.getConnection()
  322. : options.connection
  323. ? options.connection
  324. : await this.pool.acquire({
  325. useMaster: options.useMaster,
  326. type: options.type === 'SELECT' ? 'read' : 'write',
  327. });
  328. if (this.dialect.name === 'db2' && options.alter && options.alter.drop === false) {
  329. connection.dropTable = false;
  330. }
  331. const query = new this.dialect.Query(connection, this, options);
  332. try {
  333. await this.hooks.runAsync('beforeQuery', options, query);
  334. checkTransaction();
  335. return await query.run(sql, bindParameters, { minifyAliases: options.minifyAliases });
  336. } finally {
  337. await this.hooks.runAsync('afterQuery', options, query);
  338. if (!options.transaction && !options.connection) {
  339. this.pool.release(connection);
  340. }
  341. }
  342. }, retryOptions);
  343. }
  344. /**
  345. * Execute a query which would set an environment or user variable. The variables are set per connection, so this function needs a transaction.
  346. * Only works for MySQL or MariaDB.
  347. *
  348. * @param {object} variables Object with multiple variables.
  349. * @param {object} [options] query options.
  350. *
  351. * @returns {Promise}
  352. */
  353. async setSessionVariables(variables, options) {
  354. // Prepare options
  355. options = { ...this.options.setSessionVariables, ...options };
  356. if (!['mysql', 'mariadb'].includes(this.dialect.name)) {
  357. throw new Error('sequelize.setSessionVariables is only supported for mysql or mariadb');
  358. }
  359. setTransactionFromCls(options, this);
  360. if (
  361. (!options.transaction || !(options.transaction instanceof Transaction)) &&
  362. !options.connection
  363. ) {
  364. throw new Error(
  365. 'You must specify either options.transaction or options.connection, as sequelize.setSessionVariables is used to set the session options of a connection',
  366. );
  367. }
  368. // Override some options, since this isn't a SELECT
  369. options.raw = true;
  370. options.plain = true;
  371. options.type = 'SET';
  372. // Generate SQL Query
  373. const query = `SET ${map(
  374. variables,
  375. (v, k) => `@${k} := ${typeof v === 'string' ? `"${v}"` : v}`,
  376. ).join(', ')}`;
  377. return await this.query(query, options);
  378. }
  379. /**
  380. * Sync all defined models to the DB.
  381. *
  382. * @param {object} [options={}] sync options
  383. * @param {boolean} [options.force=false] If force is true, each Model will run `DROP TABLE IF EXISTS`, before it tries to create its own table
  384. * @param {boolean|Function} [options.logging=console.log] A function that logs sql queries, or false for no logging
  385. * @param {string} [options.schema='public'] The schema that the tables should be created in. This can be overridden for each table in sequelize.define
  386. * @param {string} [options.searchPath=DEFAULT] An optional parameter to specify the schema search_path (Postgres only)
  387. * @param {boolean} [options.hooks=true] If hooks is true then beforeSync, afterSync, beforeBulkSync, afterBulkSync hooks will be called
  388. * @param {boolean|object} [options.alter=false] Alters tables to fit models. Provide an object for additional configuration. Not recommended for production use. If not further configured deletes data in columns that were removed or had their type changed in the model.
  389. * @param {boolean} [options.alter.drop=true] Prevents any drop statements while altering a table when set to `false`
  390. *
  391. * @returns {Promise}
  392. */
  393. async sync(options) {
  394. options = {
  395. ...this.options.sync,
  396. ...options,
  397. hooks: options ? options.hooks !== false : true,
  398. };
  399. if ('match' in options) {
  400. throw new Error(
  401. 'The "match" option has been removed as matching against a database name does not make sense in every dialects.',
  402. );
  403. }
  404. if (options.hooks) {
  405. await this.hooks.runAsync('beforeBulkSync', options);
  406. }
  407. if (options.force) {
  408. await this.drop({
  409. ...options,
  410. cascade: this.dialect.supports.dropTable.cascade || undefined,
  411. });
  412. }
  413. // no models defined, just authenticate
  414. if (this.models.size === 0) {
  415. await this.authenticate(options);
  416. } else {
  417. const models = this.models.getModelsTopoSortedByForeignKey();
  418. if (models == null) {
  419. return this._syncModelsWithCyclicReferences(options);
  420. }
  421. // reverse to start with the one model that does not depend on anything
  422. models.reverse();
  423. // Topologically sort by foreign key constraints to give us an appropriate
  424. // creation order
  425. for (const model of models) {
  426. await model.sync(options);
  427. }
  428. }
  429. if (options.hooks) {
  430. await this.hooks.runAsync('afterBulkSync', options);
  431. }
  432. return this;
  433. }
  434. /**
  435. * Used instead of sync() when two models reference each-other, so their foreign keys cannot be created immediately.
  436. *
  437. * @param {object} options - sync options
  438. * @private
  439. */
  440. async _syncModelsWithCyclicReferences(options) {
  441. if (this.dialect.name === 'sqlite3') {
  442. // Optimisation: no need to do this in two passes in SQLite because we can temporarily disable foreign keys
  443. await withSqliteForeignKeysOff(this, options, async () => {
  444. for (const model of this.models) {
  445. await model.sync(options);
  446. }
  447. });
  448. return;
  449. }
  450. // create all tables, but don't create foreign key constraints
  451. for (const model of this.models) {
  452. await model.sync({ ...options, withoutForeignKeyConstraints: true });
  453. }
  454. // add foreign key constraints
  455. for (const model of this.models) {
  456. await model.sync({ ...options, force: false, alter: true });
  457. }
  458. }
  459. /**
  460. * Drop all tables defined through this sequelize instance.
  461. * This is done by calling {@link Model.drop} on each model.
  462. *
  463. * @param {object} [options] The options passed to each call to Model.drop
  464. * @param {boolean|Function} [options.logging] A function that logs sql queries, or false for no logging
  465. *
  466. * @returns {Promise}
  467. */
  468. async drop(options) {
  469. // if 'cascade' is specified, we don't have to worry about cyclic dependencies.
  470. if (options && options.cascade) {
  471. for (const model of this.models) {
  472. await model.drop(options);
  473. }
  474. }
  475. const sortedModels = this.models.getModelsTopoSortedByForeignKey();
  476. // no cyclic dependency between models, we can delete them in an order that will not cause an error.
  477. if (sortedModels) {
  478. for (const model of sortedModels) {
  479. await model.drop(options);
  480. }
  481. }
  482. if (this.dialect.name === 'sqlite3') {
  483. // Optimisation: no need to do this in two passes in SQLite because we can temporarily disable foreign keys
  484. await withSqliteForeignKeysOff(this, options, async () => {
  485. for (const model of this.models) {
  486. await model.drop(options);
  487. }
  488. });
  489. return;
  490. }
  491. // has cyclic dependency: we first remove each foreign key, then delete each model.
  492. for (const model of this.models) {
  493. const foreignKeys = await this.queryInterface.showConstraints(model, {
  494. ...options,
  495. constraintType: 'FOREIGN KEY',
  496. });
  497. await Promise.all(
  498. foreignKeys.map(foreignKey => {
  499. return this.queryInterface.removeConstraint(model, foreignKey.constraintName, options);
  500. }),
  501. );
  502. }
  503. for (const model of this.models) {
  504. await model.drop(options);
  505. }
  506. }
  507. /**
  508. * Test the connection by trying to authenticate. It runs `SELECT 1+1 AS result` query.
  509. *
  510. * @param {object} [options={}] query options
  511. *
  512. * @returns {Promise}
  513. */
  514. async authenticate(options) {
  515. options = {
  516. raw: true,
  517. plain: true,
  518. type: QueryTypes.SELECT,
  519. ...options,
  520. };
  521. await this.query(
  522. `SELECT 1+1 AS result${this.dialect.name === 'ibmi' ? ' FROM SYSIBM.SYSDUMMY1' : ''}`,
  523. options,
  524. );
  525. }
  526. /**
  527. * Get the fn for random based on the dialect
  528. *
  529. * @returns {Fn}
  530. */
  531. // TODO: replace with sql.random
  532. random() {
  533. if (['postgres', 'sqlite3', 'snowflake'].includes(this.dialect.name)) {
  534. return fn('RANDOM');
  535. }
  536. return fn('RAND');
  537. }
  538. // Global exports
  539. static Fn = Fn;
  540. static Col = Col;
  541. static Cast = Cast;
  542. static Literal = Literal;
  543. static Where = Where;
  544. static List = List;
  545. static Identifier = Identifier;
  546. static Attribute = Attribute;
  547. static Value = Value;
  548. static AssociationPath = AssociationPath;
  549. static JsonPath = JsonPath;
  550. static sql = sql;
  551. // these are all available on the "sql" object, but are exposed for backwards compatibility
  552. static fn = fn;
  553. static col = col;
  554. static cast = cast;
  555. static literal = literal;
  556. static json = json;
  557. static where = where;
  558. static and = and;
  559. static or = or;
  560. static isModelStatic = isModelStatic;
  561. static isSameInitialModel = isSameInitialModel;
  562. static importModels = importModels;
  563. static TransactionNestMode = TransactionNestMode;
  564. static TransactionType = TransactionType;
  565. static Lock = Lock;
  566. static IsolationLevel = IsolationLevel;
  567. log(...args) {
  568. let options;
  569. const last = args.at(-1);
  570. if (last && isPlainObject(last) && Object.hasOwn(last, 'logging')) {
  571. options = last;
  572. // remove options from set of logged arguments if options.logging is equal to console.log or console.debug
  573. // eslint-disable-next-line no-console -- intended console.log use
  574. if (options.logging === console.log || options.logging === console.debug) {
  575. args.splice(-1, 1);
  576. }
  577. } else {
  578. options = this.options;
  579. }
  580. if (options.logging) {
  581. if (options.logging === true) {
  582. Deprecations.noTrueLogging();
  583. options.logging = console.debug;
  584. }
  585. // second argument is sql-timings, when benchmarking option enabled
  586. if ((this.options.benchmark || options.benchmark) && options.logging === console.debug) {
  587. args = [`${args[0]} Elapsed time: ${args[1]}ms`];
  588. }
  589. options.logging(...args);
  590. }
  591. }
  592. normalizeAttribute(attribute) {
  593. if (!isPlainObject(attribute)) {
  594. attribute = { type: attribute };
  595. } else {
  596. attribute = { ...attribute };
  597. }
  598. if (attribute.values) {
  599. throw new TypeError(
  600. `
  601. The "values" property has been removed from column definitions. The following is no longer supported:
  602. sequelize.define('MyModel', {
  603. roles: {
  604. type: DataTypes.ENUM,
  605. values: ['admin', 'user'],
  606. },
  607. });
  608. Instead, define enum values like this:
  609. sequelize.define('MyModel', {
  610. roles: {
  611. type: DataTypes.ENUM(['admin', 'user']),
  612. },
  613. });
  614. Remove the "values" property to resolve this issue.
  615. `.trim(),
  616. );
  617. }
  618. if (!attribute.type) {
  619. return attribute;
  620. }
  621. attribute.type = this.normalizeDataType(attribute.type);
  622. return attribute;
  623. }
  624. }
  625. // Aliases
  626. Sequelize.prototype.fn = Sequelize.fn;
  627. Sequelize.prototype.col = Sequelize.col;
  628. Sequelize.prototype.cast = Sequelize.cast;
  629. Sequelize.prototype.literal = Sequelize.literal;
  630. Sequelize.prototype.and = Sequelize.and;
  631. Sequelize.prototype.or = Sequelize.or;
  632. Sequelize.prototype.json = Sequelize.json;
  633. Sequelize.prototype.where = Sequelize.where;
  634. Sequelize.prototype.validate = Sequelize.prototype.authenticate;
  635. /**
  636. * Sequelize version number.
  637. */
  638. // To avoid any errors on startup when this field is unused, only resolve it as needed.
  639. // this is to prevent any potential issues on startup with unusual environments (eg, bundled code)
  640. // where relative paths may fail that are unnecessary.
  641. Object.defineProperty(Sequelize, 'version', {
  642. enumerable: true,
  643. get() {
  644. return require('../package.json').version;
  645. },
  646. });
  647. /**
  648. * Operators symbols to be used for querying data
  649. *
  650. * @see {@link Operators}
  651. */
  652. Sequelize.Op = Op;
  653. /**
  654. * Available table hints to be used for querying data in mssql for table hints
  655. *
  656. * @see {@link TableHints}
  657. */
  658. Sequelize.TableHints = TableHints;
  659. /**
  660. * Available index hints to be used for querying data in mysql for index hints
  661. *
  662. * @see {@link IndexHints}
  663. */
  664. Sequelize.IndexHints = IndexHints;
  665. /**
  666. * A reference to the sequelize transaction class. Use this to access isolationLevels and types when creating a transaction
  667. *
  668. * @see {@link Transaction}
  669. * @see {@link Sequelize.transaction}
  670. */
  671. Sequelize.Transaction = Transaction;
  672. Sequelize.GeoJsonType = require('./geo-json').GeoJsonType;
  673. /**
  674. * A reference to Sequelize constructor from sequelize. Useful for accessing DataTypes, Errors etc.
  675. *
  676. * @see {@link Sequelize}
  677. */
  678. Sequelize.prototype.Sequelize = Sequelize;
  679. /**
  680. * Available query types for use with `sequelize.query`
  681. *
  682. * @see {@link QueryTypes}
  683. */
  684. Sequelize.prototype.QueryTypes = Sequelize.QueryTypes = QueryTypes;
  685. /**
  686. * Exposes the validator.js object, so you can extend it with custom validation functions. The validator is exposed both on the instance, and on the constructor.
  687. *
  688. * @see https://github.com/chriso/validator.js
  689. */
  690. Sequelize.prototype.Validator = Sequelize.Validator = Validator;
  691. Sequelize.Model = Model;
  692. Sequelize.AbstractQueryInterface = AbstractQueryInterface;
  693. Sequelize.BelongsToAssociation = BelongsToAssociation;
  694. Sequelize.HasOneAssociation = HasOneAssociation;
  695. Sequelize.HasManyAssociation = HasManyAssociation;
  696. Sequelize.BelongsToManyAssociation = BelongsToManyAssociation;
  697. Sequelize.DataTypes = DataTypes;
  698. for (const dataTypeName in DataTypes) {
  699. Object.defineProperty(Sequelize, dataTypeName, {
  700. get() {
  701. noSequelizeDataType();
  702. return DataTypes[dataTypeName];
  703. },
  704. });
  705. }
  706. /**
  707. * A reference to the deferrable collection. Use this to access the different deferrable options.
  708. *
  709. * @see {@link QueryInterface#addConstraint}
  710. */
  711. Sequelize.Deferrable = Deferrable;
  712. /**
  713. * A reference to the deferrable collection. Use this to access the different deferrable options.
  714. *
  715. * @see {@link Transaction.Deferrable}
  716. * @see {@link Sequelize#transaction}
  717. */
  718. Sequelize.ConstraintChecking = ConstraintChecking;
  719. /**
  720. * A reference to the sequelize association class.
  721. *
  722. * @see {@link Association}
  723. */
  724. Sequelize.prototype.Association = Sequelize.Association = Association;
  725. /**
  726. * Provide alternative version of `inflection` module to be used by `pluralize` etc.
  727. *
  728. * @param {object} _inflection - `inflection` module
  729. */
  730. Sequelize.useInflection = useInflection;
  731. Sequelize.SQL_NULL = SQL_NULL;
  732. Sequelize.JSON_NULL = JSON_NULL;
  733. Sequelize.ManualOnDelete = ManualOnDelete;
  734. Sequelize.AbstractConnectionManager = AbstractConnectionManager;
  735. Sequelize.AbstractQueryGenerator = AbstractQueryGenerator;
  736. Sequelize.AbstractQuery = AbstractQuery;
  737. Sequelize.AbstractDialect = AbstractDialect;
  738. /**
  739. * Expose various errors available
  740. */
  741. for (const error of Object.keys(SequelizeErrors)) {
  742. Sequelize[error] = SequelizeErrors[error];
  743. }
  744. /**
  745. * An AND query
  746. *
  747. * @see Model.findAll
  748. *
  749. * @param {...string|object} args Each argument will be joined by AND
  750. * @since v2.0.0-dev3
  751. * @memberof Sequelize
  752. *
  753. * @returns {Sequelize.and}
  754. */
  755. export function and(...args) {
  756. return { [Op.and]: args };
  757. }
  758. /**
  759. * An OR query
  760. *
  761. * @see
  762. * {@link Model.findAll}
  763. *
  764. * @param {...string|object} args Each argument will be joined by OR
  765. * @since v2.0.0-dev3
  766. * @memberof Sequelize
  767. *
  768. * @returns {Sequelize.or}
  769. */
  770. export function or(...args) {
  771. if (args.length === 1) {
  772. return { [Op.or]: args[0] };
  773. }
  774. return { [Op.or]: args };
  775. }