oak-domain 4.2.2 → 4.2.4
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/base-app-domain/ActionDefDict.d.ts +8 -8
- package/lib/base-app-domain/Oper/Schema.d.ts +158 -158
- package/lib/base-app-domain/Oper/Storage.js +56 -56
- package/lib/base-app-domain/User/Action.d.ts +11 -11
- package/lib/base-app-domain/User/Action.js +12 -12
- package/lib/base-app-domain/UserEntityGrant/Action.d.ts +5 -5
- package/lib/base-app-domain/UserEntityGrant/Action.js +5 -5
- package/lib/compiler/schemalBuilder.js +4167 -4167
- package/lib/entities/Oper.d.ts +12 -12
- package/lib/entities/Oper.js +36 -36
- package/lib/entities/User.d.ts +18 -18
- package/lib/entities/User.js +32 -32
- package/lib/index.d.ts +1 -1
- package/lib/index.js +3 -3
- package/lib/store/AsyncRowStore.d.ts +66 -66
- package/lib/store/CascadeStore.d.ts +109 -109
- package/lib/store/CascadeStore.js +1728 -1726
- package/lib/store/RelationAuth.js +1209 -1209
- package/lib/store/TriggerExecutor.js +468 -468
- package/lib/store/actionDef.js +278 -278
- package/lib/store/checker.js +487 -487
- package/lib/store/relation.d.ts +12 -12
- package/lib/store/relation.js +74 -74
- package/lib/triggers/index.d.ts +5 -5
- package/lib/triggers/index.js +28 -28
- package/lib/types/Configuration.d.ts +42 -42
- package/lib/types/Configuration.js +3 -3
- package/lib/types/Connector.d.ts +39 -38
- package/lib/types/Entity.d.ts +209 -209
- package/lib/types/Sync.d.ts +74 -69
- package/lib/types/Sync.js +9 -9
- package/lib/types/index.d.ts +27 -27
- package/lib/types/index.js +30 -30
- package/lib/utils/SimpleConnector.d.ts +81 -64
- package/lib/utils/SimpleConnector.js +217 -206
- package/lib/utils/assert.d.ts +5 -5
- package/lib/utils/projection.d.ts +4 -4
- package/lib/utils/relationPath.d.ts +31 -31
- package/lib/utils/relationPath.js +202 -202
- package/package.json +51 -51
- package/src/entities/ActionAuth.ts +41 -41
- package/src/entities/I18n.ts +45 -45
- package/src/entities/Modi.ts +69 -69
- package/src/entities/ModiEntity.ts +26 -26
- package/src/entities/Oper.ts +48 -48
- package/src/entities/OperEntity.ts +27 -27
- package/src/entities/Path.ts +43 -43
- package/src/entities/Relation.ts +43 -43
- package/src/entities/RelationAuth.ts +44 -44
- package/src/entities/User.ts +48 -48
- package/src/entities/UserEntityClaim.ts +29 -29
- package/src/entities/UserEntityGrant.ts +24 -24
- package/src/entities/UserRelation.ts +50 -50
package/lib/store/actionDef.js
CHANGED
|
@@ -1,278 +1,278 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.makeIntrinsicCTWs = exports.getFullProjection = void 0;
|
|
4
|
-
const types_1 = require("../types");
|
|
5
|
-
const lodash_1 = require("../utils/lodash");
|
|
6
|
-
const filter_1 = require("./filter");
|
|
7
|
-
const checkers_1 = require("../checkers");
|
|
8
|
-
const triggers_1 = require("../triggers");
|
|
9
|
-
const actionAuth_1 = require("./actionAuth");
|
|
10
|
-
function getFullProjection(entity, schema) {
|
|
11
|
-
const { attributes } = schema[entity];
|
|
12
|
-
const projection = {
|
|
13
|
-
id: 1,
|
|
14
|
-
$$createAt$$: 1,
|
|
15
|
-
$$updateAt$$: 1,
|
|
16
|
-
$$deleteAt$$: 1,
|
|
17
|
-
};
|
|
18
|
-
Object.keys(attributes).forEach((k) => Object.assign(projection, {
|
|
19
|
-
[k]: 1,
|
|
20
|
-
}));
|
|
21
|
-
return projection;
|
|
22
|
-
}
|
|
23
|
-
exports.getFullProjection = getFullProjection;
|
|
24
|
-
function makeIntrinsicWatchers(schema) {
|
|
25
|
-
const watchers = [];
|
|
26
|
-
for (const entity in schema) {
|
|
27
|
-
const { attributes } = schema[entity];
|
|
28
|
-
const { expiresAt, expired } = attributes;
|
|
29
|
-
if (expiresAt && expiresAt.type === 'datetime' && expired && expired.type === 'boolean') {
|
|
30
|
-
// 如果有定义expiresAt和expired,则自动生成一个检查的watcher
|
|
31
|
-
watchers.push({
|
|
32
|
-
entity,
|
|
33
|
-
name: `对象${entity}上的过期自动watcher`,
|
|
34
|
-
filter: () => {
|
|
35
|
-
return {
|
|
36
|
-
expired: false,
|
|
37
|
-
expiresAt: {
|
|
38
|
-
$lte: Date.now(),
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
action: 'update',
|
|
43
|
-
actionData: {
|
|
44
|
-
expired: true,
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return watchers;
|
|
50
|
-
}
|
|
51
|
-
function checkUniqueBetweenRows(rows, uniqAttrs) {
|
|
52
|
-
// 先检查这些行本身之间有无unique冲突
|
|
53
|
-
const dict = {};
|
|
54
|
-
for (const row of rows) {
|
|
55
|
-
let s = '';
|
|
56
|
-
for (const a of uniqAttrs) {
|
|
57
|
-
if (row[a] === null || row[a] === undefined) {
|
|
58
|
-
s + row.id;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
s + `-${row[a]}`;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (dict[s]) {
|
|
65
|
-
throw new types_1.OakUniqueViolationException([{
|
|
66
|
-
id: row.id,
|
|
67
|
-
attrs: uniqAttrs,
|
|
68
|
-
}]);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
dict[s] = 1;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function checkCountLessThan(count, uniqAttrs, than = 0, id) {
|
|
76
|
-
if (count instanceof Promise) {
|
|
77
|
-
return count.then((count2) => {
|
|
78
|
-
if (count2 > than) {
|
|
79
|
-
throw new types_1.OakUniqueViolationException([{
|
|
80
|
-
id,
|
|
81
|
-
attrs: uniqAttrs,
|
|
82
|
-
}]);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
if (count > than) {
|
|
87
|
-
throw new types_1.OakUniqueViolationException([{
|
|
88
|
-
id,
|
|
89
|
-
attrs: uniqAttrs,
|
|
90
|
-
}]);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function checkUnique(entity, row, context, uniqAttrs, extraFilter) {
|
|
94
|
-
const filter = (0, lodash_1.pick)(row, uniqAttrs);
|
|
95
|
-
for (const a in filter) {
|
|
96
|
-
if (filter[a] === null || filter[a] === undefined) {
|
|
97
|
-
delete filter[a];
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (Object.keys(filter).length < uniqAttrs.length) {
|
|
101
|
-
// 说明有null值,不需要检查约束
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const filter2 = extraFilter ? (0, filter_1.combineFilters)(entity, context.getSchema(), [filter, extraFilter]) : filter;
|
|
105
|
-
const count = context.count(entity, { filter: filter2 }, { dontCollect: true });
|
|
106
|
-
return checkCountLessThan(count, uniqAttrs, 0, row.id);
|
|
107
|
-
}
|
|
108
|
-
function makeIntrinsicCTWs(schema, actionDefDict) {
|
|
109
|
-
const checkers = (0, checkers_1.createDynamicCheckers)(schema);
|
|
110
|
-
const triggers = (0, triggers_1.createDynamicTriggers)(schema);
|
|
111
|
-
// action状态转换矩阵相应的checker
|
|
112
|
-
for (const entity in actionDefDict) {
|
|
113
|
-
for (const attr in actionDefDict[entity]) {
|
|
114
|
-
const def = actionDefDict[entity][attr];
|
|
115
|
-
const { stm, is } = def;
|
|
116
|
-
for (const action in stm) {
|
|
117
|
-
const actionStm = stm[action];
|
|
118
|
-
const conditionalFilter = typeof actionStm[0] === 'string' ? {
|
|
119
|
-
[attr]: actionStm[0],
|
|
120
|
-
} : {
|
|
121
|
-
[attr]: {
|
|
122
|
-
$in: actionStm[0],
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
checkers.push({
|
|
126
|
-
action: action,
|
|
127
|
-
type: 'row',
|
|
128
|
-
entity,
|
|
129
|
-
filter: conditionalFilter,
|
|
130
|
-
errMsg: '',
|
|
131
|
-
});
|
|
132
|
-
// 这里用data类型的checker改数据了不太好,先这样
|
|
133
|
-
checkers.push({
|
|
134
|
-
action: action,
|
|
135
|
-
type: 'data',
|
|
136
|
-
entity,
|
|
137
|
-
checker: (data) => {
|
|
138
|
-
Object.assign(data, {
|
|
139
|
-
[attr]: stm[action][1],
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
if (is) {
|
|
145
|
-
checkers.push({
|
|
146
|
-
action: 'create',
|
|
147
|
-
type: 'data',
|
|
148
|
-
entity,
|
|
149
|
-
priority: 10,
|
|
150
|
-
checker: (data) => {
|
|
151
|
-
if (data instanceof Array) {
|
|
152
|
-
data.forEach(ele => {
|
|
153
|
-
if (!ele[attr]) {
|
|
154
|
-
Object.assign(ele, {
|
|
155
|
-
[attr]: is,
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
if (!data[attr]) {
|
|
162
|
-
Object.assign(data, {
|
|
163
|
-
[attr]: is,
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
// unique索引相应的checker
|
|
173
|
-
for (const entity in schema) {
|
|
174
|
-
const { indexes } = schema[entity];
|
|
175
|
-
if (indexes) {
|
|
176
|
-
for (const index of indexes) {
|
|
177
|
-
if (index.config?.unique) {
|
|
178
|
-
const { attributes } = index;
|
|
179
|
-
const uniqAttrs = attributes.map(ele => ele.name);
|
|
180
|
-
checkers.push({
|
|
181
|
-
entity,
|
|
182
|
-
action: 'create',
|
|
183
|
-
type: 'logicalData',
|
|
184
|
-
priority: types_1.CHECKER_MAX_PRIORITY,
|
|
185
|
-
checker: (operation, context) => {
|
|
186
|
-
const { data } = operation;
|
|
187
|
-
if (data instanceof Array) {
|
|
188
|
-
checkUniqueBetweenRows(data, uniqAttrs);
|
|
189
|
-
const checkResult = data.map(ele => checkUnique(entity, ele, context, uniqAttrs));
|
|
190
|
-
if (checkResult[0] instanceof Promise) {
|
|
191
|
-
return Promise.all(checkResult).then(() => undefined);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
else if (data) {
|
|
195
|
-
return checkUnique(entity, data, context, uniqAttrs);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}, {
|
|
199
|
-
entity,
|
|
200
|
-
action: 'update',
|
|
201
|
-
type: 'logicalData',
|
|
202
|
-
priority: types_1.CHECKER_MAX_PRIORITY,
|
|
203
|
-
checker: (operation, context) => {
|
|
204
|
-
const { data, filter: operationFilter } = operation;
|
|
205
|
-
if (data) {
|
|
206
|
-
const attrs = Object.keys(data);
|
|
207
|
-
const refAttrs = (0, lodash_1.intersection)(attrs, uniqAttrs);
|
|
208
|
-
if (refAttrs.length === 0) {
|
|
209
|
-
// 如果本次更新和unique约束的属性之间没有交集则直接返回
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
for (const attr of refAttrs) {
|
|
213
|
-
// 如果有更新为null值,不用再检查约束
|
|
214
|
-
if (data[attr] === null || data[attr] === undefined) {
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
if (refAttrs.length === uniqAttrs.length) {
|
|
219
|
-
// 如果更新了全部属性,直接检查
|
|
220
|
-
const filter = (0, lodash_1.pick)(data, refAttrs);
|
|
221
|
-
// 在这些行以外的行不和更新后的键值冲突
|
|
222
|
-
const count = context.count(entity, {
|
|
223
|
-
filter: (0, filter_1.combineFilters)(entity, context.getSchema(), [filter, {
|
|
224
|
-
$not: operationFilter,
|
|
225
|
-
}]),
|
|
226
|
-
}, { dontCollect: true });
|
|
227
|
-
const checkCount = checkCountLessThan(count, uniqAttrs, 0, operationFilter?.id);
|
|
228
|
-
// 更新的行只能有一行
|
|
229
|
-
const rowCount = context.count(entity, {
|
|
230
|
-
filter: operationFilter,
|
|
231
|
-
}, { dontCollect: true });
|
|
232
|
-
const checkRowCount = checkCountLessThan(rowCount, uniqAttrs, 1, operationFilter?.id);
|
|
233
|
-
// 如果更新的行数为零似乎也可以,但这应该不可能出现吧,by Xc 20230131
|
|
234
|
-
if (checkRowCount instanceof Promise) {
|
|
235
|
-
return Promise.all([checkCount, checkRowCount]).then(() => undefined);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
// 否则需要结合本行现有的属性来进行检查
|
|
239
|
-
const projection = { id: 1 };
|
|
240
|
-
for (const attr of uniqAttrs) {
|
|
241
|
-
Object.assign(projection, {
|
|
242
|
-
[attr]: 1,
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
const checkWithRows = (rows2) => {
|
|
246
|
-
const rows22 = rows2.map(ele => Object.assign(ele, data));
|
|
247
|
-
// 先检查这些行本身之间是否冲突
|
|
248
|
-
checkUniqueBetweenRows(rows22, uniqAttrs);
|
|
249
|
-
const checkResults = rows22.map((row) => checkUnique(entity, row, context, uniqAttrs, {
|
|
250
|
-
$not: operationFilter
|
|
251
|
-
}));
|
|
252
|
-
if (checkResults[0] instanceof Promise) {
|
|
253
|
-
return Promise.all(checkResults).then(() => undefined);
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
const currentRows = context.select(entity, {
|
|
257
|
-
data: projection,
|
|
258
|
-
filter: operationFilter,
|
|
259
|
-
}, { dontCollect: true });
|
|
260
|
-
if (currentRows instanceof Promise) {
|
|
261
|
-
return currentRows.then((row2) => checkWithRows(row2));
|
|
262
|
-
}
|
|
263
|
-
return checkWithRows(currentRows);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
triggers.push(...actionAuth_1.triggers);
|
|
272
|
-
return {
|
|
273
|
-
triggers,
|
|
274
|
-
checkers,
|
|
275
|
-
watchers: makeIntrinsicWatchers(schema),
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
exports.makeIntrinsicCTWs = makeIntrinsicCTWs;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeIntrinsicCTWs = exports.getFullProjection = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const lodash_1 = require("../utils/lodash");
|
|
6
|
+
const filter_1 = require("./filter");
|
|
7
|
+
const checkers_1 = require("../checkers");
|
|
8
|
+
const triggers_1 = require("../triggers");
|
|
9
|
+
const actionAuth_1 = require("./actionAuth");
|
|
10
|
+
function getFullProjection(entity, schema) {
|
|
11
|
+
const { attributes } = schema[entity];
|
|
12
|
+
const projection = {
|
|
13
|
+
id: 1,
|
|
14
|
+
$$createAt$$: 1,
|
|
15
|
+
$$updateAt$$: 1,
|
|
16
|
+
$$deleteAt$$: 1,
|
|
17
|
+
};
|
|
18
|
+
Object.keys(attributes).forEach((k) => Object.assign(projection, {
|
|
19
|
+
[k]: 1,
|
|
20
|
+
}));
|
|
21
|
+
return projection;
|
|
22
|
+
}
|
|
23
|
+
exports.getFullProjection = getFullProjection;
|
|
24
|
+
function makeIntrinsicWatchers(schema) {
|
|
25
|
+
const watchers = [];
|
|
26
|
+
for (const entity in schema) {
|
|
27
|
+
const { attributes } = schema[entity];
|
|
28
|
+
const { expiresAt, expired } = attributes;
|
|
29
|
+
if (expiresAt && expiresAt.type === 'datetime' && expired && expired.type === 'boolean') {
|
|
30
|
+
// 如果有定义expiresAt和expired,则自动生成一个检查的watcher
|
|
31
|
+
watchers.push({
|
|
32
|
+
entity,
|
|
33
|
+
name: `对象${entity}上的过期自动watcher`,
|
|
34
|
+
filter: () => {
|
|
35
|
+
return {
|
|
36
|
+
expired: false,
|
|
37
|
+
expiresAt: {
|
|
38
|
+
$lte: Date.now(),
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
action: 'update',
|
|
43
|
+
actionData: {
|
|
44
|
+
expired: true,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return watchers;
|
|
50
|
+
}
|
|
51
|
+
function checkUniqueBetweenRows(rows, uniqAttrs) {
|
|
52
|
+
// 先检查这些行本身之间有无unique冲突
|
|
53
|
+
const dict = {};
|
|
54
|
+
for (const row of rows) {
|
|
55
|
+
let s = '';
|
|
56
|
+
for (const a of uniqAttrs) {
|
|
57
|
+
if (row[a] === null || row[a] === undefined) {
|
|
58
|
+
s + row.id;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
s + `-${row[a]}`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (dict[s]) {
|
|
65
|
+
throw new types_1.OakUniqueViolationException([{
|
|
66
|
+
id: row.id,
|
|
67
|
+
attrs: uniqAttrs,
|
|
68
|
+
}]);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
dict[s] = 1;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function checkCountLessThan(count, uniqAttrs, than = 0, id) {
|
|
76
|
+
if (count instanceof Promise) {
|
|
77
|
+
return count.then((count2) => {
|
|
78
|
+
if (count2 > than) {
|
|
79
|
+
throw new types_1.OakUniqueViolationException([{
|
|
80
|
+
id,
|
|
81
|
+
attrs: uniqAttrs,
|
|
82
|
+
}]);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (count > than) {
|
|
87
|
+
throw new types_1.OakUniqueViolationException([{
|
|
88
|
+
id,
|
|
89
|
+
attrs: uniqAttrs,
|
|
90
|
+
}]);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function checkUnique(entity, row, context, uniqAttrs, extraFilter) {
|
|
94
|
+
const filter = (0, lodash_1.pick)(row, uniqAttrs);
|
|
95
|
+
for (const a in filter) {
|
|
96
|
+
if (filter[a] === null || filter[a] === undefined) {
|
|
97
|
+
delete filter[a];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (Object.keys(filter).length < uniqAttrs.length) {
|
|
101
|
+
// 说明有null值,不需要检查约束
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const filter2 = extraFilter ? (0, filter_1.combineFilters)(entity, context.getSchema(), [filter, extraFilter]) : filter;
|
|
105
|
+
const count = context.count(entity, { filter: filter2 }, { dontCollect: true });
|
|
106
|
+
return checkCountLessThan(count, uniqAttrs, 0, row.id);
|
|
107
|
+
}
|
|
108
|
+
function makeIntrinsicCTWs(schema, actionDefDict) {
|
|
109
|
+
const checkers = (0, checkers_1.createDynamicCheckers)(schema);
|
|
110
|
+
const triggers = (0, triggers_1.createDynamicTriggers)(schema);
|
|
111
|
+
// action状态转换矩阵相应的checker
|
|
112
|
+
for (const entity in actionDefDict) {
|
|
113
|
+
for (const attr in actionDefDict[entity]) {
|
|
114
|
+
const def = actionDefDict[entity][attr];
|
|
115
|
+
const { stm, is } = def;
|
|
116
|
+
for (const action in stm) {
|
|
117
|
+
const actionStm = stm[action];
|
|
118
|
+
const conditionalFilter = typeof actionStm[0] === 'string' ? {
|
|
119
|
+
[attr]: actionStm[0],
|
|
120
|
+
} : {
|
|
121
|
+
[attr]: {
|
|
122
|
+
$in: actionStm[0],
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
checkers.push({
|
|
126
|
+
action: action,
|
|
127
|
+
type: 'row',
|
|
128
|
+
entity,
|
|
129
|
+
filter: conditionalFilter,
|
|
130
|
+
errMsg: '',
|
|
131
|
+
});
|
|
132
|
+
// 这里用data类型的checker改数据了不太好,先这样
|
|
133
|
+
checkers.push({
|
|
134
|
+
action: action,
|
|
135
|
+
type: 'data',
|
|
136
|
+
entity,
|
|
137
|
+
checker: (data) => {
|
|
138
|
+
Object.assign(data, {
|
|
139
|
+
[attr]: stm[action][1],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (is) {
|
|
145
|
+
checkers.push({
|
|
146
|
+
action: 'create',
|
|
147
|
+
type: 'data',
|
|
148
|
+
entity,
|
|
149
|
+
priority: 10,
|
|
150
|
+
checker: (data) => {
|
|
151
|
+
if (data instanceof Array) {
|
|
152
|
+
data.forEach(ele => {
|
|
153
|
+
if (!ele[attr]) {
|
|
154
|
+
Object.assign(ele, {
|
|
155
|
+
[attr]: is,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
if (!data[attr]) {
|
|
162
|
+
Object.assign(data, {
|
|
163
|
+
[attr]: is,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// unique索引相应的checker
|
|
173
|
+
for (const entity in schema) {
|
|
174
|
+
const { indexes } = schema[entity];
|
|
175
|
+
if (indexes) {
|
|
176
|
+
for (const index of indexes) {
|
|
177
|
+
if (index.config?.unique) {
|
|
178
|
+
const { attributes } = index;
|
|
179
|
+
const uniqAttrs = attributes.map(ele => ele.name);
|
|
180
|
+
checkers.push({
|
|
181
|
+
entity,
|
|
182
|
+
action: 'create',
|
|
183
|
+
type: 'logicalData',
|
|
184
|
+
priority: types_1.CHECKER_MAX_PRIORITY,
|
|
185
|
+
checker: (operation, context) => {
|
|
186
|
+
const { data } = operation;
|
|
187
|
+
if (data instanceof Array) {
|
|
188
|
+
checkUniqueBetweenRows(data, uniqAttrs);
|
|
189
|
+
const checkResult = data.map(ele => checkUnique(entity, ele, context, uniqAttrs));
|
|
190
|
+
if (checkResult[0] instanceof Promise) {
|
|
191
|
+
return Promise.all(checkResult).then(() => undefined);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else if (data) {
|
|
195
|
+
return checkUnique(entity, data, context, uniqAttrs);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}, {
|
|
199
|
+
entity,
|
|
200
|
+
action: 'update',
|
|
201
|
+
type: 'logicalData',
|
|
202
|
+
priority: types_1.CHECKER_MAX_PRIORITY,
|
|
203
|
+
checker: (operation, context) => {
|
|
204
|
+
const { data, filter: operationFilter } = operation;
|
|
205
|
+
if (data) {
|
|
206
|
+
const attrs = Object.keys(data);
|
|
207
|
+
const refAttrs = (0, lodash_1.intersection)(attrs, uniqAttrs);
|
|
208
|
+
if (refAttrs.length === 0) {
|
|
209
|
+
// 如果本次更新和unique约束的属性之间没有交集则直接返回
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
for (const attr of refAttrs) {
|
|
213
|
+
// 如果有更新为null值,不用再检查约束
|
|
214
|
+
if (data[attr] === null || data[attr] === undefined) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (refAttrs.length === uniqAttrs.length) {
|
|
219
|
+
// 如果更新了全部属性,直接检查
|
|
220
|
+
const filter = (0, lodash_1.pick)(data, refAttrs);
|
|
221
|
+
// 在这些行以外的行不和更新后的键值冲突
|
|
222
|
+
const count = context.count(entity, {
|
|
223
|
+
filter: (0, filter_1.combineFilters)(entity, context.getSchema(), [filter, {
|
|
224
|
+
$not: operationFilter,
|
|
225
|
+
}]),
|
|
226
|
+
}, { dontCollect: true });
|
|
227
|
+
const checkCount = checkCountLessThan(count, uniqAttrs, 0, operationFilter?.id);
|
|
228
|
+
// 更新的行只能有一行
|
|
229
|
+
const rowCount = context.count(entity, {
|
|
230
|
+
filter: operationFilter,
|
|
231
|
+
}, { dontCollect: true });
|
|
232
|
+
const checkRowCount = checkCountLessThan(rowCount, uniqAttrs, 1, operationFilter?.id);
|
|
233
|
+
// 如果更新的行数为零似乎也可以,但这应该不可能出现吧,by Xc 20230131
|
|
234
|
+
if (checkRowCount instanceof Promise) {
|
|
235
|
+
return Promise.all([checkCount, checkRowCount]).then(() => undefined);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// 否则需要结合本行现有的属性来进行检查
|
|
239
|
+
const projection = { id: 1 };
|
|
240
|
+
for (const attr of uniqAttrs) {
|
|
241
|
+
Object.assign(projection, {
|
|
242
|
+
[attr]: 1,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
const checkWithRows = (rows2) => {
|
|
246
|
+
const rows22 = rows2.map(ele => Object.assign(ele, data));
|
|
247
|
+
// 先检查这些行本身之间是否冲突
|
|
248
|
+
checkUniqueBetweenRows(rows22, uniqAttrs);
|
|
249
|
+
const checkResults = rows22.map((row) => checkUnique(entity, row, context, uniqAttrs, {
|
|
250
|
+
$not: operationFilter
|
|
251
|
+
}));
|
|
252
|
+
if (checkResults[0] instanceof Promise) {
|
|
253
|
+
return Promise.all(checkResults).then(() => undefined);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
const currentRows = context.select(entity, {
|
|
257
|
+
data: projection,
|
|
258
|
+
filter: operationFilter,
|
|
259
|
+
}, { dontCollect: true });
|
|
260
|
+
if (currentRows instanceof Promise) {
|
|
261
|
+
return currentRows.then((row2) => checkWithRows(row2));
|
|
262
|
+
}
|
|
263
|
+
return checkWithRows(currentRows);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
triggers.push(...actionAuth_1.triggers);
|
|
272
|
+
return {
|
|
273
|
+
triggers,
|
|
274
|
+
checkers,
|
|
275
|
+
watchers: makeIntrinsicWatchers(schema),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
exports.makeIntrinsicCTWs = makeIntrinsicCTWs;
|