@nocobase/database 0.9.4-alpha.1 → 0.10.0-alpha.2
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/lib/database.js +2 -1
- package/lib/eager-loading/eager-loading-tree.d.ts +4 -0
- package/lib/eager-loading/eager-loading-tree.js +79 -16
- package/lib/fields/belongs-to-field.d.ts +1 -1
- package/lib/fields/belongs-to-field.js +3 -2
- package/lib/fields/belongs-to-many-field.js +1 -1
- package/lib/fields/has-many-field.js +1 -1
- package/lib/fields/has-one-field.js +1 -1
- package/lib/filter-parser.js +15 -9
- package/lib/listeners/append-child-collection-name-after-repository-find.js +5 -1
- package/lib/options-parser.d.ts +1 -1
- package/lib/options-parser.js +15 -11
- package/lib/relation-repository/multiple-relation-repository.js +2 -1
- package/lib/relation-repository/single-relation-repository.js +2 -1
- package/lib/repository.d.ts +12 -0
- package/lib/repository.js +166 -66
- package/lib/update-associations.js +1 -1
- package/lib/view/field-type-map.d.ts +2 -0
- package/lib/view/field-type-map.js +2 -0
- package/lib/view/view-inference.js +52 -26
- package/lib/view-collection.js +0 -1
- package/package.json +4 -4
- package/src/__tests__/eager-loading/eager-loading-tree.test.ts +149 -0
- package/src/__tests__/field-options/sort-by.test.ts +3 -1
- package/src/__tests__/filter.test.ts +54 -0
- package/src/__tests__/inhertits/collection-inherits.test.ts +165 -0
- package/src/__tests__/repository/create.test.ts +129 -6
- package/src/__tests__/repository/find.test.ts +11 -0
- package/src/__tests__/repository.test.ts +24 -0
- package/src/__tests__/update-associations.test.ts +109 -1
- package/src/__tests__/view/view-inference.test.ts +1 -0
- package/src/database.ts +4 -1
- package/src/eager-loading/eager-loading-tree.ts +92 -17
- package/src/fields/belongs-to-field.ts +6 -4
- package/src/fields/belongs-to-many-field.ts +2 -1
- package/src/fields/has-many-field.ts +1 -1
- package/src/fields/has-one-field.ts +1 -1
- package/src/filter-parser.ts +17 -9
- package/src/listeners/append-child-collection-name-after-repository-find.ts +9 -5
- package/src/options-parser.ts +25 -19
- package/src/relation-repository/multiple-relation-repository.ts +1 -0
- package/src/relation-repository/single-relation-repository.ts +1 -0
- package/src/repository.ts +84 -0
- package/src/update-associations.ts +3 -0
- package/src/view/field-type-map.ts +2 -0
- package/src/view/view-inference.ts +75 -43
- package/src/view-collection.ts +0 -1
|
@@ -15,6 +15,149 @@ describe('Eager loading tree', () => {
|
|
|
15
15
|
await db.close();
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
+
it('should sort has many default by primary key', async () => {
|
|
19
|
+
const Source = db.collection({
|
|
20
|
+
name: 'source',
|
|
21
|
+
fields: [
|
|
22
|
+
{ type: 'string', name: 'name' },
|
|
23
|
+
{
|
|
24
|
+
type: 'hasMany',
|
|
25
|
+
name: 'targets',
|
|
26
|
+
target: 'target',
|
|
27
|
+
foreignKey: 'source_id',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const Target = db.collection({
|
|
33
|
+
name: 'target',
|
|
34
|
+
fields: [{ type: 'integer', name: 'seq_number' }],
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
await db.sync();
|
|
38
|
+
|
|
39
|
+
const target1 = await Target.repository.create({ values: { seq_number: 1 } });
|
|
40
|
+
const target2 = await Target.repository.create({ values: { seq_number: 3 } });
|
|
41
|
+
|
|
42
|
+
await target1.update({ values: { seq_number: 2 } });
|
|
43
|
+
|
|
44
|
+
await Source.repository.create({
|
|
45
|
+
values: { name: 's1', targets: [{ id: target2.get('id') }, { id: target1.get('id') }] },
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const source = await Source.repository.findOne({
|
|
49
|
+
appends: ['targets'],
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(source.get('targets').map((item: any) => item.get('id'))).toEqual([1, 2]);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should sort belongs to many default by target primary key', async () => {
|
|
56
|
+
const Through = db.collection({
|
|
57
|
+
name: 'through',
|
|
58
|
+
fields: [{ type: 'string', name: 'name' }],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const Source = db.collection({
|
|
62
|
+
name: 'source',
|
|
63
|
+
fields: [
|
|
64
|
+
{ type: 'string', name: 'name' },
|
|
65
|
+
{
|
|
66
|
+
type: 'belongsToMany',
|
|
67
|
+
name: 'targets',
|
|
68
|
+
target: 'target',
|
|
69
|
+
through: 'through',
|
|
70
|
+
foreignKey: 'source_id',
|
|
71
|
+
otherKey: 'target_id',
|
|
72
|
+
sourceKey: 'id',
|
|
73
|
+
targetKey: 'id',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const Target = db.collection({
|
|
79
|
+
name: 'target',
|
|
80
|
+
fields: [{ type: 'integer', name: 'seq_number' }],
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await db.sync({
|
|
84
|
+
force: true,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const targets = await Target.repository.create({
|
|
88
|
+
values: [
|
|
89
|
+
{ seq_number: 1 },
|
|
90
|
+
{ seq_number: 2 },
|
|
91
|
+
{ seq_number: 3 },
|
|
92
|
+
{ seq_number: 4 },
|
|
93
|
+
{ seq_number: 5 },
|
|
94
|
+
{ seq_number: 6 },
|
|
95
|
+
],
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
await Source.repository.create({
|
|
99
|
+
values: {
|
|
100
|
+
name: 'source1',
|
|
101
|
+
targets: [targets[2], targets[0], targets[1]],
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const source = await Source.repository.findOne({
|
|
106
|
+
appends: ['targets'],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(source.targets.map((t) => t.get('id'))).toEqual([1, 2, 3]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should handle eager loading with long field', async () => {
|
|
113
|
+
const Through = db.collection({
|
|
114
|
+
name: 'abc_abcd_abcd_abcdefg_abc_abc_a_abcdefghijk',
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const A = db.collection({
|
|
118
|
+
name: 'a',
|
|
119
|
+
fields: [
|
|
120
|
+
{ type: 'string', name: 'name' },
|
|
121
|
+
{
|
|
122
|
+
type: 'belongsToMany',
|
|
123
|
+
name: 'bs',
|
|
124
|
+
target: 'b',
|
|
125
|
+
through: 'abc_abcd_abcd_abcdefg_abc_abc_a_abcdefghijk',
|
|
126
|
+
foreignKey: 'abc_abcd_abcdefg_abcd_abc',
|
|
127
|
+
sourceKey: 'id',
|
|
128
|
+
otherKey: 'b_id',
|
|
129
|
+
targetKey: 'id',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const B = db.collection({
|
|
135
|
+
name: 'b',
|
|
136
|
+
fields: [{ type: 'string', name: 'name' }],
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await db.sync();
|
|
140
|
+
|
|
141
|
+
await A.repository.create({
|
|
142
|
+
values: {
|
|
143
|
+
name: 'a1',
|
|
144
|
+
bs: [{ name: 'b1' }, { name: 'b2' }],
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const a = await A.repository.findOne({
|
|
149
|
+
appends: ['bs'],
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
expect(a.get('bs')).toHaveLength(2);
|
|
153
|
+
const data = a.toJSON();
|
|
154
|
+
|
|
155
|
+
// @ts-ignore
|
|
156
|
+
const as = A.model.associations.bs.oneFromTarget.as;
|
|
157
|
+
|
|
158
|
+
expect(data['bs'][0][as]).toBeDefined();
|
|
159
|
+
});
|
|
160
|
+
|
|
18
161
|
it('should handle fields filter', async () => {
|
|
19
162
|
const User = db.collection({
|
|
20
163
|
name: 'users',
|
|
@@ -55,6 +198,7 @@ describe('Eager loading tree', () => {
|
|
|
55
198
|
model: User.model,
|
|
56
199
|
rootAttributes: findOptions.attributes,
|
|
57
200
|
includeOption: findOptions.include,
|
|
201
|
+
db: db,
|
|
58
202
|
});
|
|
59
203
|
|
|
60
204
|
await eagerLoadingTree.load(users.map((item) => item.id));
|
|
@@ -105,6 +249,7 @@ describe('Eager loading tree', () => {
|
|
|
105
249
|
model: User.model,
|
|
106
250
|
rootAttributes: findOptions.attributes,
|
|
107
251
|
includeOption: findOptions.include,
|
|
252
|
+
db: db,
|
|
108
253
|
});
|
|
109
254
|
|
|
110
255
|
await eagerLoadingTree.load([1, 2]);
|
|
@@ -155,6 +300,7 @@ describe('Eager loading tree', () => {
|
|
|
155
300
|
model: User.model,
|
|
156
301
|
rootAttributes: findOptions.attributes,
|
|
157
302
|
includeOption: findOptions.include,
|
|
303
|
+
db: db,
|
|
158
304
|
});
|
|
159
305
|
|
|
160
306
|
await eagerLoadingTree.load(users.map((item) => item.id));
|
|
@@ -210,6 +356,7 @@ describe('Eager loading tree', () => {
|
|
|
210
356
|
model: Post.model,
|
|
211
357
|
rootAttributes: findOptions.attributes,
|
|
212
358
|
includeOption: findOptions.include,
|
|
359
|
+
db: db,
|
|
213
360
|
});
|
|
214
361
|
|
|
215
362
|
await eagerLoadingTree.load([1, 2]);
|
|
@@ -272,6 +419,7 @@ describe('Eager loading tree', () => {
|
|
|
272
419
|
model: Post.model,
|
|
273
420
|
rootAttributes: findOptions.attributes,
|
|
274
421
|
includeOption: findOptions.include,
|
|
422
|
+
db: db,
|
|
275
423
|
});
|
|
276
424
|
await eagerLoadingTree.load([1, 2]);
|
|
277
425
|
const root = eagerLoadingTree.root;
|
|
@@ -374,6 +522,7 @@ describe('Eager loading tree', () => {
|
|
|
374
522
|
model: User.model,
|
|
375
523
|
rootAttributes: findOptions.attributes,
|
|
376
524
|
includeOption: findOptions.include,
|
|
525
|
+
db: db,
|
|
377
526
|
});
|
|
378
527
|
|
|
379
528
|
expect(eagerLoadingTree.root.children).toHaveLength(1);
|
|
@@ -151,10 +151,11 @@ describe('associated field order', () => {
|
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
const u1 = await db.getRepository('users').findOne({
|
|
154
|
-
appends: ['posts.tags'],
|
|
154
|
+
appends: ['posts.tags', 'posts.title'],
|
|
155
155
|
});
|
|
156
156
|
|
|
157
157
|
const u1Json = u1.toJSON();
|
|
158
|
+
|
|
158
159
|
const u1Posts = u1Json['posts'];
|
|
159
160
|
expect(u1Posts.map((p) => p['title'])).toEqual(['a', 'b', 'c']);
|
|
160
161
|
|
|
@@ -214,6 +215,7 @@ describe('associated field order', () => {
|
|
|
214
215
|
});
|
|
215
216
|
|
|
216
217
|
const p1JSON = p1Result.toJSON();
|
|
218
|
+
|
|
217
219
|
const p1Images = p1JSON['images'];
|
|
218
220
|
expect(p1Images.map((i) => i['url'])).toEqual(['t2', 't1']);
|
|
219
221
|
});
|
|
@@ -14,6 +14,60 @@ describe('filter', () => {
|
|
|
14
14
|
await db.close();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
+
it('should filter by belongs to many association', async () => {
|
|
18
|
+
const A = db.collection({
|
|
19
|
+
name: 'a',
|
|
20
|
+
fields: [
|
|
21
|
+
{ type: 'string', name: 'name' },
|
|
22
|
+
{ type: 'hasMany', name: 'b', target: 'b' },
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const B = db.collection({
|
|
27
|
+
name: 'b',
|
|
28
|
+
fields: [
|
|
29
|
+
{ type: 'string', name: 'name' },
|
|
30
|
+
{ type: 'belongsTo', name: 'c', target: 'c' },
|
|
31
|
+
{ type: 'belongsTo', name: 'd', target: 'd' },
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const C = db.collection({
|
|
36
|
+
name: 'c',
|
|
37
|
+
fields: [{ type: 'string', name: 'name' }],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const D = db.collection({
|
|
41
|
+
name: 'd',
|
|
42
|
+
fields: [{ type: 'string', name: 'name' }],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await db.sync();
|
|
46
|
+
|
|
47
|
+
const findArgs = {
|
|
48
|
+
filter: {
|
|
49
|
+
$and: [{ b: { c: { name: { $eq: 'c1' } } } }, { b: { d: { name: { $eq: 'd1' } } } }],
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const findOptions = A.repository.buildQueryOptions(findArgs);
|
|
54
|
+
|
|
55
|
+
const include = findOptions.include;
|
|
56
|
+
|
|
57
|
+
const associationB = include.find((i) => i.association === 'b');
|
|
58
|
+
expect(associationB).toBeDefined();
|
|
59
|
+
expect(associationB.include).toHaveLength(2);
|
|
60
|
+
|
|
61
|
+
let err;
|
|
62
|
+
try {
|
|
63
|
+
await A.repository.find({ ...findArgs });
|
|
64
|
+
} catch (e) {
|
|
65
|
+
err = e;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
expect(err).toBeUndefined();
|
|
69
|
+
});
|
|
70
|
+
|
|
17
71
|
it('should filter by hasMany association field', async () => {
|
|
18
72
|
const DeptCollection = db.collection({
|
|
19
73
|
name: 'depts',
|
|
@@ -16,6 +16,171 @@ pgOnly()('collection inherits', () => {
|
|
|
16
16
|
await db.close();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
+
it('should append __collection with eager load', async () => {
|
|
20
|
+
const Root = db.collection({
|
|
21
|
+
name: 'root',
|
|
22
|
+
fields: [
|
|
23
|
+
{ name: 'name', type: 'string' },
|
|
24
|
+
{
|
|
25
|
+
name: 'bs',
|
|
26
|
+
type: 'hasMany',
|
|
27
|
+
target: 'b',
|
|
28
|
+
foreignKey: 'root_id',
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const Child = db.collection({
|
|
34
|
+
name: 'child',
|
|
35
|
+
inherits: ['root'],
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const B = db.collection({
|
|
39
|
+
name: 'b',
|
|
40
|
+
fields: [{ name: 'name', type: 'string' }],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await db.sync();
|
|
44
|
+
|
|
45
|
+
await Child.repository.create({
|
|
46
|
+
values: {
|
|
47
|
+
name: 'child1',
|
|
48
|
+
bs: [
|
|
49
|
+
{
|
|
50
|
+
name: 'b1',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const data = await Root.repository.findOne({
|
|
57
|
+
fields: ['bs.name'],
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(data.get('__collection')).toEqual('child');
|
|
61
|
+
expect(data.get('bs')[0].get('name')).toEqual('b1');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should not remove parent field reference map after child rewrite field', async () => {
|
|
65
|
+
const through = db.collection({
|
|
66
|
+
name: 'through',
|
|
67
|
+
fields: [{ name: 'name', type: 'string' }],
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const rootCollection = db.collection({
|
|
71
|
+
name: 'root',
|
|
72
|
+
fields: [
|
|
73
|
+
{ name: 'name', type: 'string' },
|
|
74
|
+
{
|
|
75
|
+
name: 'targets',
|
|
76
|
+
type: 'belongsToMany',
|
|
77
|
+
target: 'root-target',
|
|
78
|
+
through: 'through',
|
|
79
|
+
foreignKey: 'rootId',
|
|
80
|
+
otherKey: 'targetId',
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const rootTarget = db.collection({
|
|
86
|
+
name: 'root-target',
|
|
87
|
+
fields: [{ name: 'name', type: 'string' }],
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await db.sync({ force: true });
|
|
91
|
+
|
|
92
|
+
expect(db.referenceMap.getReferences('root-target')).toHaveLength(1);
|
|
93
|
+
|
|
94
|
+
const child = db.collection({
|
|
95
|
+
name: 'child',
|
|
96
|
+
inherits: ['root'],
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const childTarget = db.collection({
|
|
100
|
+
name: 'child-target',
|
|
101
|
+
inherits: ['root-target'],
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await child.setField('targets', {
|
|
105
|
+
name: 'targets',
|
|
106
|
+
type: 'belongsToMany',
|
|
107
|
+
target: 'child-target',
|
|
108
|
+
through: 'through',
|
|
109
|
+
foreignKey: 'rootId',
|
|
110
|
+
otherKey: 'targetId',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
await db.sync();
|
|
114
|
+
|
|
115
|
+
expect(db.referenceMap.getReferences('root-target')).toHaveLength(1);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should append collection name in eager load', async () => {
|
|
119
|
+
const rootCollection = db.collection({
|
|
120
|
+
name: 'assoc',
|
|
121
|
+
fields: [
|
|
122
|
+
{ name: 'name', type: 'string' },
|
|
123
|
+
{ type: 'belongsToMany', name: 'other-assocs' },
|
|
124
|
+
],
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const childCollection = db.collection({
|
|
128
|
+
name: 'child',
|
|
129
|
+
inherits: ['assoc'],
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const otherAssoc = db.collection({
|
|
133
|
+
name: 'other-assocs',
|
|
134
|
+
fields: [{ name: 'name', type: 'string' }],
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const User = db.collection({
|
|
138
|
+
name: 'users',
|
|
139
|
+
fields: [
|
|
140
|
+
{
|
|
141
|
+
name: 'name',
|
|
142
|
+
type: 'string',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: 'assocs',
|
|
146
|
+
type: 'hasMany',
|
|
147
|
+
target: 'assoc',
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
await db.sync();
|
|
153
|
+
|
|
154
|
+
const child = await childCollection.repository.create({
|
|
155
|
+
values: {
|
|
156
|
+
name: 'child1',
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
await User.repository.create({
|
|
161
|
+
values: {
|
|
162
|
+
name: 'user1',
|
|
163
|
+
assocs: [
|
|
164
|
+
{
|
|
165
|
+
id: child.get('id'),
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const users = await User.repository.find({
|
|
172
|
+
appends: ['assocs.other-assocs'],
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const user = users[0];
|
|
176
|
+
|
|
177
|
+
const assoc = user.get('assocs')[0];
|
|
178
|
+
expect(assoc.get('__tableName')).toEqual(childCollection.model.tableName);
|
|
179
|
+
expect(assoc.get('__schemaName')).toEqual(childCollection.collectionSchema());
|
|
180
|
+
|
|
181
|
+
expect(user.get('assocs')[0].get('__collection')).toBe('child');
|
|
182
|
+
});
|
|
183
|
+
|
|
19
184
|
it('should list data filtered by child type', async () => {
|
|
20
185
|
const rootCollection = db.collection({
|
|
21
186
|
name: 'root',
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { mockDatabase } from '../index';
|
|
2
2
|
import Database from '../../database';
|
|
3
|
+
import { Collection } from '../../collection';
|
|
3
4
|
|
|
4
5
|
describe('create with hasMany', () => {
|
|
5
6
|
let db: Database;
|
|
6
|
-
let Post;
|
|
7
|
-
let User;
|
|
7
|
+
let Post: Collection;
|
|
8
|
+
let User: Collection;
|
|
8
9
|
|
|
9
10
|
afterEach(async () => {
|
|
10
11
|
await db.close();
|
|
@@ -61,8 +62,8 @@ describe('create with hasMany', () => {
|
|
|
61
62
|
|
|
62
63
|
describe('create with belongsToMany', () => {
|
|
63
64
|
let db: Database;
|
|
64
|
-
let Post;
|
|
65
|
-
let Tag;
|
|
65
|
+
let Post: Collection;
|
|
66
|
+
let Tag: Collection;
|
|
66
67
|
|
|
67
68
|
afterEach(async () => {
|
|
68
69
|
await db.close();
|
|
@@ -122,16 +123,36 @@ describe('create with belongsToMany', () => {
|
|
|
122
123
|
|
|
123
124
|
describe('create', () => {
|
|
124
125
|
let db: Database;
|
|
125
|
-
let User;
|
|
126
|
-
let Post;
|
|
126
|
+
let User: Collection;
|
|
127
|
+
let Post: Collection;
|
|
128
|
+
let Group: Collection;
|
|
129
|
+
let Role: Collection;
|
|
127
130
|
|
|
128
131
|
beforeEach(async () => {
|
|
129
132
|
db = mockDatabase();
|
|
133
|
+
await db.clean({ drop: true });
|
|
134
|
+
|
|
135
|
+
Group = db.collection({
|
|
136
|
+
name: 'groups',
|
|
137
|
+
fields: [{ type: 'string', name: 'name' }],
|
|
138
|
+
});
|
|
139
|
+
|
|
130
140
|
User = db.collection({
|
|
131
141
|
name: 'users',
|
|
132
142
|
fields: [
|
|
133
143
|
{ type: 'string', name: 'name' },
|
|
144
|
+
{ type: 'integer', name: 'age' },
|
|
134
145
|
{ type: 'hasMany', name: 'posts' },
|
|
146
|
+
{ type: 'belongsTo', name: 'group' },
|
|
147
|
+
{ type: 'belongsToMany', name: 'roles' },
|
|
148
|
+
],
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
Role = db.collection({
|
|
152
|
+
name: 'roles',
|
|
153
|
+
fields: [
|
|
154
|
+
{ type: 'string', name: 'name' },
|
|
155
|
+
{ type: 'belongsToMany', name: 'users' },
|
|
135
156
|
],
|
|
136
157
|
});
|
|
137
158
|
|
|
@@ -149,6 +170,108 @@ describe('create', () => {
|
|
|
149
170
|
await db.close();
|
|
150
171
|
});
|
|
151
172
|
|
|
173
|
+
test('firstOrCreate by filterKeys', async () => {
|
|
174
|
+
const u1 = await User.repository.firstOrCreate({
|
|
175
|
+
filterKeys: ['name'],
|
|
176
|
+
values: {
|
|
177
|
+
name: 'u1',
|
|
178
|
+
age: 10,
|
|
179
|
+
group: {
|
|
180
|
+
name: 'g1',
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
expect(u1.name).toEqual('u1');
|
|
185
|
+
const group = await u1.get('group');
|
|
186
|
+
expect(group.name).toEqual('g1');
|
|
187
|
+
|
|
188
|
+
const u2 = await User.repository.firstOrCreate({
|
|
189
|
+
filterKeys: ['group'],
|
|
190
|
+
values: {
|
|
191
|
+
group: {
|
|
192
|
+
name: 'g1',
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
expect(u2.name).toEqual('u1');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('firstOrCreate by many to many associations', async () => {
|
|
201
|
+
const roles = await Role.repository.create({
|
|
202
|
+
values: [{ name: 'r1' }, { name: 'r2' }],
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const u1 = await User.repository.firstOrCreate({
|
|
206
|
+
values: {
|
|
207
|
+
name: 'u1',
|
|
208
|
+
roles: [{ name: 'r1' }, { name: 'r2' }],
|
|
209
|
+
},
|
|
210
|
+
filterKeys: ['roles.name'],
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
expect(u1.get('roles')).toHaveLength(2);
|
|
214
|
+
|
|
215
|
+
const u1a = await User.repository.firstOrCreate({
|
|
216
|
+
values: {
|
|
217
|
+
name: 'u1',
|
|
218
|
+
roles: [{ name: 'r1' }, { name: 'r2' }],
|
|
219
|
+
},
|
|
220
|
+
filterKeys: ['roles.name'],
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
expect(u1a.get('id')).toEqual(u1.get('id'));
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test('firstOrCreate', async () => {
|
|
227
|
+
const u1 = await User.repository.firstOrCreate({
|
|
228
|
+
filterKeys: ['name'],
|
|
229
|
+
values: {
|
|
230
|
+
name: 'u1',
|
|
231
|
+
age: 10,
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
expect(u1.name).toEqual('u1');
|
|
236
|
+
expect(u1.age).toEqual(10);
|
|
237
|
+
|
|
238
|
+
expect(
|
|
239
|
+
(
|
|
240
|
+
await User.repository.firstOrCreate({
|
|
241
|
+
filterKeys: ['name'],
|
|
242
|
+
values: {
|
|
243
|
+
name: 'u1',
|
|
244
|
+
age: 10,
|
|
245
|
+
},
|
|
246
|
+
})
|
|
247
|
+
).get('id'),
|
|
248
|
+
).toEqual(u1.get('id'));
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test('updateOrCreate', async () => {
|
|
252
|
+
const u1 = await User.repository.updateOrCreate({
|
|
253
|
+
filterKeys: ['name'],
|
|
254
|
+
values: {
|
|
255
|
+
name: 'u1',
|
|
256
|
+
age: 10,
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
expect(u1.name).toEqual('u1');
|
|
261
|
+
expect(u1.age).toEqual(10);
|
|
262
|
+
|
|
263
|
+
await User.repository.updateOrCreate({
|
|
264
|
+
filterKeys: ['name'],
|
|
265
|
+
values: {
|
|
266
|
+
name: 'u1',
|
|
267
|
+
age: 20,
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
await u1.reload();
|
|
272
|
+
expect(u1.age).toEqual(20);
|
|
273
|
+
});
|
|
274
|
+
|
|
152
275
|
test('create with association', async () => {
|
|
153
276
|
const u1 = await User.repository.create({
|
|
154
277
|
values: {
|
|
@@ -488,6 +488,17 @@ describe('repository find', () => {
|
|
|
488
488
|
expect(user['posts']).toBeDefined();
|
|
489
489
|
});
|
|
490
490
|
|
|
491
|
+
test('find with nested fields', async () => {
|
|
492
|
+
const user = await User.repository.findOne({
|
|
493
|
+
fields: ['posts.comments.content'],
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
const userData = user.toJSON();
|
|
497
|
+
|
|
498
|
+
const post = userData['posts'][0];
|
|
499
|
+
expect(Object.keys(post)).toEqual(['comments']);
|
|
500
|
+
});
|
|
501
|
+
|
|
491
502
|
describe('find with appends', () => {
|
|
492
503
|
test('toJSON', async () => {
|
|
493
504
|
const user = await User.repository.findOne({
|
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
import { Collection } from '../collection';
|
|
2
2
|
import { Database } from '../database';
|
|
3
3
|
import { mockDatabase } from './';
|
|
4
|
+
import { Repository } from '@nocobase/database';
|
|
5
|
+
|
|
6
|
+
describe('repository', () => {
|
|
7
|
+
test('value to filter', async () => {
|
|
8
|
+
const value = {
|
|
9
|
+
tags: [
|
|
10
|
+
{
|
|
11
|
+
categories: [{ name: 'c1' }, { name: 'c2' }],
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
categories: [{ name: 'c3' }, { name: 'c4' }],
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const filter = Repository.valuesToFilter(value, ['tags.categories.name']);
|
|
20
|
+
expect(filter.$and).toEqual([
|
|
21
|
+
{
|
|
22
|
+
'tags.categories.name': ['c1', 'c2', 'c3', 'c4'],
|
|
23
|
+
},
|
|
24
|
+
]);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
4
27
|
|
|
5
28
|
describe('find by targetKey', function () {
|
|
6
29
|
let db: Database;
|
|
@@ -563,6 +586,7 @@ describe('repository.relatedQuery', () => {
|
|
|
563
586
|
const post2 = await userPostRepository.create({
|
|
564
587
|
values: { name: 'post2' },
|
|
565
588
|
});
|
|
589
|
+
|
|
566
590
|
expect(post2).toMatchObject({
|
|
567
591
|
name: 'post2',
|
|
568
592
|
userId: user.get('id'),
|