add-show-remove-constraint.test.ts 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. import { AggregateError, DataTypes, Op, UnknownConstraintError } from '@sequelize/core';
  2. import { assert, expect } from 'chai';
  3. import { sequelize } from '../support';
  4. const queryInterface = sequelize.queryInterface;
  5. const dialect = sequelize.dialect.name;
  6. describe('QueryInterface#{add,show,removeConstraint}', () => {
  7. describe('Without schema', () => {
  8. const defaultSchema = sequelize.dialect.getDefaultSchema();
  9. beforeEach(async () => {
  10. await queryInterface.createTable('levels', {
  11. id: {
  12. type: DataTypes.INTEGER,
  13. allowNull: false,
  14. },
  15. manager_id: {
  16. type: DataTypes.INTEGER,
  17. allowNull: false,
  18. },
  19. name: {
  20. type: DataTypes.STRING,
  21. allowNull: false,
  22. },
  23. });
  24. await queryInterface.createTable('actors', {
  25. id: {
  26. type: DataTypes.INTEGER,
  27. allowNull: false,
  28. },
  29. manager_id: {
  30. type: DataTypes.INTEGER,
  31. allowNull: false,
  32. },
  33. name: {
  34. type: DataTypes.STRING,
  35. allowNull: false,
  36. },
  37. status: {
  38. type: DataTypes.STRING,
  39. allowNull: true,
  40. },
  41. age: {
  42. type: DataTypes.INTEGER,
  43. allowNull: false,
  44. },
  45. level_id: {
  46. type: DataTypes.INTEGER,
  47. allowNull: false,
  48. },
  49. });
  50. });
  51. it('should throw an error if constraint type is missing', async () => {
  52. await expect(
  53. // @ts-expect-error -- intentionally missing type
  54. queryInterface.addConstraint('levels', {
  55. fields: ['roles'],
  56. where: { roles: ['user', 'admin', 'guest', 'moderator'] },
  57. name: 'check_user_roles',
  58. }),
  59. ).to.be.rejectedWith(Error, 'Constraint type must be specified through options.type');
  60. });
  61. it('should throw non existent constraints as UnknownConstraintError', async () => {
  62. try {
  63. await queryInterface.removeConstraint('levels', 'unknown__constraint__name', {
  64. type: 'unique',
  65. });
  66. expect.fail('Expected to throw an error');
  67. } catch (error) {
  68. let err = error;
  69. if (dialect === 'mssql') {
  70. assert(
  71. error instanceof AggregateError,
  72. 'Expected error to be an instance of AggregateError',
  73. );
  74. err = error.errors.at(-1);
  75. } else {
  76. assert(
  77. err instanceof UnknownConstraintError,
  78. 'Expected error to be an instance of UnknownConstraintError',
  79. );
  80. if (dialect !== 'ibmi') {
  81. expect(err.table).to.equal('levels');
  82. }
  83. expect(err.constraint).to.equal('unknown__constraint__name');
  84. }
  85. }
  86. });
  87. it('should add, show and delete a UNIQUE constraint', async () => {
  88. await queryInterface.addConstraint('actors', {
  89. name: 'custom_constraint_name',
  90. type: 'UNIQUE',
  91. fields: ['name', 'age'],
  92. });
  93. const constraintType = await queryInterface.showConstraints('actors', {
  94. constraintType: 'UNIQUE',
  95. });
  96. const constraints = constraintType.filter(
  97. constraint => constraint.constraintName === 'custom_constraint_name',
  98. );
  99. expect(constraints).to.have.length(1);
  100. expect(constraints[0]).to.deep.equal({
  101. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  102. constraintSchema: defaultSchema,
  103. constraintName: 'custom_constraint_name',
  104. constraintType: 'UNIQUE',
  105. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  106. tableSchema: defaultSchema,
  107. tableName: 'actors',
  108. columnNames: ['name', 'age'],
  109. ...(sequelize.dialect.supports.constraints.deferrable && {
  110. deferrable: 'INITIALLY_IMMEDIATE',
  111. }),
  112. });
  113. await queryInterface.removeConstraint('actors', 'custom_constraint_name');
  114. const constraintsAfterRemove = await queryInterface.showConstraints('actors', {
  115. constraintName: 'custom_constraint_name',
  116. });
  117. expect(constraintsAfterRemove).to.have.length(0);
  118. });
  119. it('should add, show and delete a PRIMARY & FOREIGN KEY constraint', async () => {
  120. await queryInterface.addConstraint('levels', {
  121. name: 'pk_levels',
  122. type: 'PRIMARY KEY',
  123. fields: ['id'],
  124. });
  125. await queryInterface.addConstraint('actors', {
  126. name: 'custom_constraint_name',
  127. type: 'FOREIGN KEY',
  128. fields: ['level_id'],
  129. references: {
  130. table: 'levels',
  131. field: 'id',
  132. },
  133. onDelete: 'CASCADE',
  134. });
  135. const foreignKeys = await queryInterface.showConstraints('actors', {
  136. columnName: 'level_id',
  137. constraintType: 'FOREIGN KEY',
  138. });
  139. expect(foreignKeys).to.have.length(1);
  140. expect(foreignKeys[0]).to.deep.equal({
  141. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  142. constraintSchema: defaultSchema,
  143. constraintName: 'custom_constraint_name',
  144. constraintType: 'FOREIGN KEY',
  145. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  146. tableSchema: defaultSchema,
  147. tableName: 'actors',
  148. columnNames: ['level_id'],
  149. referencedTableName: 'levels',
  150. referencedTableSchema: defaultSchema,
  151. referencedColumnNames: ['id'],
  152. deleteAction: 'CASCADE',
  153. updateAction: dialect === 'mariadb' ? 'RESTRICT' : dialect === 'sqlite3' ? '' : 'NO ACTION',
  154. ...(sequelize.dialect.supports.constraints.deferrable && {
  155. deferrable: 'INITIALLY_IMMEDIATE',
  156. }),
  157. });
  158. await queryInterface.removeConstraint('actors', 'custom_constraint_name');
  159. const fkAfterRemove = await queryInterface.showConstraints('actors', {
  160. constraintName: 'custom_constraint_name',
  161. });
  162. expect(fkAfterRemove).to.have.length(0);
  163. const primaryKeys = await queryInterface.showConstraints('levels', {
  164. columnName: 'id',
  165. constraintType: 'PRIMARY KEY',
  166. });
  167. expect(primaryKeys).to.have.length(1);
  168. expect(primaryKeys[0]).to.deep.equal({
  169. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  170. constraintSchema: defaultSchema,
  171. constraintName: ['mariadb', 'mysql'].includes(dialect) ? 'PRIMARY' : 'pk_levels',
  172. constraintType: 'PRIMARY KEY',
  173. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  174. tableSchema: defaultSchema,
  175. tableName: 'levels',
  176. columnNames: ['id'],
  177. ...(sequelize.dialect.supports.constraints.deferrable && {
  178. deferrable: 'INITIALLY_IMMEDIATE',
  179. }),
  180. });
  181. await queryInterface.removeConstraint(
  182. 'levels',
  183. ['mariadb', 'mysql'].includes(dialect) ? 'PRIMARY' : 'pk_levels',
  184. );
  185. const pkAfterRemove = await queryInterface.showConstraints('levels', {
  186. constraintName: ['mariadb', 'mysql'].includes(dialect) ? 'PRIMARY' : 'pk_levels',
  187. });
  188. expect(pkAfterRemove).to.have.length(0);
  189. });
  190. it('should add, show and delete a composite PRIMARY & FOREIGN KEY constraint', async () => {
  191. await queryInterface.addConstraint('levels', {
  192. name: 'pk_levels',
  193. type: 'PRIMARY KEY',
  194. fields: ['id', 'manager_id'],
  195. });
  196. await queryInterface.addConstraint('actors', {
  197. name: 'custom_constraint_name',
  198. type: 'FOREIGN KEY',
  199. fields: ['level_id', 'manager_id'],
  200. references: {
  201. table: 'levels',
  202. fields: ['id', 'manager_id'],
  203. },
  204. onDelete: 'CASCADE',
  205. });
  206. const foreignKeys = await queryInterface.showConstraints('actors', {
  207. constraintType: 'FOREIGN KEY',
  208. });
  209. expect(foreignKeys).to.have.length(1);
  210. expect(foreignKeys[0]).to.deep.equal({
  211. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  212. constraintSchema: defaultSchema,
  213. constraintName: 'custom_constraint_name',
  214. constraintType: 'FOREIGN KEY',
  215. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  216. tableSchema: defaultSchema,
  217. tableName: 'actors',
  218. columnNames: ['level_id', 'manager_id'],
  219. referencedTableSchema: defaultSchema,
  220. referencedTableName: 'levels',
  221. referencedColumnNames: ['id', 'manager_id'],
  222. deleteAction: 'CASCADE',
  223. updateAction: dialect === 'mariadb' ? 'RESTRICT' : dialect === 'sqlite3' ? '' : 'NO ACTION',
  224. ...(sequelize.dialect.supports.constraints.deferrable && {
  225. deferrable: 'INITIALLY_IMMEDIATE',
  226. }),
  227. });
  228. await queryInterface.removeConstraint('actors', 'custom_constraint_name');
  229. const fkAfterRemove = await queryInterface.showConstraints('actors', {
  230. constraintName: 'custom_constraint_name',
  231. });
  232. expect(fkAfterRemove).to.have.length(0);
  233. const primaryKeys = await queryInterface.showConstraints('levels', {
  234. constraintType: 'PRIMARY KEY',
  235. });
  236. expect(primaryKeys).to.have.length(1);
  237. expect(primaryKeys[0]).to.deep.equal({
  238. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  239. constraintSchema: defaultSchema,
  240. constraintName: ['mariadb', 'mysql'].includes(dialect) ? 'PRIMARY' : 'pk_levels',
  241. constraintType: 'PRIMARY KEY',
  242. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  243. tableSchema: defaultSchema,
  244. tableName: 'levels',
  245. columnNames: ['id', 'manager_id'],
  246. ...(sequelize.dialect.supports.constraints.deferrable && {
  247. deferrable: 'INITIALLY_IMMEDIATE',
  248. }),
  249. });
  250. await queryInterface.removeConstraint(
  251. 'levels',
  252. ['mariadb', 'mysql'].includes(dialect) ? 'PRIMARY' : 'pk_levels',
  253. );
  254. const pkAfterRemove = await queryInterface.showConstraints('levels', {
  255. constraintName: ['mariadb', 'mysql'].includes(dialect) ? 'PRIMARY' : 'pk_levels',
  256. });
  257. expect(pkAfterRemove).to.have.length(0);
  258. });
  259. if (sequelize.dialect.supports.constraints.onUpdate) {
  260. it('should add a FOREIGN KEY constraints with onUpdate', async () => {
  261. await queryInterface.addConstraint('levels', {
  262. name: 'pk_levels',
  263. type: 'PRIMARY KEY',
  264. fields: ['id'],
  265. });
  266. await queryInterface.addConstraint('actors', {
  267. name: 'custom_constraint_name',
  268. type: 'FOREIGN KEY',
  269. fields: ['level_id'],
  270. references: {
  271. table: 'levels',
  272. field: 'id',
  273. },
  274. onDelete: 'CASCADE',
  275. onUpdate: 'CASCADE',
  276. });
  277. const constraintType = await queryInterface.showConstraints('actors', {
  278. columnName: 'level_id',
  279. constraintType: 'FOREIGN KEY',
  280. });
  281. const constraints = constraintType.filter(
  282. constraint => constraint.constraintName === 'custom_constraint_name',
  283. );
  284. expect(constraints).to.have.length(1);
  285. expect(constraints[0]).to.deep.equal({
  286. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  287. constraintSchema: defaultSchema,
  288. constraintName: 'custom_constraint_name',
  289. constraintType: 'FOREIGN KEY',
  290. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  291. tableSchema: defaultSchema,
  292. tableName: 'actors',
  293. columnNames: ['level_id'],
  294. referencedTableName: 'levels',
  295. referencedTableSchema: defaultSchema,
  296. referencedColumnNames: ['id'],
  297. deleteAction: 'CASCADE',
  298. updateAction: 'CASCADE',
  299. ...(sequelize.dialect.supports.constraints.deferrable && {
  300. deferrable: 'INITIALLY_IMMEDIATE',
  301. }),
  302. });
  303. });
  304. }
  305. if (sequelize.dialect.supports.constraints.check) {
  306. it('should add, show and delete a CHECK constraint', async () => {
  307. await queryInterface.addConstraint('actors', {
  308. name: 'custom_constraint_name',
  309. type: 'CHECK',
  310. fields: ['age'],
  311. where: {
  312. age: {
  313. [Op.gt]: 10,
  314. },
  315. },
  316. });
  317. const constraintType = await queryInterface.showConstraints('actors', {
  318. constraintType: 'CHECK',
  319. });
  320. if (dialect === 'postgres') {
  321. // Postgres adds a CHECK constraint for each column with not null
  322. expect(constraintType).to.have.length(6);
  323. expect(constraintType[5].constraintType).to.equal('CHECK');
  324. } else {
  325. expect(constraintType).to.have.length(1);
  326. expect(constraintType[0].constraintType).to.equal('CHECK');
  327. }
  328. const constraints = constraintType.filter(
  329. constraint => constraint.constraintName === 'custom_constraint_name',
  330. );
  331. expect(constraints).to.have.length(1);
  332. expect(constraints[0]).to.deep.equal({
  333. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  334. constraintSchema: defaultSchema,
  335. constraintName: 'custom_constraint_name',
  336. constraintType: 'CHECK',
  337. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  338. tableSchema: defaultSchema,
  339. tableName: 'actors',
  340. definition:
  341. dialect === 'mssql'
  342. ? '([age]>(10))'
  343. : dialect === 'db2'
  344. ? '"age" > 10'
  345. : dialect === 'postgres'
  346. ? '(age > 10)'
  347. : ['mysql', 'sqlite3'].includes(dialect)
  348. ? '(`age` > 10)'
  349. : '`age` > 10',
  350. ...(sequelize.dialect.supports.constraints.deferrable && {
  351. deferrable: 'INITIALLY_IMMEDIATE',
  352. }),
  353. });
  354. await queryInterface.removeConstraint('actors', 'custom_constraint_name');
  355. const constraintsAfterRemove = await queryInterface.showConstraints('actors', {
  356. constraintName: 'custom_constraint_name',
  357. });
  358. expect(constraintsAfterRemove).to.have.length(0);
  359. });
  360. }
  361. if (sequelize.dialect.supports.constraints.default) {
  362. it('should add, show and delete a DEFAULT constraints', async () => {
  363. await queryInterface.addConstraint('actors', {
  364. name: 'custom_constraint_name',
  365. type: 'DEFAULT',
  366. fields: ['status'],
  367. defaultValue: 'active',
  368. });
  369. const constraintType = await queryInterface.showConstraints('actors', {
  370. columnName: 'status',
  371. constraintType: 'DEFAULT',
  372. });
  373. const constraints = constraintType.filter(
  374. constraint => constraint.constraintName === 'custom_constraint_name',
  375. );
  376. expect(constraints).to.have.length(1);
  377. expect(constraints[0]).to.deep.equal({
  378. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  379. constraintSchema: defaultSchema,
  380. constraintName: 'custom_constraint_name',
  381. constraintType: 'DEFAULT',
  382. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  383. tableSchema: defaultSchema,
  384. tableName: 'actors',
  385. columnNames: ['status'],
  386. definition: dialect === 'mssql' ? `(N'active')` : `DEFAULT 'active'`,
  387. ...(sequelize.dialect.supports.constraints.deferrable && {
  388. deferrable: 'INITIALLY_IMMEDIATE',
  389. }),
  390. });
  391. await queryInterface.removeConstraint('actors', 'custom_constraint_name');
  392. const constraintsAfterRemove = await queryInterface.showConstraints('actors', {
  393. constraintName: 'custom_constraint_name',
  394. });
  395. expect(constraintsAfterRemove).to.have.length(0);
  396. });
  397. }
  398. });
  399. if (sequelize.dialect.supports.schemas) {
  400. describe('With schema', () => {
  401. const schema = 'archive';
  402. beforeEach(async () => {
  403. await queryInterface.createSchema(schema);
  404. await queryInterface.createTable(
  405. {
  406. tableName: 'levels',
  407. schema,
  408. },
  409. {
  410. id: {
  411. type: DataTypes.INTEGER,
  412. allowNull: false,
  413. },
  414. manager_id: {
  415. type: DataTypes.INTEGER,
  416. allowNull: false,
  417. },
  418. name: {
  419. type: DataTypes.STRING,
  420. allowNull: false,
  421. },
  422. },
  423. );
  424. await queryInterface.createTable(
  425. {
  426. tableName: 'actors',
  427. schema,
  428. },
  429. {
  430. id: {
  431. type: DataTypes.INTEGER,
  432. allowNull: false,
  433. },
  434. manager_id: {
  435. type: DataTypes.INTEGER,
  436. allowNull: false,
  437. },
  438. name: {
  439. type: DataTypes.STRING,
  440. allowNull: false,
  441. },
  442. status: {
  443. type: DataTypes.STRING,
  444. allowNull: true,
  445. },
  446. age: {
  447. type: DataTypes.INTEGER,
  448. allowNull: false,
  449. },
  450. level_id: {
  451. type: DataTypes.INTEGER,
  452. allowNull: false,
  453. },
  454. },
  455. );
  456. await queryInterface.addConstraint(
  457. { tableName: 'levels', schema },
  458. {
  459. name: 'pk_levels',
  460. type: 'PRIMARY KEY',
  461. fields: ['id'],
  462. },
  463. );
  464. await queryInterface.addConstraint(
  465. { tableName: 'actors', schema },
  466. {
  467. name: 'custom_constraint_name',
  468. type: 'FOREIGN KEY',
  469. fields: ['level_id'],
  470. references: {
  471. table: { tableName: 'levels', schema },
  472. field: 'id',
  473. },
  474. onDelete: 'CASCADE',
  475. },
  476. );
  477. });
  478. it('should add, show and delete a PRIMARY & FOREIGN KEY constraint', async () => {
  479. const foreignKeys = await queryInterface.showConstraints(
  480. { tableName: 'actors', schema },
  481. { columnName: 'level_id', constraintType: 'FOREIGN KEY' },
  482. );
  483. expect(foreignKeys).to.have.length(1);
  484. expect(foreignKeys[0]).to.deep.equal({
  485. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  486. constraintSchema: schema,
  487. constraintName: 'custom_constraint_name',
  488. constraintType: 'FOREIGN KEY',
  489. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  490. tableSchema: schema,
  491. tableName: 'actors',
  492. columnNames: ['level_id'],
  493. referencedTableSchema: schema,
  494. referencedTableName: 'levels',
  495. referencedColumnNames: ['id'],
  496. deleteAction: 'CASCADE',
  497. updateAction:
  498. dialect === 'mariadb' ? 'RESTRICT' : dialect === 'sqlite3' ? '' : 'NO ACTION',
  499. ...(sequelize.dialect.supports.constraints.deferrable && {
  500. deferrable: 'INITIALLY_IMMEDIATE',
  501. }),
  502. });
  503. await queryInterface.removeConstraint(
  504. { tableName: 'actors', schema },
  505. 'custom_constraint_name',
  506. );
  507. const fkAfterRemove = await queryInterface.showConstraints(
  508. { tableName: 'actors', schema },
  509. { constraintName: 'custom_constraint_name' },
  510. );
  511. expect(fkAfterRemove).to.have.length(0);
  512. const primaryKeys = await queryInterface.showConstraints(
  513. { tableName: 'levels', schema },
  514. { columnName: 'id', constraintType: 'PRIMARY KEY' },
  515. );
  516. expect(primaryKeys).to.have.length(1);
  517. expect(primaryKeys[0]).to.deep.equal({
  518. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  519. constraintSchema: schema,
  520. constraintName: ['mariadb', 'mysql'].includes(dialect) ? 'PRIMARY' : 'pk_levels',
  521. constraintType: 'PRIMARY KEY',
  522. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  523. tableSchema: schema,
  524. tableName: 'levels',
  525. columnNames: ['id'],
  526. ...(sequelize.dialect.supports.constraints.deferrable && {
  527. deferrable: 'INITIALLY_IMMEDIATE',
  528. }),
  529. });
  530. await queryInterface.removeConstraint(
  531. { tableName: 'levels', schema },
  532. ['mariadb', 'mysql'].includes(dialect) ? 'PRIMARY' : 'pk_levels',
  533. );
  534. const pkAfterRemove = await queryInterface.showConstraints(
  535. { tableName: 'levels', schema },
  536. { constraintName: ['mariadb', 'mysql'].includes(dialect) ? 'PRIMARY' : 'pk_levels' },
  537. );
  538. expect(pkAfterRemove).to.have.length(0);
  539. });
  540. describe('when tables are present in different schemas', () => {
  541. beforeEach(async () => {
  542. await queryInterface.createTable(
  543. {
  544. tableName: 'levels',
  545. },
  546. {
  547. id: {
  548. type: DataTypes.INTEGER,
  549. allowNull: false,
  550. primaryKey: true,
  551. },
  552. name: {
  553. type: DataTypes.STRING,
  554. allowNull: false,
  555. },
  556. },
  557. );
  558. await queryInterface.createTable(
  559. {
  560. tableName: 'actors',
  561. },
  562. {
  563. id: {
  564. type: DataTypes.INTEGER,
  565. allowNull: false,
  566. },
  567. name: {
  568. type: DataTypes.STRING,
  569. allowNull: false,
  570. },
  571. level_id: {
  572. type: DataTypes.INTEGER,
  573. allowNull: false,
  574. },
  575. },
  576. );
  577. await queryInterface.addConstraint(
  578. { tableName: 'actors' },
  579. {
  580. name: 'custom_constraint_name',
  581. type: 'FOREIGN KEY',
  582. fields: ['level_id'],
  583. references: {
  584. table: { tableName: 'levels' },
  585. field: 'id',
  586. },
  587. onDelete: 'CASCADE',
  588. },
  589. );
  590. });
  591. it('should show only foreign key constraints for the table in the right schema', async () => {
  592. const foreignKeys = await queryInterface.showConstraints(
  593. { tableName: 'actors', schema },
  594. { columnName: 'level_id', constraintType: 'FOREIGN KEY' },
  595. );
  596. expect(foreignKeys).to.have.length(1);
  597. expect(foreignKeys[0]).to.deep.equal({
  598. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  599. constraintSchema: schema,
  600. constraintName: 'custom_constraint_name',
  601. constraintType: 'FOREIGN KEY',
  602. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  603. tableSchema: schema,
  604. tableName: 'actors',
  605. columnNames: ['level_id'],
  606. referencedTableSchema: schema,
  607. referencedTableName: 'levels',
  608. referencedColumnNames: ['id'],
  609. deleteAction: 'CASCADE',
  610. updateAction:
  611. dialect === 'mariadb' ? 'RESTRICT' : dialect === 'sqlite3' ? '' : 'NO ACTION',
  612. ...(sequelize.dialect.supports.constraints.deferrable && {
  613. deferrable: 'INITIALLY_IMMEDIATE',
  614. }),
  615. });
  616. });
  617. it('should show only foreign key constraints for the table in the default schema', async () => {
  618. const foreignKeys = await queryInterface.showConstraints('actors', {
  619. columnName: 'level_id',
  620. constraintType: 'FOREIGN KEY',
  621. });
  622. expect(foreignKeys).to.have.length(1);
  623. expect(foreignKeys[0]).to.deep.equal({
  624. ...(['mssql', 'postgres'].includes(dialect) && { constraintCatalog: 'sequelize_test' }),
  625. constraintSchema: sequelize.dialect.getDefaultSchema(),
  626. constraintName: 'custom_constraint_name',
  627. constraintType: 'FOREIGN KEY',
  628. ...(['mssql', 'postgres'].includes(dialect) && { tableCatalog: 'sequelize_test' }),
  629. tableSchema: sequelize.dialect.getDefaultSchema(),
  630. tableName: 'actors',
  631. columnNames: ['level_id'],
  632. referencedTableSchema: sequelize.dialect.getDefaultSchema(),
  633. referencedTableName: 'levels',
  634. referencedColumnNames: ['id'],
  635. deleteAction: 'CASCADE',
  636. updateAction:
  637. dialect === 'mariadb' ? 'RESTRICT' : dialect === 'sqlite3' ? '' : 'NO ACTION',
  638. ...(sequelize.dialect.supports.constraints.deferrable && {
  639. deferrable: 'INITIALLY_IMMEDIATE',
  640. }),
  641. });
  642. });
  643. });
  644. });
  645. }
  646. });