@nocobase/database 0.9.2-alpha.3 → 0.9.3-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/collection.js +4 -0
- package/lib/fields/field.js +1 -0
- package/lib/listeners/adjacency-list.d.ts +1 -2
- package/lib/listeners/adjacency-list.js +2 -71
- package/lib/listeners/index.js +0 -1
- package/lib/operators/array.js +7 -4
- package/lib/options-parser.js +10 -0
- package/lib/repository.js +5 -4
- package/lib/tree-repository/adjacency-list-repository.d.ts +9 -0
- package/lib/tree-repository/adjacency-list-repository.js +165 -0
- package/package.json +4 -4
- package/src/__tests__/collection.test.ts +19 -0
- package/src/__tests__/repository/find.test.ts +258 -1
- package/src/__tests__/tree.test.ts +266 -3
- package/src/collection.ts +6 -0
- package/src/fields/field.ts +4 -0
- package/src/listeners/adjacency-list.ts +0 -41
- package/src/listeners/index.ts +1 -2
- package/src/operators/array.ts +8 -4
- package/src/options-parser.ts +12 -0
- package/src/repository.ts +6 -4
- package/src/tree-repository/adjacency-list-repository.ts +159 -0
package/lib/collection.js
CHANGED
|
@@ -35,6 +35,7 @@ function _sequelize() {
|
|
|
35
35
|
var _model = require("./model");
|
|
36
36
|
var _repository = require("./repository");
|
|
37
37
|
var _utils = require("./utils");
|
|
38
|
+
var _adjacencyListRepository = require("./tree-repository/adjacency-list-repository");
|
|
38
39
|
const _excluded = ["name"],
|
|
39
40
|
_excluded2 = ["name"];
|
|
40
41
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -215,6 +216,9 @@ class Collection extends _events().EventEmitter {
|
|
|
215
216
|
if (typeof repository === 'string') {
|
|
216
217
|
repo = this.context.database.repositories.get(repository) || _repository.Repository;
|
|
217
218
|
}
|
|
219
|
+
if (this.options.tree == 'adjacency-list' || this.options.tree == 'adjacencyList') {
|
|
220
|
+
repo = _adjacencyListRepository.AdjacencyListRepository;
|
|
221
|
+
}
|
|
218
222
|
this.repository = new repo(this);
|
|
219
223
|
}
|
|
220
224
|
bindFieldEventListener() {
|
package/lib/fields/field.js
CHANGED
|
@@ -196,6 +196,7 @@ class Field {
|
|
|
196
196
|
}
|
|
197
197
|
unbind() {
|
|
198
198
|
const model = this.context.collection.model;
|
|
199
|
+
delete model.prototype[this.name];
|
|
199
200
|
model.removeAttribute(this.name);
|
|
200
201
|
if (this.options.index || this.options.unique) {
|
|
201
202
|
this.context.collection.removeIndex([this.name]);
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CollectionOptions } from '../collection';
|
|
2
2
|
export declare const beforeDefineAdjacencyListCollection: (options: CollectionOptions) => void;
|
|
3
|
-
export declare const afterDefineAdjacencyListCollection: (collection: Collection) => void;
|
|
@@ -3,25 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.beforeDefineAdjacencyListCollection =
|
|
7
|
-
function _lodash() {
|
|
8
|
-
const data = _interopRequireDefault(require("lodash"));
|
|
9
|
-
_lodash = function _lodash() {
|
|
10
|
-
return data;
|
|
11
|
-
};
|
|
12
|
-
return data;
|
|
13
|
-
}
|
|
14
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
16
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
17
|
-
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
18
|
-
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
19
|
-
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
20
|
-
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
21
|
-
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
22
|
-
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
23
|
-
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
24
|
-
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
6
|
+
exports.beforeDefineAdjacencyListCollection = void 0;
|
|
25
7
|
const beforeDefineAdjacencyListCollection = options => {
|
|
26
8
|
if (!options.tree) {
|
|
27
9
|
return;
|
|
@@ -37,55 +19,4 @@ const beforeDefineAdjacencyListCollection = options => {
|
|
|
37
19
|
}
|
|
38
20
|
});
|
|
39
21
|
};
|
|
40
|
-
exports.beforeDefineAdjacencyListCollection = beforeDefineAdjacencyListCollection;
|
|
41
|
-
const afterDefineAdjacencyListCollection = collection => {
|
|
42
|
-
if (!collection.options.tree) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
collection.model.afterFind( /*#__PURE__*/function () {
|
|
46
|
-
var _ref = _asyncToGenerator(function* (instances, options) {
|
|
47
|
-
var _collection$treeParen, _collection$treeParen2, _collection$treeChild, _collection$treeChild2;
|
|
48
|
-
if (!options.tree) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const foreignKey = (_collection$treeParen = (_collection$treeParen2 = collection.treeParentField) === null || _collection$treeParen2 === void 0 ? void 0 : _collection$treeParen2.foreignKey) !== null && _collection$treeParen !== void 0 ? _collection$treeParen : 'parentId';
|
|
52
|
-
const childrenKey = (_collection$treeChild = (_collection$treeChild2 = collection.treeChildrenField) === null || _collection$treeChild2 === void 0 ? void 0 : _collection$treeChild2.name) !== null && _collection$treeChild !== void 0 ? _collection$treeChild : 'children';
|
|
53
|
-
const arr = Array.isArray(instances) ? instances : [instances];
|
|
54
|
-
let index = 0;
|
|
55
|
-
var _iterator = _createForOfIteratorHelper(arr),
|
|
56
|
-
_step;
|
|
57
|
-
try {
|
|
58
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
59
|
-
const instance = _step.value;
|
|
60
|
-
const opts = _objectSpread({}, _lodash().default.pick(options, ['tree', 'fields', 'appends', 'except', 'sort']));
|
|
61
|
-
let __index = `${index++}`;
|
|
62
|
-
if (options.parentIndex) {
|
|
63
|
-
__index = `${options.parentIndex}.${__index}`;
|
|
64
|
-
}
|
|
65
|
-
instance.setDataValue('__index', __index);
|
|
66
|
-
const children = yield collection.repository.find(_objectSpread(_objectSpread({
|
|
67
|
-
filter: {
|
|
68
|
-
[foreignKey]: instance.id
|
|
69
|
-
},
|
|
70
|
-
transaction: options.transaction
|
|
71
|
-
}, opts), {}, {
|
|
72
|
-
// @ts-ignore
|
|
73
|
-
parentIndex: `${__index}.${childrenKey}`,
|
|
74
|
-
context: options.context
|
|
75
|
-
}));
|
|
76
|
-
if ((children === null || children === void 0 ? void 0 : children.length) > 0) {
|
|
77
|
-
instance.setDataValue(childrenKey, children.map(r => r.toJSON()));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
} catch (err) {
|
|
81
|
-
_iterator.e(err);
|
|
82
|
-
} finally {
|
|
83
|
-
_iterator.f();
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
return function (_x, _x2) {
|
|
87
|
-
return _ref.apply(this, arguments);
|
|
88
|
-
};
|
|
89
|
-
}());
|
|
90
|
-
};
|
|
91
|
-
exports.afterDefineAdjacencyListCollection = afterDefineAdjacencyListCollection;
|
|
22
|
+
exports.beforeDefineAdjacencyListCollection = beforeDefineAdjacencyListCollection;
|
package/lib/listeners/index.js
CHANGED
|
@@ -7,6 +7,5 @@ exports.registerBuiltInListeners = void 0;
|
|
|
7
7
|
var _adjacencyList = require("./adjacency-list");
|
|
8
8
|
const registerBuiltInListeners = db => {
|
|
9
9
|
db.on('beforeDefineCollection', _adjacencyList.beforeDefineAdjacencyListCollection);
|
|
10
|
-
db.on('afterDefineCollection', _adjacencyList.afterDefineAdjacencyListCollection);
|
|
11
10
|
};
|
|
12
11
|
exports.registerBuiltInListeners = registerBuiltInListeners;
|
package/lib/operators/array.js
CHANGED
|
@@ -20,6 +20,10 @@ const escape = (value, ctx) => {
|
|
|
20
20
|
const sequelize = ctx.db.sequelize;
|
|
21
21
|
return sequelize.escape(value);
|
|
22
22
|
};
|
|
23
|
+
const getQueryInterface = ctx => {
|
|
24
|
+
const sequelize = ctx.db.sequelize;
|
|
25
|
+
return sequelize.getQueryInterface();
|
|
26
|
+
};
|
|
23
27
|
const sqliteExistQuery = (value, ctx) => {
|
|
24
28
|
const fieldName = getFieldName(ctx);
|
|
25
29
|
const name = ctx.fullName === fieldName ? `"${ctx.model.name}"."${fieldName}"` : `"${fieldName}"`;
|
|
@@ -44,10 +48,9 @@ var _default = {
|
|
|
44
48
|
$match(value, ctx) {
|
|
45
49
|
const fieldName = getFieldName(ctx);
|
|
46
50
|
if ((0, _utils.isPg)(ctx)) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
};
|
|
51
|
+
const name = ctx.fullName === fieldName ? `"${ctx.model.name}"."${fieldName}"` : `"${fieldName}"`;
|
|
52
|
+
const queryValue = escape(JSON.stringify(value), ctx);
|
|
53
|
+
return _sequelize().Sequelize.literal(`${name} @> ${queryValue}::JSONB AND ${name} <@ ${queryValue}::JSONB`);
|
|
51
54
|
}
|
|
52
55
|
value = escape(JSON.stringify(value.sort()), ctx);
|
|
53
56
|
if ((0, _utils.isMySQL)(ctx)) {
|
package/lib/options-parser.js
CHANGED
|
@@ -252,6 +252,10 @@ class OptionsParser {
|
|
|
252
252
|
lastLevel = true;
|
|
253
253
|
}
|
|
254
254
|
if (appendFields.length == 2) {
|
|
255
|
+
const association = associations[appendFields[0]];
|
|
256
|
+
if (!association) {
|
|
257
|
+
throw new Error(`association ${appendFields[0]} in ${model.name} not found`);
|
|
258
|
+
}
|
|
255
259
|
const associationModel = associations[appendFields[0]].target;
|
|
256
260
|
if (associationModel.rawAttributes[appendFields[1]]) {
|
|
257
261
|
lastLevel = true;
|
|
@@ -298,6 +302,12 @@ class OptionsParser {
|
|
|
298
302
|
attributes
|
|
299
303
|
});
|
|
300
304
|
} else {
|
|
305
|
+
const existInclude = queryParams['include'][existIncludeIndex];
|
|
306
|
+
if (existInclude.attributes && Array.isArray(existInclude.attributes) && existInclude.attributes.length == 0) {
|
|
307
|
+
existInclude.attributes = {
|
|
308
|
+
include: []
|
|
309
|
+
};
|
|
310
|
+
}
|
|
301
311
|
setInclude(model.associations[queryParams['include'][existIncludeIndex].association].target, queryParams['include'][existIncludeIndex], appendFields.filter((_, index) => index !== 0).join('.'));
|
|
302
312
|
}
|
|
303
313
|
};
|
package/lib/repository.js
CHANGED
|
@@ -135,7 +135,7 @@ class Repository {
|
|
|
135
135
|
* find
|
|
136
136
|
* @param options
|
|
137
137
|
*/
|
|
138
|
-
find(options) {
|
|
138
|
+
find(options = {}) {
|
|
139
139
|
var _this2 = this;
|
|
140
140
|
return _asyncToGenerator(function* () {
|
|
141
141
|
const model = _this2.collection.model;
|
|
@@ -147,6 +147,7 @@ class Repository {
|
|
|
147
147
|
if (opts.include && opts.include.length > 0) {
|
|
148
148
|
// @ts-ignore
|
|
149
149
|
const primaryKeyField = model.primaryKeyField || model.primaryKeyAttribute;
|
|
150
|
+
// find all ids
|
|
150
151
|
const ids = (yield model.findAll(_objectSpread(_objectSpread({}, opts), {}, {
|
|
151
152
|
includeIgnoreAttributes: false,
|
|
152
153
|
attributes: [primaryKeyField],
|
|
@@ -165,6 +166,7 @@ class Repository {
|
|
|
165
166
|
if (ids.length == 0) {
|
|
166
167
|
return [];
|
|
167
168
|
}
|
|
169
|
+
// find template model
|
|
168
170
|
const templateModel = yield model.findOne(_objectSpread(_objectSpread({}, opts), {}, {
|
|
169
171
|
includeIgnoreAttributes: false,
|
|
170
172
|
attributes: [primaryKeyField],
|
|
@@ -180,7 +182,7 @@ class Repository {
|
|
|
180
182
|
};
|
|
181
183
|
rows = yield (0, _utils.handleAppendsQuery)({
|
|
182
184
|
queryPromises: opts.include.map(include => {
|
|
183
|
-
const options = _objectSpread(_objectSpread({}, (0, _lodash().omit)(opts, ['limit', 'offset'])), {}, {
|
|
185
|
+
const options = _objectSpread(_objectSpread({}, (0, _lodash().omit)(opts, ['limit', 'offset', 'filter'])), {}, {
|
|
184
186
|
include: include,
|
|
185
187
|
where,
|
|
186
188
|
transaction
|
|
@@ -214,9 +216,8 @@ class Repository {
|
|
|
214
216
|
findAndCount(options) {
|
|
215
217
|
var _this3 = this;
|
|
216
218
|
return _asyncToGenerator(function* () {
|
|
217
|
-
const transaction = yield _this3.getTransaction(options);
|
|
218
219
|
options = _objectSpread(_objectSpread({}, options), {}, {
|
|
219
|
-
transaction
|
|
220
|
+
transaction: yield _this3.getTransaction(options)
|
|
220
221
|
});
|
|
221
222
|
const count = yield _this3.count(options);
|
|
222
223
|
const results = count ? yield _this3.find(options) : [];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FindOptions, Repository } from '../repository';
|
|
2
|
+
export declare class AdjacencyListRepository extends Repository {
|
|
3
|
+
update(options: any): Promise<any>;
|
|
4
|
+
find(options?: FindOptions & {
|
|
5
|
+
addIndex?: boolean;
|
|
6
|
+
}): Promise<any>;
|
|
7
|
+
private addIndex;
|
|
8
|
+
private querySQL;
|
|
9
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.AdjacencyListRepository = void 0;
|
|
7
|
+
var _repository = require("../repository");
|
|
8
|
+
function _lodash() {
|
|
9
|
+
const data = _interopRequireDefault(require("lodash"));
|
|
10
|
+
_lodash = function _lodash() {
|
|
11
|
+
return data;
|
|
12
|
+
};
|
|
13
|
+
return data;
|
|
14
|
+
}
|
|
15
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
17
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
18
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
19
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
20
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
21
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
22
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
23
|
+
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
24
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
25
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
26
|
+
class AdjacencyListRepository extends _repository.Repository {
|
|
27
|
+
update(options) {
|
|
28
|
+
var _superprop_getUpdate = () => super.update,
|
|
29
|
+
_this = this;
|
|
30
|
+
return _asyncToGenerator(function* () {
|
|
31
|
+
return _superprop_getUpdate().call(_this, _objectSpread(_objectSpread({}, options || {}), {}, {
|
|
32
|
+
addIndex: false
|
|
33
|
+
}));
|
|
34
|
+
})();
|
|
35
|
+
}
|
|
36
|
+
find(options = {}) {
|
|
37
|
+
var _superprop_getFind = () => super.find,
|
|
38
|
+
_this2 = this;
|
|
39
|
+
return _asyncToGenerator(function* () {
|
|
40
|
+
var _collection$treeChild, _collection$treeChild2;
|
|
41
|
+
if (options.raw || !options.tree) {
|
|
42
|
+
return yield _superprop_getFind().call(_this2, options);
|
|
43
|
+
}
|
|
44
|
+
const collection = _this2.collection;
|
|
45
|
+
const primaryKey = collection.model.primaryKeyAttribute;
|
|
46
|
+
if (options.fields && !options.fields.includes(primaryKey)) {
|
|
47
|
+
options.fields.push(primaryKey);
|
|
48
|
+
}
|
|
49
|
+
const parentNodes = yield _superprop_getFind().call(_this2, options);
|
|
50
|
+
if (parentNodes.length === 0) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
const treeParentField = collection.treeParentField;
|
|
54
|
+
const foreignKey = treeParentField.options.foreignKey;
|
|
55
|
+
const childrenKey = (_collection$treeChild = (_collection$treeChild2 = collection.treeChildrenField) === null || _collection$treeChild2 === void 0 ? void 0 : _collection$treeChild2.name) !== null && _collection$treeChild !== void 0 ? _collection$treeChild : 'children';
|
|
56
|
+
const parentIds = parentNodes.map(node => node[primaryKey]);
|
|
57
|
+
if (parentIds.length == 0) {
|
|
58
|
+
_this2.database.logger.warn('parentIds is empty');
|
|
59
|
+
return parentNodes;
|
|
60
|
+
}
|
|
61
|
+
const sql = _this2.querySQL(parentIds, collection);
|
|
62
|
+
const childNodes = yield _this2.database.sequelize.query(sql, {
|
|
63
|
+
type: 'SELECT',
|
|
64
|
+
transaction: options.transaction
|
|
65
|
+
});
|
|
66
|
+
const childIds = childNodes.map(node => node[primaryKey]);
|
|
67
|
+
const findChildrenOptions = _objectSpread(_objectSpread({}, _lodash().default.omit(options, ['limit', 'offset', 'filterByTk'])), {}, {
|
|
68
|
+
filter: {
|
|
69
|
+
[primaryKey]: childIds
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
if (findChildrenOptions.fields) {
|
|
73
|
+
[primaryKey, foreignKey].forEach(field => {
|
|
74
|
+
if (!findChildrenOptions.fields.includes(field)) {
|
|
75
|
+
findChildrenOptions.fields.push(field);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
const childInstances = yield _superprop_getFind().call(_this2, findChildrenOptions);
|
|
80
|
+
const nodeMap = {};
|
|
81
|
+
childInstances.forEach(node => {
|
|
82
|
+
if (!nodeMap[`${node[foreignKey]}`]) {
|
|
83
|
+
nodeMap[`${node[foreignKey]}`] = [];
|
|
84
|
+
}
|
|
85
|
+
nodeMap[`${node[foreignKey]}`].push(node);
|
|
86
|
+
});
|
|
87
|
+
function buildTree(parentId) {
|
|
88
|
+
const children = nodeMap[parentId];
|
|
89
|
+
if (!children) {
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
return children.map(child => {
|
|
93
|
+
const childrenValues = buildTree(child.id);
|
|
94
|
+
if (childrenValues.length > 0) {
|
|
95
|
+
child.setDataValue(childrenKey, childrenValues);
|
|
96
|
+
}
|
|
97
|
+
return child;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
var _iterator = _createForOfIteratorHelper(parentNodes),
|
|
101
|
+
_step;
|
|
102
|
+
try {
|
|
103
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
104
|
+
const parent = _step.value;
|
|
105
|
+
const parentId = parent[primaryKey];
|
|
106
|
+
const children = buildTree(parentId);
|
|
107
|
+
if (children.length > 0) {
|
|
108
|
+
parent.setDataValue(childrenKey, children);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch (err) {
|
|
112
|
+
_iterator.e(err);
|
|
113
|
+
} finally {
|
|
114
|
+
_iterator.f();
|
|
115
|
+
}
|
|
116
|
+
_this2.addIndex(parentNodes, childrenKey, options);
|
|
117
|
+
return parentNodes;
|
|
118
|
+
})();
|
|
119
|
+
}
|
|
120
|
+
addIndex(treeArray, childrenKey, options) {
|
|
121
|
+
function traverse(node, index) {
|
|
122
|
+
// patch for sequelize toJSON
|
|
123
|
+
if (node._options.includeNames && !node._options.includeNames.includes(childrenKey)) {
|
|
124
|
+
node._options.includeNames.push(childrenKey);
|
|
125
|
+
}
|
|
126
|
+
if (options.addIndex !== false) {
|
|
127
|
+
node.setDataValue('__index', `${index}`);
|
|
128
|
+
}
|
|
129
|
+
const children = node.getDataValue(childrenKey);
|
|
130
|
+
if (children && children.length === 0) {
|
|
131
|
+
node.setDataValue(childrenKey, undefined);
|
|
132
|
+
}
|
|
133
|
+
if (children && children.length > 0) {
|
|
134
|
+
children.forEach((child, i) => {
|
|
135
|
+
traverse(child, `${index}.${childrenKey}.${i}`);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
treeArray.forEach((tree, i) => {
|
|
140
|
+
traverse(tree, i);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
querySQL(rootIds, collection) {
|
|
144
|
+
const treeParentField = collection.treeParentField;
|
|
145
|
+
const foreignKey = treeParentField.options.foreignKey;
|
|
146
|
+
const foreignKeyField = collection.model.rawAttributes[foreignKey].field;
|
|
147
|
+
const primaryKey = collection.model.primaryKeyAttribute;
|
|
148
|
+
const queryInterface = this.database.sequelize.getQueryInterface();
|
|
149
|
+
const q = queryInterface.quoteIdentifier.bind(queryInterface);
|
|
150
|
+
return `
|
|
151
|
+
WITH RECURSIVE cte AS (
|
|
152
|
+
SELECT ${q(primaryKey)}, ${q(foreignKeyField)}, 1 AS level
|
|
153
|
+
FROM ${collection.quotedTableName()}
|
|
154
|
+
WHERE ${q(foreignKeyField)} IN (${rootIds.join(',')})
|
|
155
|
+
UNION ALL
|
|
156
|
+
SELECT t.${q(primaryKey)}, t.${q(foreignKeyField)}, cte.level + 1 AS level
|
|
157
|
+
FROM ${collection.quotedTableName()} t
|
|
158
|
+
JOIN cte ON t.${q(foreignKeyField)} = cte.${q(primaryKey)}
|
|
159
|
+
)
|
|
160
|
+
SELECT ${q(primaryKey)}, ${q(foreignKeyField)} as ${q(foreignKey)}, level
|
|
161
|
+
FROM cte
|
|
162
|
+
`;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.AdjacencyListRepository = AdjacencyListRepository;
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/database",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3-alpha.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@nocobase/logger": "0.9.
|
|
10
|
-
"@nocobase/utils": "0.9.
|
|
9
|
+
"@nocobase/logger": "0.9.3-alpha.1",
|
|
10
|
+
"@nocobase/utils": "0.9.3-alpha.1",
|
|
11
11
|
"async-mutex": "^0.3.2",
|
|
12
12
|
"cron-parser": "4.4.0",
|
|
13
13
|
"deepmerge": "^4.2.2",
|
|
@@ -28,5 +28,5 @@
|
|
|
28
28
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
29
29
|
"directory": "packages/database"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "24979bc561537c0b84469c161eeef1a6de4c4684"
|
|
32
32
|
}
|
|
@@ -17,6 +17,25 @@ describe('collection', () => {
|
|
|
17
17
|
await db.close();
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
+
it('should remove sequelize model prototype methods after field remove', async () => {
|
|
21
|
+
db.collection({
|
|
22
|
+
name: 'tags',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const UserCollection = db.collection({
|
|
26
|
+
name: 'users',
|
|
27
|
+
fields: [{ type: 'belongsToMany', name: 'tags' }],
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
console.log(Object.getOwnPropertyNames(UserCollection.model.prototype));
|
|
31
|
+
|
|
32
|
+
await UserCollection.removeField('tags');
|
|
33
|
+
|
|
34
|
+
console.log(Object.getOwnPropertyNames(UserCollection.model.prototype));
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
expect(UserCollection.model.prototype.getTags).toBeUndefined();
|
|
37
|
+
});
|
|
38
|
+
|
|
20
39
|
it('should not throw error when create empty collection in sqlite and mysql', async () => {
|
|
21
40
|
if (!db.inDialect('sqlite', 'mysql')) {
|
|
22
41
|
return;
|