dao.test.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. 'use strict';
  2. const chai = require('chai');
  3. const expect = chai.expect;
  4. const Support = require('../../support');
  5. const dialect = Support.getTestDialect();
  6. const { DataTypes, Op } = require('@sequelize/core');
  7. describe('[POSTGRES Specific] DAO', () => {
  8. if (dialect !== 'postgres') {
  9. return;
  10. }
  11. beforeEach(async function () {
  12. this.User = this.sequelize.define('User', {
  13. username: DataTypes.STRING,
  14. email: { type: DataTypes.ARRAY(DataTypes.TEXT) },
  15. settings: DataTypes.HSTORE,
  16. document: { type: DataTypes.HSTORE, defaultValue: { default: "'value'" } },
  17. phones: DataTypes.ARRAY(DataTypes.HSTORE),
  18. friends: {
  19. type: DataTypes.ARRAY(DataTypes.JSON),
  20. defaultValue: [],
  21. },
  22. magic_numbers: {
  23. type: DataTypes.ARRAY(DataTypes.INTEGER),
  24. defaultValue: [],
  25. },
  26. course_period: DataTypes.RANGE(DataTypes.DATE),
  27. acceptable_marks: { type: DataTypes.RANGE(DataTypes.DECIMAL), defaultValue: [0.65, 1] },
  28. available_amount: DataTypes.RANGE,
  29. holidays: DataTypes.ARRAY(DataTypes.RANGE(DataTypes.DATE)),
  30. location: DataTypes.GEOMETRY(),
  31. });
  32. await this.User.sync({ force: true });
  33. });
  34. it('should be able to search within an array', async function () {
  35. await this.User.findAll({
  36. where: {
  37. email: ['hello', 'world'],
  38. },
  39. attributes: ['id', 'username', 'email', 'settings', 'document', 'phones', 'friends'],
  40. logging(sql) {
  41. expect(sql).to.equal(
  42. 'Executing (default): SELECT "id", "username", "email", "settings", "document", "phones", "friends" FROM "Users" AS "User" WHERE "User"."email" = ARRAY[\'hello\',\'world\'];',
  43. );
  44. },
  45. });
  46. });
  47. it('should be able to update a field with type ARRAY(JSON)', async function () {
  48. const userInstance = await this.User.create({
  49. username: 'bob',
  50. email: ['myemail@email.com'],
  51. friends: [
  52. {
  53. name: 'John Smith',
  54. },
  55. ],
  56. });
  57. expect(userInstance.friends).to.have.length(1);
  58. expect(userInstance.friends[0].name).to.equal('John Smith');
  59. const obj = await userInstance.update({
  60. friends: [
  61. {
  62. name: 'John Smythe',
  63. },
  64. ],
  65. });
  66. const friends = obj.friends;
  67. expect(friends).to.have.length(1);
  68. expect(friends[0].name).to.equal('John Smythe');
  69. });
  70. it('should be able to find a record while searching in an array', async function () {
  71. await this.User.bulkCreate([
  72. { username: 'bob', email: ['myemail@email.com'] },
  73. { username: 'tony', email: ['wrongemail@email.com'] },
  74. ]);
  75. const user = await this.User.findAll({ where: { email: ['myemail@email.com'] } });
  76. expect(user).to.be.instanceof(Array);
  77. expect(user).to.have.length(1);
  78. expect(user[0].username).to.equal('bob');
  79. });
  80. describe('hstore', () => {
  81. it('should tell me that a column is hstore and not USER-DEFINED', async function () {
  82. const table = await this.sequelize.queryInterface.describeTable('Users');
  83. expect(table.settings.type).to.equal('HSTORE');
  84. expect(table.document.type).to.equal('HSTORE');
  85. });
  86. // TODO: move to select QueryGenerator unit tests
  87. it('should NOT stringify hstore with insert', async function () {
  88. await this.User.create(
  89. {
  90. username: 'bob',
  91. email: ['myemail@email.com'],
  92. settings: { mailing: 'false', push: 'facebook', frequency: '3' },
  93. },
  94. {
  95. logging(sql) {
  96. const unexpected =
  97. '\'"mailing"=>"false","push"=>"facebook","frequency"=>"3"\',\'"default"=>"\'\'value\'\'"\'';
  98. expect(sql).not.to.include(unexpected);
  99. },
  100. },
  101. );
  102. });
  103. // TODO: move to select QueryGenerator unit tests
  104. it('should not rename hstore fields', async function () {
  105. const Equipment = this.sequelize.define('Equipment', {
  106. grapplingHook: {
  107. type: DataTypes.STRING,
  108. field: 'grappling_hook',
  109. },
  110. utilityBelt: {
  111. type: DataTypes.HSTORE,
  112. },
  113. });
  114. await Equipment.sync({ force: true });
  115. await Equipment.findAll({
  116. where: {
  117. utilityBelt: {
  118. grapplingHook: 'true',
  119. },
  120. },
  121. logging(sql) {
  122. expect(sql).to.contains(
  123. ' WHERE "Equipment"."utilityBelt" = \'"grapplingHook"=>"true"\';',
  124. );
  125. },
  126. });
  127. });
  128. });
  129. describe('range', () => {
  130. it('should tell me that a column is range and not USER-DEFINED', async function () {
  131. const table = await this.sequelize.queryInterface.describeTable('Users');
  132. expect(table.course_period.type).to.equal('TSTZRANGE');
  133. expect(table.available_amount.type).to.equal('INT4RANGE');
  134. });
  135. });
  136. describe('enums', () => {
  137. it('should be able to create enums with escape values', async function () {
  138. const User = this.sequelize.define('UserEnums', {
  139. mood: DataTypes.ENUM('happy', 'sad', "1970's"),
  140. });
  141. await User.sync({ force: true });
  142. });
  143. it('should be able to ignore enum types that already exist', async function () {
  144. const User = this.sequelize.define('UserEnums', {
  145. mood: DataTypes.ENUM('happy', 'sad', 'meh'),
  146. });
  147. await User.sync({ force: true });
  148. await User.sync();
  149. });
  150. it('should be able to create/drop enums multiple times', async function () {
  151. const User = this.sequelize.define('UserEnums', {
  152. mood: DataTypes.ENUM('happy', 'sad', 'meh'),
  153. });
  154. await User.sync({ force: true });
  155. await User.sync({ force: true });
  156. });
  157. it('should be able to create/drop multiple enums multiple times', async function () {
  158. const DummyModel = this.sequelize.define('Dummy-pg', {
  159. username: DataTypes.STRING,
  160. theEnumOne: {
  161. type: DataTypes.ENUM(['one', 'two', 'three']),
  162. },
  163. theEnumTwo: {
  164. type: DataTypes.ENUM(['four', 'five', 'six']),
  165. },
  166. });
  167. await DummyModel.sync({ force: true });
  168. // now sync one more time:
  169. await DummyModel.sync({ force: true });
  170. // sync without dropping
  171. await DummyModel.sync();
  172. });
  173. it('should be able to create/drop multiple enums multiple times with field name (#7812)', async function () {
  174. const DummyModel = this.sequelize.define('Dummy-pg', {
  175. username: DataTypes.STRING,
  176. theEnumOne: {
  177. field: 'oh_my_this_enum_one',
  178. type: DataTypes.ENUM(['one', 'two', 'three']),
  179. },
  180. theEnumTwo: {
  181. field: 'oh_my_this_enum_two',
  182. type: DataTypes.ENUM(['four', 'five', 'six']),
  183. },
  184. });
  185. await DummyModel.sync({ force: true });
  186. // now sync one more time:
  187. await DummyModel.sync({ force: true });
  188. // sync without dropping
  189. await DummyModel.sync();
  190. });
  191. it('should be able to add values to enum types', async function () {
  192. let User = this.sequelize.define('UserEnums', {
  193. mood: DataTypes.ENUM('happy', 'sad', 'meh'),
  194. });
  195. await User.sync({ force: true });
  196. User = this.sequelize.define('UserEnums', {
  197. mood: DataTypes.ENUM('neutral', 'happy', 'sad', 'ecstatic', 'meh', 'joyful'),
  198. });
  199. await User.sync();
  200. const enums = await this.sequelize.queryInterface.pgListEnums(User.table);
  201. expect(enums).to.have.length(1);
  202. expect(enums[0].enum_value).to.deep.equal([
  203. 'neutral',
  204. 'happy',
  205. 'sad',
  206. 'ecstatic',
  207. 'meh',
  208. 'joyful',
  209. ]);
  210. });
  211. it('should be able to add multiple values with different order', async function () {
  212. let User = this.sequelize.define('UserEnums', {
  213. priority: DataTypes.ENUM('1', '2', '6'),
  214. });
  215. await User.sync({ force: true });
  216. User = this.sequelize.define('UserEnums', {
  217. priority: DataTypes.ENUM('0', '1', '2', '3', '4', '5', '6', '7'),
  218. });
  219. await User.sync();
  220. const enums = await this.sequelize.queryInterface.pgListEnums(User.table);
  221. expect(enums).to.have.length(1);
  222. expect(enums[0].enum_value).to.deep.equal(['0', '1', '2', '3', '4', '5', '6', '7']);
  223. });
  224. describe('ARRAY(ENUM)', () => {
  225. it('should be able to ignore enum types that already exist', async function () {
  226. const User = this.sequelize.define('UserEnums', {
  227. permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])),
  228. });
  229. await User.sync({ force: true });
  230. await User.sync();
  231. });
  232. it('should be able to create/drop enums multiple times', async function () {
  233. const User = this.sequelize.define('UserEnums', {
  234. permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])),
  235. });
  236. await User.sync({ force: true });
  237. await User.sync({ force: true });
  238. });
  239. it('should be able to add values to enum types', async function () {
  240. let User = this.sequelize.define('UserEnums', {
  241. permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])),
  242. });
  243. await User.sync({ force: true });
  244. User = this.sequelize.define('UserEnums', {
  245. permissions: DataTypes.ARRAY(
  246. DataTypes.ENUM('view', 'access', 'edit', 'write', 'check', 'delete'),
  247. ),
  248. });
  249. await User.sync();
  250. const enums = await this.sequelize.queryInterface.pgListEnums(User.table);
  251. expect(enums).to.have.length(1);
  252. expect(enums[0].enum_value).to.deep.equal([
  253. 'view',
  254. 'access',
  255. 'edit',
  256. 'write',
  257. 'check',
  258. 'delete',
  259. ]);
  260. });
  261. it('should be able to insert new record', async function () {
  262. const User = this.sequelize.define('UserEnums', {
  263. name: DataTypes.STRING,
  264. type: DataTypes.ENUM('A', 'B', 'C'),
  265. owners: DataTypes.ARRAY(DataTypes.STRING),
  266. permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])),
  267. });
  268. await User.sync({ force: true });
  269. const user = await User.create({
  270. name: 'file.exe',
  271. type: 'C',
  272. owners: ['userA', 'userB'],
  273. permissions: ['access', 'write'],
  274. });
  275. expect(user.name).to.equal('file.exe');
  276. expect(user.type).to.equal('C');
  277. expect(user.owners).to.deep.equal(['userA', 'userB']);
  278. expect(user.permissions).to.deep.equal(['access', 'write']);
  279. });
  280. it('should be able to insert a new record even with a redefined field name', async function () {
  281. const User = this.sequelize.define('UserEnums', {
  282. name: DataTypes.STRING,
  283. type: DataTypes.ENUM('A', 'B', 'C'),
  284. owners: DataTypes.ARRAY(DataTypes.STRING),
  285. specialPermissions: {
  286. type: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])),
  287. field: 'special_permissions',
  288. },
  289. });
  290. await User.sync({ force: true });
  291. const user = await User.bulkCreate([
  292. {
  293. name: 'file.exe',
  294. type: 'C',
  295. owners: ['userA', 'userB'],
  296. specialPermissions: ['access', 'write'],
  297. },
  298. ]);
  299. expect(user.length).to.equal(1);
  300. });
  301. it('should be able to insert a new record with an array of enums in a schema', async function () {
  302. const schema = 'special_schema';
  303. await this.sequelize.createSchema(schema);
  304. const User = this.sequelize.define(
  305. 'UserEnums',
  306. {
  307. name: DataTypes.STRING,
  308. type: DataTypes.ENUM('A', 'B', 'C'),
  309. owners: DataTypes.ARRAY(DataTypes.STRING),
  310. specialPermissions: {
  311. type: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])),
  312. field: 'special_permissions',
  313. },
  314. },
  315. {
  316. schema,
  317. },
  318. );
  319. await User.sync({ force: true });
  320. const user = await User.bulkCreate([
  321. {
  322. name: 'file.exe',
  323. type: 'C',
  324. owners: ['userA', 'userB'],
  325. specialPermissions: ['access', 'write'],
  326. },
  327. ]);
  328. expect(user.length).to.equal(1);
  329. });
  330. it('should fail when trying to insert foreign element on ARRAY(ENUM)', async function () {
  331. const User = this.sequelize.define('UserEnums', {
  332. name: DataTypes.STRING,
  333. type: DataTypes.ENUM('A', 'B', 'C'),
  334. owners: DataTypes.ARRAY(DataTypes.STRING),
  335. permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])),
  336. });
  337. await User.sync({ force: true });
  338. await expect(
  339. User.create({
  340. name: 'file.exe',
  341. type: 'C',
  342. owners: ['userA', 'userB'],
  343. permissions: ['cosmic_ray_disk_access'],
  344. }),
  345. ).to.be.rejectedWith(
  346. `'cosmic_ray_disk_access' is not a valid choice for enum [ 'access', 'write', 'check', 'delete' ]`,
  347. );
  348. });
  349. it('should be able to find records', async function () {
  350. const User = this.sequelize.define('UserEnums', {
  351. name: DataTypes.STRING,
  352. type: DataTypes.ENUM('A', 'B', 'C'),
  353. permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])),
  354. });
  355. await User.sync({ force: true });
  356. await User.bulkCreate([
  357. {
  358. name: 'file1.exe',
  359. type: 'C',
  360. permissions: ['access', 'write'],
  361. },
  362. {
  363. name: 'file2.exe',
  364. type: 'A',
  365. permissions: ['access', 'check'],
  366. },
  367. {
  368. name: 'file3.exe',
  369. type: 'B',
  370. permissions: ['access', 'write', 'delete'],
  371. },
  372. ]);
  373. const users = await User.findAll({
  374. where: {
  375. type: {
  376. [Op.in]: ['A', 'C'],
  377. },
  378. permissions: {
  379. [Op.contains]: ['write'],
  380. },
  381. },
  382. });
  383. expect(users.length).to.equal(1);
  384. expect(users[0].name).to.equal('file1.exe');
  385. expect(users[0].type).to.equal('C');
  386. expect(users[0].permissions).to.deep.equal(['access', 'write']);
  387. });
  388. });
  389. });
  390. describe('integers', () => {
  391. describe('integer', () => {
  392. beforeEach(async function () {
  393. this.User = this.sequelize.define('User', {
  394. aNumber: DataTypes.INTEGER,
  395. });
  396. await this.User.sync({ force: true });
  397. });
  398. it('positive', async function () {
  399. const User = this.User;
  400. const user = await User.create({ aNumber: 2_147_483_647 });
  401. expect(user.aNumber).to.equal(2_147_483_647);
  402. const _user = await User.findOne({ where: { aNumber: 2_147_483_647 } });
  403. expect(_user.aNumber).to.equal(2_147_483_647);
  404. });
  405. it('negative', async function () {
  406. const User = this.User;
  407. const user = await User.create({ aNumber: -2_147_483_647 });
  408. expect(user.aNumber).to.equal(-2_147_483_647);
  409. const _user = await User.findOne({ where: { aNumber: -2_147_483_647 } });
  410. expect(_user.aNumber).to.equal(-2_147_483_647);
  411. });
  412. });
  413. describe('bigint', () => {
  414. beforeEach(async function () {
  415. this.User = this.sequelize.define('User', {
  416. aNumber: DataTypes.BIGINT,
  417. });
  418. await this.User.sync({ force: true });
  419. });
  420. it('positive', async function () {
  421. const User = this.User;
  422. const user = await User.create({ aNumber: '9223372036854775807' });
  423. expect(user.aNumber).to.equal('9223372036854775807');
  424. const _user = await User.findOne({ where: { aNumber: '9223372036854775807' } });
  425. expect(_user.aNumber).to.equal('9223372036854775807');
  426. });
  427. it('negative', async function () {
  428. const User = this.User;
  429. const user = await User.create({ aNumber: '-9223372036854775807' });
  430. expect(user.aNumber).to.equal('-9223372036854775807');
  431. const _user = await User.findOne({ where: { aNumber: '-9223372036854775807' } });
  432. expect(_user.aNumber).to.equal('-9223372036854775807');
  433. });
  434. });
  435. });
  436. describe('timestamps', () => {
  437. beforeEach(async function () {
  438. this.User = this.sequelize.define('User', {
  439. dates: DataTypes.ARRAY(DataTypes.DATE),
  440. });
  441. await this.User.sync({ force: true });
  442. });
  443. it('should use bind params instead of "TIMESTAMP WITH TIME ZONE"', async function () {
  444. await this.User.create(
  445. {
  446. dates: [],
  447. },
  448. {
  449. logging(sql) {
  450. expect(sql).not.to.contain('TIMESTAMP WITH TIME ZONE');
  451. expect(sql).not.to.contain('DATETIME');
  452. },
  453. },
  454. );
  455. });
  456. });
  457. describe('model', () => {
  458. it('create handles array correctly', async function () {
  459. const oldUser = await this.User.create({
  460. username: 'user',
  461. email: ['foo@bar.com', 'bar@baz.com'],
  462. });
  463. expect(oldUser.email).to.contain.members(['foo@bar.com', 'bar@baz.com']);
  464. });
  465. it('should save hstore correctly', async function () {
  466. const newUser = await this.User.create({
  467. username: 'user',
  468. email: ['foo@bar.com'],
  469. settings: { created: '"value"' },
  470. });
  471. // Check to see if the default value for an hstore field works
  472. expect(newUser.document).to.deep.equal({ default: "'value'" });
  473. expect(newUser.settings).to.deep.equal({ created: '"value"' });
  474. // Check to see if updating an hstore field works
  475. const oldUser = await newUser.update({
  476. settings: { should: 'update', to: 'this', first: 'place' },
  477. });
  478. // Postgres always returns keys in alphabetical order (ascending)
  479. expect(oldUser.settings).to.deep.equal({ first: 'place', should: 'update', to: 'this' });
  480. });
  481. it('should save hstore array correctly', async function () {
  482. const User = this.User;
  483. await this.User.create({
  484. username: 'bob',
  485. email: ['myemail@email.com'],
  486. phones: [
  487. { number: '123456789', type: 'mobile' },
  488. { number: '987654321', type: 'landline' },
  489. { number: '8675309', type: "Jenny's" },
  490. { number: '5555554321', type: '"home\n"' },
  491. ],
  492. });
  493. const user = await User.findByPk(1);
  494. expect(user.phones.length).to.equal(4);
  495. expect(user.phones[1].number).to.equal('987654321');
  496. expect(user.phones[2].type).to.equal("Jenny's");
  497. expect(user.phones[3].type).to.equal('"home\n"');
  498. });
  499. it('should bulkCreate with hstore property', async function () {
  500. const User = this.User;
  501. await this.User.bulkCreate([
  502. {
  503. username: 'bob',
  504. email: ['myemail@email.com'],
  505. settings: { mailing: 'true', push: 'facebook', frequency: '3' },
  506. },
  507. ]);
  508. const user = await User.findByPk(1);
  509. expect(user.settings.mailing).to.equal('true');
  510. });
  511. it('should update hstore correctly', async function () {
  512. const newUser = await this.User.create({
  513. username: 'user',
  514. email: ['foo@bar.com'],
  515. settings: { test: '"value"' },
  516. });
  517. // Check to see if the default value for an hstore field works
  518. expect(newUser.document).to.deep.equal({ default: "'value'" });
  519. expect(newUser.settings).to.deep.equal({ test: '"value"' });
  520. // Check to see if updating an hstore field works
  521. await this.User.update(
  522. { settings: { should: 'update', to: 'this', first: 'place' } },
  523. { where: newUser.where() },
  524. );
  525. await newUser.reload();
  526. // Postgres always returns keys in alphabetical order (ascending)
  527. expect(newUser.settings).to.deep.equal({ first: 'place', should: 'update', to: 'this' });
  528. });
  529. it('should update hstore correctly and return the affected rows', async function () {
  530. const oldUser = await this.User.create({
  531. username: 'user',
  532. email: ['foo@bar.com'],
  533. settings: { test: '"value"' },
  534. });
  535. // Update the user and check that the returned object's fields have been parsed by the hstore library
  536. const [count, users] = await this.User.update(
  537. { settings: { should: 'update', to: 'this', first: 'place' } },
  538. { where: oldUser.where(), returning: true },
  539. );
  540. expect(count).to.equal(1);
  541. expect(users[0].settings).to.deep.equal({ should: 'update', to: 'this', first: 'place' });
  542. });
  543. it('should read hstore correctly', async function () {
  544. const data = { username: 'user', email: ['foo@bar.com'], settings: { test: '"value"' } };
  545. await this.User.create(data);
  546. const user = await this.User.findOne({ where: { username: 'user' } });
  547. // Check that the hstore fields are the same when retrieving the user
  548. expect(user.settings).to.deep.equal(data.settings);
  549. });
  550. it('should read an hstore array correctly', async function () {
  551. const data = {
  552. username: 'user',
  553. email: ['foo@bar.com'],
  554. phones: [
  555. { number: '123456789', type: 'mobile' },
  556. { number: '987654321', type: 'landline' },
  557. ],
  558. };
  559. await this.User.create(data);
  560. // Check that the hstore fields are the same when retrieving the user
  561. const user = await this.User.findOne({ where: { username: 'user' } });
  562. expect(user.phones).to.deep.equal(data.phones);
  563. });
  564. it('should read hstore correctly from multiple rows', async function () {
  565. await this.User.create({
  566. username: 'user1',
  567. email: ['foo@bar.com'],
  568. settings: { test: '"value"' },
  569. });
  570. await this.User.create({
  571. username: 'user2',
  572. email: ['foo2@bar.com'],
  573. settings: { another: '"example"' },
  574. });
  575. // Check that the hstore fields are the same when retrieving the user
  576. const users = await this.User.findAll({ order: ['username'] });
  577. expect(users[0].settings).to.deep.equal({ test: '"value"' });
  578. expect(users[1].settings).to.deep.equal({ another: '"example"' });
  579. });
  580. it('should read hstore correctly from included models as well', async function () {
  581. const HstoreSubmodel = this.sequelize.define('hstoreSubmodel', {
  582. someValue: DataTypes.HSTORE,
  583. });
  584. const submodelValue = { testing: '"hstore"' };
  585. this.User.hasMany(HstoreSubmodel);
  586. await this.sequelize.sync({ force: true });
  587. const user0 = await this.User.create({ username: 'user1' });
  588. const submodel = await HstoreSubmodel.create({ someValue: submodelValue });
  589. await user0.setHstoreSubmodels([submodel]);
  590. const user = await this.User.findOne({
  591. where: { username: 'user1' },
  592. include: [HstoreSubmodel],
  593. });
  594. expect(user.hasOwnProperty('hstoreSubmodels')).to.be.ok;
  595. expect(user.hstoreSubmodels.length).to.equal(1);
  596. expect(user.hstoreSubmodels[0].someValue).to.deep.equal(submodelValue);
  597. });
  598. it('should save range correctly', async function () {
  599. const period = [new Date(2015, 0, 1), new Date(2015, 11, 31)];
  600. const newUser = await this.User.create({
  601. username: 'user',
  602. email: ['foo@bar.com'],
  603. course_period: period,
  604. });
  605. // Check to see if the default value for a range field works
  606. expect(newUser.acceptable_marks.length).to.equal(2);
  607. expect(newUser.acceptable_marks[0].value).to.equal('0.65'); // lower bound
  608. expect(newUser.acceptable_marks[1].value).to.equal('1'); // upper bound
  609. expect(newUser.acceptable_marks[0].inclusive).to.deep.equal(true); // inclusive
  610. expect(newUser.acceptable_marks[1].inclusive).to.deep.equal(false); // exclusive
  611. expect(newUser.course_period[0].value instanceof Date).to.be.ok; // lower bound
  612. expect(newUser.course_period[1].value instanceof Date).to.be.ok; // upper bound
  613. expect(newUser.course_period[0].value).to.equalTime(period[0]); // lower bound
  614. expect(newUser.course_period[1].value).to.equalTime(period[1]); // upper bound
  615. expect(newUser.course_period[0].inclusive).to.deep.equal(true); // inclusive
  616. expect(newUser.course_period[1].inclusive).to.deep.equal(false); // exclusive
  617. // Check to see if updating a range field works
  618. await newUser.update({ acceptable_marks: [0.8, 0.9] });
  619. await newUser.reload(); // Ensure the acceptable_marks array is loaded with the complete range definition
  620. expect(newUser.acceptable_marks.length).to.equal(2);
  621. expect(newUser.acceptable_marks[0].value).to.equal('0.8'); // lower bound
  622. expect(newUser.acceptable_marks[1].value).to.equal('0.9'); // upper bound
  623. });
  624. it('should save range array correctly', async function () {
  625. const User = this.User;
  626. const holidays = [
  627. [new Date(2015, 3, 1), new Date(2015, 3, 15)],
  628. [new Date(2015, 8, 1), new Date(2015, 9, 15)],
  629. ];
  630. await User.create({
  631. username: 'bob',
  632. email: ['myemail@email.com'],
  633. holidays,
  634. });
  635. const user = await User.findByPk(1);
  636. expect(user.holidays.length).to.equal(2);
  637. expect(user.holidays[0].length).to.equal(2);
  638. expect(user.holidays[0][0].value instanceof Date).to.be.ok;
  639. expect(user.holidays[0][1].value instanceof Date).to.be.ok;
  640. expect(user.holidays[0][0].value).to.equalTime(holidays[0][0]);
  641. expect(user.holidays[0][1].value).to.equalTime(holidays[0][1]);
  642. expect(user.holidays[1].length).to.equal(2);
  643. expect(user.holidays[1][0].value instanceof Date).to.be.ok;
  644. expect(user.holidays[1][1].value instanceof Date).to.be.ok;
  645. expect(user.holidays[1][0].value).to.equalTime(holidays[1][0]);
  646. expect(user.holidays[1][1].value).to.equalTime(holidays[1][1]);
  647. });
  648. it('should bulkCreate with range property', async function () {
  649. const User = this.User;
  650. const period = [new Date(2015, 0, 1), new Date(2015, 11, 31)];
  651. await User.bulkCreate([
  652. {
  653. username: 'bob',
  654. email: ['myemail@email.com'],
  655. course_period: period,
  656. },
  657. ]);
  658. const user = await User.findByPk(1);
  659. expect(user.course_period[0].value instanceof Date).to.be.ok;
  660. expect(user.course_period[1].value instanceof Date).to.be.ok;
  661. expect(user.course_period[0].value).to.equalTime(period[0]); // lower bound
  662. expect(user.course_period[1].value).to.equalTime(period[1]); // upper bound
  663. expect(user.course_period[0].inclusive).to.deep.equal(true); // inclusive
  664. expect(user.course_period[1].inclusive).to.deep.equal(false); // exclusive
  665. });
  666. it('should update range correctly', async function () {
  667. const User = this.User;
  668. const period = [new Date(2015, 0, 1), new Date(2015, 11, 31)];
  669. const newUser = await User.create({
  670. username: 'user',
  671. email: ['foo@bar.com'],
  672. course_period: period,
  673. });
  674. // Check to see if the default value for a range field works
  675. expect(newUser.acceptable_marks.length).to.equal(2);
  676. expect(newUser.acceptable_marks[0].value).to.equal('0.65'); // lower bound
  677. expect(newUser.acceptable_marks[1].value).to.equal('1'); // upper bound
  678. expect(newUser.acceptable_marks[0].inclusive).to.deep.equal(true); // inclusive
  679. expect(newUser.acceptable_marks[1].inclusive).to.deep.equal(false); // exclusive
  680. expect(newUser.course_period[0].value instanceof Date).to.be.ok;
  681. expect(newUser.course_period[1].value instanceof Date).to.be.ok;
  682. expect(newUser.course_period[0].value).to.equalTime(period[0]); // lower bound
  683. expect(newUser.course_period[1].value).to.equalTime(period[1]); // upper bound
  684. expect(newUser.course_period[0].inclusive).to.deep.equal(true); // inclusive
  685. expect(newUser.course_period[1].inclusive).to.deep.equal(false); // exclusive
  686. const period2 = [new Date(2015, 1, 1), new Date(2015, 10, 30)];
  687. // Check to see if updating a range field works
  688. await User.update({ course_period: period2 }, { where: newUser.where() });
  689. await newUser.reload();
  690. expect(newUser.course_period[0].value instanceof Date).to.be.ok;
  691. expect(newUser.course_period[1].value instanceof Date).to.be.ok;
  692. expect(newUser.course_period[0].value).to.equalTime(period2[0]); // lower bound
  693. expect(newUser.course_period[1].value).to.equalTime(period2[1]); // upper bound
  694. expect(newUser.course_period[0].inclusive).to.deep.equal(true); // inclusive
  695. expect(newUser.course_period[1].inclusive).to.deep.equal(false); // exclusive
  696. });
  697. it('should update range correctly and return the affected rows', async function () {
  698. const User = this.User;
  699. const period = [new Date(2015, 1, 1), new Date(2015, 10, 30)];
  700. const oldUser = await User.create({
  701. username: 'user',
  702. email: ['foo@bar.com'],
  703. course_period: [new Date(2015, 0, 1), new Date(2015, 11, 31)],
  704. });
  705. // Update the user and check that the returned object's fields have been parsed by the range parser
  706. const [count, users] = await User.update(
  707. { course_period: period },
  708. { where: oldUser.where(), returning: true },
  709. );
  710. expect(count).to.equal(1);
  711. expect(users[0].course_period[0].value instanceof Date).to.be.ok;
  712. expect(users[0].course_period[1].value instanceof Date).to.be.ok;
  713. expect(users[0].course_period[0].value).to.equalTime(period[0]); // lower bound
  714. expect(users[0].course_period[1].value).to.equalTime(period[1]); // upper bound
  715. expect(users[0].course_period[0].inclusive).to.deep.equal(true); // inclusive
  716. expect(users[0].course_period[1].inclusive).to.deep.equal(false); // exclusive
  717. });
  718. it('should read range correctly', async function () {
  719. const User = this.User;
  720. const course_period = [
  721. { value: new Date(2015, 1, 1), inclusive: false },
  722. { value: new Date(2015, 10, 30), inclusive: false },
  723. ];
  724. const data = { username: 'user', email: ['foo@bar.com'], course_period };
  725. await User.create(data);
  726. const user = await User.findOne({ where: { username: 'user' } });
  727. // Check that the range fields are the same when retrieving the user
  728. expect(user.course_period).to.deep.equal(data.course_period);
  729. });
  730. it('should read range array correctly', async function () {
  731. const User = this.User;
  732. const holidays = [
  733. [
  734. { value: new Date(2015, 3, 1, 10), inclusive: true },
  735. { value: new Date(2015, 3, 15), inclusive: true },
  736. ],
  737. [
  738. { value: new Date(2015, 8, 1), inclusive: true },
  739. { value: new Date(2015, 9, 15), inclusive: true },
  740. ],
  741. ];
  742. const data = { username: 'user', email: ['foo@bar.com'], holidays };
  743. await User.create(data);
  744. // Check that the range fields are the same when retrieving the user
  745. const user = await User.findOne({ where: { username: 'user' } });
  746. expect(user.holidays).to.deep.equal(data.holidays);
  747. });
  748. it('should read range correctly from multiple rows', async function () {
  749. const User = this.User;
  750. const periods = [
  751. [new Date(2015, 0, 1), new Date(2015, 11, 31)],
  752. [new Date(2016, 0, 1), new Date(2016, 11, 31)],
  753. ];
  754. await User.create({ username: 'user1', email: ['foo@bar.com'], course_period: periods[0] });
  755. await User.create({ username: 'user2', email: ['foo2@bar.com'], course_period: periods[1] });
  756. // Check that the range fields are the same when retrieving the user
  757. const users = await User.findAll({ order: ['username'] });
  758. expect(users[0].course_period[0].value).to.equalTime(periods[0][0]); // lower bound
  759. expect(users[0].course_period[1].value).to.equalTime(periods[0][1]); // upper bound
  760. expect(users[0].course_period[0].inclusive).to.deep.equal(true); // inclusive
  761. expect(users[0].course_period[1].inclusive).to.deep.equal(false); // exclusive
  762. expect(users[1].course_period[0].value).to.equalTime(periods[1][0]); // lower bound
  763. expect(users[1].course_period[1].value).to.equalTime(periods[1][1]); // upper bound
  764. expect(users[1].course_period[0].inclusive).to.deep.equal(true); // inclusive
  765. expect(users[1].course_period[1].inclusive).to.deep.equal(false); // exclusive
  766. });
  767. it('should read range correctly from included models as well', async function () {
  768. const period = [new Date(2016, 0, 1), new Date(2016, 11, 31)];
  769. const HolidayDate = this.sequelize.define('holidayDate', {
  770. period: DataTypes.RANGE(DataTypes.DATE),
  771. });
  772. this.User.hasMany(HolidayDate);
  773. await this.sequelize.sync({ force: true });
  774. const user0 = await this.User.create({ username: 'user', email: ['foo@bar.com'] });
  775. const holidayDate = await HolidayDate.create({ period });
  776. await user0.setHolidayDates([holidayDate]);
  777. const user = await this.User.findOne({ where: { username: 'user' }, include: [HolidayDate] });
  778. expect(user.hasOwnProperty('holidayDates')).to.be.ok;
  779. expect(user.holidayDates.length).to.equal(1);
  780. expect(user.holidayDates[0].period.length).to.equal(2);
  781. expect(user.holidayDates[0].period[0].value).to.equalTime(period[0]);
  782. expect(user.holidayDates[0].period[1].value).to.equalTime(period[1]);
  783. });
  784. });
  785. it('should save geometry correctly', async function () {
  786. const point = { type: 'Point', coordinates: [39.807_222, -76.984_722] };
  787. const newUser = await this.User.create({
  788. username: 'user',
  789. email: ['foo@bar.com'],
  790. location: point,
  791. });
  792. expect(newUser.location).to.deep.include(point);
  793. });
  794. it('should update geometry correctly', async function () {
  795. const User = this.User;
  796. const point1 = { type: 'Point', coordinates: [39.807_222, -76.984_722] };
  797. const point2 = { type: 'Point', coordinates: [39.828_333, -77.232_222] };
  798. const oldUser = await User.create({
  799. username: 'user',
  800. email: ['foo@bar.com'],
  801. location: point1,
  802. });
  803. const [, updatedUsers] = await User.update(
  804. { location: point2 },
  805. { where: { username: oldUser.username }, returning: true },
  806. );
  807. expect(updatedUsers[0].location).to.deep.include(point2);
  808. });
  809. it('should read geometry correctly', async function () {
  810. const User = this.User;
  811. const point = { type: 'Point', coordinates: [39.807_222, -76.984_722] };
  812. const user0 = await User.create({ username: 'user', email: ['foo@bar.com'], location: point });
  813. const user = await User.findOne({ where: { username: user0.username } });
  814. expect(user.location).to.deep.include(point);
  815. });
  816. });