@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 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() {
@@ -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 { Collection, CollectionOptions } from '../collection';
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 = exports.afterDefineAdjacencyListCollection = void 0;
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;
@@ -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;
@@ -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
- return {
48
- [_sequelize().Op.contained]: value,
49
- [_sequelize().Op.contains]: value
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)) {
@@ -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.2-alpha.3",
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.2-alpha.3",
10
- "@nocobase/utils": "0.9.2-alpha.3",
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": "b6b5f9372202d942c97d2d90a4197e060db05124"
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;