@igojs/db 6.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,510 @@
1
+
2
+
3
+ require('./init');
4
+
5
+ const assert = require('assert');
6
+ const _ = require('lodash');
7
+
8
+ const Model = require('@igojs/db').Model;
9
+
10
+ describe('db.Model', () => {
11
+
12
+ const schema = {
13
+ table: 'books',
14
+ primary: ['id'],
15
+ columns: [
16
+ 'id',
17
+ 'code',
18
+ 'title',
19
+ {name: 'details_json', type: 'json', attr: 'details'},
20
+ {name:'is_available', type: 'boolean'},
21
+ 'library_id',
22
+ 'created_at'
23
+ ]
24
+ };
25
+
26
+ class Book extends Model(schema) {}
27
+
28
+ const schema2 = {
29
+ table: 'books',
30
+ primary: ['id'],
31
+ columns: [
32
+ 'id',
33
+ 'code',
34
+ 'title',
35
+ {name: 'details_json', type: 'json', attr: 'details'},
36
+ {name:'is_available', type: 'boolean'},
37
+ 'library_id',
38
+ 'created_at'
39
+ ],
40
+ scopes: {
41
+ default: query => query.limit(2)
42
+ }
43
+ };
44
+
45
+ class Book2 extends Model(schema2) {}
46
+
47
+ describe('standard crud operations', () => {
48
+
49
+ //
50
+ describe('insert', () => {
51
+
52
+ it('should insert a book', async () => {
53
+ const book = await Book.create();
54
+ assert(book && book.id);
55
+ assert.strictEqual(book.is_available, null);
56
+ });
57
+
58
+ it('should insert a book with values', async () => {
59
+ const book = await Book.create({code: 123});
60
+ assert(book && book.id);
61
+ assert.strictEqual(book.code, '123');
62
+ });
63
+
64
+ it('should insert a book with values and go through beforeCreate', async () => {
65
+ class BookWithTitle extends Model(schema) {
66
+ beforeCreate() {
67
+ this.title = this.title || this.code;
68
+ }
69
+ }
70
+
71
+ const book = await BookWithTitle.create({code: 123});
72
+ assert(book && book.id);
73
+ assert.strictEqual(book.code, '123');
74
+ assert.strictEqual(book.title, '123');
75
+ });
76
+
77
+ });
78
+
79
+ //
80
+ describe('find', () => {
81
+ it('should find book by id', async () => {
82
+ const first = await Book.create();
83
+ const book = await Book.find(first.id);
84
+ assert.strictEqual(book.id, first.id);
85
+ });
86
+
87
+ it('should not find book if id is null', async () => {
88
+ await Book.create();
89
+ const book = await Book.find(null);
90
+ assert.strictEqual(book, null);
91
+ });
92
+ });
93
+
94
+ //
95
+ describe('list', () => {
96
+
97
+ it('should handle empty arrays in where conditions', async () => {
98
+ const books = await Book.where({id: []}).list();
99
+ assert.strictEqual(0, books.length);
100
+ });
101
+
102
+ it('should handle 1k elements', async () => {
103
+ const nb = 1000;
104
+ const books = [];
105
+ for (let n = 0; n < nb; n++) {
106
+ const book = await Book.create();
107
+ books.push(book);
108
+ }
109
+ // const books = await Book.create(next)
110
+ assert.strictEqual(nb, books.length);
111
+ const books2 = await Book.list();
112
+ assert.strictEqual(nb, books2.length);
113
+ });
114
+
115
+ it('should handle a simple where condition as string', async () => {
116
+ const book1 = await Book.create();
117
+ const book2 = await Book.create();
118
+ const books = await Book.where('`id` > ' + book1.id).list();
119
+ assert.strictEqual(1, books.length);
120
+ assert.strictEqual(books[0].id, book2.id);
121
+ });
122
+
123
+ it('should handle a simple where condition with param', async () => {
124
+ const book1 = await Book.create();
125
+ const book2 = await Book.create();
126
+ const books = await Book.where('`id` > ?', book1.id).list();
127
+ assert.strictEqual(1, books.length);
128
+ assert.strictEqual(books[0].id, book2.id);
129
+ });
130
+
131
+ it('should handle where not condition with id', async () => {
132
+ const book1 = await Book.create();
133
+ const book2 = await Book.create();
134
+ const books = await Book.whereNot({id: book1.id}).list();
135
+ assert.strictEqual(1, books.length);
136
+ assert.strictEqual(books[0].id, book2.id);
137
+ });
138
+
139
+ it('should handle where not with array', async () => {
140
+ const book1 = await Book.create();
141
+ const book2 = await Book.create();
142
+ const books = await Book.whereNot({id: [book1.id, book2.id]}).list();
143
+ assert.strictEqual(0, books.length);
144
+ });
145
+
146
+ it('should handle where not with empty array', async () => {
147
+ await Book.create();
148
+ await Book.create();
149
+ const books = await Book.whereNot({id: []}).list();
150
+ assert.strictEqual(2, books.length);
151
+ });
152
+
153
+ it('should handle two where / whereNot conditions', async () => {
154
+ const book1 = await Book.create();
155
+ const book2 = await Book.create();
156
+ const books = await Book.where('`id` > ?', book1.id).whereNot({ id: book2.id }).list();
157
+ assert.strictEqual(0, books.length);
158
+ });
159
+
160
+ it('should handle two whereNoy / where conditions', async () => {
161
+ const book1 = await Book.create();
162
+ const book2 = await Book.create();
163
+ const books = await Book.whereNot({ id: book2.id }).where('`id` > ?', book1.id).list();
164
+ assert.strictEqual(0, books.length);
165
+ });
166
+
167
+ it.skip('should allow override default scope limit', async () => {
168
+ await Book2.create({ code: '123', title: 'title' });
169
+ await Book2.create({ code: '12345', title: 'title 2' });
170
+ const books = await Book2.list();
171
+ assert.strictEqual(books.length, 2);
172
+
173
+ const one = await Book2.limit(1).list();
174
+ assert.strictEqual(one.id, 1);
175
+ });
176
+
177
+ });
178
+
179
+ //
180
+ describe('first', () => {
181
+ it('should select first book', async () => {
182
+ const first = await Book.create();
183
+ const hibook = await Book.create({title: 'hi'});
184
+ await Book.create();
185
+ const book = await Book.unscoped().first();
186
+ assert.strictEqual(first.id, book.id);
187
+ assert.strictEqual('hi', hibook.title);
188
+ });
189
+
190
+ it('should allow a limit in the default scope and select first book', async () => {
191
+ const first = await Book2.create();
192
+ const hibook = await Book2.create({title: 'hi'});
193
+ await Book2.create();
194
+ const book = await Book2.first();
195
+ assert.strictEqual(first.id, book.id);
196
+ assert.strictEqual('hi', hibook.title);
197
+ });
198
+ });
199
+
200
+ //
201
+ describe('last', () => {
202
+ it('should select last book', async () => {
203
+ await Book.create();
204
+ await Book.create();
205
+ const last = await Book.create();
206
+ const book = await Book.unscoped().last();
207
+ assert.strictEqual(last.id, book.id);
208
+ });
209
+ });
210
+
211
+ //
212
+ describe('delete', () => {
213
+ it('should delete a book', async () => {
214
+ const first = await Book.create();
215
+ await Book.create();
216
+ await Book.create();
217
+ await Book.delete(first.id);
218
+ const book = await Book.find(first.id);
219
+ assert(!book);
220
+ });
221
+
222
+ it('should delete selected books', async () => {
223
+ await Book.create({ code: '123' });
224
+ await Book.create({ code: '123' });
225
+ await Book.create();
226
+ await Book.where({ code: '123' }).delete();
227
+ const books = await Book.list();
228
+ assert(books.length, 1);
229
+ });
230
+ });
231
+
232
+ //
233
+ describe('update', () => {
234
+ it('should update books', async () => {
235
+ await Book.create({ code: '123' });
236
+ await Book.create({ code: '123' });
237
+ await Book.create();
238
+ await Book.where({ code: '123' }).update({ title: 'undeuxtrois'});
239
+ const books = await Book.where({ title: 'undeuxtrois'}).list();
240
+ assert.strictEqual(books.length, 2);
241
+ });
242
+
243
+ it('should update all books', async () => {
244
+ await Book.create({ code: '123' });
245
+ await Book.create({ code: '123' });
246
+ await Book.create();
247
+ await Book.update({ title: 'undeuxtrois'});
248
+ const books = await Book.where({ title: 'undeuxtrois'}).list();
249
+ assert.strictEqual(books.length, 3);
250
+ });
251
+
252
+ it('should load distinct codes', async () => {
253
+ await Book.create({ code: '000' });
254
+ await Book.create({ code: '111' });
255
+ await Book.create({ code: '111' });
256
+ const codes = await Book.distinct('code').list();
257
+ assert.strictEqual(codes.length, 2);
258
+ });
259
+
260
+ it('should load distinct codes and titles', async () => {
261
+ await Book.create({ code: '000' });
262
+ await Book.create({ code: '111', title: '111' });
263
+ await Book.create({ code: '111', title: '111' });
264
+ await Book.create({ code: '222', title: '111' });
265
+ const res = await Book.where({title: '111' }).distinct([ 'code', 'title' ]).list();
266
+ assert.strictEqual(res.length, 2);
267
+ });
268
+ });
269
+
270
+ //
271
+ describe('select', () => {
272
+ it('should use custom select', async () => {
273
+ await Book.create({ code: '123', title: 'title' });
274
+ const books = await Book.select('title').list();
275
+ assert(books[0].title, 'title');
276
+ assert(!books[0].code);
277
+ });
278
+
279
+ it('should use custom select', async () => {
280
+ await Book.create({ code: '123', title: 'title' });
281
+ const books = await Book.select('*, EXTRACT(YEAR FROM created_at) AS "year"').list();
282
+ const currentYear = new Date().getFullYear();
283
+ assert(books[0].title, 'title');
284
+ assert(books[0].year, currentYear);
285
+ });
286
+ });
287
+
288
+ //
289
+ describe('count', () => {
290
+ it('should count elements', async () => {
291
+ const nb = 100;
292
+ const books = [];
293
+ for (let n = 0; n < nb; n++) {
294
+ const book = await Book.create();
295
+ books.push(book);
296
+ }
297
+ assert.strictEqual(nb, books.length);
298
+
299
+ const count = await Book.count();
300
+ assert.strictEqual(nb, count);
301
+ });
302
+ });
303
+ });
304
+
305
+
306
+ describe('instance operations', () => {
307
+
308
+ describe('delete', () => {
309
+ it('should delete a book', async () => {
310
+ await Book.create();
311
+ await Book.create();
312
+ const last = await Book.create();
313
+ await last.delete();
314
+ const book = await Book.find(last.id);
315
+ assert(!book);
316
+ });
317
+ });
318
+
319
+ describe('update', () => {
320
+ it('should update a book', async () => {
321
+ let book = await Book.create();
322
+ book = await book.update({ code: 'hop', hello: 'world' });
323
+ assert.strictEqual(book.code, 'hop');
324
+ assert.notStrictEqual(book.hello, 'world');
325
+ book = await book.reload();
326
+ assert.strictEqual(book.code, 'hop');
327
+ });
328
+
329
+ it('should update a book with beforeUpdate', async () => {
330
+ class BookWithBeforeUpdate extends Model(schema) {
331
+ beforeUpdate(values) {
332
+ values.title = values.code;
333
+ }
334
+ }
335
+ let book = await BookWithBeforeUpdate.create();
336
+ book = await book.update({ code: '234' });
337
+ assert.strictEqual(book.title, '234');
338
+ book = await book.reload();
339
+ assert.strictEqual(book.title, '234');
340
+ });
341
+ });
342
+
343
+ });
344
+
345
+ describe('scopes', () => {
346
+
347
+ var schema = {
348
+ table: 'books',
349
+ primary: ['id'],
350
+ columns: [
351
+ 'id',
352
+ 'code',
353
+ 'title',
354
+ {name: 'details_json', type: 'json', attr: 'details'},
355
+ {name:'is_available', type: 'boolean'},
356
+ 'library_id',
357
+ 'created_at'
358
+ ],
359
+ scopes: {
360
+ default: query => query.where({ code: 'abc' }),
361
+ a: query => query.where({ code: 'a' }),
362
+ }
363
+ };
364
+
365
+ class BookWithScopes extends Model(schema) {}
366
+
367
+ it('should use default scope', async () => {
368
+ await BookWithScopes.create({code: 'a'});
369
+ await BookWithScopes.create({code: 'abc'});
370
+ const books = await BookWithScopes.list();
371
+ assert.strictEqual(books.length, 1);
372
+ });
373
+
374
+ it('should use a scope', async () => {
375
+ await BookWithScopes.create({code: 'a'});
376
+ await BookWithScopes.create({code: 'abc'});
377
+ const books = await BookWithScopes.unscoped().scope('a').list();
378
+ assert.strictEqual(books.length, 1);
379
+ });
380
+ });
381
+
382
+ describe('count', () => {
383
+ it('should count rows', async () => {
384
+ for (let n = 0; n < 10; n++) {
385
+ await Book.create({ code: 'first' });
386
+ }
387
+ for (let n = 0; n < 20; n++) {
388
+ await Book.create({ code: 'second' });
389
+ }
390
+
391
+ let count = await Book.where({code: 'first'}).count();
392
+ assert.strictEqual(count, 10);
393
+
394
+ count = await Book.count();
395
+ assert.strictEqual(count, 30);
396
+ });
397
+ });
398
+
399
+
400
+ describe('group', () => {
401
+ it('should group by code', async () => {
402
+ for (let n = 0; n < 10; n++) {
403
+ await Book.create({ code: 'first' });
404
+ }
405
+ for (let n = 0; n < 20; n++) {
406
+ await Book.create({ code: 'second' });
407
+ }
408
+
409
+ const groups = await Book.select('COUNT(*) AS "count", code').group('code').list();
410
+ const firsts = _.find(groups, {code: 'first'});
411
+ const seconds = _.find(groups, {code: 'second'});
412
+ assert.strictEqual(firsts.count, 10);
413
+ assert.strictEqual(seconds.count, 20);
414
+ });
415
+
416
+ it('should group by year', async () => {
417
+ for (let n = 0; n < 10; n++) {
418
+ await Book.create({ code: 'first' });
419
+ }
420
+ for (let n = 0; n < 20; n++) {
421
+ await Book.create({ code: 'second' });
422
+ }
423
+
424
+ const groups = await Book.select('COUNT(*) AS "count", EXTRACT(YEAR FROM created_at) AS "year"').group('year').list();
425
+ const currentYear = new Date().getFullYear();
426
+ assert.strictEqual(groups[0].count, 30);
427
+ assert.strictEqual(groups[0].year, currentYear);
428
+ });
429
+ });
430
+
431
+
432
+ describe('json columns', () => {
433
+
434
+ const details = { a: 'hello', b: 'world', c: { d: '!' } };
435
+
436
+ it('should stringify on insert', async () => {
437
+ let book = await Book.create({ details });
438
+ assert.strictEqual(book.details.a, 'hello');
439
+ book = await Book.find(book.id);
440
+ assert.strictEqual(book.details.a, 'hello');
441
+ });
442
+
443
+ it('should stringify on update', async () => {
444
+ let book = await Book.create({ details });
445
+ book = await book.update({ details: { a: 'world' }});
446
+ assert.strictEqual(book.details.a, 'world');
447
+ book = await Book.find(book.id);
448
+ assert.strictEqual(book.details.a, 'world');
449
+ });
450
+
451
+ it('should stringify on global update', async () => {
452
+ let book = await Book.create({ details });
453
+ await Book.update({ details: { a: 'world' }});
454
+ book = await Book.find(book.id);
455
+ assert.strictEqual(book.details.a, 'world');
456
+ });
457
+
458
+ it('should parsejson on reload', async () => {
459
+ let book = await Book.create({ details });
460
+ book = await book.reload();
461
+ assert.strictEqual(book.details.a, 'hello');
462
+ });
463
+ });
464
+
465
+ describe('bool columns', () => {
466
+ it('should handle true booleans', async () => {
467
+ const book = await Book.create({ is_available: 'true' });
468
+ assert.strictEqual(book.is_available, true);
469
+ });
470
+ it('should handle false booleans', async () => {
471
+ const book = await Book.create({ is_available: '' });
472
+ assert.strictEqual(book.is_available, false);
473
+ });
474
+ it.skip('should let boolean to null', async () => {
475
+ const book = await Book.create({ is_available: null });
476
+ assert.strictEqual(book.is_available, null);
477
+ });
478
+ });
479
+
480
+
481
+ describe('array columns', () => {
482
+ var schema = {
483
+ table: 'books',
484
+ primary: ['id'],
485
+ columns: [
486
+ 'id',
487
+ 'code',
488
+ 'title',
489
+ {name: 'details_json', type: 'array', attr: 'details'},
490
+ {name:'is_available', type: 'boolean'},
491
+ 'library_id',
492
+ 'created_at'
493
+ ]
494
+ };
495
+ class Book extends Model(schema) {}
496
+
497
+ it('should handle array', async () => {
498
+ const book = await Book.create({ details: [1, 2] });
499
+ assert(Array.isArray(book.details));
500
+ assert.strictEqual(book.details.length, 2);
501
+ });
502
+
503
+ it('should handle array', async () => {
504
+ const book = await Book.create({ details: '' });
505
+ assert(Array.isArray(book.details));
506
+ assert.strictEqual(book.details.length, 0);
507
+ });
508
+ });
509
+
510
+ });