@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.
- package/README.md +153 -0
- package/examples/PaginatedOptimizedQueryExample.js +936 -0
- package/index.js +27 -0
- package/package.json +27 -0
- package/src/CacheStats.js +33 -0
- package/src/CachedQuery.js +40 -0
- package/src/DataTypes.js +23 -0
- package/src/Db.js +147 -0
- package/src/Model.js +261 -0
- package/src/PaginatedOptimizedQuery.js +902 -0
- package/src/PaginatedOptimizedSql.js +1352 -0
- package/src/Query.js +584 -0
- package/src/Schema.js +52 -0
- package/src/Sql.js +311 -0
- package/src/context.js +12 -0
- package/src/dbs.js +26 -0
- package/src/drivers/mysql.js +74 -0
- package/src/drivers/postgresql.js +70 -0
- package/src/migrations.js +140 -0
- package/test/AssociationsTest.js +301 -0
- package/test/CacheStatsTest.js +40 -0
- package/test/CachedQueryTest.js +49 -0
- package/test/JoinTest.js +207 -0
- package/test/ModelTest.js +510 -0
- package/test/PaginatedOptimizedQueryTest.js +1183 -0
- package/test/PerfTest.js +58 -0
- package/test/PostgreSqlTest.js +95 -0
- package/test/QueryTest.js +27 -0
- package/test/SimplifiedSyntaxTest.js +473 -0
- package/test/SqlTest.js +95 -0
- package/test/init.js +2 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
require('./init');
|
|
2
|
+
const assert = require('assert');
|
|
3
|
+
const Model = require('@igojs/db').Model;
|
|
4
|
+
|
|
5
|
+
describe('includes', () => {
|
|
6
|
+
|
|
7
|
+
class Library extends Model({
|
|
8
|
+
table: 'libraries',
|
|
9
|
+
primary: ['id'],
|
|
10
|
+
columns: [
|
|
11
|
+
'id',
|
|
12
|
+
'title'
|
|
13
|
+
],
|
|
14
|
+
associations: () => ([
|
|
15
|
+
['has_many', 'books', Book, 'id', 'library_id'],
|
|
16
|
+
])
|
|
17
|
+
}) {}
|
|
18
|
+
|
|
19
|
+
class Book extends Model({
|
|
20
|
+
table: 'books',
|
|
21
|
+
primary: ['id'],
|
|
22
|
+
columns: [
|
|
23
|
+
'id',
|
|
24
|
+
'code',
|
|
25
|
+
'title',
|
|
26
|
+
{ name: 'details_json', type: 'json', attr: 'details' },
|
|
27
|
+
{ name: 'is_available', type: 'boolean' },
|
|
28
|
+
'library_id',
|
|
29
|
+
'created_at'
|
|
30
|
+
],
|
|
31
|
+
associations: () => ([
|
|
32
|
+
['belongs_to', 'library', Library, 'library_id', 'id'],
|
|
33
|
+
])
|
|
34
|
+
}) {}
|
|
35
|
+
|
|
36
|
+
describe('belongs_to', () => {
|
|
37
|
+
|
|
38
|
+
it('should find a book with its library', async () => {
|
|
39
|
+
const library = await Library.create();
|
|
40
|
+
const book = await Book.create({ library_id: library.id });
|
|
41
|
+
const foundBook = await Book.includes('library').find({id: book.id});
|
|
42
|
+
assert(foundBook.library);
|
|
43
|
+
assert.strictEqual(foundBook.library.id, library.id);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should set association to null if wrong id', async () => {
|
|
47
|
+
await Library.create();
|
|
48
|
+
const book = await Book.create({ library_id: 99999 });
|
|
49
|
+
const foundBook = await Book.includes('library').find(book.id);
|
|
50
|
+
assert.strictEqual(foundBook.library, null);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should list books with their libraries', async () => {
|
|
54
|
+
const library = await Library.create();
|
|
55
|
+
const library2 = await Library.create();
|
|
56
|
+
await Book.create({ library_id: library.id });
|
|
57
|
+
await Book.create({ library_id: library2.id });
|
|
58
|
+
const books = await Book.includes('library').list();
|
|
59
|
+
assert.strictEqual(books.length, 2);
|
|
60
|
+
assert.strictEqual(books[0].library.id, library.id);
|
|
61
|
+
assert.strictEqual(books[1].library.id, library2.id);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('has_many', () => {
|
|
66
|
+
|
|
67
|
+
const schema = {
|
|
68
|
+
table: 'libraries',
|
|
69
|
+
primary: ['id'],
|
|
70
|
+
columns: ['id', 'title'],
|
|
71
|
+
associations: () => [
|
|
72
|
+
['has_many', 'books', Book, 'id', 'library_id'],
|
|
73
|
+
]
|
|
74
|
+
};
|
|
75
|
+
class Library extends Model(schema) {}
|
|
76
|
+
|
|
77
|
+
it('should find a library with its books', async () => {
|
|
78
|
+
const library = await Library.create();
|
|
79
|
+
await Book.create({ library_id: library.id });
|
|
80
|
+
await Book.create({ library_id: library.id });
|
|
81
|
+
const foundLibrary = await Library.includes('books').find(library.id);
|
|
82
|
+
assert.strictEqual(foundLibrary.books.length, 2);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should return an empty array if ref null', async () => {
|
|
86
|
+
const library = await Library.create();
|
|
87
|
+
await Book.create({ library_id: null });
|
|
88
|
+
const foundLibrary = await Library.includes('books').find(library.id);
|
|
89
|
+
assert(Array.isArray(foundLibrary.books));
|
|
90
|
+
assert.strictEqual(foundLibrary.books.length, 0);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should return an empty array if wrong id', async () => {
|
|
94
|
+
const library = await Library.create();
|
|
95
|
+
await Book.create({ library_id: 99999 });
|
|
96
|
+
const foundLibrary = await Library.includes('books').find(library.id);
|
|
97
|
+
assert(Array.isArray(foundLibrary.books));
|
|
98
|
+
assert.strictEqual(foundLibrary.books.length, 0);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should list libraries with their books', async () => {
|
|
102
|
+
const library = await Library.create();
|
|
103
|
+
const library2 = await Library.create();
|
|
104
|
+
await Book.create({ library_id: library.id });
|
|
105
|
+
await Book.create({ library_id: library.id });
|
|
106
|
+
await Book.create({ library_id: library2.id });
|
|
107
|
+
const libraries = await Library.includes('books').list();
|
|
108
|
+
assert.strictEqual(libraries[0].books.length, 2);
|
|
109
|
+
assert.strictEqual(libraries[1].books.length, 1);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should handle default [] values correctly', async () => {
|
|
113
|
+
await Library.create();
|
|
114
|
+
await Library.create();
|
|
115
|
+
const libraries = await Library.includes('books').list();
|
|
116
|
+
libraries[0].books.push({ hello: 'world' });
|
|
117
|
+
assert.strictEqual(libraries[0].books.length, 1);
|
|
118
|
+
assert.strictEqual(libraries[1].books.length, 0);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
schema.scopes = {
|
|
122
|
+
default: q => q.includes('books')
|
|
123
|
+
};
|
|
124
|
+
class Library2 extends Model(schema) {}
|
|
125
|
+
|
|
126
|
+
// it.only('should ignore associations for inserts', async () => {
|
|
127
|
+
// const err = await Library2.create();
|
|
128
|
+
// assert(!err);
|
|
129
|
+
// });
|
|
130
|
+
|
|
131
|
+
it('should ignore associations for updates', async () => {
|
|
132
|
+
const library = await Library2.create();
|
|
133
|
+
assert(library);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('has_many from array', () => {
|
|
138
|
+
|
|
139
|
+
const schema = {
|
|
140
|
+
table: 'libraries',
|
|
141
|
+
primary: ['id'],
|
|
142
|
+
columns: [
|
|
143
|
+
'id',
|
|
144
|
+
'title',
|
|
145
|
+
{ name: 'books_ids_json', type: 'json', attr: 'books_ids' },
|
|
146
|
+
],
|
|
147
|
+
associations: () => [
|
|
148
|
+
['has_many', 'books', Book, 'books_ids', 'id'],
|
|
149
|
+
]
|
|
150
|
+
};
|
|
151
|
+
class Library extends Model(schema) {}
|
|
152
|
+
|
|
153
|
+
it('should find a library with its books', async () => {
|
|
154
|
+
const book1 = await Book.create();
|
|
155
|
+
const book2 = await Book.create();
|
|
156
|
+
const library = await Library.create({ books_ids: [book1.id, book2.id] });
|
|
157
|
+
const foundLibrary = await Library.includes('books').find(library.id);
|
|
158
|
+
assert.strictEqual(foundLibrary.books.length, 2);
|
|
159
|
+
assert.strictEqual(foundLibrary.books[0].id, book1.id);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should return an empty array if ref null', async () => {
|
|
163
|
+
const book1 = await Book.create();
|
|
164
|
+
const book2 = await Book.create();
|
|
165
|
+
const library = await Library.create({ books_ids: null });
|
|
166
|
+
const foundLibrary = await Library.includes('books').find(library.id);
|
|
167
|
+
assert(Array.isArray(foundLibrary.books));
|
|
168
|
+
assert.strictEqual(foundLibrary.books.length, 0);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should return an empty array if wrong id', async () => {
|
|
172
|
+
const book1 = await Book.create();
|
|
173
|
+
const book2 = await Book.create();
|
|
174
|
+
const library = await Library.create({ books_ids: [99999] });
|
|
175
|
+
const foundLibrary = await Library.includes('books').find(library.id);
|
|
176
|
+
assert(Array.isArray(foundLibrary.books));
|
|
177
|
+
assert.strictEqual(foundLibrary.books.length, 0);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should list libraries with their books (2)', async () => {
|
|
181
|
+
const book1 = await Book.create();
|
|
182
|
+
const book2 = await Book.create();
|
|
183
|
+
const book3 = await Book.create();
|
|
184
|
+
await Library.create({ books_ids: [book1.id] });
|
|
185
|
+
await Library.create({ books_ids: [book1.id, book2.id, book3.id] });
|
|
186
|
+
const libraries = await Library.includes('books').list();
|
|
187
|
+
assert.strictEqual(libraries[0].books.length, 1);
|
|
188
|
+
assert.strictEqual(libraries[1].books.length, 3);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should include associations on reload', async () => {
|
|
192
|
+
const library = await Library.create();
|
|
193
|
+
const book = await Book.create({ library_id: library.id });
|
|
194
|
+
const reloadedBook = await book.reload('library');
|
|
195
|
+
assert.strictEqual(reloadedBook.library.id, library.id);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('scopes', () => {
|
|
200
|
+
|
|
201
|
+
it('should merge default scope with string include', async () => {
|
|
202
|
+
class Library2 extends Model({
|
|
203
|
+
table: 'libraries',
|
|
204
|
+
primary: ['id'],
|
|
205
|
+
columns: [
|
|
206
|
+
'id',
|
|
207
|
+
'title'
|
|
208
|
+
],
|
|
209
|
+
associations: () => ([
|
|
210
|
+
['has_many', 'books', Book, 'id', 'library_id'],
|
|
211
|
+
]),
|
|
212
|
+
scopes: {
|
|
213
|
+
default: q => q.includes('books')
|
|
214
|
+
}
|
|
215
|
+
}) {}
|
|
216
|
+
|
|
217
|
+
const library = await Library2.create();
|
|
218
|
+
await Book.create({ library_id: library.id });
|
|
219
|
+
const libraries = await Library2.includes({ books: 'library' }).list();
|
|
220
|
+
assert.strictEqual(libraries.length, 1);
|
|
221
|
+
assert.strictEqual(libraries[0].books.length, 1);
|
|
222
|
+
assert.strictEqual(libraries[0].books[0].library.id, library.id);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should merge default scope with object include', async () => {
|
|
226
|
+
class Library2 extends Model({
|
|
227
|
+
table: 'libraries',
|
|
228
|
+
primary: ['id'],
|
|
229
|
+
columns: [
|
|
230
|
+
'id',
|
|
231
|
+
'title'
|
|
232
|
+
],
|
|
233
|
+
associations: () => ([
|
|
234
|
+
['has_many', 'books', Book, 'id', 'library_id'],
|
|
235
|
+
]),
|
|
236
|
+
scopes: {
|
|
237
|
+
default: q => q.includes({ books: 'library' })
|
|
238
|
+
}
|
|
239
|
+
}) {}
|
|
240
|
+
|
|
241
|
+
const library = await Library2.create();
|
|
242
|
+
await Book.create({ library_id: library.id });
|
|
243
|
+
const libraries = await Library2.includes('books').list();
|
|
244
|
+
assert.strictEqual(libraries.length, 1);
|
|
245
|
+
assert.strictEqual(libraries[0].books.length, 1);
|
|
246
|
+
assert.strictEqual(libraries[0].books[0].library.id, library.id);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should override default scope with 2-levels object includes', async () => {
|
|
250
|
+
class Library2 extends Model({
|
|
251
|
+
table: 'libraries',
|
|
252
|
+
primary: ['id'],
|
|
253
|
+
columns: [
|
|
254
|
+
'id',
|
|
255
|
+
'title'
|
|
256
|
+
],
|
|
257
|
+
associations: () => ([
|
|
258
|
+
['has_many', 'books', Book, 'id', 'library_id'],
|
|
259
|
+
]),
|
|
260
|
+
scopes: {
|
|
261
|
+
default: q => q.includes({ books: 'library' })
|
|
262
|
+
}
|
|
263
|
+
}) {}
|
|
264
|
+
|
|
265
|
+
const library = await Library2.create();
|
|
266
|
+
await Book.create({ library_id: library.id });
|
|
267
|
+
const libraries = await Library2.includes({ books: { library: 'books' } }).list();
|
|
268
|
+
assert.strictEqual(libraries.length, 1);
|
|
269
|
+
assert.strictEqual(libraries[0].books.length, 1);
|
|
270
|
+
assert.strictEqual(libraries[0].books[0].library.id, library.id);
|
|
271
|
+
assert.strictEqual(libraries[0].books[0].library.books.length, 1);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should override default scope with 4-levels object includes', async () => {
|
|
275
|
+
class Library2 extends Model({
|
|
276
|
+
table: 'libraries',
|
|
277
|
+
primary: ['id'],
|
|
278
|
+
columns: [
|
|
279
|
+
'id',
|
|
280
|
+
'title'
|
|
281
|
+
],
|
|
282
|
+
associations: () => ([
|
|
283
|
+
['has_many', 'books', Book, 'id', 'library_id'],
|
|
284
|
+
]),
|
|
285
|
+
scopes: {
|
|
286
|
+
default: q => q.includes({ books: { library: { books: 'library' } } })
|
|
287
|
+
}
|
|
288
|
+
}) {}
|
|
289
|
+
|
|
290
|
+
const library = await Library2.create();
|
|
291
|
+
await Book.create({ library_id: library.id });
|
|
292
|
+
const libraries = await Library2.includes({ books: 'library' }).list();
|
|
293
|
+
assert.strictEqual(libraries.length, 1);
|
|
294
|
+
assert.strictEqual(libraries[0].books.length, 1);
|
|
295
|
+
assert.strictEqual(libraries[0].books[0].library.id, library.id);
|
|
296
|
+
assert.strictEqual(libraries[0].books[0].library.books.length, 1);
|
|
297
|
+
assert.strictEqual(libraries[0].books[0].library.books[0].library.id, library.id);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
require('./init');
|
|
4
|
+
|
|
5
|
+
const assert = require('assert');
|
|
6
|
+
|
|
7
|
+
const Model = require('@igojs/db').Model;
|
|
8
|
+
const CacheStats = require('@igojs/db').CacheStats;
|
|
9
|
+
|
|
10
|
+
//
|
|
11
|
+
describe('db.CacheStats', function() {
|
|
12
|
+
|
|
13
|
+
class Book extends Model({
|
|
14
|
+
table: 'books',
|
|
15
|
+
primary: ['id'],
|
|
16
|
+
columns: [
|
|
17
|
+
'id',
|
|
18
|
+
'code',
|
|
19
|
+
'title',
|
|
20
|
+
'created_at'
|
|
21
|
+
],
|
|
22
|
+
cache: {
|
|
23
|
+
ttl: 100
|
|
24
|
+
}
|
|
25
|
+
}) {}
|
|
26
|
+
|
|
27
|
+
//
|
|
28
|
+
describe('getStats', function() {
|
|
29
|
+
|
|
30
|
+
it('should save stats in cache', async () => {
|
|
31
|
+
const book1 = await Book.create();
|
|
32
|
+
await Book.find(book1.id);
|
|
33
|
+
const stats = await CacheStats.getStats();
|
|
34
|
+
assert.strictEqual(stats.length, 1);
|
|
35
|
+
assert.strictEqual(stats[0].hits, 1);
|
|
36
|
+
assert.strictEqual(stats[0].total, 2);
|
|
37
|
+
assert.strictEqual(stats[0].table, 'books');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require('./init');
|
|
2
|
+
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const Model = require('@igojs/db').Model;
|
|
5
|
+
const cache = require('@igojs/server').cache;
|
|
6
|
+
|
|
7
|
+
describe('db.CachedQuery', function () {
|
|
8
|
+
|
|
9
|
+
class Book extends Model({
|
|
10
|
+
table: 'books',
|
|
11
|
+
primary: ['id'],
|
|
12
|
+
columns: [
|
|
13
|
+
'id',
|
|
14
|
+
'code',
|
|
15
|
+
'title',
|
|
16
|
+
'created_at'
|
|
17
|
+
],
|
|
18
|
+
cache: {
|
|
19
|
+
ttl: 100
|
|
20
|
+
}
|
|
21
|
+
}) {}
|
|
22
|
+
|
|
23
|
+
describe('find', function () {
|
|
24
|
+
|
|
25
|
+
const key = id => '{"sql":"SELECT `books`.* FROM `books` WHERE `books`.`id` = ? ORDER BY `books`.`id` ASC LIMIT ?, ?","params":[' + id + ',0,1]}';
|
|
26
|
+
|
|
27
|
+
it('should put rows in cache', async () => {
|
|
28
|
+
const book1 = await Book.create();
|
|
29
|
+
const book = await Book.find(book1.id);
|
|
30
|
+
|
|
31
|
+
assert.strictEqual(book.id, book1.id);
|
|
32
|
+
|
|
33
|
+
const rows = await cache.get('_cached.books', key(book1.id));
|
|
34
|
+
assert.ok(rows, 'Expected cached rows to exist');
|
|
35
|
+
assert.strictEqual(rows.length, 1);
|
|
36
|
+
assert.strictEqual(rows[0].id, book.id);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should clear cache after update', async function () {
|
|
40
|
+
const book1 = await Book.create();
|
|
41
|
+
await book1.update({ title: 'abc' });
|
|
42
|
+
|
|
43
|
+
const rows = await cache.get('_cached.books', key(book1.id));
|
|
44
|
+
assert.strictEqual(rows, null, 'Expected cache to be cleared after update');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
});
|
package/test/JoinTest.js
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
require('./init');
|
|
2
|
+
const assert = require('assert');
|
|
3
|
+
const Model = require('@igojs/db').Model;
|
|
4
|
+
|
|
5
|
+
describe('includes', () => {
|
|
6
|
+
|
|
7
|
+
class Country extends Model({
|
|
8
|
+
table: 'countries',
|
|
9
|
+
primary: ['id'],
|
|
10
|
+
columns: [
|
|
11
|
+
'id',
|
|
12
|
+
'name',
|
|
13
|
+
],
|
|
14
|
+
associations: () => ([
|
|
15
|
+
['has_many', 'cities', City, 'id', 'country_id'],
|
|
16
|
+
])
|
|
17
|
+
}) {}
|
|
18
|
+
|
|
19
|
+
class City extends Model({
|
|
20
|
+
table: 'cities',
|
|
21
|
+
primary: ['id'],
|
|
22
|
+
columns: [
|
|
23
|
+
'id',
|
|
24
|
+
'name',
|
|
25
|
+
'country_id',
|
|
26
|
+
],
|
|
27
|
+
associations: () => ([
|
|
28
|
+
['has_many', 'libraries', Library, 'id', 'city_id'],
|
|
29
|
+
['belongs_to', 'country', Country, 'country_id', 'id'],
|
|
30
|
+
])
|
|
31
|
+
}) {}
|
|
32
|
+
|
|
33
|
+
class Library extends Model({
|
|
34
|
+
table: 'libraries',
|
|
35
|
+
primary: ['id'],
|
|
36
|
+
columns: [
|
|
37
|
+
'id',
|
|
38
|
+
'title',
|
|
39
|
+
'collection',
|
|
40
|
+
'city_id',
|
|
41
|
+
{ name: 'details_json', type: 'json', attr: 'details' },
|
|
42
|
+
],
|
|
43
|
+
associations: () => ([
|
|
44
|
+
['has_many', 'books', Book, 'id', 'library_id'],
|
|
45
|
+
['belongs_to', 'city', City, 'city_id', 'id'],
|
|
46
|
+
]),
|
|
47
|
+
scopes: {
|
|
48
|
+
default: query => query.includes('city')
|
|
49
|
+
}
|
|
50
|
+
}) {}
|
|
51
|
+
|
|
52
|
+
class Book extends Model({
|
|
53
|
+
table: 'books',
|
|
54
|
+
primary: ['id'],
|
|
55
|
+
columns: [
|
|
56
|
+
'id',
|
|
57
|
+
'code',
|
|
58
|
+
'title',
|
|
59
|
+
{ name: 'details_json', type: 'json', attr: 'details' },
|
|
60
|
+
{ name: 'is_available', type: 'boolean' },
|
|
61
|
+
'library_id',
|
|
62
|
+
'original_library_id',
|
|
63
|
+
'created_at'
|
|
64
|
+
],
|
|
65
|
+
associations: () => ([
|
|
66
|
+
['belongs_to', 'library', Library, 'library_id', 'id'],
|
|
67
|
+
['belongs_to', 'original_library', Library, 'original_library_id', 'id'],
|
|
68
|
+
])
|
|
69
|
+
}) {}
|
|
70
|
+
|
|
71
|
+
describe('join', () => {
|
|
72
|
+
it('should load a book join with its library collection', async () => {
|
|
73
|
+
const library = await Library.create({ title: 'the big library', collection: 'A' });
|
|
74
|
+
const book = await Book.create({ library_id: library.id });
|
|
75
|
+
|
|
76
|
+
const foundBook = await Book.join('library').find(book.id);
|
|
77
|
+
assert.strictEqual(foundBook.id, book.id);
|
|
78
|
+
assert.strictEqual(foundBook.library.collection, library.collection);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should load a book join with its library collection with custom select', async () => {
|
|
82
|
+
const library = await Library.create({ title: 'A' });
|
|
83
|
+
const book = await Book.create({ library_id: library.id });
|
|
84
|
+
const foundBook = await Book
|
|
85
|
+
.select('`books`.`id`, `libraries`.`title` AS library_title')
|
|
86
|
+
.join('library')
|
|
87
|
+
.find(book.id);
|
|
88
|
+
assert.strictEqual(foundBook.library_title, library.title);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should load a book join with specified columns, and a filter', async () => {
|
|
92
|
+
const library = await Library.create({ title: 'A' });
|
|
93
|
+
const book = await Book.create({ library_id: library.id });
|
|
94
|
+
const foundBook = await Book.join('library', ['title'])
|
|
95
|
+
.where({ 'library.title': library.title })
|
|
96
|
+
.find(book.id);
|
|
97
|
+
assert.strictEqual(foundBook.library.title, library.title);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// count with join
|
|
101
|
+
it('should count books with join and where condition', async () => {
|
|
102
|
+
const libraryA = await Library.create({ title: 'A' });
|
|
103
|
+
const libraryB = await Library.create({ title: 'B' });
|
|
104
|
+
await Book.create({ library_id: libraryA.id });
|
|
105
|
+
await Book.create({ library_id: libraryA.id });
|
|
106
|
+
await Book.create({ library_id: libraryB.id });
|
|
107
|
+
|
|
108
|
+
const count = await Book.join('library').where('`library`.`title` = \'B\'').count();
|
|
109
|
+
|
|
110
|
+
assert.strictEqual(count, 1);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// cascade joins
|
|
114
|
+
it('should load books with libraries and cities', async () => {
|
|
115
|
+
const city = await City.create({ name: 'Paris' });
|
|
116
|
+
const library = await Library.create({ title: 'A', city_id: city.id });
|
|
117
|
+
await Book.create({ library_id: library.id });
|
|
118
|
+
await Book.create({ library_id: library.id });
|
|
119
|
+
|
|
120
|
+
const books = await Book.join({library: 'city'}).list();
|
|
121
|
+
|
|
122
|
+
assert.strictEqual(books.length, 2);
|
|
123
|
+
assert.strictEqual(books[0].library.city.id, city.id);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should load a book even if no library', async () => {
|
|
127
|
+
const book = await Book.create({});
|
|
128
|
+
const foundBook = await Book.join('library').find(book.id);
|
|
129
|
+
assert(foundBook);
|
|
130
|
+
assert.strictEqual(foundBook.library, null);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should load a book with a double join', async () => {
|
|
134
|
+
const library = await Library.create({ title: 'the big library' });
|
|
135
|
+
const originalLibrary = await Library.create({ title: 'the original one' });
|
|
136
|
+
const book = await Book.create({ library_id: library.id, original_library_id: originalLibrary.id });
|
|
137
|
+
|
|
138
|
+
const foundBook = await Book.join(['library', 'original_library']).find(book.id);
|
|
139
|
+
assert.strictEqual(foundBook.id, book.id);
|
|
140
|
+
assert.strictEqual(foundBook.library.title, library.title);
|
|
141
|
+
assert.strictEqual(foundBook.original_library.title, originalLibrary.title);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should load a book with a three-level join', async () => {
|
|
145
|
+
const country = await Country.create({ name: 'France' });
|
|
146
|
+
const city = await City.create({ name: 'Paris', country_id: country.id });
|
|
147
|
+
const library = await Library.create({ title: 'the big library', city_id: city.id });
|
|
148
|
+
const book = await Book.create({ library_id: library.id });
|
|
149
|
+
|
|
150
|
+
const foundBook = await Book.join({ library: { city: 'country' } }).find(book.id);
|
|
151
|
+
assert.strictEqual(foundBook.id, book.id);
|
|
152
|
+
assert.strictEqual(foundBook.library.city.country.name, country.name);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should load a book and its library with includes city', async () => {
|
|
156
|
+
const city = await City.create({ name: 'London' });
|
|
157
|
+
const library = await Library.create({ title: 'London Library', city_id: city.id });
|
|
158
|
+
const book = await Book.create({ library_id: library.id });
|
|
159
|
+
|
|
160
|
+
const foundBook = await Book.join('library').includes('library.city').find(book.id);
|
|
161
|
+
assert.strictEqual(foundBook.id, book.id);
|
|
162
|
+
assert.strictEqual(foundBook.library.city.name, city.name);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should load a book and its library with its books', async () => {
|
|
166
|
+
const library = await Library.create({ title: 'London Library' });
|
|
167
|
+
const book = await Book.create({ library_id: library.id });
|
|
168
|
+
const book2 = await Book.create({ library_id: library.id });
|
|
169
|
+
|
|
170
|
+
const foundBook = await Book.join('library').includes('library.books').find(book.id);
|
|
171
|
+
assert.strictEqual(foundBook.id, book.id);
|
|
172
|
+
assert.strictEqual(foundBook.library.books.length, 2);
|
|
173
|
+
assert.strictEqual(foundBook.library.books[0].id, book.id);
|
|
174
|
+
assert.strictEqual(foundBook.library.books[1].id, book2.id);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should load a book and the city\'s libraries (nested includes)', async () => {
|
|
178
|
+
const country = await Country.create({ name: 'France' });
|
|
179
|
+
const city = await City.create({ name: 'Paris', country_id: country.id });
|
|
180
|
+
const library1 = await Library.create({ title: 'Paris Library 1', city_id: city.id });
|
|
181
|
+
const library2 = await Library.create({ title: 'Paris Library 2', city_id: city.id });
|
|
182
|
+
await Library.create({ title: 'Other Library', city_id: null }); // Not associated with Paris
|
|
183
|
+
const book = await Book.create({ library_id: library1.id });
|
|
184
|
+
|
|
185
|
+
const foundBook = await Book.join({library: 'city'}).includes('library.city.libraries').find(book.id);
|
|
186
|
+
|
|
187
|
+
assert.strictEqual(foundBook.id, book.id);
|
|
188
|
+
assert.strictEqual(foundBook.library.id, library1.id);
|
|
189
|
+
assert.strictEqual(foundBook.library.city.id, city.id);
|
|
190
|
+
assert(Array.isArray(foundBook.library.city.libraries));
|
|
191
|
+
assert.strictEqual(foundBook.library.city.libraries.length, 2);
|
|
192
|
+
assert.strictEqual(foundBook.library.city.libraries[0].id, library1.id);
|
|
193
|
+
assert.strictEqual(foundBook.library.city.libraries[1].id, library2.id);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should load a book join with its library and details', async () => {
|
|
197
|
+
const library = await Library.create({ title: 'the big library', collection: 'A', details: { description: 'A big library' } });
|
|
198
|
+
const book = await Book.create({ library_id: library.id });
|
|
199
|
+
|
|
200
|
+
const foundBook = await Book.join('library').find(book.id);
|
|
201
|
+
assert.strictEqual(foundBook.id, book.id);
|
|
202
|
+
assert.strictEqual(foundBook.library.collection, library.collection);
|
|
203
|
+
assert.strictEqual(foundBook.library.details.description, library.details.description);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
});
|