'use strict'; const chai = require('chai'); const expect = chai.expect; const Support = require('../../support'); const dialect = Support.getTestDialect(); const { DataTypes, Op } = require('@sequelize/core'); describe('[POSTGRES Specific] DAO', () => { if (dialect !== 'postgres') { return; } beforeEach(async function () { this.User = this.sequelize.define('User', { username: DataTypes.STRING, email: { type: DataTypes.ARRAY(DataTypes.TEXT) }, settings: DataTypes.HSTORE, document: { type: DataTypes.HSTORE, defaultValue: { default: "'value'" } }, phones: DataTypes.ARRAY(DataTypes.HSTORE), friends: { type: DataTypes.ARRAY(DataTypes.JSON), defaultValue: [], }, magic_numbers: { type: DataTypes.ARRAY(DataTypes.INTEGER), defaultValue: [], }, course_period: DataTypes.RANGE(DataTypes.DATE), acceptable_marks: { type: DataTypes.RANGE(DataTypes.DECIMAL), defaultValue: [0.65, 1] }, available_amount: DataTypes.RANGE, holidays: DataTypes.ARRAY(DataTypes.RANGE(DataTypes.DATE)), location: DataTypes.GEOMETRY(), }); await this.User.sync({ force: true }); }); it('should be able to search within an array', async function () { await this.User.findAll({ where: { email: ['hello', 'world'], }, attributes: ['id', 'username', 'email', 'settings', 'document', 'phones', 'friends'], logging(sql) { expect(sql).to.equal( 'Executing (default): SELECT "id", "username", "email", "settings", "document", "phones", "friends" FROM "Users" AS "User" WHERE "User"."email" = ARRAY[\'hello\',\'world\'];', ); }, }); }); it('should be able to update a field with type ARRAY(JSON)', async function () { const userInstance = await this.User.create({ username: 'bob', email: ['myemail@email.com'], friends: [ { name: 'John Smith', }, ], }); expect(userInstance.friends).to.have.length(1); expect(userInstance.friends[0].name).to.equal('John Smith'); const obj = await userInstance.update({ friends: [ { name: 'John Smythe', }, ], }); const friends = obj.friends; expect(friends).to.have.length(1); expect(friends[0].name).to.equal('John Smythe'); }); it('should be able to find a record while searching in an array', async function () { await this.User.bulkCreate([ { username: 'bob', email: ['myemail@email.com'] }, { username: 'tony', email: ['wrongemail@email.com'] }, ]); const user = await this.User.findAll({ where: { email: ['myemail@email.com'] } }); expect(user).to.be.instanceof(Array); expect(user).to.have.length(1); expect(user[0].username).to.equal('bob'); }); describe('hstore', () => { it('should tell me that a column is hstore and not USER-DEFINED', async function () { const table = await this.sequelize.queryInterface.describeTable('Users'); expect(table.settings.type).to.equal('HSTORE'); expect(table.document.type).to.equal('HSTORE'); }); // TODO: move to select QueryGenerator unit tests it('should NOT stringify hstore with insert', async function () { await this.User.create( { username: 'bob', email: ['myemail@email.com'], settings: { mailing: 'false', push: 'facebook', frequency: '3' }, }, { logging(sql) { const unexpected = '\'"mailing"=>"false","push"=>"facebook","frequency"=>"3"\',\'"default"=>"\'\'value\'\'"\''; expect(sql).not.to.include(unexpected); }, }, ); }); // TODO: move to select QueryGenerator unit tests it('should not rename hstore fields', async function () { const Equipment = this.sequelize.define('Equipment', { grapplingHook: { type: DataTypes.STRING, field: 'grappling_hook', }, utilityBelt: { type: DataTypes.HSTORE, }, }); await Equipment.sync({ force: true }); await Equipment.findAll({ where: { utilityBelt: { grapplingHook: 'true', }, }, logging(sql) { expect(sql).to.contains( ' WHERE "Equipment"."utilityBelt" = \'"grapplingHook"=>"true"\';', ); }, }); }); }); describe('range', () => { it('should tell me that a column is range and not USER-DEFINED', async function () { const table = await this.sequelize.queryInterface.describeTable('Users'); expect(table.course_period.type).to.equal('TSTZRANGE'); expect(table.available_amount.type).to.equal('INT4RANGE'); }); }); describe('enums', () => { it('should be able to create enums with escape values', async function () { const User = this.sequelize.define('UserEnums', { mood: DataTypes.ENUM('happy', 'sad', "1970's"), }); await User.sync({ force: true }); }); it('should be able to ignore enum types that already exist', async function () { const User = this.sequelize.define('UserEnums', { mood: DataTypes.ENUM('happy', 'sad', 'meh'), }); await User.sync({ force: true }); await User.sync(); }); it('should be able to create/drop enums multiple times', async function () { const User = this.sequelize.define('UserEnums', { mood: DataTypes.ENUM('happy', 'sad', 'meh'), }); await User.sync({ force: true }); await User.sync({ force: true }); }); it('should be able to create/drop multiple enums multiple times', async function () { const DummyModel = this.sequelize.define('Dummy-pg', { username: DataTypes.STRING, theEnumOne: { type: DataTypes.ENUM(['one', 'two', 'three']), }, theEnumTwo: { type: DataTypes.ENUM(['four', 'five', 'six']), }, }); await DummyModel.sync({ force: true }); // now sync one more time: await DummyModel.sync({ force: true }); // sync without dropping await DummyModel.sync(); }); it('should be able to create/drop multiple enums multiple times with field name (#7812)', async function () { const DummyModel = this.sequelize.define('Dummy-pg', { username: DataTypes.STRING, theEnumOne: { field: 'oh_my_this_enum_one', type: DataTypes.ENUM(['one', 'two', 'three']), }, theEnumTwo: { field: 'oh_my_this_enum_two', type: DataTypes.ENUM(['four', 'five', 'six']), }, }); await DummyModel.sync({ force: true }); // now sync one more time: await DummyModel.sync({ force: true }); // sync without dropping await DummyModel.sync(); }); it('should be able to add values to enum types', async function () { let User = this.sequelize.define('UserEnums', { mood: DataTypes.ENUM('happy', 'sad', 'meh'), }); await User.sync({ force: true }); User = this.sequelize.define('UserEnums', { mood: DataTypes.ENUM('neutral', 'happy', 'sad', 'ecstatic', 'meh', 'joyful'), }); await User.sync(); const enums = await this.sequelize.queryInterface.pgListEnums(User.table); expect(enums).to.have.length(1); expect(enums[0].enum_value).to.deep.equal([ 'neutral', 'happy', 'sad', 'ecstatic', 'meh', 'joyful', ]); }); it('should be able to add multiple values with different order', async function () { let User = this.sequelize.define('UserEnums', { priority: DataTypes.ENUM('1', '2', '6'), }); await User.sync({ force: true }); User = this.sequelize.define('UserEnums', { priority: DataTypes.ENUM('0', '1', '2', '3', '4', '5', '6', '7'), }); await User.sync(); const enums = await this.sequelize.queryInterface.pgListEnums(User.table); expect(enums).to.have.length(1); expect(enums[0].enum_value).to.deep.equal(['0', '1', '2', '3', '4', '5', '6', '7']); }); describe('ARRAY(ENUM)', () => { it('should be able to ignore enum types that already exist', async function () { const User = this.sequelize.define('UserEnums', { permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])), }); await User.sync({ force: true }); await User.sync(); }); it('should be able to create/drop enums multiple times', async function () { const User = this.sequelize.define('UserEnums', { permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])), }); await User.sync({ force: true }); await User.sync({ force: true }); }); it('should be able to add values to enum types', async function () { let User = this.sequelize.define('UserEnums', { permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])), }); await User.sync({ force: true }); User = this.sequelize.define('UserEnums', { permissions: DataTypes.ARRAY( DataTypes.ENUM('view', 'access', 'edit', 'write', 'check', 'delete'), ), }); await User.sync(); const enums = await this.sequelize.queryInterface.pgListEnums(User.table); expect(enums).to.have.length(1); expect(enums[0].enum_value).to.deep.equal([ 'view', 'access', 'edit', 'write', 'check', 'delete', ]); }); it('should be able to insert new record', async function () { const User = this.sequelize.define('UserEnums', { name: DataTypes.STRING, type: DataTypes.ENUM('A', 'B', 'C'), owners: DataTypes.ARRAY(DataTypes.STRING), permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])), }); await User.sync({ force: true }); const user = await User.create({ name: 'file.exe', type: 'C', owners: ['userA', 'userB'], permissions: ['access', 'write'], }); expect(user.name).to.equal('file.exe'); expect(user.type).to.equal('C'); expect(user.owners).to.deep.equal(['userA', 'userB']); expect(user.permissions).to.deep.equal(['access', 'write']); }); it('should be able to insert a new record even with a redefined field name', async function () { const User = this.sequelize.define('UserEnums', { name: DataTypes.STRING, type: DataTypes.ENUM('A', 'B', 'C'), owners: DataTypes.ARRAY(DataTypes.STRING), specialPermissions: { type: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])), field: 'special_permissions', }, }); await User.sync({ force: true }); const user = await User.bulkCreate([ { name: 'file.exe', type: 'C', owners: ['userA', 'userB'], specialPermissions: ['access', 'write'], }, ]); expect(user.length).to.equal(1); }); it('should be able to insert a new record with an array of enums in a schema', async function () { const schema = 'special_schema'; await this.sequelize.createSchema(schema); const User = this.sequelize.define( 'UserEnums', { name: DataTypes.STRING, type: DataTypes.ENUM('A', 'B', 'C'), owners: DataTypes.ARRAY(DataTypes.STRING), specialPermissions: { type: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])), field: 'special_permissions', }, }, { schema, }, ); await User.sync({ force: true }); const user = await User.bulkCreate([ { name: 'file.exe', type: 'C', owners: ['userA', 'userB'], specialPermissions: ['access', 'write'], }, ]); expect(user.length).to.equal(1); }); it('should fail when trying to insert foreign element on ARRAY(ENUM)', async function () { const User = this.sequelize.define('UserEnums', { name: DataTypes.STRING, type: DataTypes.ENUM('A', 'B', 'C'), owners: DataTypes.ARRAY(DataTypes.STRING), permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])), }); await User.sync({ force: true }); await expect( User.create({ name: 'file.exe', type: 'C', owners: ['userA', 'userB'], permissions: ['cosmic_ray_disk_access'], }), ).to.be.rejectedWith( `'cosmic_ray_disk_access' is not a valid choice for enum [ 'access', 'write', 'check', 'delete' ]`, ); }); it('should be able to find records', async function () { const User = this.sequelize.define('UserEnums', { name: DataTypes.STRING, type: DataTypes.ENUM('A', 'B', 'C'), permissions: DataTypes.ARRAY(DataTypes.ENUM(['access', 'write', 'check', 'delete'])), }); await User.sync({ force: true }); await User.bulkCreate([ { name: 'file1.exe', type: 'C', permissions: ['access', 'write'], }, { name: 'file2.exe', type: 'A', permissions: ['access', 'check'], }, { name: 'file3.exe', type: 'B', permissions: ['access', 'write', 'delete'], }, ]); const users = await User.findAll({ where: { type: { [Op.in]: ['A', 'C'], }, permissions: { [Op.contains]: ['write'], }, }, }); expect(users.length).to.equal(1); expect(users[0].name).to.equal('file1.exe'); expect(users[0].type).to.equal('C'); expect(users[0].permissions).to.deep.equal(['access', 'write']); }); }); }); describe('integers', () => { describe('integer', () => { beforeEach(async function () { this.User = this.sequelize.define('User', { aNumber: DataTypes.INTEGER, }); await this.User.sync({ force: true }); }); it('positive', async function () { const User = this.User; const user = await User.create({ aNumber: 2_147_483_647 }); expect(user.aNumber).to.equal(2_147_483_647); const _user = await User.findOne({ where: { aNumber: 2_147_483_647 } }); expect(_user.aNumber).to.equal(2_147_483_647); }); it('negative', async function () { const User = this.User; const user = await User.create({ aNumber: -2_147_483_647 }); expect(user.aNumber).to.equal(-2_147_483_647); const _user = await User.findOne({ where: { aNumber: -2_147_483_647 } }); expect(_user.aNumber).to.equal(-2_147_483_647); }); }); describe('bigint', () => { beforeEach(async function () { this.User = this.sequelize.define('User', { aNumber: DataTypes.BIGINT, }); await this.User.sync({ force: true }); }); it('positive', async function () { const User = this.User; const user = await User.create({ aNumber: '9223372036854775807' }); expect(user.aNumber).to.equal('9223372036854775807'); const _user = await User.findOne({ where: { aNumber: '9223372036854775807' } }); expect(_user.aNumber).to.equal('9223372036854775807'); }); it('negative', async function () { const User = this.User; const user = await User.create({ aNumber: '-9223372036854775807' }); expect(user.aNumber).to.equal('-9223372036854775807'); const _user = await User.findOne({ where: { aNumber: '-9223372036854775807' } }); expect(_user.aNumber).to.equal('-9223372036854775807'); }); }); }); describe('timestamps', () => { beforeEach(async function () { this.User = this.sequelize.define('User', { dates: DataTypes.ARRAY(DataTypes.DATE), }); await this.User.sync({ force: true }); }); it('should use bind params instead of "TIMESTAMP WITH TIME ZONE"', async function () { await this.User.create( { dates: [], }, { logging(sql) { expect(sql).not.to.contain('TIMESTAMP WITH TIME ZONE'); expect(sql).not.to.contain('DATETIME'); }, }, ); }); }); describe('model', () => { it('create handles array correctly', async function () { const oldUser = await this.User.create({ username: 'user', email: ['foo@bar.com', 'bar@baz.com'], }); expect(oldUser.email).to.contain.members(['foo@bar.com', 'bar@baz.com']); }); it('should save hstore correctly', async function () { const newUser = await this.User.create({ username: 'user', email: ['foo@bar.com'], settings: { created: '"value"' }, }); // Check to see if the default value for an hstore field works expect(newUser.document).to.deep.equal({ default: "'value'" }); expect(newUser.settings).to.deep.equal({ created: '"value"' }); // Check to see if updating an hstore field works const oldUser = await newUser.update({ settings: { should: 'update', to: 'this', first: 'place' }, }); // Postgres always returns keys in alphabetical order (ascending) expect(oldUser.settings).to.deep.equal({ first: 'place', should: 'update', to: 'this' }); }); it('should save hstore array correctly', async function () { const User = this.User; await this.User.create({ username: 'bob', email: ['myemail@email.com'], phones: [ { number: '123456789', type: 'mobile' }, { number: '987654321', type: 'landline' }, { number: '8675309', type: "Jenny's" }, { number: '5555554321', type: '"home\n"' }, ], }); const user = await User.findByPk(1); expect(user.phones.length).to.equal(4); expect(user.phones[1].number).to.equal('987654321'); expect(user.phones[2].type).to.equal("Jenny's"); expect(user.phones[3].type).to.equal('"home\n"'); }); it('should bulkCreate with hstore property', async function () { const User = this.User; await this.User.bulkCreate([ { username: 'bob', email: ['myemail@email.com'], settings: { mailing: 'true', push: 'facebook', frequency: '3' }, }, ]); const user = await User.findByPk(1); expect(user.settings.mailing).to.equal('true'); }); it('should update hstore correctly', async function () { const newUser = await this.User.create({ username: 'user', email: ['foo@bar.com'], settings: { test: '"value"' }, }); // Check to see if the default value for an hstore field works expect(newUser.document).to.deep.equal({ default: "'value'" }); expect(newUser.settings).to.deep.equal({ test: '"value"' }); // Check to see if updating an hstore field works await this.User.update( { settings: { should: 'update', to: 'this', first: 'place' } }, { where: newUser.where() }, ); await newUser.reload(); // Postgres always returns keys in alphabetical order (ascending) expect(newUser.settings).to.deep.equal({ first: 'place', should: 'update', to: 'this' }); }); it('should update hstore correctly and return the affected rows', async function () { const oldUser = await this.User.create({ username: 'user', email: ['foo@bar.com'], settings: { test: '"value"' }, }); // Update the user and check that the returned object's fields have been parsed by the hstore library const [count, users] = await this.User.update( { settings: { should: 'update', to: 'this', first: 'place' } }, { where: oldUser.where(), returning: true }, ); expect(count).to.equal(1); expect(users[0].settings).to.deep.equal({ should: 'update', to: 'this', first: 'place' }); }); it('should read hstore correctly', async function () { const data = { username: 'user', email: ['foo@bar.com'], settings: { test: '"value"' } }; await this.User.create(data); const user = await this.User.findOne({ where: { username: 'user' } }); // Check that the hstore fields are the same when retrieving the user expect(user.settings).to.deep.equal(data.settings); }); it('should read an hstore array correctly', async function () { const data = { username: 'user', email: ['foo@bar.com'], phones: [ { number: '123456789', type: 'mobile' }, { number: '987654321', type: 'landline' }, ], }; await this.User.create(data); // Check that the hstore fields are the same when retrieving the user const user = await this.User.findOne({ where: { username: 'user' } }); expect(user.phones).to.deep.equal(data.phones); }); it('should read hstore correctly from multiple rows', async function () { await this.User.create({ username: 'user1', email: ['foo@bar.com'], settings: { test: '"value"' }, }); await this.User.create({ username: 'user2', email: ['foo2@bar.com'], settings: { another: '"example"' }, }); // Check that the hstore fields are the same when retrieving the user const users = await this.User.findAll({ order: ['username'] }); expect(users[0].settings).to.deep.equal({ test: '"value"' }); expect(users[1].settings).to.deep.equal({ another: '"example"' }); }); it('should read hstore correctly from included models as well', async function () { const HstoreSubmodel = this.sequelize.define('hstoreSubmodel', { someValue: DataTypes.HSTORE, }); const submodelValue = { testing: '"hstore"' }; this.User.hasMany(HstoreSubmodel); await this.sequelize.sync({ force: true }); const user0 = await this.User.create({ username: 'user1' }); const submodel = await HstoreSubmodel.create({ someValue: submodelValue }); await user0.setHstoreSubmodels([submodel]); const user = await this.User.findOne({ where: { username: 'user1' }, include: [HstoreSubmodel], }); expect(user.hasOwnProperty('hstoreSubmodels')).to.be.ok; expect(user.hstoreSubmodels.length).to.equal(1); expect(user.hstoreSubmodels[0].someValue).to.deep.equal(submodelValue); }); it('should save range correctly', async function () { const period = [new Date(2015, 0, 1), new Date(2015, 11, 31)]; const newUser = await this.User.create({ username: 'user', email: ['foo@bar.com'], course_period: period, }); // Check to see if the default value for a range field works expect(newUser.acceptable_marks.length).to.equal(2); expect(newUser.acceptable_marks[0].value).to.equal('0.65'); // lower bound expect(newUser.acceptable_marks[1].value).to.equal('1'); // upper bound expect(newUser.acceptable_marks[0].inclusive).to.deep.equal(true); // inclusive expect(newUser.acceptable_marks[1].inclusive).to.deep.equal(false); // exclusive expect(newUser.course_period[0].value instanceof Date).to.be.ok; // lower bound expect(newUser.course_period[1].value instanceof Date).to.be.ok; // upper bound expect(newUser.course_period[0].value).to.equalTime(period[0]); // lower bound expect(newUser.course_period[1].value).to.equalTime(period[1]); // upper bound expect(newUser.course_period[0].inclusive).to.deep.equal(true); // inclusive expect(newUser.course_period[1].inclusive).to.deep.equal(false); // exclusive // Check to see if updating a range field works await newUser.update({ acceptable_marks: [0.8, 0.9] }); await newUser.reload(); // Ensure the acceptable_marks array is loaded with the complete range definition expect(newUser.acceptable_marks.length).to.equal(2); expect(newUser.acceptable_marks[0].value).to.equal('0.8'); // lower bound expect(newUser.acceptable_marks[1].value).to.equal('0.9'); // upper bound }); it('should save range array correctly', async function () { const User = this.User; const holidays = [ [new Date(2015, 3, 1), new Date(2015, 3, 15)], [new Date(2015, 8, 1), new Date(2015, 9, 15)], ]; await User.create({ username: 'bob', email: ['myemail@email.com'], holidays, }); const user = await User.findByPk(1); expect(user.holidays.length).to.equal(2); expect(user.holidays[0].length).to.equal(2); expect(user.holidays[0][0].value instanceof Date).to.be.ok; expect(user.holidays[0][1].value instanceof Date).to.be.ok; expect(user.holidays[0][0].value).to.equalTime(holidays[0][0]); expect(user.holidays[0][1].value).to.equalTime(holidays[0][1]); expect(user.holidays[1].length).to.equal(2); expect(user.holidays[1][0].value instanceof Date).to.be.ok; expect(user.holidays[1][1].value instanceof Date).to.be.ok; expect(user.holidays[1][0].value).to.equalTime(holidays[1][0]); expect(user.holidays[1][1].value).to.equalTime(holidays[1][1]); }); it('should bulkCreate with range property', async function () { const User = this.User; const period = [new Date(2015, 0, 1), new Date(2015, 11, 31)]; await User.bulkCreate([ { username: 'bob', email: ['myemail@email.com'], course_period: period, }, ]); const user = await User.findByPk(1); expect(user.course_period[0].value instanceof Date).to.be.ok; expect(user.course_period[1].value instanceof Date).to.be.ok; expect(user.course_period[0].value).to.equalTime(period[0]); // lower bound expect(user.course_period[1].value).to.equalTime(period[1]); // upper bound expect(user.course_period[0].inclusive).to.deep.equal(true); // inclusive expect(user.course_period[1].inclusive).to.deep.equal(false); // exclusive }); it('should update range correctly', async function () { const User = this.User; const period = [new Date(2015, 0, 1), new Date(2015, 11, 31)]; const newUser = await User.create({ username: 'user', email: ['foo@bar.com'], course_period: period, }); // Check to see if the default value for a range field works expect(newUser.acceptable_marks.length).to.equal(2); expect(newUser.acceptable_marks[0].value).to.equal('0.65'); // lower bound expect(newUser.acceptable_marks[1].value).to.equal('1'); // upper bound expect(newUser.acceptable_marks[0].inclusive).to.deep.equal(true); // inclusive expect(newUser.acceptable_marks[1].inclusive).to.deep.equal(false); // exclusive expect(newUser.course_period[0].value instanceof Date).to.be.ok; expect(newUser.course_period[1].value instanceof Date).to.be.ok; expect(newUser.course_period[0].value).to.equalTime(period[0]); // lower bound expect(newUser.course_period[1].value).to.equalTime(period[1]); // upper bound expect(newUser.course_period[0].inclusive).to.deep.equal(true); // inclusive expect(newUser.course_period[1].inclusive).to.deep.equal(false); // exclusive const period2 = [new Date(2015, 1, 1), new Date(2015, 10, 30)]; // Check to see if updating a range field works await User.update({ course_period: period2 }, { where: newUser.where() }); await newUser.reload(); expect(newUser.course_period[0].value instanceof Date).to.be.ok; expect(newUser.course_period[1].value instanceof Date).to.be.ok; expect(newUser.course_period[0].value).to.equalTime(period2[0]); // lower bound expect(newUser.course_period[1].value).to.equalTime(period2[1]); // upper bound expect(newUser.course_period[0].inclusive).to.deep.equal(true); // inclusive expect(newUser.course_period[1].inclusive).to.deep.equal(false); // exclusive }); it('should update range correctly and return the affected rows', async function () { const User = this.User; const period = [new Date(2015, 1, 1), new Date(2015, 10, 30)]; const oldUser = await User.create({ username: 'user', email: ['foo@bar.com'], course_period: [new Date(2015, 0, 1), new Date(2015, 11, 31)], }); // Update the user and check that the returned object's fields have been parsed by the range parser const [count, users] = await User.update( { course_period: period }, { where: oldUser.where(), returning: true }, ); expect(count).to.equal(1); expect(users[0].course_period[0].value instanceof Date).to.be.ok; expect(users[0].course_period[1].value instanceof Date).to.be.ok; expect(users[0].course_period[0].value).to.equalTime(period[0]); // lower bound expect(users[0].course_period[1].value).to.equalTime(period[1]); // upper bound expect(users[0].course_period[0].inclusive).to.deep.equal(true); // inclusive expect(users[0].course_period[1].inclusive).to.deep.equal(false); // exclusive }); it('should read range correctly', async function () { const User = this.User; const course_period = [ { value: new Date(2015, 1, 1), inclusive: false }, { value: new Date(2015, 10, 30), inclusive: false }, ]; const data = { username: 'user', email: ['foo@bar.com'], course_period }; await User.create(data); const user = await User.findOne({ where: { username: 'user' } }); // Check that the range fields are the same when retrieving the user expect(user.course_period).to.deep.equal(data.course_period); }); it('should read range array correctly', async function () { const User = this.User; const holidays = [ [ { value: new Date(2015, 3, 1, 10), inclusive: true }, { value: new Date(2015, 3, 15), inclusive: true }, ], [ { value: new Date(2015, 8, 1), inclusive: true }, { value: new Date(2015, 9, 15), inclusive: true }, ], ]; const data = { username: 'user', email: ['foo@bar.com'], holidays }; await User.create(data); // Check that the range fields are the same when retrieving the user const user = await User.findOne({ where: { username: 'user' } }); expect(user.holidays).to.deep.equal(data.holidays); }); it('should read range correctly from multiple rows', async function () { const User = this.User; const periods = [ [new Date(2015, 0, 1), new Date(2015, 11, 31)], [new Date(2016, 0, 1), new Date(2016, 11, 31)], ]; await User.create({ username: 'user1', email: ['foo@bar.com'], course_period: periods[0] }); await User.create({ username: 'user2', email: ['foo2@bar.com'], course_period: periods[1] }); // Check that the range fields are the same when retrieving the user const users = await User.findAll({ order: ['username'] }); expect(users[0].course_period[0].value).to.equalTime(periods[0][0]); // lower bound expect(users[0].course_period[1].value).to.equalTime(periods[0][1]); // upper bound expect(users[0].course_period[0].inclusive).to.deep.equal(true); // inclusive expect(users[0].course_period[1].inclusive).to.deep.equal(false); // exclusive expect(users[1].course_period[0].value).to.equalTime(periods[1][0]); // lower bound expect(users[1].course_period[1].value).to.equalTime(periods[1][1]); // upper bound expect(users[1].course_period[0].inclusive).to.deep.equal(true); // inclusive expect(users[1].course_period[1].inclusive).to.deep.equal(false); // exclusive }); it('should read range correctly from included models as well', async function () { const period = [new Date(2016, 0, 1), new Date(2016, 11, 31)]; const HolidayDate = this.sequelize.define('holidayDate', { period: DataTypes.RANGE(DataTypes.DATE), }); this.User.hasMany(HolidayDate); await this.sequelize.sync({ force: true }); const user0 = await this.User.create({ username: 'user', email: ['foo@bar.com'] }); const holidayDate = await HolidayDate.create({ period }); await user0.setHolidayDates([holidayDate]); const user = await this.User.findOne({ where: { username: 'user' }, include: [HolidayDate] }); expect(user.hasOwnProperty('holidayDates')).to.be.ok; expect(user.holidayDates.length).to.equal(1); expect(user.holidayDates[0].period.length).to.equal(2); expect(user.holidayDates[0].period[0].value).to.equalTime(period[0]); expect(user.holidayDates[0].period[1].value).to.equalTime(period[1]); }); }); it('should save geometry correctly', async function () { const point = { type: 'Point', coordinates: [39.807_222, -76.984_722] }; const newUser = await this.User.create({ username: 'user', email: ['foo@bar.com'], location: point, }); expect(newUser.location).to.deep.include(point); }); it('should update geometry correctly', async function () { const User = this.User; const point1 = { type: 'Point', coordinates: [39.807_222, -76.984_722] }; const point2 = { type: 'Point', coordinates: [39.828_333, -77.232_222] }; const oldUser = await User.create({ username: 'user', email: ['foo@bar.com'], location: point1, }); const [, updatedUsers] = await User.update( { location: point2 }, { where: { username: oldUser.username }, returning: true }, ); expect(updatedUsers[0].location).to.deep.include(point2); }); it('should read geometry correctly', async function () { const User = this.User; const point = { type: 'Point', coordinates: [39.807_222, -76.984_722] }; const user0 = await User.create({ username: 'user', email: ['foo@bar.com'], location: point }); const user = await User.findOne({ where: { username: user0.username } }); expect(user.location).to.deep.include(point); }); });