@nocobase/plugin-ui-schema-storage 0.7.0-alpha.0

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.
Files changed (117) hide show
  1. package/LICENSE +201 -0
  2. package/esm/actions/ui-schema-action.d.ts +16 -0
  3. package/esm/actions/ui-schema-action.js +100 -0
  4. package/esm/actions/ui-schema-action.js.map +1 -0
  5. package/esm/collections/uiSchemaServerHooks.d.ts +3 -0
  6. package/esm/collections/uiSchemaServerHooks.js +27 -0
  7. package/esm/collections/uiSchemaServerHooks.js.map +1 -0
  8. package/esm/collections/uiSchemaTemplates.d.ts +2 -0
  9. package/esm/collections/uiSchemaTemplates.js +39 -0
  10. package/esm/collections/uiSchemaTemplates.js.map +1 -0
  11. package/esm/collections/uiSchemaTreePath.d.ts +3 -0
  12. package/esm/collections/uiSchemaTreePath.js +42 -0
  13. package/esm/collections/uiSchemaTreePath.js.map +1 -0
  14. package/esm/collections/uiSchemas.d.ts +3 -0
  15. package/esm/collections/uiSchemas.js +32 -0
  16. package/esm/collections/uiSchemas.js.map +1 -0
  17. package/esm/dao/ui_schema_dao.d.ts +4 -0
  18. package/esm/dao/ui_schema_dao.js +6 -0
  19. package/esm/dao/ui_schema_dao.js.map +1 -0
  20. package/esm/dao/ui_schema_node_dao.d.ts +22 -0
  21. package/esm/dao/ui_schema_node_dao.js +6 -0
  22. package/esm/dao/ui_schema_node_dao.js.map +1 -0
  23. package/esm/helper.d.ts +0 -0
  24. package/esm/helper.js +1 -0
  25. package/esm/helper.js.map +1 -0
  26. package/esm/index.d.ts +3 -0
  27. package/esm/index.js +4 -0
  28. package/esm/index.js.map +1 -0
  29. package/esm/model.d.ts +6 -0
  30. package/esm/model.js +9 -0
  31. package/esm/model.js.map +1 -0
  32. package/esm/repository.d.ts +72 -0
  33. package/esm/repository.js +858 -0
  34. package/esm/repository.js.map +1 -0
  35. package/esm/server-hooks/hooks/bind-menu-to-role.d.ts +5 -0
  36. package/esm/server-hooks/hooks/bind-menu-to-role.js +26 -0
  37. package/esm/server-hooks/hooks/bind-menu-to-role.js.map +1 -0
  38. package/esm/server-hooks/hooks/factory.d.ts +6 -0
  39. package/esm/server-hooks/hooks/factory.js +8 -0
  40. package/esm/server-hooks/hooks/factory.js.map +1 -0
  41. package/esm/server-hooks/hooks/index.d.ts +6 -0
  42. package/esm/server-hooks/hooks/index.js +12 -0
  43. package/esm/server-hooks/hooks/index.js.map +1 -0
  44. package/esm/server-hooks/hooks/remove-parents-if-no-children.d.ts +6 -0
  45. package/esm/server-hooks/hooks/remove-parents-if-no-children.js +21 -0
  46. package/esm/server-hooks/hooks/remove-parents-if-no-children.js.map +1 -0
  47. package/esm/server-hooks/hooks/remove-schema.d.ts +6 -0
  48. package/esm/server-hooks/hooks/remove-schema.js +29 -0
  49. package/esm/server-hooks/hooks/remove-schema.js.map +1 -0
  50. package/esm/server-hooks/index.d.ts +23 -0
  51. package/esm/server-hooks/index.js +133 -0
  52. package/esm/server-hooks/index.js.map +1 -0
  53. package/esm/server-hooks/model.d.ts +3 -0
  54. package/esm/server-hooks/model.js +4 -0
  55. package/esm/server-hooks/model.js.map +1 -0
  56. package/esm/server.d.ts +10 -0
  57. package/esm/server.js +78 -0
  58. package/esm/server.js.map +1 -0
  59. package/lib/actions/ui-schema-action.d.ts +16 -0
  60. package/lib/actions/ui-schema-action.js +106 -0
  61. package/lib/actions/ui-schema-action.js.map +1 -0
  62. package/lib/collections/uiSchemaServerHooks.d.ts +3 -0
  63. package/lib/collections/uiSchemaServerHooks.js +29 -0
  64. package/lib/collections/uiSchemaServerHooks.js.map +1 -0
  65. package/lib/collections/uiSchemaTemplates.d.ts +2 -0
  66. package/lib/collections/uiSchemaTemplates.js +41 -0
  67. package/lib/collections/uiSchemaTemplates.js.map +1 -0
  68. package/lib/collections/uiSchemaTreePath.d.ts +3 -0
  69. package/lib/collections/uiSchemaTreePath.js +44 -0
  70. package/lib/collections/uiSchemaTreePath.js.map +1 -0
  71. package/lib/collections/uiSchemas.d.ts +3 -0
  72. package/lib/collections/uiSchemas.js +34 -0
  73. package/lib/collections/uiSchemas.js.map +1 -0
  74. package/lib/dao/ui_schema_dao.d.ts +4 -0
  75. package/lib/dao/ui_schema_dao.js +10 -0
  76. package/lib/dao/ui_schema_dao.js.map +1 -0
  77. package/lib/dao/ui_schema_node_dao.d.ts +22 -0
  78. package/lib/dao/ui_schema_node_dao.js +10 -0
  79. package/lib/dao/ui_schema_node_dao.js.map +1 -0
  80. package/lib/helper.d.ts +0 -0
  81. package/lib/helper.js +1 -0
  82. package/lib/helper.js.map +1 -0
  83. package/lib/index.d.ts +3 -0
  84. package/lib/index.js +21 -0
  85. package/lib/index.js.map +1 -0
  86. package/lib/model.d.ts +6 -0
  87. package/lib/model.js +12 -0
  88. package/lib/model.js.map +1 -0
  89. package/lib/repository.d.ts +72 -0
  90. package/lib/repository.js +865 -0
  91. package/lib/repository.js.map +1 -0
  92. package/lib/server-hooks/hooks/bind-menu-to-role.d.ts +5 -0
  93. package/lib/server-hooks/hooks/bind-menu-to-role.js +30 -0
  94. package/lib/server-hooks/hooks/bind-menu-to-role.js.map +1 -0
  95. package/lib/server-hooks/hooks/factory.d.ts +6 -0
  96. package/lib/server-hooks/hooks/factory.js +12 -0
  97. package/lib/server-hooks/hooks/factory.js.map +1 -0
  98. package/lib/server-hooks/hooks/index.d.ts +6 -0
  99. package/lib/server-hooks/hooks/index.js +15 -0
  100. package/lib/server-hooks/hooks/index.js.map +1 -0
  101. package/lib/server-hooks/hooks/remove-parents-if-no-children.d.ts +6 -0
  102. package/lib/server-hooks/hooks/remove-parents-if-no-children.js +25 -0
  103. package/lib/server-hooks/hooks/remove-parents-if-no-children.js.map +1 -0
  104. package/lib/server-hooks/hooks/remove-schema.d.ts +6 -0
  105. package/lib/server-hooks/hooks/remove-schema.js +33 -0
  106. package/lib/server-hooks/hooks/remove-schema.js.map +1 -0
  107. package/lib/server-hooks/index.d.ts +23 -0
  108. package/lib/server-hooks/index.js +137 -0
  109. package/lib/server-hooks/index.js.map +1 -0
  110. package/lib/server-hooks/model.d.ts +3 -0
  111. package/lib/server-hooks/model.js +8 -0
  112. package/lib/server-hooks/model.js.map +1 -0
  113. package/lib/server.d.ts +10 -0
  114. package/lib/server.js +85 -0
  115. package/lib/server.js.map +1 -0
  116. package/package.json +22 -0
  117. package/tsconfig.build.json +9 -0
@@ -0,0 +1,865 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
9
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
10
+ return new (P || (P = Promise))(function (resolve, reject) {
11
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
12
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
13
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
14
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
15
+ });
16
+ };
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.UiSchemaRepository = void 0;
22
+ const database_1 = require("@nocobase/database");
23
+ const utils_1 = require("@nocobase/utils");
24
+ const lodash_1 = __importDefault(require("lodash"));
25
+ const nodeKeys = ['properties', 'definitions', 'patternProperties', 'additionalProperties', 'items'];
26
+ function transaction(transactionAbleArgPosition) {
27
+ return (target, propertyKey, descriptor) => {
28
+ const originalMethod = descriptor.value;
29
+ descriptor.value = function (...args) {
30
+ return __awaiter(this, void 0, void 0, function* () {
31
+ if (!lodash_1.default.isNumber(transactionAbleArgPosition)) {
32
+ transactionAbleArgPosition = originalMethod.length - 1;
33
+ }
34
+ let transaction = lodash_1.default.get(args, [transactionAbleArgPosition, 'transaction']);
35
+ let handleTransaction = false;
36
+ if (!transaction) {
37
+ transaction = yield this.database.sequelize.transaction();
38
+ handleTransaction = true;
39
+ lodash_1.default.set(args, transactionAbleArgPosition, Object.assign(Object.assign({}, lodash_1.default.get(args, transactionAbleArgPosition, {})), { transaction }));
40
+ }
41
+ if (handleTransaction) {
42
+ try {
43
+ const results = yield originalMethod.apply(this, args);
44
+ yield transaction.commit();
45
+ return results;
46
+ }
47
+ catch (e) {
48
+ yield transaction.rollback();
49
+ throw e;
50
+ }
51
+ }
52
+ else {
53
+ return yield originalMethod.apply(this, args);
54
+ }
55
+ });
56
+ };
57
+ return descriptor;
58
+ };
59
+ }
60
+ class UiSchemaRepository extends database_1.Repository {
61
+ tableNameAdapter(tableName) {
62
+ if (this.database.sequelize.getDialect() === 'postgres') {
63
+ return `"${tableName}"`;
64
+ }
65
+ return tableName;
66
+ }
67
+ get uiSchemasTableName() {
68
+ return this.tableNameAdapter(this.model.tableName);
69
+ }
70
+ get uiSchemaTreePathTableName() {
71
+ const model = this.database.getCollection('uiSchemaTreePath').model;
72
+ return this.tableNameAdapter(model.tableName);
73
+ }
74
+ sqlAdapter(sql) {
75
+ if (this.database.sequelize.getDialect() === 'mysql') {
76
+ return lodash_1.default.replace(sql, /"/g, '`');
77
+ }
78
+ return sql;
79
+ }
80
+ static schemaToSingleNodes(schema, carry = [], childOptions = null) {
81
+ const node = lodash_1.default.cloneDeep(lodash_1.default.isString(schema)
82
+ ? {
83
+ 'x-uid': schema,
84
+ }
85
+ : schema);
86
+ if (!lodash_1.default.get(node, 'name')) {
87
+ node.name = (0, utils_1.uid)();
88
+ }
89
+ if (!lodash_1.default.get(node, 'x-uid')) {
90
+ node['x-uid'] = (0, utils_1.uid)();
91
+ }
92
+ if (childOptions) {
93
+ node.childOptions = childOptions;
94
+ }
95
+ carry.push(node);
96
+ for (const nodeKey of nodeKeys) {
97
+ const nodeProperty = lodash_1.default.get(node, nodeKey);
98
+ const childNodeChildOptions = {
99
+ parentUid: node['x-uid'],
100
+ parentPath: [node['x-uid'], ...lodash_1.default.get(childOptions, 'parentPath', [])],
101
+ type: nodeKey,
102
+ };
103
+ // array items
104
+ if (nodeKey === 'items' && nodeProperty) {
105
+ const handleItems = lodash_1.default.isArray(nodeProperty) ? nodeProperty : [nodeProperty];
106
+ for (const [i, item] of handleItems.entries()) {
107
+ carry = this.schemaToSingleNodes(item, carry, Object.assign(Object.assign({}, childNodeChildOptions), { sort: i + 1 }));
108
+ }
109
+ }
110
+ else if (lodash_1.default.isPlainObject(nodeProperty)) {
111
+ const subNodeNames = lodash_1.default.keys(lodash_1.default.get(node, nodeKey));
112
+ delete node[nodeKey];
113
+ for (const [i, subNodeName] of subNodeNames.entries()) {
114
+ const subSchema = Object.assign({ name: subNodeName }, lodash_1.default.get(nodeProperty, subNodeName));
115
+ carry = this.schemaToSingleNodes(subSchema, carry, Object.assign(Object.assign({}, childNodeChildOptions), { sort: i + 1 }));
116
+ }
117
+ }
118
+ }
119
+ return carry;
120
+ }
121
+ getProperties(uid, options = {}) {
122
+ return __awaiter(this, void 0, void 0, function* () {
123
+ const { transaction } = options;
124
+ const db = this.database;
125
+ const rawSql = `
126
+ SELECT "SchemaTable"."x-uid" as "x-uid", "SchemaTable"."name" as "name", "SchemaTable"."schema" as "schema",
127
+ TreePath.depth as depth,
128
+ NodeInfo.type as type, NodeInfo.async as async, ParentPath.ancestor as parent, ParentPath.sort as sort
129
+ FROM ${this.uiSchemaTreePathTableName} as TreePath
130
+ LEFT JOIN ${this.uiSchemasTableName} as "SchemaTable" ON "SchemaTable"."x-uid" = TreePath.descendant
131
+ LEFT JOIN ${this.uiSchemaTreePathTableName} as NodeInfo ON NodeInfo.descendant = "SchemaTable"."x-uid" and NodeInfo.descendant = NodeInfo.ancestor and NodeInfo.depth = 0
132
+ LEFT JOIN ${this.uiSchemaTreePathTableName} as ParentPath ON (ParentPath.descendant = "SchemaTable"."x-uid" AND ParentPath.depth = 1)
133
+ WHERE TreePath.ancestor = :ancestor AND (NodeInfo.async = false or TreePath.depth = 1)`;
134
+ const nodes = yield db.sequelize.query(this.sqlAdapter(rawSql), {
135
+ replacements: {
136
+ ancestor: uid,
137
+ },
138
+ transaction,
139
+ });
140
+ if (nodes[0].length == 0) {
141
+ return {};
142
+ }
143
+ const schema = this.nodesToSchema(nodes[0], uid);
144
+ return lodash_1.default.pick(schema, ['type', 'properties']);
145
+ });
146
+ }
147
+ getJsonSchema(uid, options) {
148
+ return __awaiter(this, void 0, void 0, function* () {
149
+ const db = this.database;
150
+ const treeTable = this.uiSchemaTreePathTableName;
151
+ const rawSql = `
152
+ SELECT "SchemaTable"."x-uid" as "x-uid", "SchemaTable"."name" as name, "SchemaTable"."schema" as "schema" ,
153
+ TreePath.depth as depth,
154
+ NodeInfo.type as type, NodeInfo.async as async, ParentPath.ancestor as parent, ParentPath.sort as sort
155
+ FROM ${treeTable} as TreePath
156
+ LEFT JOIN ${this.uiSchemasTableName} as "SchemaTable" ON "SchemaTable"."x-uid" = TreePath.descendant
157
+ LEFT JOIN ${treeTable} as NodeInfo ON NodeInfo.descendant = "SchemaTable"."x-uid" and NodeInfo.descendant = NodeInfo.ancestor and NodeInfo.depth = 0
158
+ LEFT JOIN ${treeTable} as ParentPath ON (ParentPath.descendant = "SchemaTable"."x-uid" AND ParentPath.depth = 1)
159
+ WHERE TreePath.ancestor = :ancestor ${(options === null || options === void 0 ? void 0 : options.includeAsyncNode) ? '' : 'AND (NodeInfo.async != true )'}
160
+ `;
161
+ const nodes = yield db.sequelize.query(this.sqlAdapter(rawSql), {
162
+ replacements: {
163
+ ancestor: uid,
164
+ },
165
+ transaction: options === null || options === void 0 ? void 0 : options.transaction,
166
+ });
167
+ if (nodes[0].length == 0) {
168
+ return {};
169
+ }
170
+ const schema = this.nodesToSchema(nodes[0], uid);
171
+ return schema;
172
+ });
173
+ }
174
+ ignoreSchemaProperties(schemaProperties) {
175
+ return lodash_1.default.omit(schemaProperties, nodeKeys);
176
+ }
177
+ nodesToSchema(nodes, rootUid) {
178
+ const nodeAttributeSanitize = (node) => {
179
+ const schema = Object.assign(Object.assign(Object.assign({}, this.ignoreSchemaProperties(lodash_1.default.isPlainObject(node.schema) ? node.schema : JSON.parse(node.schema))), lodash_1.default.pick(node, [...nodeKeys, 'name'])), { ['x-uid']: node['x-uid'], ['x-async']: !!node.async });
180
+ if (lodash_1.default.isNumber(node.sort)) {
181
+ schema['x-index'] = node.sort;
182
+ }
183
+ return schema;
184
+ };
185
+ const buildTree = (rootNode) => {
186
+ const children = nodes.filter((node) => node.parent == rootNode['x-uid']);
187
+ if (children.length > 0) {
188
+ const childrenGroupByType = lodash_1.default.groupBy(children, 'type');
189
+ for (const childType of Object.keys(childrenGroupByType)) {
190
+ const properties = childrenGroupByType[childType]
191
+ .map((child) => buildTree(child))
192
+ .sort((a, b) => a['x-index'] - b['x-index']);
193
+ rootNode[childType] =
194
+ childType == 'items'
195
+ ? properties.length == 1
196
+ ? properties[0]
197
+ : properties
198
+ : properties.reduce((carry, item) => {
199
+ carry[item.name] = item;
200
+ delete item['name'];
201
+ return carry;
202
+ }, {});
203
+ }
204
+ }
205
+ return nodeAttributeSanitize(rootNode);
206
+ };
207
+ return buildTree(nodes.find((node) => node['x-uid'] == rootUid));
208
+ }
209
+ clearAncestor(uid, options) {
210
+ return __awaiter(this, void 0, void 0, function* () {
211
+ const db = this.database;
212
+ const treeTable = this.uiSchemaTreePathTableName;
213
+ yield db.sequelize.query(`DELETE
214
+ FROM ${treeTable}
215
+ WHERE descendant IN
216
+ (SELECT descendant FROM (SELECT descendant FROM ${treeTable} WHERE ancestor = :uid) as descendantTable)
217
+ AND ancestor IN (SELECT ancestor
218
+ FROM (SELECT ancestor FROM ${treeTable} WHERE descendant = :uid AND ancestor != descendant) as ancestorTable)
219
+ `, {
220
+ type: 'DELETE',
221
+ replacements: {
222
+ uid,
223
+ },
224
+ transaction: options.transaction,
225
+ });
226
+ });
227
+ }
228
+ patch(newSchema, options) {
229
+ return __awaiter(this, void 0, void 0, function* () {
230
+ const { transaction } = options;
231
+ const rootUid = newSchema['x-uid'];
232
+ const oldTree = yield this.getJsonSchema(rootUid);
233
+ const traverSchemaTree = (schema, path = []) => __awaiter(this, void 0, void 0, function* () {
234
+ const node = schema;
235
+ const oldNode = path.length == 0 ? oldTree : lodash_1.default.get(oldTree, path);
236
+ const oldNodeUid = oldNode['x-uid'];
237
+ yield this.updateNode(oldNodeUid, node, transaction);
238
+ const properties = node.properties;
239
+ if (lodash_1.default.isPlainObject(properties)) {
240
+ for (const name of Object.keys(properties)) {
241
+ yield traverSchemaTree(properties[name], [...path, 'properties', name]);
242
+ }
243
+ }
244
+ });
245
+ yield traverSchemaTree(newSchema);
246
+ });
247
+ }
248
+ updateNode(uid, schema, transaction) {
249
+ return __awaiter(this, void 0, void 0, function* () {
250
+ const nodeModel = yield this.findOne({
251
+ filter: {
252
+ 'x-uid': uid,
253
+ },
254
+ });
255
+ yield nodeModel.update({
256
+ schema: Object.assign(Object.assign({}, nodeModel.get('schema')), lodash_1.default.omit(schema, ['x-async', 'name', 'x-uid', 'properties'])),
257
+ }, {
258
+ hooks: false,
259
+ transaction,
260
+ });
261
+ });
262
+ }
263
+ childrenCount(uid, transaction) {
264
+ return __awaiter(this, void 0, void 0, function* () {
265
+ const db = this.database;
266
+ const countResult = yield db.sequelize.query(`SELECT COUNT(*) as count FROM ${this.uiSchemaTreePathTableName} where ancestor = :ancestor and depth = 1`, {
267
+ replacements: {
268
+ ancestor: uid,
269
+ },
270
+ type: 'SELECT',
271
+ transaction,
272
+ });
273
+ return parseInt(countResult[0]['count']);
274
+ });
275
+ }
276
+ isLeafNode(uid, transaction) {
277
+ return __awaiter(this, void 0, void 0, function* () {
278
+ const childrenCount = yield this.childrenCount(uid, transaction);
279
+ return childrenCount === 0;
280
+ });
281
+ }
282
+ findParentUid(uid, transaction) {
283
+ return __awaiter(this, void 0, void 0, function* () {
284
+ const parent = yield this.database.getRepository('uiSchemaTreePath').findOne({
285
+ filter: {
286
+ descendant: uid,
287
+ depth: 1,
288
+ },
289
+ transaction,
290
+ });
291
+ return parent ? parent.get('ancestor') : null;
292
+ });
293
+ }
294
+ findNodeSchemaWithParent(uid, transaction) {
295
+ return __awaiter(this, void 0, void 0, function* () {
296
+ const schema = yield this.database.getRepository('uiSchemas').findOne({
297
+ filter: {
298
+ 'x-uid': uid,
299
+ },
300
+ transaction,
301
+ });
302
+ return {
303
+ parentUid: yield this.findParentUid(uid, transaction),
304
+ schema,
305
+ };
306
+ });
307
+ }
308
+ isSingleChild(uid, transaction) {
309
+ return __awaiter(this, void 0, void 0, function* () {
310
+ const db = this.database;
311
+ const parent = yield this.findParentUid(uid, transaction);
312
+ if (!parent) {
313
+ return null;
314
+ }
315
+ const parentChildrenCount = yield this.childrenCount(parent, transaction);
316
+ if (parentChildrenCount == 1) {
317
+ const schema = yield db.getRepository('uiSchemas').findOne({
318
+ filter: {
319
+ 'x-uid': parent,
320
+ },
321
+ transaction,
322
+ });
323
+ return schema;
324
+ }
325
+ return null;
326
+ });
327
+ }
328
+ removeEmptyParents(options) {
329
+ return __awaiter(this, void 0, void 0, function* () {
330
+ const { transaction, uid, breakRemoveOn } = options;
331
+ const removeParent = (nodeUid) => __awaiter(this, void 0, void 0, function* () {
332
+ const parent = yield this.isSingleChild(nodeUid, transaction);
333
+ if (parent && !this.breakOnMatched(parent, breakRemoveOn)) {
334
+ yield removeParent(parent.get('x-uid'));
335
+ }
336
+ else {
337
+ yield this.remove(nodeUid, { transaction });
338
+ }
339
+ });
340
+ yield removeParent(uid);
341
+ });
342
+ }
343
+ breakOnMatched(schemaInstance, breakRemoveOn) {
344
+ if (!breakRemoveOn) {
345
+ return false;
346
+ }
347
+ for (const key of Object.keys(breakRemoveOn)) {
348
+ const instanceValue = schemaInstance.get(key);
349
+ const breakRemoveOnValue = breakRemoveOn[key];
350
+ if (instanceValue !== breakRemoveOnValue) {
351
+ return false;
352
+ }
353
+ }
354
+ return true;
355
+ }
356
+ recursivelyRemoveIfNoChildren(options) {
357
+ return __awaiter(this, void 0, void 0, function* () {
358
+ const { uid, transaction, breakRemoveOn } = options;
359
+ const removeLeafNode = (nodeUid) => __awaiter(this, void 0, void 0, function* () {
360
+ const isLeafNode = yield this.isLeafNode(nodeUid, transaction);
361
+ if (isLeafNode) {
362
+ const { parentUid, schema } = yield this.findNodeSchemaWithParent(nodeUid, transaction);
363
+ if (this.breakOnMatched(schema, breakRemoveOn)) {
364
+ // break at here
365
+ return;
366
+ }
367
+ else {
368
+ // remove current node
369
+ yield this.remove(nodeUid, {
370
+ transaction,
371
+ });
372
+ // continue remove
373
+ yield removeLeafNode(parentUid);
374
+ }
375
+ }
376
+ });
377
+ yield removeLeafNode(uid);
378
+ });
379
+ }
380
+ remove(uid, options) {
381
+ return __awaiter(this, void 0, void 0, function* () {
382
+ let { transaction } = options;
383
+ if (options === null || options === void 0 ? void 0 : options.removeParentsIfNoChildren) {
384
+ yield this.removeEmptyParents({ transaction, uid, breakRemoveOn: options.breakRemoveOn });
385
+ return;
386
+ }
387
+ yield this.database.sequelize.query(this.sqlAdapter(`DELETE FROM ${this.uiSchemasTableName} WHERE "x-uid" IN (
388
+ SELECT descendant FROM ${this.uiSchemaTreePathTableName} WHERE ancestor = :uid
389
+ )`), {
390
+ replacements: {
391
+ uid,
392
+ },
393
+ transaction,
394
+ });
395
+ yield this.database.sequelize.query(` DELETE FROM ${this.uiSchemaTreePathTableName}
396
+ WHERE descendant IN (
397
+ select descendant FROM
398
+ (SELECT descendant
399
+ FROM ${this.uiSchemaTreePathTableName}
400
+ WHERE ancestor = :uid)as descendantTable) `, {
401
+ replacements: {
402
+ uid,
403
+ },
404
+ transaction,
405
+ });
406
+ });
407
+ }
408
+ insertBeside(targetUid, schema, side, options) {
409
+ return __awaiter(this, void 0, void 0, function* () {
410
+ const { transaction } = options;
411
+ const targetParent = yield this.findParentUid(targetUid, transaction);
412
+ const db = this.database;
413
+ const treeTable = this.uiSchemaTreePathTableName;
414
+ const typeQuery = yield db.sequelize.query(`SELECT type from ${treeTable} WHERE ancestor = :uid AND depth = 0;`, {
415
+ type: 'SELECT',
416
+ replacements: {
417
+ uid: targetUid,
418
+ },
419
+ transaction,
420
+ });
421
+ const nodes = UiSchemaRepository.schemaToSingleNodes(schema);
422
+ const rootNode = nodes[0];
423
+ rootNode.childOptions = {
424
+ parentUid: targetParent,
425
+ type: typeQuery[0]['type'],
426
+ position: {
427
+ type: side,
428
+ target: targetUid,
429
+ },
430
+ };
431
+ const insertedNodes = yield this.insertNodes(nodes, options);
432
+ return yield this.getJsonSchema(insertedNodes[0].get('x-uid'), {
433
+ transaction,
434
+ });
435
+ });
436
+ }
437
+ insertInner(targetUid, schema, position, options) {
438
+ return __awaiter(this, void 0, void 0, function* () {
439
+ const { transaction } = options;
440
+ const nodes = UiSchemaRepository.schemaToSingleNodes(schema);
441
+ const rootNode = nodes[0];
442
+ rootNode.childOptions = {
443
+ parentUid: targetUid,
444
+ type: lodash_1.default.get(schema, 'x-node-type', 'properties'),
445
+ position,
446
+ };
447
+ const insertedNodes = yield this.insertNodes(nodes, options);
448
+ return yield this.getJsonSchema(insertedNodes[0].get('x-uid'), {
449
+ transaction,
450
+ });
451
+ });
452
+ }
453
+ schemaExists(schema, options) {
454
+ return __awaiter(this, void 0, void 0, function* () {
455
+ if (lodash_1.default.isObject(schema) && !schema['x-uid']) {
456
+ return false;
457
+ }
458
+ const { transaction } = options;
459
+ const result = yield this.database.sequelize.query(this.sqlAdapter(`select "x-uid" from ${this.uiSchemasTableName} where "x-uid" = :uid`), {
460
+ type: 'SELECT',
461
+ replacements: {
462
+ uid: lodash_1.default.isString(schema) ? schema : schema['x-uid'],
463
+ },
464
+ transaction,
465
+ });
466
+ return result.length > 0;
467
+ });
468
+ }
469
+ insertAdjacent(position, target, schema, options) {
470
+ return __awaiter(this, void 0, void 0, function* () {
471
+ const { transaction } = options;
472
+ if (options.wrap) {
473
+ // insert wrap schema using insertNewSchema
474
+ const wrapSchemaNodes = yield this.insertNewSchema(options.wrap, {
475
+ transaction,
476
+ returnNode: true,
477
+ });
478
+ const lastWrapNode = wrapSchemaNodes[wrapSchemaNodes.length - 1];
479
+ // insert schema into wrap schema
480
+ yield this.insertAdjacent('afterBegin', lastWrapNode['x-uid'], schema, lodash_1.default.omit(options, 'wrap'));
481
+ schema = wrapSchemaNodes[0]['x-uid'];
482
+ options.removeParentsIfNoChildren = false;
483
+ }
484
+ else {
485
+ const schemaExists = yield this.schemaExists(schema, { transaction });
486
+ if (schemaExists) {
487
+ schema = lodash_1.default.isString(schema) ? schema : schema['x-uid'];
488
+ }
489
+ else {
490
+ const insertedSchema = yield this.insertNewSchema(schema, {
491
+ transaction,
492
+ returnNode: true,
493
+ });
494
+ schema = insertedSchema[0]['x-uid'];
495
+ }
496
+ }
497
+ return yield this[`insert${lodash_1.default.upperFirst(position)}`](target, schema, options);
498
+ });
499
+ }
500
+ insertAfterBegin(targetUid, schema, options) {
501
+ return __awaiter(this, void 0, void 0, function* () {
502
+ return yield this.insertInner(targetUid, schema, 'first', options);
503
+ });
504
+ }
505
+ insertBeforeEnd(targetUid, schema, options) {
506
+ return __awaiter(this, void 0, void 0, function* () {
507
+ return yield this.insertInner(targetUid, schema, 'last', options);
508
+ });
509
+ }
510
+ insertBeforeBegin(targetUid, schema, options) {
511
+ return __awaiter(this, void 0, void 0, function* () {
512
+ return yield this.insertBeside(targetUid, schema, 'before', options);
513
+ });
514
+ }
515
+ insertAfterEnd(targetUid, schema, options) {
516
+ return __awaiter(this, void 0, void 0, function* () {
517
+ return yield this.insertBeside(targetUid, schema, 'after', options);
518
+ });
519
+ }
520
+ insertNodes(nodes, options) {
521
+ return __awaiter(this, void 0, void 0, function* () {
522
+ const { transaction } = options;
523
+ const insertedNodes = [];
524
+ for (const node of nodes) {
525
+ insertedNodes.push(yield this.insertSingleNode(node, Object.assign(Object.assign({}, options), { transaction })));
526
+ }
527
+ return insertedNodes;
528
+ });
529
+ }
530
+ insert(schema, options) {
531
+ return __awaiter(this, void 0, void 0, function* () {
532
+ const nodes = UiSchemaRepository.schemaToSingleNodes(schema);
533
+ const insertedNodes = yield this.insertNodes(nodes, options);
534
+ return this.getJsonSchema(insertedNodes[0].get('x-uid'), {
535
+ transaction: options === null || options === void 0 ? void 0 : options.transaction,
536
+ });
537
+ });
538
+ }
539
+ insertNewSchema(schema, options) {
540
+ return __awaiter(this, void 0, void 0, function* () {
541
+ const { transaction } = options;
542
+ const nodes = UiSchemaRepository.schemaToSingleNodes(schema);
543
+ // insert schema fist
544
+ yield this.database.sequelize.query(this.sqlAdapter(`INSERT INTO ${this.uiSchemasTableName} ("x-uid", "name", "schema") VALUES ${nodes
545
+ .map((n) => '(?)')
546
+ .join(',')};`), {
547
+ replacements: lodash_1.default.cloneDeep(nodes).map((node) => {
548
+ const { uid, name } = this.prepareSingleNodeForInsert(node);
549
+ return [uid, name, JSON.stringify(node)];
550
+ }),
551
+ type: 'insert',
552
+ transaction,
553
+ });
554
+ const treePathData = lodash_1.default.cloneDeep(nodes).reduce((carry, item) => {
555
+ const { uid, childOptions, async } = this.prepareSingleNodeForInsert(item);
556
+ return [
557
+ ...carry,
558
+ // self reference
559
+ [uid, uid, 0, (childOptions === null || childOptions === void 0 ? void 0 : childOptions.type) || null, async, null],
560
+ // parent references
561
+ ...lodash_1.default.get(childOptions, 'parentPath', []).map((parentUid, index) => {
562
+ return [parentUid, uid, index + 1, null, null, childOptions.sort];
563
+ }),
564
+ ];
565
+ }, []);
566
+ // insert tree path
567
+ yield this.database.sequelize.query(this.sqlAdapter(`INSERT INTO ${this.uiSchemaTreePathTableName} (ancestor, descendant, depth, type, async, sort) VALUES ${treePathData.map((item) => '(?)').join(',')}`), {
568
+ replacements: treePathData,
569
+ type: 'insert',
570
+ transaction,
571
+ });
572
+ const rootNode = nodes[0];
573
+ if (rootNode['x-server-hooks']) {
574
+ const rootModel = yield this.findOne({ filter: { 'x-uid': rootNode['x-uid'] }, transaction });
575
+ yield this.database.emitAsync(`${this.collection.name}.afterCreateWithAssociations`, rootModel, options);
576
+ }
577
+ if (options === null || options === void 0 ? void 0 : options.returnNode) {
578
+ return nodes;
579
+ }
580
+ return this.getJsonSchema(nodes[0]['x-uid'], {
581
+ transaction,
582
+ });
583
+ });
584
+ }
585
+ insertSchemaRecord(name, uid, schema, transaction) {
586
+ return __awaiter(this, void 0, void 0, function* () {
587
+ const serverHooks = schema['x-server-hooks'] || [];
588
+ const node = yield this.create({
589
+ values: {
590
+ name,
591
+ ['x-uid']: uid,
592
+ schema,
593
+ serverHooks,
594
+ },
595
+ transaction,
596
+ context: {
597
+ disableInsertHook: true,
598
+ },
599
+ });
600
+ return node;
601
+ });
602
+ }
603
+ prepareSingleNodeForInsert(schema) {
604
+ const uid = schema['x-uid'];
605
+ const name = schema['name'];
606
+ const async = lodash_1.default.get(schema, 'x-async', false);
607
+ const childOptions = schema['childOptions'];
608
+ delete schema['x-uid'];
609
+ delete schema['x-async'];
610
+ delete schema['name'];
611
+ delete schema['childOptions'];
612
+ return { uid, name, async, childOptions };
613
+ }
614
+ insertSingleNode(schema, options) {
615
+ return __awaiter(this, void 0, void 0, function* () {
616
+ const { transaction } = options;
617
+ const db = this.database;
618
+ const { uid, name, async, childOptions } = this.prepareSingleNodeForInsert(schema);
619
+ let savedNode;
620
+ // check node exists or not
621
+ const existsNode = yield this.findOne({
622
+ filter: {
623
+ 'x-uid': uid,
624
+ },
625
+ transaction,
626
+ });
627
+ const treeTable = this.uiSchemaTreePathTableName;
628
+ if (existsNode) {
629
+ savedNode = existsNode;
630
+ }
631
+ else {
632
+ savedNode = yield this.insertSchemaRecord(name, uid, schema, transaction);
633
+ }
634
+ if (childOptions) {
635
+ const oldParentUid = yield this.findParentUid(uid, transaction);
636
+ const parentUid = childOptions.parentUid;
637
+ const childrenCount = yield this.childrenCount(uid, transaction);
638
+ const isTree = childrenCount > 0;
639
+ // if node is a tree root move tree to new path
640
+ if (isTree) {
641
+ yield this.clearAncestor(uid, { transaction });
642
+ // insert new tree path
643
+ yield db.sequelize.query(`INSERT INTO ${treeTable} (ancestor, descendant, depth)
644
+ SELECT supertree.ancestor, subtree.descendant, supertree.depth + subtree.depth + 1
645
+ FROM ${treeTable} AS supertree
646
+ CROSS JOIN ${treeTable} AS subtree
647
+ WHERE supertree.descendant = :parentUid
648
+ AND subtree.ancestor = :uid;`, {
649
+ type: 'INSERT',
650
+ replacements: {
651
+ uid,
652
+ parentUid,
653
+ },
654
+ transaction,
655
+ });
656
+ }
657
+ // update type
658
+ yield db.sequelize.query(`UPDATE ${treeTable} SET type = :type WHERE depth = 0 AND ancestor = :uid AND descendant = :uid`, {
659
+ type: 'update',
660
+ transaction,
661
+ replacements: {
662
+ type: childOptions.type,
663
+ uid,
664
+ },
665
+ });
666
+ if (!isTree) {
667
+ if (existsNode) {
668
+ // remove old path
669
+ yield db.sequelize.query(`DELETE FROM ${treeTable} WHERE descendant = :uid AND ancestor != descendant`, {
670
+ type: 'DELETE',
671
+ replacements: {
672
+ uid,
673
+ },
674
+ transaction,
675
+ });
676
+ }
677
+ // insert tree path
678
+ yield db.sequelize.query(`INSERT INTO ${treeTable} (ancestor, descendant, depth)
679
+ SELECT t.ancestor, :modelKey, depth + 1 FROM ${treeTable} AS t WHERE t.descendant = :modelParentKey `, {
680
+ type: 'INSERT',
681
+ transaction,
682
+ replacements: {
683
+ modelKey: savedNode.get('x-uid'),
684
+ modelParentKey: parentUid,
685
+ },
686
+ });
687
+ }
688
+ if (!existsNode) {
689
+ // insert type && async
690
+ yield db.sequelize.query(`INSERT INTO ${treeTable}(ancestor, descendant, depth, type, async) VALUES (:modelKey, :modelKey, 0, :type, :async )`, {
691
+ type: 'INSERT',
692
+ replacements: {
693
+ modelKey: savedNode.get('x-uid'),
694
+ type: childOptions.type,
695
+ async,
696
+ },
697
+ transaction,
698
+ });
699
+ }
700
+ const nodePosition = childOptions.position || 'last';
701
+ let sort;
702
+ // insert at first
703
+ if (nodePosition === 'first') {
704
+ sort = 1;
705
+ let updateSql = `UPDATE ${treeTable} as TreeTable
706
+ SET sort = TreeTable.sort + 1
707
+ FROM ${treeTable} as NodeInfo
708
+ WHERE NodeInfo.descendant = TreeTable.descendant and NodeInfo.depth = 0
709
+ AND TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and NodeInfo.type = :type`;
710
+ // Compatible with mysql
711
+ if (this.database.sequelize.getDialect() === 'mysql') {
712
+ updateSql = `UPDATE ${treeTable} as TreeTable
713
+ JOIN ${treeTable} as NodeInfo ON (NodeInfo.descendant = TreeTable.descendant and NodeInfo.depth = 0)
714
+ SET TreeTable.sort = TreeTable.sort + 1
715
+ WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and NodeInfo.type = :type`;
716
+ }
717
+ // move all child last index
718
+ yield db.sequelize.query(updateSql, {
719
+ replacements: {
720
+ ancestor: childOptions.parentUid,
721
+ type: childOptions.type,
722
+ },
723
+ transaction,
724
+ });
725
+ }
726
+ if (nodePosition === 'last') {
727
+ const maxSort = yield db.sequelize.query(`SELECT ${this.database.sequelize.getDialect() === 'postgres' ? 'coalesce' : 'ifnull'}(MAX(TreeTable.sort), 0) as maxsort FROM ${treeTable} as TreeTable
728
+ LEFT JOIN ${treeTable} as NodeInfo
729
+ ON NodeInfo.descendant = TreeTable.descendant and NodeInfo.depth = 0
730
+ WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and NodeInfo.type = :type`, {
731
+ type: 'SELECT',
732
+ replacements: {
733
+ ancestor: childOptions.parentUid,
734
+ type: childOptions.type,
735
+ },
736
+ transaction,
737
+ });
738
+ sort = parseInt(maxSort[0]['maxsort']) + 1;
739
+ }
740
+ if (lodash_1.default.isPlainObject(nodePosition)) {
741
+ const targetPosition = nodePosition;
742
+ const target = targetPosition.target;
743
+ const targetSort = yield db.sequelize.query(`SELECT TreeTable.sort as sort FROM ${treeTable} as TreeTable
744
+ LEFT JOIN ${treeTable} as NodeInfo
745
+ ON NodeInfo.descendant = TreeTable.descendant and NodeInfo.depth = 0 WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor AND TreeTable.descendant = :descendant and NodeInfo.type = :type`, {
746
+ type: 'SELECT',
747
+ replacements: {
748
+ ancestor: childOptions.parentUid,
749
+ descendant: target,
750
+ type: childOptions.type,
751
+ },
752
+ transaction,
753
+ });
754
+ sort = targetSort[0].sort;
755
+ if (targetPosition.type == 'after') {
756
+ sort += 1;
757
+ }
758
+ let updateSql = `UPDATE ${treeTable} as TreeTable
759
+ SET sort = TreeTable.sort + 1
760
+ FROM ${treeTable} as NodeInfo
761
+ WHERE NodeInfo.descendant = TreeTable.descendant
762
+ and NodeInfo.depth = 0
763
+ AND TreeTable.depth = 1
764
+ AND TreeTable.ancestor = :ancestor
765
+ and TreeTable.sort >= :sort
766
+ and NodeInfo.type = :type`;
767
+ if (this.database.sequelize.getDialect() === 'mysql') {
768
+ updateSql = `UPDATE ${treeTable} as TreeTable
769
+ JOIN ${treeTable} as NodeInfo ON (NodeInfo.descendant = TreeTable.descendant and NodeInfo.depth = 0)
770
+ SET TreeTable.sort = TreeTable.sort + 1
771
+ WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and TreeTable.sort >= :sort and NodeInfo.type = :type`;
772
+ }
773
+ yield db.sequelize.query(updateSql, {
774
+ replacements: {
775
+ ancestor: childOptions.parentUid,
776
+ sort,
777
+ type: childOptions.type,
778
+ },
779
+ transaction,
780
+ });
781
+ }
782
+ // update order
783
+ const updateSql = `UPDATE ${treeTable} SET sort = :sort WHERE depth = 1 AND ancestor = :ancestor AND descendant = :descendant`;
784
+ yield db.sequelize.query(updateSql, {
785
+ type: 'UPDATE',
786
+ replacements: {
787
+ ancestor: childOptions.parentUid,
788
+ sort,
789
+ descendant: uid,
790
+ },
791
+ transaction,
792
+ });
793
+ // move node to new parent
794
+ if (oldParentUid !== null && oldParentUid !== parentUid) {
795
+ yield this.database.emitAsync('uiSchemaMove', savedNode, {
796
+ transaction,
797
+ oldParentUid,
798
+ parentUid,
799
+ });
800
+ if (options.removeParentsIfNoChildren) {
801
+ yield this.recursivelyRemoveIfNoChildren({
802
+ transaction,
803
+ uid: oldParentUid,
804
+ breakRemoveOn: options.breakRemoveOn,
805
+ });
806
+ }
807
+ }
808
+ }
809
+ else {
810
+ // insert root node path
811
+ yield db.sequelize.query(`INSERT INTO ${treeTable}(ancestor, descendant, depth, async) VALUES (:modelKey, :modelKey, 0, :async )`, {
812
+ type: 'INSERT',
813
+ replacements: {
814
+ modelKey: savedNode.get('x-uid'),
815
+ async,
816
+ },
817
+ transaction,
818
+ });
819
+ }
820
+ return savedNode;
821
+ });
822
+ }
823
+ }
824
+ __decorate([
825
+ transaction()
826
+ ], UiSchemaRepository.prototype, "clearAncestor", null);
827
+ __decorate([
828
+ transaction()
829
+ ], UiSchemaRepository.prototype, "patch", null);
830
+ __decorate([
831
+ transaction()
832
+ ], UiSchemaRepository.prototype, "remove", null);
833
+ __decorate([
834
+ transaction()
835
+ ], UiSchemaRepository.prototype, "insertBeside", null);
836
+ __decorate([
837
+ transaction()
838
+ ], UiSchemaRepository.prototype, "insertInner", null);
839
+ __decorate([
840
+ transaction()
841
+ ], UiSchemaRepository.prototype, "insertAdjacent", null);
842
+ __decorate([
843
+ transaction()
844
+ ], UiSchemaRepository.prototype, "insertAfterBegin", null);
845
+ __decorate([
846
+ transaction()
847
+ ], UiSchemaRepository.prototype, "insertBeforeEnd", null);
848
+ __decorate([
849
+ transaction()
850
+ ], UiSchemaRepository.prototype, "insertBeforeBegin", null);
851
+ __decorate([
852
+ transaction()
853
+ ], UiSchemaRepository.prototype, "insertAfterEnd", null);
854
+ __decorate([
855
+ transaction()
856
+ ], UiSchemaRepository.prototype, "insertNodes", null);
857
+ __decorate([
858
+ transaction()
859
+ ], UiSchemaRepository.prototype, "insert", null);
860
+ __decorate([
861
+ transaction()
862
+ ], UiSchemaRepository.prototype, "insertNewSchema", null);
863
+ exports.UiSchemaRepository = UiSchemaRepository;
864
+ exports.default = UiSchemaRepository;
865
+ //# sourceMappingURL=repository.js.map