values.test.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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 { Col, DataTypes, Fn } = require('@sequelize/core');
  7. describe(Support.getTestDialectTeaser('DAO'), () => {
  8. describe('Values', () => {
  9. describe('set', () => {
  10. it("doesn't overwrite generated primary keys", function () {
  11. const User = this.sequelize.define('User', {
  12. name: { type: DataTypes.STRING },
  13. });
  14. const user = User.build({ id: 1, name: 'Mick' });
  15. expect(user.get('id')).to.equal(1);
  16. expect(user.get('name')).to.equal('Mick');
  17. user.set({
  18. id: 2,
  19. name: 'Jan',
  20. });
  21. expect(user.get('id')).to.equal(1);
  22. expect(user.get('name')).to.equal('Jan');
  23. });
  24. it("doesn't overwrite defined primary keys", function () {
  25. const User = this.sequelize.define('User', {
  26. identifier: { type: DataTypes.STRING, primaryKey: true },
  27. });
  28. const user = User.build({ identifier: 'identifier' });
  29. expect(user.get('identifier')).to.equal('identifier');
  30. user.set('identifier', 'another identifier');
  31. expect(user.get('identifier')).to.equal('identifier');
  32. });
  33. it("doesn't set timestamps", function () {
  34. const User = this.sequelize.define('User', {
  35. identifier: { type: DataTypes.STRING, primaryKey: true },
  36. });
  37. const user = User.build(
  38. {},
  39. {
  40. isNewRecord: false,
  41. },
  42. );
  43. user.set({
  44. createdAt: new Date(2000, 1, 1),
  45. updatedAt: new Date(2000, 1, 1),
  46. });
  47. expect(user.get('createdAt')).not.to.be.ok;
  48. expect(user.get('updatedAt')).not.to.be.ok;
  49. });
  50. it("doesn't set underscored timestamps", function () {
  51. const User = this.sequelize.define(
  52. 'User',
  53. {
  54. identifier: { type: DataTypes.STRING, primaryKey: true },
  55. },
  56. {
  57. underscored: true,
  58. },
  59. );
  60. const user = User.build(
  61. {},
  62. {
  63. isNewRecord: false,
  64. },
  65. );
  66. user.set({
  67. created_at: new Date(2000, 1, 1),
  68. updated_at: new Date(2000, 1, 1),
  69. });
  70. expect(user.get('created_at')).not.to.be.ok;
  71. expect(user.get('updated_at')).not.to.be.ok;
  72. });
  73. it('allows use of sequelize.fn and sequelize.col in date and bool fields', async function () {
  74. const User = this.sequelize.define(
  75. 'User',
  76. {
  77. d: DataTypes.DATE,
  78. b: DataTypes.BOOLEAN,
  79. always_false: {
  80. type: DataTypes.BOOLEAN,
  81. defaultValue: false,
  82. },
  83. },
  84. { timestamps: false },
  85. );
  86. await User.sync({ force: true });
  87. const user = await User.create({});
  88. // Create the user first to set the proper default values. PG does not support column references in insert,
  89. // so we must create a record with the right value for always_false, then reference it in an update
  90. const now =
  91. dialect === 'sqlite3'
  92. ? this.sequelize.fn('', this.sequelize.fn('datetime', 'now'))
  93. : dialect === 'mssql'
  94. ? this.sequelize.fn('', this.sequelize.fn('getdate'))
  95. : this.sequelize.fn('NOW');
  96. user.set({
  97. d: now,
  98. b: this.sequelize.col('always_false'),
  99. });
  100. expect(user.get('d')).to.be.instanceof(Fn);
  101. expect(user.get('b')).to.be.instanceof(Col);
  102. await user.save();
  103. await user.reload();
  104. expect(user.d).to.equalDate(new Date());
  105. expect(user.b).to.equal(false);
  106. });
  107. describe('includes', () => {
  108. it('should support basic includes', function () {
  109. const Product = this.sequelize.define('product', {
  110. title: DataTypes.STRING,
  111. });
  112. const Tag = this.sequelize.define('tag', {
  113. name: DataTypes.STRING,
  114. });
  115. const User = this.sequelize.define('user', {
  116. first_name: DataTypes.STRING,
  117. last_name: DataTypes.STRING,
  118. });
  119. Product.hasMany(Tag);
  120. Product.belongsTo(User);
  121. const product = Product.build(
  122. {},
  123. {
  124. include: [User, Tag],
  125. },
  126. );
  127. product.set({
  128. id: 1,
  129. title: 'Chair',
  130. tags: [
  131. { id: 1, name: 'Alpha' },
  132. { id: 2, name: 'Beta' },
  133. ],
  134. user: {
  135. id: 1,
  136. first_name: 'Mick',
  137. last_name: 'Hansen',
  138. },
  139. });
  140. expect(product.tags).to.be.ok;
  141. expect(product.tags.length).to.equal(2);
  142. expect(product.tags[0]).to.be.instanceof(Tag);
  143. expect(product.user).to.be.ok;
  144. expect(product.user).to.be.instanceof(User);
  145. });
  146. it('should support basic includes (with raw: true)', function () {
  147. const Product = this.sequelize.define('Product', {
  148. title: DataTypes.STRING,
  149. });
  150. const Tag = this.sequelize.define('tag', {
  151. name: DataTypes.STRING,
  152. });
  153. const User = this.sequelize.define('user', {
  154. first_name: DataTypes.STRING,
  155. last_name: DataTypes.STRING,
  156. });
  157. Product.hasMany(Tag);
  158. Product.belongsTo(User);
  159. const product = Product.build(
  160. {},
  161. {
  162. include: [User, Tag],
  163. },
  164. );
  165. product.set(
  166. {
  167. id: 1,
  168. title: 'Chair',
  169. tags: [
  170. { id: 1, name: 'Alpha' },
  171. { id: 2, name: 'Beta' },
  172. ],
  173. user: {
  174. id: 1,
  175. first_name: 'Mick',
  176. last_name: 'Hansen',
  177. },
  178. },
  179. { raw: true },
  180. );
  181. expect(product.tags).to.be.ok;
  182. expect(product.tags.length).to.equal(2);
  183. expect(product.tags[0]).to.be.instanceof(Tag);
  184. expect(product.user).to.be.ok;
  185. expect(product.user).to.be.instanceof(User);
  186. });
  187. });
  188. });
  189. describe('get', () => {
  190. it('should use custom attribute getters in get(key)', function () {
  191. const Product = this.sequelize.define('Product', {
  192. price: {
  193. type: DataTypes.FLOAT,
  194. get() {
  195. return this.dataValues.price * 100;
  196. },
  197. },
  198. });
  199. const product = Product.build({
  200. price: 10,
  201. });
  202. expect(product.get('price')).to.equal(1000);
  203. });
  204. it('should work with save', async function () {
  205. const Contact = this.sequelize.define('Contact', {
  206. first: { type: DataTypes.STRING },
  207. last: { type: DataTypes.STRING },
  208. tags: {
  209. type: DataTypes.STRING,
  210. get(field) {
  211. const val = this.getDataValue(field);
  212. return JSON.parse(val);
  213. },
  214. set(val, field) {
  215. this.setDataValue(field, JSON.stringify(val));
  216. },
  217. },
  218. });
  219. await this.sequelize.sync();
  220. const contact = Contact.build({
  221. first: 'My',
  222. last: 'Name',
  223. tags: ['yes', 'no'],
  224. });
  225. expect(contact.get('tags')).to.deep.equal(['yes', 'no']);
  226. const me = await contact.save();
  227. expect(me.get('tags')).to.deep.equal(['yes', 'no']);
  228. });
  229. describe('plain', () => {
  230. it('should return plain values when true', function () {
  231. const Product = this.sequelize.define('product', {
  232. title: DataTypes.STRING,
  233. });
  234. const User = this.sequelize.define('user', {
  235. first_name: DataTypes.STRING,
  236. last_name: DataTypes.STRING,
  237. });
  238. Product.belongsTo(User);
  239. const product = Product.build(
  240. {},
  241. {
  242. include: [User],
  243. },
  244. );
  245. product.set(
  246. {
  247. id: 1,
  248. title: 'Chair',
  249. user: {
  250. id: 1,
  251. first_name: 'Mick',
  252. last_name: 'Hansen',
  253. },
  254. },
  255. { raw: true },
  256. );
  257. expect(product.get('user', { plain: true })).not.to.be.instanceof(User);
  258. expect(product.get({ plain: true }).user).not.to.be.instanceof(User);
  259. });
  260. });
  261. describe('clone', () => {
  262. it('should copy the values', function () {
  263. const Product = this.sequelize.define('product', {
  264. title: DataTypes.STRING,
  265. });
  266. const product = Product.build(
  267. {
  268. id: 1,
  269. title: 'Chair',
  270. },
  271. { raw: true },
  272. );
  273. const values = product.get({ clone: true });
  274. delete values.title;
  275. expect(product.get({ clone: true }).title).to.be.ok;
  276. });
  277. });
  278. });
  279. describe('changed', () => {
  280. it('should return false if object was built from database', async function () {
  281. const User = this.sequelize.define('User', {
  282. name: { type: DataTypes.STRING },
  283. });
  284. await User.sync();
  285. const user0 = await User.create({ name: 'Jan Meier' });
  286. expect(user0.changed('name')).to.be.false;
  287. expect(user0.changed()).not.to.be.ok;
  288. const [user] = await User.bulkCreate([{ name: 'Jan Meier' }]);
  289. expect(user.changed('name')).to.be.false;
  290. expect(user.changed()).not.to.be.ok;
  291. });
  292. it('should return true if previous value is different', function () {
  293. const User = this.sequelize.define('User', {
  294. name: { type: DataTypes.STRING },
  295. });
  296. const user = User.build({
  297. name: 'Jan Meier',
  298. });
  299. user.set('name', 'Mick Hansen');
  300. expect(user.changed('name')).to.be.true;
  301. expect(user.changed()).to.be.ok;
  302. });
  303. it('should return false immediately after saving', async function () {
  304. const User = this.sequelize.define('User', {
  305. name: { type: DataTypes.STRING },
  306. });
  307. await User.sync();
  308. const user = User.build({
  309. name: 'Jan Meier',
  310. });
  311. user.set('name', 'Mick Hansen');
  312. expect(user.changed('name')).to.be.true;
  313. expect(user.changed()).to.be.ok;
  314. await user.save();
  315. expect(user.changed('name')).to.be.false;
  316. expect(user.changed()).not.to.be.ok;
  317. });
  318. it('should be available to a afterUpdate hook', async function () {
  319. const User = this.sequelize.define('User', {
  320. name: { type: DataTypes.STRING },
  321. });
  322. let changed;
  323. User.afterUpdate(instance => {
  324. changed = instance.changed();
  325. });
  326. await User.sync({ force: true });
  327. const user0 = await User.create({
  328. name: 'Ford Prefect',
  329. });
  330. const user = await user0.update({
  331. name: 'Arthur Dent',
  332. });
  333. expect(changed).to.be.ok;
  334. expect(changed.length).to.be.ok;
  335. expect(changed).to.include('name');
  336. expect(user.changed()).not.to.be.ok;
  337. });
  338. });
  339. describe('previous', () => {
  340. it('should return an object with the previous values', function () {
  341. const User = this.sequelize.define('User', {
  342. name: { type: DataTypes.STRING },
  343. title: { type: DataTypes.STRING },
  344. });
  345. const user = User.build({
  346. name: 'Jan Meier',
  347. title: 'Mr',
  348. });
  349. user.set('name', 'Mick Hansen');
  350. user.set('title', 'Dr');
  351. expect(user.previous()).to.eql({ name: 'Jan Meier', title: 'Mr' });
  352. });
  353. it('should return the previous value', function () {
  354. const User = this.sequelize.define('User', {
  355. name: { type: DataTypes.STRING },
  356. });
  357. const user = User.build({
  358. name: 'Jan Meier',
  359. });
  360. user.set('name', 'Mick Hansen');
  361. expect(user.previous('name')).to.equal('Jan Meier');
  362. expect(user.get('name')).to.equal('Mick Hansen');
  363. });
  364. });
  365. });
  366. });