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