insert.test.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. 'use strict';
  2. const Support = require('../../support');
  3. const { DataTypes } = require('@sequelize/core');
  4. const { expect } = require('chai');
  5. const expectsql = Support.expectsql;
  6. const current = Support.sequelize;
  7. const sql = current.dialect.queryGenerator;
  8. const dialect = current.dialect;
  9. // Notice: [] will be replaced by dialect specific tick/quote character when there is not dialect specific expectation but only a default expectation
  10. describe(Support.getTestDialectTeaser('SQL'), () => {
  11. describe('insert', () => {
  12. it('with temp table for trigger', () => {
  13. const User = Support.sequelize.define(
  14. 'user',
  15. {
  16. username: {
  17. type: DataTypes.STRING,
  18. field: 'user_name',
  19. },
  20. },
  21. {
  22. timestamps: false,
  23. hasTrigger: true,
  24. },
  25. );
  26. const options = {
  27. returning: true,
  28. hasTrigger: true,
  29. };
  30. expectsql(
  31. sql.insertQuery(User.table, { user_name: 'triggertest' }, User.getAttributes(), options),
  32. {
  33. query: {
  34. ibmi: 'SELECT * FROM FINAL TABLE (INSERT INTO "users" ("user_name") VALUES ($sequelize_1))',
  35. mssql:
  36. 'DECLARE @tmp TABLE ([id] INTEGER,[user_name] NVARCHAR(255)); INSERT INTO [users] ([user_name]) OUTPUT INSERTED.[id], INSERTED.[user_name] INTO @tmp VALUES ($sequelize_1); SELECT * FROM @tmp;',
  37. sqlite3:
  38. 'INSERT INTO `users` (`user_name`) VALUES ($sequelize_1) RETURNING `id`, `user_name`;',
  39. postgres:
  40. 'INSERT INTO "users" ("user_name") VALUES ($sequelize_1) RETURNING "id", "user_name";',
  41. db2: 'SELECT * FROM FINAL TABLE (INSERT INTO "users" ("user_name") VALUES ($sequelize_1));',
  42. snowflake: 'INSERT INTO "users" ("user_name") VALUES ($sequelize_1);',
  43. default: 'INSERT INTO `users` (`user_name`) VALUES ($sequelize_1);',
  44. },
  45. bind: { sequelize_1: 'triggertest' },
  46. },
  47. );
  48. });
  49. it('allow insert primary key with 0', () => {
  50. const M = Support.sequelize.define('m', {
  51. id: {
  52. type: DataTypes.INTEGER,
  53. primaryKey: true,
  54. autoIncrement: true,
  55. },
  56. });
  57. expectsql(sql.insertQuery(M.table, { id: 0 }, M.getAttributes()), {
  58. query: {
  59. mssql:
  60. 'SET IDENTITY_INSERT [ms] ON; INSERT INTO [ms] ([id]) VALUES ($sequelize_1); SET IDENTITY_INSERT [ms] OFF;',
  61. db2: 'SELECT * FROM FINAL TABLE (INSERT INTO "ms" ("id") VALUES ($sequelize_1));',
  62. ibmi: 'SELECT * FROM FINAL TABLE (INSERT INTO "ms" ("id") VALUES ($sequelize_1))',
  63. postgres: 'INSERT INTO "ms" ("id") VALUES ($sequelize_1);',
  64. snowflake: 'INSERT INTO "ms" ("id") VALUES ($sequelize_1);',
  65. default: 'INSERT INTO `ms` (`id`) VALUES ($sequelize_1);',
  66. },
  67. bind: { sequelize_1: 0 },
  68. });
  69. });
  70. it(
  71. current.dialect.supports.inserts.onConflictWhere
  72. ? 'adds conflictWhere clause to generated queries'
  73. : 'throws error if conflictWhere is provided',
  74. () => {
  75. const User = Support.sequelize.define(
  76. 'user',
  77. {
  78. username: {
  79. type: DataTypes.STRING,
  80. field: 'user_name',
  81. primaryKey: true,
  82. },
  83. password: {
  84. type: DataTypes.STRING,
  85. field: 'pass_word',
  86. },
  87. createdAt: {
  88. type: DataTypes.DATE,
  89. field: 'created_at',
  90. },
  91. updatedAt: {
  92. type: DataTypes.DATE,
  93. field: 'updated_at',
  94. },
  95. },
  96. {
  97. timestamps: true,
  98. },
  99. );
  100. const upsertKeys = ['user_name'];
  101. let result;
  102. try {
  103. result = sql.insertQuery(
  104. User.table,
  105. { user_name: 'testuser', pass_word: '12345' },
  106. User.fieldRawAttributesMap,
  107. {
  108. updateOnDuplicate: ['user_name', 'pass_word', 'updated_at'],
  109. conflictWhere: {
  110. user_name: 'test where value',
  111. },
  112. upsertKeys,
  113. },
  114. );
  115. } catch (error) {
  116. result = error;
  117. }
  118. expectsql(result, {
  119. default: new Error('missing dialect support for conflictWhere option'),
  120. 'postgres sqlite3': `INSERT INTO [users] ([user_name],[pass_word]) VALUES ($sequelize_1,$sequelize_2) ON CONFLICT ([user_name]) WHERE [user_name] = 'test where value' DO UPDATE SET [user_name]=EXCLUDED.[user_name],[pass_word]=EXCLUDED.[pass_word],[updated_at]=EXCLUDED.[updated_at];`,
  121. });
  122. },
  123. );
  124. });
  125. describe('dates', () => {
  126. if (!dialect.supports.globalTimeZoneConfig) {
  127. it('rejects specifying the global timezone option', () => {
  128. expect(() => Support.createSequelizeInstance({ timezone: 'CET' })).to.throw(
  129. 'Setting a custom timezone is not supported',
  130. );
  131. });
  132. } else {
  133. it('supports the global timezone option', () => {
  134. const timezoneSequelize = Support.createSequelizeInstance({
  135. timezone: 'CET',
  136. });
  137. const User = timezoneSequelize.define(
  138. 'user',
  139. {
  140. date: {
  141. type: DataTypes.DATE(3),
  142. },
  143. },
  144. {
  145. timestamps: false,
  146. },
  147. );
  148. expectsql(
  149. timezoneSequelize.dialect.queryGenerator.insertQuery(
  150. User.table,
  151. { date: new Date(Date.UTC(2015, 0, 20)) },
  152. User.getAttributes(),
  153. {},
  154. ),
  155. {
  156. query: {
  157. default: 'INSERT INTO [users] ([date]) VALUES ($sequelize_1);',
  158. },
  159. bind: {
  160. // these dialects change the DB-side timezone, and the input doesn't specify the timezone offset, so we have to offset the value ourselves
  161. // because it will be interpreted as CET by the dialect.
  162. snowflake: { sequelize_1: '2015-01-20 01:00:00.000' },
  163. mysql: { sequelize_1: '2015-01-20 01:00:00.000' },
  164. mariadb: { sequelize_1: '2015-01-20 01:00:00.000' },
  165. // These dialects do specify the offset, so they can use whichever offset they want.
  166. postgres: { sequelize_1: '2015-01-20 01:00:00.000 +01:00' },
  167. },
  168. },
  169. );
  170. });
  171. }
  172. it('formats the date correctly when inserting', () => {
  173. const User = current.define(
  174. 'user',
  175. {
  176. date: {
  177. type: DataTypes.DATE(3),
  178. },
  179. },
  180. {
  181. timestamps: false,
  182. },
  183. );
  184. expectsql(
  185. current.dialect.queryGenerator.insertQuery(
  186. User.table,
  187. { date: new Date(Date.UTC(2015, 0, 20)) },
  188. User.getAttributes(),
  189. {},
  190. ),
  191. {
  192. query: {
  193. ibmi: 'SELECT * FROM FINAL TABLE (INSERT INTO "users" ("date") VALUES ($sequelize_1))',
  194. postgres: 'INSERT INTO "users" ("date") VALUES ($sequelize_1);',
  195. db2: 'SELECT * FROM FINAL TABLE (INSERT INTO "users" ("date") VALUES ($sequelize_1));',
  196. snowflake: 'INSERT INTO "users" ("date") VALUES ($sequelize_1);',
  197. mssql: 'INSERT INTO [users] ([date]) VALUES ($sequelize_1);',
  198. default: 'INSERT INTO `users` (`date`) VALUES ($sequelize_1);',
  199. },
  200. bind: {
  201. ibmi: { sequelize_1: '2015-01-20 00:00:00.000' },
  202. db2: { sequelize_1: '2015-01-20 00:00:00.000' },
  203. snowflake: { sequelize_1: '2015-01-20 00:00:00.000' },
  204. mysql: { sequelize_1: '2015-01-20 00:00:00.000' },
  205. mariadb: { sequelize_1: '2015-01-20 00:00:00.000' },
  206. sqlite3: { sequelize_1: '2015-01-20 00:00:00.000 +00:00' },
  207. mssql: { sequelize_1: '2015-01-20 00:00:00.000 +00:00' },
  208. postgres: { sequelize_1: '2015-01-20 00:00:00.000 +00:00' },
  209. },
  210. },
  211. );
  212. });
  213. it('formats date correctly when sub-second precision is explicitly specified', () => {
  214. const User = current.define(
  215. 'user',
  216. {
  217. date: {
  218. type: DataTypes.DATE(3),
  219. },
  220. },
  221. {
  222. timestamps: false,
  223. },
  224. );
  225. expectsql(
  226. current.dialect.queryGenerator.insertQuery(
  227. User.table,
  228. { date: new Date(Date.UTC(2015, 0, 20, 1, 2, 3, 89)) },
  229. User.getAttributes(),
  230. {},
  231. ),
  232. {
  233. query: {
  234. ibmi: 'SELECT * FROM FINAL TABLE (INSERT INTO "users" ("date") VALUES ($sequelize_1))',
  235. postgres: 'INSERT INTO "users" ("date") VALUES ($sequelize_1);',
  236. db2: 'SELECT * FROM FINAL TABLE (INSERT INTO "users" ("date") VALUES ($sequelize_1));',
  237. snowflake: 'INSERT INTO "users" ("date") VALUES ($sequelize_1);',
  238. mssql: 'INSERT INTO [users] ([date]) VALUES ($sequelize_1);',
  239. default: 'INSERT INTO `users` (`date`) VALUES ($sequelize_1);',
  240. },
  241. bind: {
  242. ibmi: { sequelize_1: '2015-01-20 01:02:03.089' },
  243. db2: { sequelize_1: '2015-01-20 01:02:03.089' },
  244. snowflake: { sequelize_1: '2015-01-20 01:02:03.089' },
  245. mariadb: { sequelize_1: '2015-01-20 01:02:03.089' },
  246. mysql: { sequelize_1: '2015-01-20 01:02:03.089' },
  247. sqlite3: { sequelize_1: '2015-01-20 01:02:03.089 +00:00' },
  248. postgres: { sequelize_1: '2015-01-20 01:02:03.089 +00:00' },
  249. mssql: { sequelize_1: '2015-01-20 01:02:03.089 +00:00' },
  250. },
  251. },
  252. );
  253. });
  254. });
  255. describe('strings', () => {
  256. it('formats null characters correctly when inserting', () => {
  257. const User = Support.sequelize.define(
  258. 'user',
  259. {
  260. username: {
  261. type: DataTypes.STRING,
  262. field: 'user_name',
  263. },
  264. },
  265. {
  266. timestamps: false,
  267. },
  268. );
  269. expectsql(sql.insertQuery(User.table, { user_name: 'null\0test' }, User.getAttributes()), {
  270. query: {
  271. ibmi: 'SELECT * FROM FINAL TABLE (INSERT INTO "users" ("user_name") VALUES ($sequelize_1))',
  272. postgres: 'INSERT INTO "users" ("user_name") VALUES ($sequelize_1);',
  273. db2: 'SELECT * FROM FINAL TABLE (INSERT INTO "users" ("user_name") VALUES ($sequelize_1));',
  274. snowflake: 'INSERT INTO "users" ("user_name") VALUES ($sequelize_1);',
  275. mssql: 'INSERT INTO [users] ([user_name]) VALUES ($sequelize_1);',
  276. default: 'INSERT INTO `users` (`user_name`) VALUES ($sequelize_1);',
  277. },
  278. bind: {
  279. postgres: { sequelize_1: 'null\u0000test' },
  280. default: { sequelize_1: 'null\0test' },
  281. },
  282. });
  283. });
  284. });
  285. describe('bulkCreate', () => {
  286. it('bulk create with onDuplicateKeyUpdate', () => {
  287. const User = Support.sequelize.define(
  288. 'user',
  289. {
  290. username: {
  291. type: DataTypes.STRING,
  292. field: 'user_name',
  293. primaryKey: true,
  294. },
  295. password: {
  296. type: DataTypes.STRING,
  297. field: 'pass_word',
  298. },
  299. createdAt: {
  300. field: 'created_at',
  301. },
  302. updatedAt: {
  303. field: 'updated_at',
  304. },
  305. },
  306. {
  307. timestamps: true,
  308. },
  309. );
  310. // mapping primary keys to their "field" override values
  311. const primaryKeys = User.primaryKeyAttributes.map(
  312. attr => User.getAttributes()[attr].field || attr,
  313. );
  314. expectsql(
  315. sql.bulkInsertQuery(
  316. User.table,
  317. [{ user_name: 'testuser', pass_word: '12345' }],
  318. { updateOnDuplicate: ['user_name', 'pass_word', 'updated_at'], upsertKeys: primaryKeys },
  319. User.fieldRawAttributesMap,
  320. ),
  321. {
  322. default: "INSERT INTO `users` (`user_name`,`pass_word`) VALUES ('testuser','12345');",
  323. ibmi: 'SELECT * FROM FINAL TABLE (INSERT INTO "users" ("user_name","pass_word") VALUES (\'testuser\',\'12345\'))',
  324. snowflake:
  325. 'INSERT INTO "users" ("user_name","pass_word") VALUES (\'testuser\',\'12345\');',
  326. postgres:
  327. 'INSERT INTO "users" ("user_name","pass_word") VALUES (\'testuser\',\'12345\') ON CONFLICT ("user_name") DO UPDATE SET "user_name"=EXCLUDED."user_name","pass_word"=EXCLUDED."pass_word","updated_at"=EXCLUDED."updated_at";',
  328. mssql: "INSERT INTO [users] ([user_name],[pass_word]) VALUES (N'testuser',N'12345');",
  329. db2: 'INSERT INTO "users" ("user_name","pass_word") VALUES (\'testuser\',\'12345\');',
  330. mariadb:
  331. "INSERT INTO `users` (`user_name`,`pass_word`) VALUES ('testuser','12345') ON DUPLICATE KEY UPDATE `user_name`=VALUES(`user_name`),`pass_word`=VALUES(`pass_word`),`updated_at`=VALUES(`updated_at`);",
  332. mysql:
  333. "INSERT INTO `users` (`user_name`,`pass_word`) VALUES ('testuser','12345') ON DUPLICATE KEY UPDATE `user_name`=VALUES(`user_name`),`pass_word`=VALUES(`pass_word`),`updated_at`=VALUES(`updated_at`);",
  334. sqlite3:
  335. "INSERT INTO `users` (`user_name`,`pass_word`) VALUES ('testuser','12345') ON CONFLICT (`user_name`) DO UPDATE SET `user_name`=EXCLUDED.`user_name`,`pass_word`=EXCLUDED.`pass_word`,`updated_at`=EXCLUDED.`updated_at`;",
  336. },
  337. );
  338. });
  339. it('allow bulk insert primary key with 0', () => {
  340. const M = Support.sequelize.define('m', {
  341. id: {
  342. type: DataTypes.INTEGER,
  343. primaryKey: true,
  344. autoIncrement: true,
  345. },
  346. });
  347. expectsql(
  348. sql.bulkInsertQuery(M.table, [{ id: 0 }, { id: null }], {}, M.fieldRawAttributesMap),
  349. {
  350. query: {
  351. mssql:
  352. 'SET IDENTITY_INSERT [ms] ON; INSERT INTO [ms] DEFAULT VALUES;INSERT INTO [ms] ([id]) VALUES (0),(NULL); SET IDENTITY_INSERT [ms] OFF;',
  353. postgres: 'INSERT INTO "ms" ("id") VALUES (0),(DEFAULT);',
  354. db2: 'INSERT INTO "ms" VALUES (1);INSERT INTO "ms" ("id") VALUES (0),(NULL);',
  355. ibmi: 'SELECT * FROM FINAL TABLE (INSERT INTO "ms" ("id") VALUES (0),(DEFAULT))',
  356. snowflake: 'INSERT INTO "ms" ("id") VALUES (0),(NULL);',
  357. default: 'INSERT INTO `ms` (`id`) VALUES (0),(NULL);',
  358. },
  359. },
  360. );
  361. });
  362. if (current.dialect.supports.inserts.updateOnDuplicate) {
  363. it('correctly generates SQL for conflictWhere', () => {
  364. const User = Support.sequelize.define(
  365. 'user',
  366. {
  367. username: {
  368. type: DataTypes.STRING,
  369. field: 'user_name',
  370. primaryKey: true,
  371. },
  372. password: {
  373. type: DataTypes.STRING,
  374. field: 'pass_word',
  375. },
  376. createdAt: {
  377. type: DataTypes.DATE,
  378. field: 'created_at',
  379. },
  380. updatedAt: {
  381. type: DataTypes.DATE,
  382. field: 'updated_at',
  383. },
  384. deletedAt: {
  385. type: DataTypes.DATE,
  386. field: 'deleted_at',
  387. },
  388. },
  389. {
  390. timestamps: true,
  391. },
  392. );
  393. // mapping primary keys to their "field" override values
  394. const primaryKeys = User.primaryKeyAttributes.map(
  395. attr => User.getAttributes()[attr].field || attr,
  396. );
  397. let result;
  398. try {
  399. result = sql.bulkInsertQuery(
  400. User.table,
  401. [{ user_name: 'testuser', pass_word: '12345' }],
  402. {
  403. updateOnDuplicate: ['user_name', 'pass_word', 'updated_at'],
  404. upsertKeys: primaryKeys,
  405. conflictWhere: { deleted_at: null },
  406. },
  407. User.fieldRawAttributesMap,
  408. );
  409. } catch (error) {
  410. result = error;
  411. }
  412. expectsql(result, {
  413. default: new Error(`conflictWhere not supported for dialect ${dialect.name}`),
  414. 'postgres sqlite3':
  415. "INSERT INTO [users] ([user_name],[pass_word]) VALUES ('testuser','12345') ON CONFLICT ([user_name]) WHERE [deleted_at] IS NULL DO UPDATE SET [user_name]=EXCLUDED.[user_name],[pass_word]=EXCLUDED.[pass_word],[updated_at]=EXCLUDED.[updated_at];",
  416. });
  417. });
  418. }
  419. });
  420. });