mythix-orm 1.0.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/.eslintrc.js +94 -0
- package/.vscode/launch.json +34 -0
- package/.vscode/settings.json +10 -0
- package/LICENSE +21 -0
- package/README.md +15 -0
- package/lib/connection/connection-base.js +877 -0
- package/lib/connection/index.js +11 -0
- package/lib/connection/literals/average-literal.js +14 -0
- package/lib/connection/literals/count-literal.js +18 -0
- package/lib/connection/literals/distinct-literal.js +14 -0
- package/lib/connection/literals/index.js +23 -0
- package/lib/connection/literals/literal-base.js +62 -0
- package/lib/connection/literals/literal-field-base.js +45 -0
- package/lib/connection/literals/literal.js +11 -0
- package/lib/connection/literals/max-literal.js +14 -0
- package/lib/connection/literals/min-literal.js +14 -0
- package/lib/connection/literals/sum-literal.js +14 -0
- package/lib/connection/query-generator-base.js +864 -0
- package/lib/errors/base-error.js +14 -0
- package/lib/errors/connection/access-denied-error.js +13 -0
- package/lib/errors/connection/connection-acquire-timeout-error.js +13 -0
- package/lib/errors/connection/connection-refused-error.js +13 -0
- package/lib/errors/connection/connection-timed-out-error.js +13 -0
- package/lib/errors/connection/host-not-found-error.js +13 -0
- package/lib/errors/connection/host-not-reachable-error.js +13 -0
- package/lib/errors/connection/index.js +19 -0
- package/lib/errors/connection/invalid-connection-error.js +13 -0
- package/lib/errors/connection-base-error.js +13 -0
- package/lib/errors/database/exclusion-constraint-error.js +13 -0
- package/lib/errors/database/foreign-key-constraint-error.js +13 -0
- package/lib/errors/database/index.js +13 -0
- package/lib/errors/database/timeout-error.js +13 -0
- package/lib/errors/database/unknown-constraint-error.js +13 -0
- package/lib/errors/database-base-error.js +17 -0
- package/lib/errors/index.js +44 -0
- package/lib/field.js +18 -0
- package/lib/index.js +43 -0
- package/lib/model.js +1374 -0
- package/lib/proxy-class/index.js +3 -0
- package/lib/proxy-class/proxy-class.js +269 -0
- package/lib/query-engine/field-scope.js +99 -0
- package/lib/query-engine/index.js +13 -0
- package/lib/query-engine/model-scope.js +198 -0
- package/lib/query-engine/query-engine-base.js +325 -0
- package/lib/query-engine/query-engine.js +212 -0
- package/lib/types/concrete/bigint-type.js +62 -0
- package/lib/types/concrete/blob-type.js +46 -0
- package/lib/types/concrete/boolean-type.js +41 -0
- package/lib/types/concrete/char-type.js +39 -0
- package/lib/types/concrete/date-type.js +87 -0
- package/lib/types/concrete/datetime-type.js +92 -0
- package/lib/types/concrete/float-type.js +47 -0
- package/lib/types/concrete/foreign-key-type.js +208 -0
- package/lib/types/concrete/index.js +53 -0
- package/lib/types/concrete/integer-type.js +51 -0
- package/lib/types/concrete/string-type.js +44 -0
- package/lib/types/concrete/text-type.js +44 -0
- package/lib/types/concrete/uuid-base.js +77 -0
- package/lib/types/concrete/uuid-v1-type.js +99 -0
- package/lib/types/concrete/uuid-v3-type.js +108 -0
- package/lib/types/concrete/uuid-v4-type.js +90 -0
- package/lib/types/concrete/uuid-v5-type.js +108 -0
- package/lib/types/concrete/xid-type.js +58 -0
- package/lib/types/helpers/default-helpers.js +127 -0
- package/lib/types/helpers/index.js +35 -0
- package/lib/types/index.js +94 -0
- package/lib/types/type.js +244 -0
- package/lib/types/virtual/index.js +14 -0
- package/lib/types/virtual/model-type.js +141 -0
- package/lib/types/virtual/models-type.js +264 -0
- package/lib/types/virtual/relational-type-base.js +323 -0
- package/lib/utils/index.js +65 -0
- package/lib/utils/misc-utils.js +73 -0
- package/lib/utils/model-utils.js +704 -0
- package/lib/utils/query-utils.js +186 -0
- package/package.json +63 -0
- package/playground/test01.js +15 -0
- package/spec/connection/connection-base-spec.js +126 -0
- package/spec/connection/literals/average-literal-spec.js +45 -0
- package/spec/connection/literals/count-literal-spec.js +42 -0
- package/spec/connection/literals/distinct-literal-spec.js +42 -0
- package/spec/connection/literals/literal-spec.js +26 -0
- package/spec/connection/literals/max-literal-spec.js +42 -0
- package/spec/connection/literals/min-literal-spec.js +42 -0
- package/spec/connection/literals/sum-literal-spec.js +42 -0
- package/spec/helpers/default-helpers-spec.js +108 -0
- package/spec/model-spec.js +736 -0
- package/spec/proxy-class/proxy-class-spec.js +173 -0
- package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_chain_query_conditions-001.snapshot +94 -0
- package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_construct_a_query_context_with_a_model_call-001.snapshot +35 -0
- package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_construct_a_query_context_with_a_model_sub-001.snapshot +35 -0
- package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_set_a_default_scope_on_a_model-001.snapshot +57 -0
- package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_unscope_default_scope_on_a_model-001.snapshot +35 -0
- package/spec/query-engine/query-engine-spec.js +99 -0
- package/spec/support/jasmine.json +13 -0
- package/spec/support/models/blob-test-model.js +19 -0
- package/spec/support/models/extended-user-model.js +38 -0
- package/spec/support/models/index.js +27 -0
- package/spec/support/models/number-model.js +24 -0
- package/spec/support/models/role-model.js +26 -0
- package/spec/support/models/role-thing-model.js +41 -0
- package/spec/support/models/scoped-user-model.js +13 -0
- package/spec/support/models/time-model.js +36 -0
- package/spec/support/models/user-model.js +70 -0
- package/spec/support/models/user-role-model.js +36 -0
- package/spec/support/models/user-thing-model.js +46 -0
- package/spec/support/models/validation-test-model.js +40 -0
- package/spec/support/snapshots.js +293 -0
- package/spec/support/test-helpers.js +13 -0
- package/spec/types/concrete/bigint-type-spec.js +84 -0
- package/spec/types/concrete/boolean-type-spec.js +83 -0
- package/spec/types/concrete/date-type-spec.js +85 -0
- package/spec/types/concrete/datetime-type-spec.js +87 -0
- package/spec/types/concrete/float-type-spec.js +71 -0
- package/spec/types/concrete/foreign-key-type-spec.js +64 -0
- package/spec/types/concrete/integer-type-spec.js +71 -0
- package/spec/types/concrete/string-type-spec.js +91 -0
- package/spec/types/concrete/uuid-v1-type-spec.js +73 -0
- package/spec/types/concrete/uuid-v4-type-spec.js +65 -0
- package/spec/types/type-spec.js +101 -0
- package/spec/types/virtual/model-types-spec.js +401 -0
- package/spec/utils/misc-utils-spec.js +61 -0
- package/spec/utils/model-utils-spec.js +55 -0
- package/spec/utils/query-utils-spec.js +105 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
/* global describe, it, expect, beforeAll */
|
|
6
|
+
|
|
7
|
+
const { Types, ConnectionBase } = require('../../lib');
|
|
8
|
+
|
|
9
|
+
class CustomType extends Types.Type {
|
|
10
|
+
constructor(...args) {
|
|
11
|
+
super(...args);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('Type', () => {
|
|
16
|
+
let connection;
|
|
17
|
+
let User;
|
|
18
|
+
|
|
19
|
+
beforeAll(async () => {
|
|
20
|
+
connection = new ConnectionBase({
|
|
21
|
+
bindModels: false,
|
|
22
|
+
models: require('../support/models'),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
let models = connection.getModels();
|
|
26
|
+
User = models.User;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('will store arguments', () => {
|
|
30
|
+
let type = new CustomType('test', 123, true);
|
|
31
|
+
expect(type._args).toEqual([ 'test', 123, true ]);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('clone', () => {
|
|
35
|
+
it('can clone (static)', () => {
|
|
36
|
+
expect(CustomType.clone()).toBe(CustomType);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('can clone (instance)', () => {
|
|
40
|
+
let instance = new CustomType('hello', 'world');
|
|
41
|
+
let clone = instance.clone();
|
|
42
|
+
|
|
43
|
+
expect(clone).not.toBe(instance);
|
|
44
|
+
expect(instance._args).toEqual(clone._args);
|
|
45
|
+
expect(clone).toBeInstanceOf(CustomType);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('instantiateType', () => {
|
|
50
|
+
it('will throw an error if type is empty', () => {
|
|
51
|
+
expect(() => CustomType.instantiateType()).toThrow(new TypeError('Type::instantiateType: "type" is required.'));
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should construct a type if it is not constructed', () => {
|
|
55
|
+
const UserIDType = Types.UUIDV4Type;
|
|
56
|
+
let instance = UserIDType.instantiateType(User.fields.id.type);
|
|
57
|
+
expect(UserIDType).not.toBeInstanceOf(UserIDType);
|
|
58
|
+
expect(instance).toBeInstanceOf(UserIDType);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('getField', () => {
|
|
63
|
+
it('can get the types field', () => {
|
|
64
|
+
const UserIDType = Types.UUIDV4Type;
|
|
65
|
+
let instance = UserIDType.instantiateType(User.fields.id.type);
|
|
66
|
+
expect(instance.getField()).toBe(User.fields.id);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('getModel', () => {
|
|
71
|
+
it('can get the types model', () => {
|
|
72
|
+
const UserIDType = Types.UUIDV4Type;
|
|
73
|
+
let instance = UserIDType.instantiateType(User.fields.id.type);
|
|
74
|
+
expect(instance.getModel()).toBe(User);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('can get the types model even if there is only a model instance', () => {
|
|
78
|
+
const UserIDType = Types.UUIDV4Type;
|
|
79
|
+
let instance = new UserIDType();
|
|
80
|
+
|
|
81
|
+
instance.setModel(null);
|
|
82
|
+
instance.setField(User.fields.id);
|
|
83
|
+
|
|
84
|
+
expect(instance._Model).toBe(null);
|
|
85
|
+
expect(instance.getModel()).toBe(User);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should fail to get model if Model and instance are empty', () => {
|
|
89
|
+
const UserIDType = Types.UUIDV4Type;
|
|
90
|
+
let instance = new UserIDType();
|
|
91
|
+
|
|
92
|
+
instance.setModel(null);
|
|
93
|
+
expect(instance.getModel()).toBe(undefined);
|
|
94
|
+
|
|
95
|
+
instance.setField(User.fields.id);
|
|
96
|
+
|
|
97
|
+
expect(instance._Model).toBe(null);
|
|
98
|
+
expect(instance.getModel()).toBe(User);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/* eslint-disable max-classes-per-file */
|
|
2
|
+
/* eslint-disable no-magic-numbers */
|
|
3
|
+
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
/* global describe, it, expect, beforeAll, spyOn */
|
|
7
|
+
|
|
8
|
+
const UUID = require('uuid');
|
|
9
|
+
const { Types, ConnectionBase } = require('../../../lib');
|
|
10
|
+
const ModelUtils = require('../../../lib/utils/model-utils');
|
|
11
|
+
|
|
12
|
+
describe('ModelType', () => {
|
|
13
|
+
let connection;
|
|
14
|
+
let User;
|
|
15
|
+
let UserRole;
|
|
16
|
+
let RoleThing;
|
|
17
|
+
let UserThing;
|
|
18
|
+
let Role;
|
|
19
|
+
|
|
20
|
+
beforeAll(() => {
|
|
21
|
+
try {
|
|
22
|
+
connection = new ConnectionBase({
|
|
23
|
+
bindModels: false,
|
|
24
|
+
models: require('../../support/models'),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
let models = connection.getModels();
|
|
28
|
+
User = models.User;
|
|
29
|
+
UserRole = models.UserRole;
|
|
30
|
+
RoleThing = models.RoleThing;
|
|
31
|
+
UserThing = models.UserThing;
|
|
32
|
+
Role = models.Role;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error('Error in beforeAll: ', error);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('can construct from class', () => {
|
|
39
|
+
let type = new Types.ModelType('Role:userID');
|
|
40
|
+
expect(type.toString()).toEqual('ModelType {}');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('can construct from type helper', () => {
|
|
44
|
+
let type = Types.Model('Role:userID');
|
|
45
|
+
expect(type.toString()).toEqual('ModelType {}');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('can walk a field relation', async () => {
|
|
49
|
+
let relations = [];
|
|
50
|
+
let user = new User({
|
|
51
|
+
id: '664e9071-11d9-4544-85fe-1359ce1904b1',
|
|
52
|
+
firstName: 'Mary',
|
|
53
|
+
lastName: 'Anne',
|
|
54
|
+
primaryRoleID: '5016a9dc-0271-41a0-937a-a0c95acd117b',
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
await User.fields.userThingRole.type.walkQueryRelations(connection, (context) => {
|
|
58
|
+
relations.push(context);
|
|
59
|
+
}, { self: user, field: User.fields.roles });
|
|
60
|
+
|
|
61
|
+
expect(relations).toEqual([
|
|
62
|
+
{
|
|
63
|
+
PrimaryModel: User,
|
|
64
|
+
TargetModel: Role,
|
|
65
|
+
TargetField: Role.fields.id,
|
|
66
|
+
source: {
|
|
67
|
+
Model: RoleThing,
|
|
68
|
+
modelName: 'RoleThing',
|
|
69
|
+
field: RoleThing.fields.roleID,
|
|
70
|
+
fieldName: 'roleID',
|
|
71
|
+
},
|
|
72
|
+
target: {
|
|
73
|
+
Model: Role,
|
|
74
|
+
modelName: 'Role',
|
|
75
|
+
field: Role.fields.id,
|
|
76
|
+
fieldName: 'id',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
PrimaryModel: User,
|
|
81
|
+
TargetModel: Role,
|
|
82
|
+
TargetField: Role.fields.id,
|
|
83
|
+
source: {
|
|
84
|
+
Model: UserThing,
|
|
85
|
+
modelName: 'UserThing',
|
|
86
|
+
field: UserThing.fields.roleThingID,
|
|
87
|
+
fieldName: 'roleThingID',
|
|
88
|
+
},
|
|
89
|
+
target: {
|
|
90
|
+
Model: RoleThing,
|
|
91
|
+
modelName: 'RoleThing',
|
|
92
|
+
field: RoleThing.fields.id,
|
|
93
|
+
fieldName: 'id',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// it('will throw error on attempt to cast without being able to fetch target model', () => {
|
|
100
|
+
// let type = Types.Model('Role:userID');
|
|
101
|
+
|
|
102
|
+
// spyOn(type, 'getTargetModel').and.callFake(() => null);
|
|
103
|
+
// expect(() => type.castToType({ value: 20 })).toThrow(new TypeError('ModelType::castToType: Failed when attempting to fetch the required model.'));
|
|
104
|
+
// });
|
|
105
|
+
|
|
106
|
+
// it('will throw error on attempt to cast without a proper value type', () => {
|
|
107
|
+
// let type = Types.Model('Role:userID');
|
|
108
|
+
|
|
109
|
+
// class FakeModel {}
|
|
110
|
+
// spyOn(type, 'getTargetModel').and.callFake(() => FakeModel);
|
|
111
|
+
|
|
112
|
+
// expect(() => type.castToType({ value: 20 })).toThrow(new TypeError('ModelType::castToType: Unable to cast provided value. Value must be a model instance, or a raw object.'));
|
|
113
|
+
// });
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// describe('ModelsType', () => {
|
|
117
|
+
// it('can construct from class', () => {
|
|
118
|
+
// let type = new Types.ModelsType('Role:userID');
|
|
119
|
+
// expect(type.toString()).toEqual('ModelsType {}');
|
|
120
|
+
// });
|
|
121
|
+
|
|
122
|
+
// it('can construct from type helper', () => {
|
|
123
|
+
// let type = Types.Models('Role:userID');
|
|
124
|
+
// expect(type.toString()).toEqual('ModelsType {}');
|
|
125
|
+
// });
|
|
126
|
+
|
|
127
|
+
// it('will throw error on attempt to cast without being able to fetch target model', () => {
|
|
128
|
+
// let type = Types.Models('Role:userID');
|
|
129
|
+
|
|
130
|
+
// spyOn(type, 'getTargetModel').and.callFake(() => null);
|
|
131
|
+
// expect(() => type.castToType({ value: 20 })).toThrow(new TypeError('ModelsType::castToType: Failed when attempting to fetch the required model.'));
|
|
132
|
+
// });
|
|
133
|
+
|
|
134
|
+
// it('will throw error on attempt to cast without a proper value type', () => {
|
|
135
|
+
// let type = Types.Models('Role:userID');
|
|
136
|
+
|
|
137
|
+
// class FakeModel {}
|
|
138
|
+
// spyOn(type, 'getTargetModel').and.callFake(() => FakeModel);
|
|
139
|
+
|
|
140
|
+
// expect(() => type.castToType({ value: 20 })).toThrow(new TypeError('ModelsType::castToType: Unable to cast provided value at index 0. Value must be a model instance, or a raw object.'));
|
|
141
|
+
// });
|
|
142
|
+
// });
|
|
143
|
+
|
|
144
|
+
// describe('Model relations', () => {
|
|
145
|
+
// let connection;
|
|
146
|
+
// let User;
|
|
147
|
+
// let Role;
|
|
148
|
+
// let UserThing;
|
|
149
|
+
// let RoleThing;
|
|
150
|
+
|
|
151
|
+
// beforeAll(() => {
|
|
152
|
+
// try {
|
|
153
|
+
// connection = new ConnectionBase({
|
|
154
|
+
// bindModels: false,
|
|
155
|
+
// models: require('../../support/models'),
|
|
156
|
+
// });
|
|
157
|
+
|
|
158
|
+
// let models = connection.getModels();
|
|
159
|
+
// User = models.User;
|
|
160
|
+
// Role = models.Role;
|
|
161
|
+
// UserThing = models.UserThing;
|
|
162
|
+
// RoleThing = models.RoleThing;
|
|
163
|
+
// } catch (error) {
|
|
164
|
+
// console.error('Error in beforeAll: ', error);
|
|
165
|
+
// }
|
|
166
|
+
// });
|
|
167
|
+
|
|
168
|
+
// describe('setRelationalValues', () => {
|
|
169
|
+
// it('can set relational values on a model instance', () => {
|
|
170
|
+
// let user = new User(null, { connection });
|
|
171
|
+
// let role = new Role({ id: UUID.v4(), name: 'test' }, { connection });
|
|
172
|
+
|
|
173
|
+
// ModelUtils.setRelationalValues(connection, User, user, Role, role);
|
|
174
|
+
|
|
175
|
+
// expect(user.primaryRoleID).toEqual(role.id);
|
|
176
|
+
// });
|
|
177
|
+
|
|
178
|
+
// it('can set relational values on a model instance when related model is null', () => {
|
|
179
|
+
// let user = new User({ primaryRoleID: UUID.v4() }, { connection });
|
|
180
|
+
|
|
181
|
+
// ModelUtils.setRelationalValues(connection, User, user, Role);
|
|
182
|
+
|
|
183
|
+
// expect(user.primaryRoleID).toBe(null);
|
|
184
|
+
// });
|
|
185
|
+
// });
|
|
186
|
+
|
|
187
|
+
// describe('walkTargetRelation', () => {
|
|
188
|
+
// it('can walk target relation #1', () => {
|
|
189
|
+
// let user = new User(null, { connection });
|
|
190
|
+
// let field = user.getField('roles');
|
|
191
|
+
|
|
192
|
+
// let result = field.type.walkTargetRelation(connection, ({ source, target }) => {
|
|
193
|
+
// let sourceStr = `${source.modelName}:${source.fieldName}`;
|
|
194
|
+
// let targetStr = `${target.modelName}:${target.fieldName}`;
|
|
195
|
+
// return `${sourceStr} -> ${targetStr}`;
|
|
196
|
+
// });
|
|
197
|
+
|
|
198
|
+
// expect(result).toEqual([
|
|
199
|
+
// 'User:roles -> Role:id',
|
|
200
|
+
// ]);
|
|
201
|
+
// });
|
|
202
|
+
|
|
203
|
+
// it('can walk target relation #2', () => {
|
|
204
|
+
// let user = new User(null, { connection });
|
|
205
|
+
// let field = user.getField('userThingRole');
|
|
206
|
+
|
|
207
|
+
// let result = field.type.walkTargetRelation(connection, ({ source, target }) => {
|
|
208
|
+
// let sourceStr = `${source.modelName}:${source.fieldName}`;
|
|
209
|
+
// let targetStr = `${target.modelName}:${target.fieldName}`;
|
|
210
|
+
// return `${sourceStr} -> ${targetStr}`;
|
|
211
|
+
// });
|
|
212
|
+
|
|
213
|
+
// expect(result).toEqual([
|
|
214
|
+
// 'User:userThingRole -> Role:id',
|
|
215
|
+
// ]);
|
|
216
|
+
// });
|
|
217
|
+
// });
|
|
218
|
+
|
|
219
|
+
// describe('walkSourceRelation', () => {
|
|
220
|
+
// it('can walk source relation #1', () => {
|
|
221
|
+
// let user = new User(null, { connection });
|
|
222
|
+
// let field = user.getField('roles');
|
|
223
|
+
|
|
224
|
+
// let result = field.type.walkSourceRelation(connection, ({ source, target }) => {
|
|
225
|
+
// let sourceStr = `${source.modelName}:${source.fieldName}`;
|
|
226
|
+
// let targetStr = `${target.modelName}:${target.fieldName}`;
|
|
227
|
+
// return `${sourceStr} -> ${targetStr}`;
|
|
228
|
+
// });
|
|
229
|
+
|
|
230
|
+
// expect(result).toEqual([
|
|
231
|
+
// 'User:roles -> User:userRoles',
|
|
232
|
+
// 'User:userRoles -> UserRole:role',
|
|
233
|
+
// 'UserRole:role -> UserRole:roleID',
|
|
234
|
+
// 'UserRole:roleID -> Role:id',
|
|
235
|
+
// ]);
|
|
236
|
+
// });
|
|
237
|
+
|
|
238
|
+
// it('can walk source relation #2', () => {
|
|
239
|
+
// let user = new User(null, { connection });
|
|
240
|
+
// let field = user.getField('userThingRole');
|
|
241
|
+
|
|
242
|
+
// let result = field.type.walkSourceRelation(connection, ({ source, target }) => {
|
|
243
|
+
// let sourceStr = `${source.modelName}:${source.fieldName}`;
|
|
244
|
+
// let targetStr = `${target.modelName}:${target.fieldName}`;
|
|
245
|
+
// return `${sourceStr} -> ${targetStr}`;
|
|
246
|
+
// });
|
|
247
|
+
|
|
248
|
+
// expect(result).toEqual([
|
|
249
|
+
// 'User:userThingRole -> User:userThing',
|
|
250
|
+
// 'User:userThing -> UserThing:role',
|
|
251
|
+
// 'UserThing:role -> UserThing:roleThing',
|
|
252
|
+
// 'UserThing:roleThing -> RoleThing:role',
|
|
253
|
+
// 'RoleThing:role -> RoleThing:roleID',
|
|
254
|
+
// 'RoleThing:roleID -> Role:id',
|
|
255
|
+
// ]);
|
|
256
|
+
// });
|
|
257
|
+
// });
|
|
258
|
+
|
|
259
|
+
// describe('getSourceField', () => {
|
|
260
|
+
// it('can get source field', () => {
|
|
261
|
+
// let user = new User(null, { connection });
|
|
262
|
+
// let field = user.getField('primaryRole');
|
|
263
|
+
|
|
264
|
+
// let result = field.type.getSourceField(connection);
|
|
265
|
+
// expect(result).toBe(User.fields.primaryRoleID);
|
|
266
|
+
// });
|
|
267
|
+
|
|
268
|
+
// it('will skip following foreign keys if requested', () => {
|
|
269
|
+
// let roleThing = new RoleThing(null, { connection });
|
|
270
|
+
// let field = roleThing.getField('user');
|
|
271
|
+
|
|
272
|
+
// let result = field.type.getSourceField(connection, { recursive: true, followForeignKeys: false });
|
|
273
|
+
// expect(result).toBe(UserThing.fields.userID);
|
|
274
|
+
|
|
275
|
+
// result = field.type.getSourceField(connection, { recursive: true });
|
|
276
|
+
// expect(result).toBe(User.fields.id);
|
|
277
|
+
// });
|
|
278
|
+
|
|
279
|
+
// it('can get source field recursively', () => {
|
|
280
|
+
// let user = new User(null, { connection });
|
|
281
|
+
// let field = user.getField('roles');
|
|
282
|
+
|
|
283
|
+
// let result = field.type.getSourceField(connection, { recursive: true });
|
|
284
|
+
// expect(result).toBe(Role.fields.id);
|
|
285
|
+
// });
|
|
286
|
+
// });
|
|
287
|
+
|
|
288
|
+
// describe('getJoinableRelations', () => {
|
|
289
|
+
// it('can recursively parse target relations #1', () => {
|
|
290
|
+
// let user = new User(null, { connection });
|
|
291
|
+
// let rolesField = user.getField('roles');
|
|
292
|
+
|
|
293
|
+
// let result = rolesField.type.getJoinableRelations(connection);
|
|
294
|
+
// expect(result).toEqual([
|
|
295
|
+
// {
|
|
296
|
+
// sourceModelName: 'UserRole',
|
|
297
|
+
// sourceFieldName: 'roleID',
|
|
298
|
+
// targetModelName: 'Role',
|
|
299
|
+
// targetFieldName: 'id',
|
|
300
|
+
// },
|
|
301
|
+
// {
|
|
302
|
+
// sourceModelName: 'User',
|
|
303
|
+
// sourceFieldName: 'id',
|
|
304
|
+
// targetModelName: 'UserRole',
|
|
305
|
+
// targetFieldName: 'userID',
|
|
306
|
+
// },
|
|
307
|
+
// ]);
|
|
308
|
+
// });
|
|
309
|
+
|
|
310
|
+
// it('can recursively parse relations #2', () => {
|
|
311
|
+
// let user = new User(null, { connection });
|
|
312
|
+
// let userThingRoleField = user.getField('userThingRole');
|
|
313
|
+
|
|
314
|
+
// let result = userThingRoleField.type.getJoinableRelations(connection);
|
|
315
|
+
// expect(result).toEqual([
|
|
316
|
+
// {
|
|
317
|
+
// sourceModelName: 'RoleThing',
|
|
318
|
+
// sourceFieldName: 'roleID',
|
|
319
|
+
// targetModelName: 'Role',
|
|
320
|
+
// targetFieldName: 'id',
|
|
321
|
+
// },
|
|
322
|
+
// {
|
|
323
|
+
// sourceModelName: 'User',
|
|
324
|
+
// sourceFieldName: 'id',
|
|
325
|
+
// targetModelName: 'UserThing',
|
|
326
|
+
// targetFieldName: 'userID',
|
|
327
|
+
// },
|
|
328
|
+
// {
|
|
329
|
+
// sourceModelName: 'UserThing',
|
|
330
|
+
// sourceFieldName: 'roleThingID',
|
|
331
|
+
// targetModelName: 'RoleThing',
|
|
332
|
+
// targetFieldName: 'id',
|
|
333
|
+
// },
|
|
334
|
+
// ]);
|
|
335
|
+
// });
|
|
336
|
+
|
|
337
|
+
// it('can recursively parse relations #3', () => {
|
|
338
|
+
// let user = new User(null, { connection });
|
|
339
|
+
// let rolesField = user.getField('roles');
|
|
340
|
+
|
|
341
|
+
// let result = rolesField.type.getJoinableRelations(connection);
|
|
342
|
+
// expect(result).toEqual([
|
|
343
|
+
// {
|
|
344
|
+
// sourceModelName: 'UserRole',
|
|
345
|
+
// sourceFieldName: 'roleID',
|
|
346
|
+
// targetModelName: 'Role',
|
|
347
|
+
// targetFieldName: 'id',
|
|
348
|
+
// },
|
|
349
|
+
// {
|
|
350
|
+
// sourceModelName: 'User',
|
|
351
|
+
// sourceFieldName: 'id',
|
|
352
|
+
// targetModelName: 'UserRole',
|
|
353
|
+
// targetFieldName: 'userID',
|
|
354
|
+
// },
|
|
355
|
+
// ]);
|
|
356
|
+
// });
|
|
357
|
+
|
|
358
|
+
// it('can recursively parse relations #4', () => {
|
|
359
|
+
// let user = new User(null, { connection });
|
|
360
|
+
// let userThingRoleField = user.getField('userThingRole');
|
|
361
|
+
|
|
362
|
+
// let result = userThingRoleField.type.getJoinableRelations(connection);
|
|
363
|
+
// expect(result).toEqual([
|
|
364
|
+
// {
|
|
365
|
+
// sourceModelName: 'RoleThing',
|
|
366
|
+
// sourceFieldName: 'roleID',
|
|
367
|
+
// targetModelName: 'Role',
|
|
368
|
+
// targetFieldName: 'id',
|
|
369
|
+
// },
|
|
370
|
+
// {
|
|
371
|
+
// sourceModelName: 'User',
|
|
372
|
+
// sourceFieldName: 'id',
|
|
373
|
+
// targetModelName: 'UserThing',
|
|
374
|
+
// targetFieldName: 'userID',
|
|
375
|
+
// },
|
|
376
|
+
// {
|
|
377
|
+
// sourceModelName: 'UserThing',
|
|
378
|
+
// sourceFieldName: 'roleThingID',
|
|
379
|
+
// targetModelName: 'RoleThing',
|
|
380
|
+
// targetFieldName: 'id',
|
|
381
|
+
// },
|
|
382
|
+
|
|
383
|
+
// ]);
|
|
384
|
+
// });
|
|
385
|
+
|
|
386
|
+
// it('can recursively parse relations #5', () => {
|
|
387
|
+
// let user = new User(null, { connection });
|
|
388
|
+
// let field = user.getField('primaryRole');
|
|
389
|
+
|
|
390
|
+
// let result = field.type.getJoinableRelations(connection);
|
|
391
|
+
// expect(result).toEqual([
|
|
392
|
+
// {
|
|
393
|
+
// sourceModelName: 'User',
|
|
394
|
+
// sourceFieldName: 'primaryRoleID',
|
|
395
|
+
// targetModelName: 'Role',
|
|
396
|
+
// targetFieldName: 'id',
|
|
397
|
+
// },
|
|
398
|
+
// ]);
|
|
399
|
+
// });
|
|
400
|
+
// });
|
|
401
|
+
// });
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
/* global describe, it, expect */
|
|
6
|
+
|
|
7
|
+
const { Utils } = require('../../lib');
|
|
8
|
+
|
|
9
|
+
describe('Utils::misc', () => {
|
|
10
|
+
describe('iterateStaticProps', () => {
|
|
11
|
+
it('should throw an error if a function is not provided', () => {
|
|
12
|
+
expect(() => Utils.iterateStaticProps({}, () => {})).toThrow(new TypeError('Utils::iterateStaticProps: "Klass" argument must be a function.'));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('can copy static props from a class', () => {
|
|
16
|
+
class Test {
|
|
17
|
+
static testFunc() {
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static fields = [];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let keys = [];
|
|
25
|
+
Utils.iterateStaticProps(Test, ({ key }) => {
|
|
26
|
+
keys.push(key);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
expect(keys.sort()).toEqual([
|
|
30
|
+
'fields',
|
|
31
|
+
'testFunc',
|
|
32
|
+
]);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('copyStaticProps', () => {
|
|
37
|
+
it('should throw an error if a function is not provided', () => {
|
|
38
|
+
expect(() => Utils.copyStaticProps({}, () => {})).toThrow(new TypeError('Utils::copyStaticProps: "Klass" argument must be a function.'));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('can copy static props from a class', () => {
|
|
42
|
+
class Test {
|
|
43
|
+
static testFunc() {
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static fields = [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// eslint-disable-next-line no-unused-vars
|
|
51
|
+
function test(arg1, arg2, arg3) {}
|
|
52
|
+
|
|
53
|
+
Utils.copyStaticProps(Test, test);
|
|
54
|
+
|
|
55
|
+
expect(typeof test.testFunc).toEqual('function');
|
|
56
|
+
expect(typeof test.fields).toEqual('object');
|
|
57
|
+
expect(test.fields).toBeInstanceOf(Array);
|
|
58
|
+
expect(test.length).toEqual(3);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
/* global describe, it, expect */
|
|
6
|
+
|
|
7
|
+
const UUID = require('uuid');
|
|
8
|
+
const { Utils } = require('../../lib');
|
|
9
|
+
const { UUID_REGEXP } = require('../support/test-helpers');
|
|
10
|
+
|
|
11
|
+
describe('Utils::model', () => {
|
|
12
|
+
describe('isUUID', () => {
|
|
13
|
+
it('should be able to generate and verify UUID V1', () => {
|
|
14
|
+
let value = UUID.v1();
|
|
15
|
+
expect(value).toMatch(UUID_REGEXP);
|
|
16
|
+
expect(Utils.isUUID(value)).toEqual(true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should be able to generate and verify UUID V4', () => {
|
|
20
|
+
let value = UUID.v4();
|
|
21
|
+
expect(value).toMatch(UUID_REGEXP);
|
|
22
|
+
expect(Utils.isUUID(value)).toEqual(true);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('sanitizeFieldString', () => {
|
|
27
|
+
it('should strip all but certain characters', () => {
|
|
28
|
+
expect(Utils.sanitizeFieldString('"User":: derp-y ... _field !$%%^#@$^ 2')).toEqual('User:derpy._field2');
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('parseQualifiedName', () => {
|
|
33
|
+
it('should be able to parse model name and fieldNames', () => {
|
|
34
|
+
expect(Utils.parseQualifiedName('"User":: derp-y ... _field !$%%^#@$^ 2')).toEqual({
|
|
35
|
+
modelName: 'User',
|
|
36
|
+
fieldNames: [ 'derpy', '_field2' ],
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(Utils.parseQualifiedName(' :: derp-y ... _field !$%%^#@$^ 2')).toEqual({
|
|
40
|
+
modelName: undefined,
|
|
41
|
+
fieldNames: [ 'derpy', '_field2' ],
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(Utils.parseQualifiedName('field')).toEqual({
|
|
45
|
+
modelName: undefined,
|
|
46
|
+
fieldNames: [ 'field' ],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
expect(Utils.parseQualifiedName('field.id')).toEqual({
|
|
50
|
+
modelName: undefined,
|
|
51
|
+
fieldNames: [ 'field', 'id' ],
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|