create.test.js 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636
  1. 'use strict';
  2. const range = require('lodash/range');
  3. const chai = require('chai');
  4. const sinon = require('sinon');
  5. const expect = chai.expect;
  6. const Support = require('../support');
  7. const { DataTypes, Op, Sequelize, sql } = require('@sequelize/core');
  8. const delay = require('delay');
  9. const assert = require('node:assert');
  10. const pTimeout = require('p-timeout');
  11. const current = Support.sequelize;
  12. const dialect = current.dialect;
  13. const dialectName = Support.getTestDialect();
  14. describe(Support.getTestDialectTeaser('Model'), () => {
  15. beforeEach(async function () {
  16. const sequelize = await Support.createMultiTransactionalTestSequelizeInstance(this.sequelize);
  17. this.customSequelize = sequelize;
  18. this.User = this.customSequelize.define('User', {
  19. username: DataTypes.STRING,
  20. secretValue: DataTypes.STRING,
  21. data: DataTypes.STRING,
  22. intVal: DataTypes.INTEGER,
  23. theDate: DataTypes.DATE,
  24. aBool: DataTypes.BOOLEAN,
  25. uniqueName: { type: DataTypes.STRING, unique: true },
  26. });
  27. this.Account = this.customSequelize.define('Account', {
  28. accountName: DataTypes.STRING,
  29. });
  30. this.Student = this.customSequelize.define('Student', {
  31. no: { type: DataTypes.INTEGER, primaryKey: true },
  32. name: { type: DataTypes.STRING, allowNull: false },
  33. });
  34. await this.customSequelize.sync({ force: true });
  35. });
  36. afterEach(function () {
  37. return this.customSequelize.close();
  38. });
  39. // TODO: move to own suite
  40. describe('findOrCreate', () => {
  41. if (current.dialect.supports.transactions) {
  42. it('supports transactions', async function () {
  43. const t = await this.customSequelize.startUnmanagedTransaction();
  44. await this.User.findOrCreate({
  45. where: {
  46. username: 'Username',
  47. },
  48. defaults: {
  49. data: 'some data',
  50. },
  51. transaction: t,
  52. });
  53. const count = await this.User.count();
  54. expect(count).to.equal(0);
  55. await t.commit();
  56. const count0 = await this.User.count();
  57. expect(count0).to.equal(1);
  58. });
  59. it('supports more than one models per transaction', async function () {
  60. const t = await this.customSequelize.startUnmanagedTransaction();
  61. await this.User.findOrCreate({
  62. where: { username: 'Username' },
  63. defaults: { data: 'some data' },
  64. transaction: t,
  65. });
  66. await this.Account.findOrCreate({ where: { accountName: 'accountName' }, transaction: t });
  67. await t.commit();
  68. });
  69. }
  70. it('should error correctly when defaults contain a unique key', async function () {
  71. const User = this.customSequelize.define('user', {
  72. objectId: {
  73. type: DataTypes.STRING,
  74. unique: true,
  75. },
  76. username: {
  77. type: DataTypes.STRING,
  78. unique: true,
  79. },
  80. });
  81. await User.sync({ force: true });
  82. await User.create({
  83. username: 'gottlieb',
  84. });
  85. await expect(
  86. User.findOrCreate({
  87. where: {
  88. objectId: 'asdasdasd',
  89. },
  90. defaults: {
  91. username: 'gottlieb',
  92. },
  93. }),
  94. ).to.eventually.be.rejectedWith(Sequelize.UniqueConstraintError);
  95. });
  96. it('should error correctly when defaults contain a unique key and a non-existent field', async function () {
  97. const User = this.customSequelize.define('user', {
  98. objectId: {
  99. type: DataTypes.STRING,
  100. unique: true,
  101. },
  102. username: {
  103. type: DataTypes.STRING,
  104. unique: true,
  105. },
  106. });
  107. await User.sync({ force: true });
  108. await User.create({
  109. username: 'gottlieb',
  110. });
  111. await expect(
  112. User.findOrCreate({
  113. where: {
  114. objectId: 'asdasdasd',
  115. },
  116. defaults: {
  117. username: 'gottlieb',
  118. foo: 'bar', // field that's not a defined attribute
  119. bar: 121,
  120. },
  121. }),
  122. ).to.eventually.be.rejectedWith(Sequelize.UniqueConstraintError);
  123. });
  124. it('should error correctly when defaults contain a unique key and the where clause is complex', async function () {
  125. const User = this.customSequelize.define('user', {
  126. objectId: {
  127. type: DataTypes.STRING,
  128. unique: true,
  129. },
  130. username: {
  131. type: DataTypes.STRING,
  132. unique: true,
  133. },
  134. });
  135. await User.sync({ force: true });
  136. await User.create({ username: 'gottlieb' });
  137. try {
  138. await User.findOrCreate({
  139. where: {
  140. [Op.or]: [
  141. {
  142. objectId: 'asdasdasd1',
  143. },
  144. {
  145. objectId: 'asdasdasd2',
  146. },
  147. ],
  148. },
  149. defaults: {
  150. username: 'gottlieb',
  151. },
  152. });
  153. } catch (error) {
  154. expect(error).to.be.instanceof(Sequelize.UniqueConstraintError);
  155. if (dialectName !== 'ibmi') {
  156. expect(error.errors[0].path).to.be.a('string', 'username');
  157. }
  158. }
  159. });
  160. it('should work with empty uuid primary key in where', async function () {
  161. const User = this.customSequelize.define('User', {
  162. id: {
  163. type: DataTypes.UUID,
  164. primaryKey: true,
  165. allowNull: false,
  166. defaultValue: sql.uuidV4,
  167. },
  168. name: {
  169. type: DataTypes.STRING,
  170. },
  171. });
  172. await User.sync({ force: true });
  173. await User.findOrCreate({
  174. where: {},
  175. defaults: {
  176. name: Math.random().toString(),
  177. },
  178. });
  179. });
  180. if (!['sqlite3', 'mssql', 'db2', 'ibmi'].includes(current.dialect.name)) {
  181. it('should not deadlock with no existing entries and no outer transaction', async function () {
  182. const User = this.customSequelize.define('User', {
  183. email: {
  184. type: DataTypes.STRING,
  185. unique: 'company_user_email',
  186. },
  187. companyId: {
  188. type: DataTypes.INTEGER,
  189. unique: 'company_user_email',
  190. },
  191. });
  192. await User.sync({ force: true });
  193. await Promise.all(
  194. range(50).map(i => {
  195. return User.findOrCreate({
  196. where: {
  197. email: `unique.email.${i}@sequelizejs.com`,
  198. companyId: Math.floor(Math.random() * 5),
  199. },
  200. });
  201. }),
  202. );
  203. });
  204. it('should not deadlock with existing entries and no outer transaction', async function () {
  205. const User = this.customSequelize.define('User', {
  206. email: {
  207. type: DataTypes.STRING,
  208. unique: 'company_user_email',
  209. },
  210. companyId: {
  211. type: DataTypes.INTEGER,
  212. unique: 'company_user_email',
  213. },
  214. });
  215. await User.sync({ force: true });
  216. await Promise.all(
  217. range(50).map(i => {
  218. return User.findOrCreate({
  219. where: {
  220. email: `unique.email.${i}@sequelizejs.com`,
  221. companyId: 2,
  222. },
  223. });
  224. }),
  225. );
  226. await Promise.all(
  227. range(50).map(i => {
  228. return User.findOrCreate({
  229. where: {
  230. email: `unique.email.${i}@sequelizejs.com`,
  231. companyId: 2,
  232. },
  233. });
  234. }),
  235. );
  236. });
  237. it('should not deadlock with concurrency duplicate entries and no outer transaction', async function () {
  238. const User = this.customSequelize.define('User', {
  239. email: {
  240. type: DataTypes.STRING,
  241. unique: 'company_user_email',
  242. },
  243. companyId: {
  244. type: DataTypes.INTEGER,
  245. unique: 'company_user_email',
  246. },
  247. });
  248. await User.sync({ force: true });
  249. await Promise.all(
  250. range(50).map(() => {
  251. return User.findOrCreate({
  252. where: {
  253. email: 'unique.email.1@sequelizejs.com',
  254. companyId: 2,
  255. },
  256. });
  257. }),
  258. );
  259. });
  260. }
  261. it('should support special characters in defaults', async function () {
  262. const User = this.customSequelize.define('user', {
  263. objectId: {
  264. type: DataTypes.INTEGER,
  265. unique: true,
  266. },
  267. description: {
  268. type: DataTypes.TEXT,
  269. },
  270. });
  271. await User.sync({ force: true });
  272. await User.findOrCreate({
  273. where: {
  274. objectId: 1,
  275. },
  276. defaults: {
  277. description: "$$ and !! and :: and ? and ^ and * and '",
  278. },
  279. });
  280. });
  281. it('should support bools in defaults', async function () {
  282. const User = this.customSequelize.define('user', {
  283. objectId: {
  284. type: DataTypes.INTEGER,
  285. unique: true,
  286. },
  287. bool: DataTypes.BOOLEAN,
  288. });
  289. await User.sync({ force: true });
  290. await User.findOrCreate({
  291. where: {
  292. objectId: 1,
  293. },
  294. defaults: {
  295. bool: false,
  296. },
  297. });
  298. });
  299. it('returns instance if already existent. Single find field.', async function () {
  300. const data = {
  301. username: 'Username',
  302. };
  303. const user = await this.User.create(data);
  304. const [_user, created] = await this.User.findOrCreate({
  305. where: {
  306. username: user.username,
  307. },
  308. });
  309. expect(_user.id).to.equal(user.id);
  310. expect(_user.username).to.equal('Username');
  311. expect(created).to.be.false;
  312. });
  313. it('Returns instance if already existent. Multiple find fields.', async function () {
  314. const data = {
  315. username: 'Username',
  316. data: 'ThisIsData',
  317. };
  318. const user = await this.User.create(data);
  319. const [_user, created] = await this.User.findOrCreate({ where: data });
  320. expect(_user.id).to.equal(user.id);
  321. expect(_user.username).to.equal('Username');
  322. expect(_user.data).to.equal('ThisIsData');
  323. expect(created).to.be.false;
  324. });
  325. it('does not include exception catcher in response', async function () {
  326. const data = {
  327. username: 'Username',
  328. data: 'ThisIsData',
  329. };
  330. const [user0] = await this.User.findOrCreate({
  331. where: data,
  332. defaults: {},
  333. });
  334. expect(user0.dataValues.sequelize_caught_exception).to.be.undefined;
  335. const [user] = await this.User.findOrCreate({
  336. where: data,
  337. defaults: {},
  338. });
  339. expect(user.dataValues.sequelize_caught_exception).to.be.undefined;
  340. });
  341. it('creates new instance with default value.', async function () {
  342. const data = {
  343. username: 'Username',
  344. };
  345. const default_values = {
  346. data: 'ThisIsData',
  347. };
  348. const [user, created] = await this.User.findOrCreate({
  349. where: data,
  350. defaults: default_values,
  351. });
  352. expect(user.username).to.equal('Username');
  353. expect(user.data).to.equal('ThisIsData');
  354. expect(created).to.be.true;
  355. });
  356. it('supports .or() (only using default values)', async function () {
  357. const [user, created] = await this.User.findOrCreate({
  358. where: Sequelize.or({ username: 'Fooobzz' }, { secretValue: 'Yolo' }),
  359. defaults: { username: 'Fooobzz', secretValue: 'Yolo' },
  360. });
  361. expect(user.username).to.equal('Fooobzz');
  362. expect(user.secretValue).to.equal('Yolo');
  363. expect(created).to.be.true;
  364. });
  365. it('should ignore option returning', async function () {
  366. const [user, created] = await this.User.findOrCreate({
  367. where: { username: 'Username' },
  368. defaults: { data: 'ThisIsData' },
  369. returning: false,
  370. });
  371. expect(user.username).to.equal('Username');
  372. expect(user.data).to.equal('ThisIsData');
  373. expect(created).to.be.true;
  374. });
  375. if (current.dialect.supports.transactions) {
  376. it('should release transaction when meeting errors', async function () {
  377. const test = async times => {
  378. if (times > 10) {
  379. return true;
  380. }
  381. try {
  382. return await pTimeout(
  383. this.Student.findOrCreate({
  384. where: {
  385. no: 1,
  386. },
  387. }),
  388. 1000,
  389. );
  390. } catch (error) {
  391. if (error instanceof Sequelize.ValidationError) {
  392. return test(times + 1);
  393. }
  394. if (error instanceof pTimeout.TimeoutError) {
  395. throw new TypeError(error);
  396. }
  397. throw error;
  398. }
  399. };
  400. await test(0);
  401. });
  402. }
  403. describe('several concurrent calls', () => {
  404. if (current.dialect.supports.transactions) {
  405. it('works with a transaction', async function () {
  406. const transaction = await this.customSequelize.startUnmanagedTransaction();
  407. const [first, second] = await Promise.all([
  408. this.User.findOrCreate({ where: { uniqueName: 'winner' }, transaction }),
  409. this.User.findOrCreate({ where: { uniqueName: 'winner' }, transaction }),
  410. ]);
  411. const firstInstance = first[0];
  412. const firstCreated = first[1];
  413. const secondInstance = second[0];
  414. const secondCreated = second[1];
  415. // Depending on execution order and MAGIC either the first OR the second call should return true
  416. expect(firstCreated ? !secondCreated : secondCreated).to.be.ok; // XOR
  417. expect(firstInstance).to.be.ok;
  418. expect(secondInstance).to.be.ok;
  419. expect(firstInstance.id).to.equal(secondInstance.id);
  420. await transaction.commit();
  421. });
  422. }
  423. it('should not fail silently with concurrency higher than pool, a unique constraint and a create hook resulting in mismatched values', async function () {
  424. if (['sqlite3', 'mssql', 'db2', 'ibmi'].includes(dialectName)) {
  425. return;
  426. }
  427. const User = this.customSequelize.define('user', {
  428. username: {
  429. type: DataTypes.STRING,
  430. unique: true,
  431. columnName: 'user_name',
  432. },
  433. });
  434. User.beforeCreate(instance => {
  435. instance.username += ' h.';
  436. });
  437. const spy = sinon.spy();
  438. const names = ['mick', 'mick', 'mick', 'mick', 'mick', 'mick', 'mick'];
  439. await User.sync({ force: true });
  440. await Promise.all(
  441. names.map(async username => {
  442. try {
  443. return await User.findOrCreate({ where: { username } });
  444. } catch (error) {
  445. spy();
  446. expect(error.message).to.equal(
  447. `user#findOrCreate: value used for username was not equal for both the find and the create calls, 'mick' vs 'mick h.'`,
  448. );
  449. }
  450. }),
  451. );
  452. expect(spy).to.have.been.called;
  453. });
  454. it('should error correctly when defaults contain a unique key without a transaction', async function () {
  455. if (dialectName === 'sqlite3') {
  456. return;
  457. }
  458. const User = this.customSequelize.define('user', {
  459. objectId: {
  460. type: DataTypes.STRING,
  461. unique: true,
  462. },
  463. username: {
  464. type: DataTypes.STRING,
  465. unique: true,
  466. },
  467. });
  468. await User.sync({ force: true });
  469. await User.create({
  470. username: 'gottlieb',
  471. });
  472. return Promise.all([
  473. (async () => {
  474. const error = await expect(
  475. User.findOrCreate({
  476. where: {
  477. objectId: 'asdasdasd',
  478. },
  479. defaults: {
  480. username: 'gottlieb',
  481. },
  482. }),
  483. ).to.be.rejectedWith(Sequelize.UniqueConstraintError);
  484. expect(error.fields).to.be.ok;
  485. })(),
  486. (async () => {
  487. const error = await expect(
  488. User.findOrCreate({
  489. where: {
  490. objectId: 'asdasdasd',
  491. },
  492. defaults: {
  493. username: 'gottlieb',
  494. },
  495. }),
  496. ).to.be.rejectedWith(Sequelize.UniqueConstraintError);
  497. expect(error.fields).to.be.ok;
  498. })(),
  499. ]);
  500. });
  501. it('works without a transaction', async function () {
  502. // Creating two concurrent transactions and selecting / inserting from the same table throws sqlite off
  503. if (dialectName === 'sqlite3') {
  504. return;
  505. }
  506. const [first, second] = await Promise.all([
  507. this.User.findOrCreate({ where: { uniqueName: 'winner' } }),
  508. this.User.findOrCreate({ where: { uniqueName: 'winner' } }),
  509. ]);
  510. const firstInstance = first[0];
  511. const firstCreated = first[1];
  512. const secondInstance = second[0];
  513. const secondCreated = second[1];
  514. // Depending on execution order and MAGIC either the first OR the second call should return true
  515. expect(firstCreated ? !secondCreated : secondCreated).to.be.ok; // XOR
  516. expect(firstInstance).to.be.ok;
  517. expect(secondInstance).to.be.ok;
  518. expect(firstInstance.id).to.equal(secondInstance.id);
  519. });
  520. });
  521. });
  522. // TODO: move to own suite
  523. describe('findCreateFind', () => {
  524. if (dialectName !== 'sqlite3') {
  525. it('should work with multiple concurrent calls', async function () {
  526. const [[instance1, created1], [instance2, created2], [instance3, created3]] =
  527. await Promise.all([
  528. this.User.findCreateFind({ where: { uniqueName: 'winner' } }),
  529. this.User.findCreateFind({ where: { uniqueName: 'winner' } }),
  530. this.User.findCreateFind({ where: { uniqueName: 'winner' } }),
  531. ]);
  532. // All instances are the same
  533. expect(instance1.id).to.equal(instance2.id);
  534. expect(instance2.id).to.equal(instance3.id);
  535. // Only one of the createdN values is true
  536. expect(Boolean(created1 ^ created2 ^ created3)).to.be.true;
  537. });
  538. if (current.dialect.supports.transactions) {
  539. it('should work with multiple concurrent calls within a transaction', async function () {
  540. const t = await this.customSequelize.startUnmanagedTransaction();
  541. const [[instance1, created1], [instance2, created2], [instance3, created3]] =
  542. await Promise.all([
  543. this.User.findCreateFind({ transaction: t, where: { uniqueName: 'winner' } }),
  544. this.User.findCreateFind({ transaction: t, where: { uniqueName: 'winner' } }),
  545. this.User.findCreateFind({ transaction: t, where: { uniqueName: 'winner' } }),
  546. ]);
  547. await t.commit();
  548. // All instances are the same
  549. expect(instance1.id).to.equal(1);
  550. expect(instance2.id).to.equal(1);
  551. expect(instance3.id).to.equal(1);
  552. // Only one of the createdN values is true
  553. expect(Boolean(created1 ^ created2 ^ created3)).to.be.true;
  554. });
  555. }
  556. }
  557. });
  558. describe('create', () => {
  559. it('works with multiple non-integer primary keys with a default value', async function () {
  560. const User = this.customSequelize.define('User', {
  561. id1: {
  562. primaryKey: true,
  563. type: DataTypes.UUID,
  564. defaultValue: sql.uuidV4,
  565. },
  566. id2: {
  567. primaryKey: true,
  568. type: DataTypes.UUID,
  569. defaultValue: sql.uuidV4,
  570. },
  571. email: {
  572. type: DataTypes.UUID,
  573. defaultValue: sql.uuidV4,
  574. },
  575. });
  576. await this.customSequelize.sync({ force: true });
  577. const user = await User.create({});
  578. expect(user).to.be.ok;
  579. expect(user.id1).to.be.ok;
  580. expect(user.id2).to.be.ok;
  581. });
  582. it('should return an error for a unique constraint error', async function () {
  583. const User = this.customSequelize.define('User', {
  584. email: {
  585. type: DataTypes.STRING,
  586. unique: { name: 'email', msg: 'Email is already registered.' },
  587. validate: {
  588. notEmpty: true,
  589. isEmail: true,
  590. },
  591. },
  592. });
  593. await this.customSequelize.sync({ force: true });
  594. await User.create({ email: 'hello@sequelize.com' });
  595. try {
  596. await User.create({ email: 'hello@sequelize.com' });
  597. assert(false);
  598. } catch (error) {
  599. expect(error).to.be.ok;
  600. expect(error).to.be.an.instanceof(Error);
  601. }
  602. });
  603. it('runs validation', async function () {
  604. const User = this.customSequelize.define('User', {
  605. email: {
  606. type: DataTypes.STRING,
  607. validate: {
  608. isEmail: true,
  609. },
  610. },
  611. });
  612. const error = await expect(User.create({ email: 'invalid' })).to.be.rejectedWith(
  613. Sequelize.ValidationError,
  614. );
  615. expect(error.get('email')).to.be.instanceof(Array);
  616. expect(error.get('email')[0]).to.exist;
  617. expect(error.get('email')[0].message).to.equal('Validation isEmail on email failed');
  618. });
  619. it('works without any primary key', async function () {
  620. const Log = this.customSequelize.define('log', {
  621. level: DataTypes.STRING,
  622. });
  623. Log.removeAttribute('id');
  624. await this.customSequelize.sync({ force: true });
  625. await Promise.all([
  626. Log.create({ level: 'info' }),
  627. Log.bulkCreate([{ level: 'error' }, { level: 'debug' }]),
  628. ]);
  629. const logs = await Log.findAll();
  630. for (const log of logs) {
  631. expect(log.get('id')).not.to.be.ok;
  632. }
  633. });
  634. it('should be able to set createdAt and updatedAt if using silent: true', async function () {
  635. const User = this.customSequelize.define(
  636. 'user',
  637. {
  638. name: DataTypes.STRING,
  639. },
  640. {
  641. timestamps: true,
  642. },
  643. );
  644. const createdAt = new Date(2012, 10, 10, 10, 10, 10);
  645. const updatedAt = new Date(2011, 11, 11, 11, 11, 11);
  646. await User.sync({ force: true });
  647. const user = await User.create(
  648. {
  649. createdAt,
  650. updatedAt,
  651. },
  652. {
  653. silent: true,
  654. },
  655. );
  656. expect(createdAt.getTime()).to.equal(user.get('createdAt').getTime());
  657. expect(updatedAt.getTime()).to.equal(user.get('updatedAt').getTime());
  658. const user0 = await User.findOne({
  659. where: {
  660. updatedAt: {
  661. [Op.ne]: null,
  662. },
  663. },
  664. });
  665. expect(createdAt.getTime()).to.equal(user0.get('createdAt').getTime());
  666. expect(updatedAt.getTime()).to.equal(user0.get('updatedAt').getTime());
  667. });
  668. it('works with custom timestamps with a default value', async function () {
  669. const User = this.customSequelize.define(
  670. 'User',
  671. {
  672. username: DataTypes.STRING,
  673. date_of_birth: DataTypes.DATE,
  674. email: DataTypes.STRING,
  675. password: DataTypes.STRING,
  676. created_time: {
  677. type: DataTypes.DATE(3),
  678. allowNull: false,
  679. defaultValue: DataTypes.NOW,
  680. },
  681. updated_time: {
  682. type: DataTypes.DATE(3),
  683. allowNull: false,
  684. defaultValue: DataTypes.NOW,
  685. },
  686. },
  687. {
  688. createdAt: 'created_time',
  689. updatedAt: 'updated_time',
  690. tableName: 'users',
  691. underscored: true,
  692. freezeTableName: true,
  693. force: false,
  694. },
  695. );
  696. await this.customSequelize.sync({ force: true });
  697. const user1 = await User.create({});
  698. await delay(10);
  699. const user2 = await User.create({});
  700. for (const user of [user1, user2]) {
  701. expect(user).to.be.ok;
  702. expect(user.created_time).to.be.ok;
  703. expect(user.updated_time).to.be.ok;
  704. }
  705. // Timestamps should have milliseconds. However, there is a small chance that
  706. // it really is 0 for one of them, by coincidence. So we check twice with two
  707. // users created almost at the same time.
  708. expect([
  709. user1.created_time.getMilliseconds(),
  710. user2.created_time.getMilliseconds(),
  711. ]).not.to.deep.equal([0, 0]);
  712. expect([
  713. user1.updated_time.getMilliseconds(),
  714. user2.updated_time.getMilliseconds(),
  715. ]).not.to.deep.equal([0, 0]);
  716. });
  717. it('works with custom timestamps and underscored', async function () {
  718. const User = this.customSequelize.define(
  719. 'User',
  720. {},
  721. {
  722. createdAt: 'createdAt',
  723. updatedAt: 'updatedAt',
  724. underscored: true,
  725. },
  726. );
  727. await this.customSequelize.sync({ force: true });
  728. const user = await User.create({});
  729. expect(user).to.be.ok;
  730. expect(user.createdAt).to.be.ok;
  731. expect(user.updatedAt).to.be.ok;
  732. expect(user.created_at).not.to.be.ok;
  733. expect(user.updated_at).not.to.be.ok;
  734. });
  735. if (current.dialect.supports.transactions) {
  736. it('supports transactions', async function () {
  737. const t = await this.customSequelize.startUnmanagedTransaction();
  738. await this.User.create({ username: 'user' }, { transaction: t });
  739. const count = await this.User.count();
  740. expect(count).to.equal(0);
  741. await t.commit();
  742. const count0 = await this.User.count();
  743. expect(count0).to.equal(1);
  744. });
  745. }
  746. if (current.dialect.supports.returnValues) {
  747. describe('return values', () => {
  748. it('should make the autoincremented values available on the returned instances', async function () {
  749. const User = this.customSequelize.define('user', {});
  750. await User.sync({ force: true });
  751. const user = await User.create({}, { returning: true });
  752. expect(user.get('id')).to.be.ok;
  753. expect(user.get('id')).to.equal(1);
  754. });
  755. it('should make the autoincremented values available on the returned instances with custom fields', async function () {
  756. const User = this.customSequelize.define('user', {
  757. maId: {
  758. type: DataTypes.INTEGER,
  759. primaryKey: true,
  760. autoIncrement: true,
  761. field: 'yo_id',
  762. },
  763. });
  764. await User.sync({ force: true });
  765. const user = await User.create({}, { returning: true });
  766. expect(user.get('maId')).to.be.ok;
  767. expect(user.get('maId')).to.equal(1);
  768. });
  769. });
  770. }
  771. it('is possible to use casting when creating an instance', async function () {
  772. const type = ['mysql', 'mariadb'].includes(dialectName) ? 'signed' : 'integer';
  773. const bindParam =
  774. dialectName === 'postgres'
  775. ? '$1'
  776. : dialectName === 'sqlite3'
  777. ? '$sequelize_1'
  778. : dialectName === 'mssql'
  779. ? '@sequelize_1'
  780. : '?';
  781. let match = false;
  782. const user = await this.User.create(
  783. {
  784. intVal: this.customSequelize.cast('1', type),
  785. },
  786. {
  787. logging(sql) {
  788. expect(sql).to.include(`CAST(${bindParam} AS ${type.toUpperCase()})`);
  789. match = true;
  790. },
  791. },
  792. );
  793. const user0 = await this.User.findByPk(user.id);
  794. expect(user0.intVal).to.equal(1);
  795. expect(match).to.equal(true);
  796. });
  797. it('is possible to use casting multiple times mixed in with other utilities', async function () {
  798. let type = this.customSequelize.cast(
  799. this.customSequelize.cast(this.customSequelize.literal('1-2'), 'integer'),
  800. 'integer',
  801. );
  802. let match = false;
  803. if (['mysql', 'mariadb'].includes(dialectName)) {
  804. type = this.customSequelize.cast(
  805. this.customSequelize.cast(this.customSequelize.literal('1-2'), 'unsigned'),
  806. 'signed',
  807. );
  808. }
  809. const user = await this.User.create(
  810. {
  811. intVal: type,
  812. },
  813. {
  814. logging(sql) {
  815. if (['mysql', 'mariadb'].includes(dialectName)) {
  816. expect(sql).to.contain('CAST(CAST(1-2 AS UNSIGNED) AS SIGNED)');
  817. } else {
  818. expect(sql).to.contain('CAST(CAST(1-2 AS INTEGER) AS INTEGER)');
  819. }
  820. match = true;
  821. },
  822. },
  823. );
  824. const user0 = await this.User.findByPk(user.id);
  825. expect(user0.intVal).to.equal(-1);
  826. expect(match).to.equal(true);
  827. });
  828. it('is possible to just use .literal() to bypass escaping', async function () {
  829. const user = await this.User.create({
  830. intVal: this.customSequelize.literal(
  831. `CAST(1-2 AS ${dialectName === 'mysql' ? 'SIGNED' : 'INTEGER'})`,
  832. ),
  833. });
  834. const user0 = await this.User.findByPk(user.id);
  835. expect(user0.intVal).to.equal(-1);
  836. });
  837. it('is possible to use funtions when creating an instance', async function () {
  838. const user = await this.User.create({
  839. secretValue: this.customSequelize.fn('upper', 'sequelize'),
  840. });
  841. const user0 = await this.User.findByPk(user.id);
  842. expect(user0.secretValue).to.equal('SEQUELIZE');
  843. });
  844. it('should escape $ in sequelize functions arguments', async function () {
  845. const user = await this.User.create({
  846. secretValue: this.customSequelize.fn('upper', '$sequelize'),
  847. });
  848. const user0 = await this.User.findByPk(user.id);
  849. expect(user0.secretValue).to.equal('$SEQUELIZE');
  850. });
  851. it('should work with a non-id named uuid primary key columns', async function () {
  852. const Monkey = this.customSequelize.define('Monkey', {
  853. monkeyId: {
  854. type: DataTypes.UUID,
  855. primaryKey: true,
  856. defaultValue: sql.uuidV4,
  857. allowNull: false,
  858. },
  859. });
  860. await this.customSequelize.sync({ force: true });
  861. const monkey = await Monkey.create();
  862. expect(monkey.get('monkeyId')).to.be.ok;
  863. });
  864. it('is possible to use functions as default values', async function () {
  865. let userWithDefaults;
  866. if (dialectName.startsWith('postgres')) {
  867. await this.customSequelize.query('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"');
  868. userWithDefaults = this.customSequelize.define('userWithDefaults', {
  869. uuid: {
  870. type: 'UUID',
  871. defaultValue: this.customSequelize.fn('uuid_generate_v4'),
  872. },
  873. });
  874. await userWithDefaults.sync({ force: true });
  875. const user = await userWithDefaults.create({});
  876. // uuid validation regex taken from http://stackoverflow.com/a/13653180/800016
  877. expect(user.uuid).to.match(
  878. /^[\da-f]{8}-[\da-f]{4}-[1-5][\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{12}$/i,
  879. );
  880. return;
  881. }
  882. if (dialectName === 'sqlite3') {
  883. // The definition here is a bit hacky. sqlite expects () around the expression for default values, so we call a function without a name
  884. // to enclose the date function in (). http://www.sqlite.org/syntaxdiagrams.html#column-constraint
  885. userWithDefaults = this.customSequelize.define('userWithDefaults', {
  886. year: {
  887. type: DataTypes.STRING,
  888. defaultValue: this.customSequelize.fn('', this.customSequelize.fn('date', 'now')),
  889. },
  890. });
  891. await userWithDefaults.sync({ force: true });
  892. const user = await userWithDefaults.create({});
  893. const user0 = await userWithDefaults.findByPk(user.id);
  894. const now = new Date();
  895. const pad = number => number.toString().padStart(2, '0');
  896. expect(user0.year).to.equal(
  897. `${now.getUTCFullYear()}-${pad(now.getUTCMonth() + 1)}-${pad(now.getUTCDate())}`,
  898. );
  899. }
  900. // functions as default values are not supported in mysql, see http://stackoverflow.com/a/270338/800016
  901. });
  902. if (dialectName === 'postgres') {
  903. it('does not cast arrays for postgresql insert', async function () {
  904. const User = this.customSequelize.define('UserWithArray', {
  905. myvals: { type: DataTypes.ARRAY(DataTypes.INTEGER) },
  906. mystr: { type: DataTypes.ARRAY(DataTypes.STRING) },
  907. });
  908. let test = false;
  909. await User.sync({ force: true });
  910. await User.create(
  911. { myvals: [], mystr: [] },
  912. {
  913. logging(sql) {
  914. test = true;
  915. expect(sql).to.contain(
  916. 'INSERT INTO "UserWithArrays" ("id","myvals","mystr","createdAt","updatedAt") VALUES (DEFAULT,$1,$2,$3,$4)',
  917. );
  918. },
  919. },
  920. );
  921. expect(test).to.be.true;
  922. });
  923. it('does not cast arrays for postgres update', async function () {
  924. const User = this.customSequelize.define('UserWithArray', {
  925. myvals: { type: DataTypes.ARRAY(DataTypes.INTEGER) },
  926. mystr: { type: DataTypes.ARRAY(DataTypes.STRING) },
  927. });
  928. let test = false;
  929. await User.sync({ force: true });
  930. const user = await User.create({
  931. myvals: [1, 2, 3, 4],
  932. mystr: ['One', 'Two', 'Three', 'Four'],
  933. });
  934. user.myvals = [];
  935. user.mystr = [];
  936. await user.save({
  937. logging(sql) {
  938. test = true;
  939. expect(sql).to.contain(
  940. 'UPDATE "UserWithArrays" SET "myvals"=$1,"mystr"=$2,"updatedAt"=$3 WHERE "id" = $4',
  941. );
  942. },
  943. });
  944. expect(test).to.be.true;
  945. });
  946. }
  947. it("doesn't allow duplicated records with unique:true", async function () {
  948. const User = this.customSequelize.define('UserWithUniqueUsername', {
  949. username: { type: DataTypes.STRING, unique: true },
  950. });
  951. await User.sync({ force: true });
  952. await User.create({ username: 'foo' });
  953. try {
  954. await User.create({ username: 'foo' });
  955. } catch (error) {
  956. if (!(error instanceof Sequelize.UniqueConstraintError)) {
  957. throw error;
  958. }
  959. expect(error).to.be.ok;
  960. }
  961. });
  962. if (dialect.supports.dataTypes.CITEXT) {
  963. it(`doesn't allow case-insensitive duplicated records using CITEXT`, async function () {
  964. const User = this.customSequelize.define('UserWithUniqueCITEXT', {
  965. username: { type: DataTypes.CITEXT, unique: true },
  966. });
  967. try {
  968. await User.sync({ force: true });
  969. await User.create({ username: 'foo' });
  970. await User.create({ username: 'fOO' });
  971. } catch (error) {
  972. if (!(error instanceof Sequelize.UniqueConstraintError)) {
  973. throw error;
  974. }
  975. expect(error).to.be.ok;
  976. }
  977. });
  978. }
  979. if (dialectName === 'postgres') {
  980. it('allows the creation of a TSVECTOR field', async function () {
  981. const User = this.customSequelize.define('UserWithTSVECTOR', {
  982. name: DataTypes.TSVECTOR,
  983. });
  984. await User.sync({ force: true });
  985. await User.create({ name: 'John Doe' });
  986. });
  987. it('TSVECTOR only allow string', async function () {
  988. const User = this.customSequelize.define('UserWithTSVECTOR', {
  989. username: { type: DataTypes.TSVECTOR },
  990. });
  991. try {
  992. await User.sync({ force: true });
  993. await User.create({ username: 42 });
  994. } catch (error) {
  995. if (!(error instanceof Sequelize.ValidationError)) {
  996. throw error;
  997. }
  998. expect(error).to.be.ok;
  999. }
  1000. });
  1001. }
  1002. if (current.dialect.supports.index.functionBased) {
  1003. it(`doesn't allow duplicated records with unique function based indexes`, async function () {
  1004. const User = this.customSequelize.define('UserWithUniqueUsernameFunctionIndex', {
  1005. username: DataTypes.STRING,
  1006. email: { type: DataTypes.STRING, unique: true },
  1007. });
  1008. try {
  1009. await User.sync({ force: true });
  1010. await this.customSequelize.query(
  1011. `CREATE UNIQUE INDEX lower_case_username ON ${this.customSequelize.queryGenerator.quoteTable(User)} ((lower("username")))`,
  1012. );
  1013. await User.create({ username: 'foo' });
  1014. await User.create({ username: 'foo' });
  1015. } catch (error) {
  1016. if (!(error instanceof Sequelize.UniqueConstraintError)) {
  1017. throw error;
  1018. }
  1019. expect(error).to.be.ok;
  1020. }
  1021. });
  1022. }
  1023. it('raises an error if created object breaks definition constraints', async function () {
  1024. const UserNull = this.customSequelize.define('UserWithNonNullSmth', {
  1025. username: { type: DataTypes.STRING, unique: true },
  1026. smth: { type: DataTypes.STRING, allowNull: false },
  1027. });
  1028. await UserNull.sync({ force: true });
  1029. try {
  1030. await UserNull.create({ username: 'foo2', smth: null });
  1031. } catch (error) {
  1032. expect(error).to.exist;
  1033. const smth1 = error.get('smth')[0] || {};
  1034. expect(smth1.path).to.equal('smth');
  1035. expect(smth1.type || smth1.origin).to.match(/notNull violation/);
  1036. }
  1037. });
  1038. it('raises an error if created object breaks definition constraints', async function () {
  1039. const UserNull = this.customSequelize.define('UserWithNonNullSmth', {
  1040. username: { type: DataTypes.STRING, unique: true },
  1041. smth: { type: DataTypes.STRING, allowNull: false },
  1042. });
  1043. await UserNull.sync({ force: true });
  1044. await UserNull.create({ username: 'foo', smth: 'foo' });
  1045. try {
  1046. await UserNull.create({ username: 'foo', smth: 'bar' });
  1047. } catch (error) {
  1048. if (!(error instanceof Sequelize.UniqueConstraintError)) {
  1049. throw error;
  1050. }
  1051. expect(error).to.be.ok;
  1052. }
  1053. });
  1054. it('raises an error if saving an empty string into a column allowing null or URL', async function () {
  1055. const StringIsNullOrUrl = this.customSequelize.define('StringIsNullOrUrl', {
  1056. str: { type: DataTypes.STRING, allowNull: true, validate: { isURL: true } },
  1057. });
  1058. await StringIsNullOrUrl.sync({ force: true });
  1059. const str1 = await StringIsNullOrUrl.create({ str: null });
  1060. expect(str1.str).to.be.null;
  1061. const str2 = await StringIsNullOrUrl.create({ str: 'http://sequelizejs.org' });
  1062. expect(str2.str).to.equal('http://sequelizejs.org');
  1063. try {
  1064. await StringIsNullOrUrl.create({ str: '' });
  1065. } catch (error) {
  1066. expect(error).to.exist;
  1067. expect(error.get('str')[0].message).to.match(/Validation isURL on str failed/);
  1068. }
  1069. });
  1070. if (current.dialect.supports.dataTypes.BIGINT) {
  1071. it('sets a 64 bit int in bigint', async function () {
  1072. const User = this.customSequelize.define('UserWithBigIntFields', {
  1073. big: DataTypes.BIGINT,
  1074. });
  1075. await User.sync({ force: true });
  1076. const user = await User.create({ big: '9223372036854775807' });
  1077. expect(user.big).to.equal('9223372036854775807');
  1078. });
  1079. }
  1080. it('sets auto increment fields', async function () {
  1081. const User = this.customSequelize.define('UserWithAutoIncrementField', {
  1082. userid: {
  1083. type: DataTypes.INTEGER,
  1084. autoIncrement: true,
  1085. primaryKey: true,
  1086. allowNull: false,
  1087. },
  1088. });
  1089. await User.sync({ force: true });
  1090. const user = await User.create({});
  1091. expect(user.userid).to.equal(1);
  1092. const user0 = await User.create({});
  1093. expect(user0.userid).to.equal(2);
  1094. });
  1095. it('allows the usage of options as attribute', async function () {
  1096. const User = this.customSequelize.define('UserWithNameAndOptions', {
  1097. name: DataTypes.STRING,
  1098. options: DataTypes.TEXT,
  1099. });
  1100. const options = JSON.stringify({ foo: 'bar', bar: 'foo' });
  1101. await User.sync({ force: true });
  1102. const user = await User.create({ name: 'John Doe', options });
  1103. expect(user.options).to.equal(options);
  1104. });
  1105. it('allows sql logging', async function () {
  1106. const User = this.customSequelize.define('UserWithUniqueNameAndNonNullSmth', {
  1107. name: { type: DataTypes.STRING, unique: true },
  1108. smth: { type: DataTypes.STRING, allowNull: false },
  1109. });
  1110. let test = false;
  1111. await User.sync({ force: true });
  1112. await User.create(
  1113. { name: 'Fluffy Bunny', smth: 'else' },
  1114. {
  1115. logging(sql) {
  1116. expect(sql).to.exist;
  1117. test = true;
  1118. expect(sql.toUpperCase()).to.contain('INSERT');
  1119. },
  1120. },
  1121. );
  1122. expect(test).to.be.true;
  1123. });
  1124. it('should only store the values passed in the whitelist', async function () {
  1125. // A unique column do not accept NULL in Db2. Unique column must have value in insert statement.
  1126. const data = { username: 'Peter', secretValue: '42', uniqueName: 'name' };
  1127. const fields =
  1128. dialectName === 'db2' ? { fields: ['username', 'uniqueName'] } : { fields: ['username'] };
  1129. const user = await this.User.create(data, fields);
  1130. const _user = await this.User.findByPk(user.id);
  1131. expect(_user.username).to.equal(data.username);
  1132. expect(_user.secretValue).not.to.equal(data.secretValue);
  1133. expect(_user.secretValue).to.equal(null);
  1134. });
  1135. it('should store all values if no whitelist is specified', async function () {
  1136. const data = { username: 'Peter', secretValue: '42' };
  1137. const user = await this.User.create(data);
  1138. const _user = await this.User.findByPk(user.id);
  1139. expect(_user.username).to.equal(data.username);
  1140. expect(_user.secretValue).to.equal(data.secretValue);
  1141. });
  1142. it('can omit autoincremental columns', async function () {
  1143. const data = { title: 'Iliad' };
  1144. const dataTypes = [DataTypes.INTEGER];
  1145. const sync = [];
  1146. const promises = [];
  1147. const books = [];
  1148. if (current.dialect.supports.dataTypes.BIGINT) {
  1149. dataTypes.push(DataTypes.BIGINT);
  1150. }
  1151. for (const [index, dataType] of dataTypes.entries()) {
  1152. books[index] = this.customSequelize.define(`Book${index}`, {
  1153. id: { type: dataType, primaryKey: true, autoIncrement: true },
  1154. title: DataTypes.TEXT,
  1155. });
  1156. }
  1157. for (const b of books) {
  1158. sync.push(b.sync({ force: true }));
  1159. }
  1160. await Promise.all(sync);
  1161. for (const [index, b] of books.entries()) {
  1162. promises.push(
  1163. (async () => {
  1164. const book = await b.create(data);
  1165. expect(book.title).to.equal(data.title);
  1166. expect(book.author).to.equal(data.author);
  1167. expect(books[index].getAttributes().id.type instanceof dataTypes[index]).to.be.ok;
  1168. })(),
  1169. );
  1170. }
  1171. await Promise.all(promises);
  1172. });
  1173. it('saves data with single quote', async function () {
  1174. const quote = "single'quote";
  1175. const user = await this.User.create({ data: quote });
  1176. expect(user.data).to.equal(quote);
  1177. const user0 = await this.User.findOne({ where: { id: user.id } });
  1178. expect(user0.data).to.equal(quote);
  1179. });
  1180. it('saves data with double quote', async function () {
  1181. const quote = 'double"quote';
  1182. const user = await this.User.create({ data: quote });
  1183. expect(user.data).to.equal(quote);
  1184. const user0 = await this.User.findOne({ where: { id: user.id } });
  1185. expect(user0.data).to.equal(quote);
  1186. });
  1187. it('saves stringified JSON data', async function () {
  1188. const json = JSON.stringify({ key: 'value' });
  1189. const user = await this.User.create({ data: json });
  1190. expect(user.data).to.equal(json);
  1191. const user0 = await this.User.findOne({ where: { id: user.id } });
  1192. expect(user0.data).to.equal(json);
  1193. });
  1194. it('stores the current date in createdAt', async function () {
  1195. const user = await this.User.create({ username: 'foo' });
  1196. expect(Number.parseInt(Number(user.createdAt) / 5000, 10)).to.be.closeTo(
  1197. Number.parseInt(Date.now() / 5000, 10),
  1198. 1.5,
  1199. );
  1200. });
  1201. it('allows setting custom IDs', async function () {
  1202. const user = await this.User.create({ id: 42 });
  1203. expect(user.id).to.equal(42);
  1204. const user0 = await this.User.findByPk(42);
  1205. expect(user0).to.exist;
  1206. });
  1207. it('should allow blank creates (with timestamps: false)', async function () {
  1208. const Worker = this.customSequelize.define('Worker', {}, { timestamps: false });
  1209. await Worker.sync();
  1210. const worker = await Worker.create({}, { fields: [] });
  1211. expect(worker).to.be.ok;
  1212. });
  1213. it('should allow truly blank creates', async function () {
  1214. const Worker = this.customSequelize.define('Worker', {}, { timestamps: false });
  1215. await Worker.sync();
  1216. const worker = await Worker.create({}, { fields: [] });
  1217. expect(worker).to.be.ok;
  1218. });
  1219. it('should only set passed fields', async function () {
  1220. const User = this.customSequelize.define('User', {
  1221. email: {
  1222. type: DataTypes.STRING,
  1223. },
  1224. name: {
  1225. type: DataTypes.STRING,
  1226. },
  1227. });
  1228. await this.customSequelize.sync({ force: true });
  1229. const user = await User.create(
  1230. {
  1231. name: 'Yolo Bear',
  1232. email: 'yolo@bear.com',
  1233. },
  1234. {
  1235. fields: ['name'],
  1236. },
  1237. );
  1238. expect(user.name).to.be.ok;
  1239. expect(user.email).not.to.be.ok;
  1240. const user0 = await User.findByPk(user.id);
  1241. expect(user0.name).to.be.ok;
  1242. expect(user0.email).not.to.be.ok;
  1243. });
  1244. it('Works even when SQL query has a values of transaction keywords such as BEGIN TRANSACTION', async function () {
  1245. const Task = this.customSequelize.define('task', {
  1246. title: DataTypes.STRING,
  1247. });
  1248. await Task.sync({ force: true });
  1249. const newTasks = await Promise.all([
  1250. Task.create({ title: 'BEGIN TRANSACTION' }),
  1251. Task.create({ title: 'COMMIT TRANSACTION' }),
  1252. Task.create({ title: 'ROLLBACK TRANSACTION' }),
  1253. Task.create({ title: 'SAVE TRANSACTION' }),
  1254. ]);
  1255. expect(newTasks).to.have.lengthOf(4);
  1256. expect(newTasks[0].title).to.equal('BEGIN TRANSACTION');
  1257. expect(newTasks[1].title).to.equal('COMMIT TRANSACTION');
  1258. expect(newTasks[2].title).to.equal('ROLLBACK TRANSACTION');
  1259. expect(newTasks[3].title).to.equal('SAVE TRANSACTION');
  1260. });
  1261. describe('enums', () => {
  1262. it('correctly restores enum values', async function () {
  1263. const Item = this.customSequelize.define('Item', {
  1264. state: { type: DataTypes.ENUM(['available', 'in_cart', 'shipped']) },
  1265. });
  1266. await Item.sync({ force: true });
  1267. const _item = await Item.create({ state: 'available' });
  1268. const item = await Item.findOne({ where: { state: 'available' } });
  1269. expect(item.id).to.equal(_item.id);
  1270. });
  1271. it('allows null values', async function () {
  1272. const Enum = this.customSequelize.define('Enum', {
  1273. state: {
  1274. type: DataTypes.ENUM(['happy', 'sad']),
  1275. allowNull: true,
  1276. },
  1277. });
  1278. await Enum.sync({ force: true });
  1279. const _enum = await Enum.create({ state: null });
  1280. expect(_enum.state).to.be.null;
  1281. });
  1282. describe('when defined via { field: DataTypes.ENUM }', () => {
  1283. it('allows values passed as parameters', async function () {
  1284. const Enum = this.customSequelize.define('Enum', {
  1285. state: DataTypes.ENUM('happy', 'sad'),
  1286. });
  1287. await Enum.sync({ force: true });
  1288. await Enum.create({ state: 'happy' });
  1289. });
  1290. it('allows values passed as an array', async function () {
  1291. const Enum = this.customSequelize.define('Enum', {
  1292. state: DataTypes.ENUM(['happy', 'sad']),
  1293. });
  1294. await Enum.sync({ force: true });
  1295. await Enum.create({ state: 'happy' });
  1296. });
  1297. });
  1298. describe('when defined via { field: { type: DataTypes.ENUM } }', () => {
  1299. it('allows values passed as parameters', async function () {
  1300. const Enum = this.customSequelize.define('Enum', {
  1301. state: {
  1302. type: DataTypes.ENUM('happy', 'sad'),
  1303. },
  1304. });
  1305. await Enum.sync({ force: true });
  1306. await Enum.create({ state: 'happy' });
  1307. });
  1308. it('allows values passed as an array', async function () {
  1309. const Enum = this.customSequelize.define('Enum', {
  1310. state: {
  1311. type: DataTypes.ENUM(['happy', 'sad']),
  1312. },
  1313. });
  1314. await Enum.sync({ force: true });
  1315. await Enum.create({ state: 'happy' });
  1316. });
  1317. });
  1318. describe('can safely sync multiple times', () => {
  1319. it('through the factory', async function () {
  1320. const Enum = this.customSequelize.define('Enum', {
  1321. state: {
  1322. type: DataTypes.ENUM(['happy', 'sad']),
  1323. allowNull: true,
  1324. },
  1325. });
  1326. await Enum.sync({ force: true });
  1327. await Enum.sync();
  1328. await Enum.sync({ force: true });
  1329. });
  1330. it('through sequelize', async function () {
  1331. this.customSequelize.define('Enum', {
  1332. state: {
  1333. type: DataTypes.ENUM(['happy', 'sad']),
  1334. allowNull: true,
  1335. },
  1336. });
  1337. await this.customSequelize.sync({ force: true });
  1338. await this.customSequelize.sync();
  1339. await this.customSequelize.sync({ force: true });
  1340. });
  1341. });
  1342. });
  1343. });
  1344. it('should return autoIncrement primary key (create)', async function () {
  1345. const Maya = this.customSequelize.define('Maya', {});
  1346. const M1 = {};
  1347. await Maya.sync({ force: true });
  1348. const m = await Maya.create(M1, { returning: true });
  1349. expect(m.id).to.be.eql(1);
  1350. });
  1351. it('should support logging', async function () {
  1352. const spy = sinon.spy();
  1353. await this.User.create(
  1354. {},
  1355. {
  1356. logging: spy,
  1357. },
  1358. );
  1359. expect(spy.called).to.be.ok;
  1360. });
  1361. if (current.dialect.supports.returnValues) {
  1362. it('should return default value set by the database (create)', async function () {
  1363. const User = this.customSequelize.define('User', {
  1364. name: DataTypes.STRING,
  1365. code: { type: DataTypes.INTEGER, defaultValue: Sequelize.literal(2020) },
  1366. });
  1367. await User.sync({ force: true });
  1368. const user = await User.create({ name: 'FooBar' });
  1369. expect(user.name).to.equal('FooBar');
  1370. expect(user.code).to.equal(2020);
  1371. });
  1372. }
  1373. });