@nocobase/database 0.9.1-alpha.2 → 0.9.2-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.
Files changed (168) hide show
  1. package/lib/collection-group-manager.d.ts +13 -0
  2. package/lib/collection-group-manager.js +91 -0
  3. package/lib/collection-importer.js +0 -24
  4. package/lib/collection.d.ts +24 -3
  5. package/lib/collection.js +176 -236
  6. package/lib/database-utils/index.js +3 -15
  7. package/lib/database.d.ts +3 -0
  8. package/lib/database.js +160 -298
  9. package/lib/decorators/must-have-filter-decorator.js +0 -7
  10. package/lib/decorators/transaction-decorator.js +5 -18
  11. package/lib/errors/identifier-error.js +0 -3
  12. package/lib/features/ReferencesMap.js +1 -14
  13. package/lib/features/referential-integrity-check.js +7 -21
  14. package/lib/field-repository/array-field-repository.js +5 -45
  15. package/lib/fields/array-field.js +0 -13
  16. package/lib/fields/belongs-to-field.js +24 -50
  17. package/lib/fields/belongs-to-many-field.js +23 -47
  18. package/lib/fields/boolean-field.js +0 -7
  19. package/lib/fields/context-field.js +2 -23
  20. package/lib/fields/date-field.d.ts +4 -0
  21. package/lib/fields/date-field.js +15 -7
  22. package/lib/fields/field.js +32 -85
  23. package/lib/fields/has-many-field.js +16 -49
  24. package/lib/fields/has-one-field.js +18 -52
  25. package/lib/fields/index.js +0 -44
  26. package/lib/fields/json-field.js +0 -12
  27. package/lib/fields/number-field.js +0 -23
  28. package/lib/fields/password-field.js +8 -35
  29. package/lib/fields/radio-field.js +0 -18
  30. package/lib/fields/relation-field.js +4 -16
  31. package/lib/fields/set-field.js +0 -8
  32. package/lib/fields/sort-field.js +84 -73
  33. package/lib/fields/string-field.js +0 -7
  34. package/lib/fields/text-field.js +0 -7
  35. package/lib/fields/time-field.js +0 -7
  36. package/lib/fields/uid-field.js +4 -22
  37. package/lib/fields/uuid-field.js +3 -12
  38. package/lib/fields/virtual-field.js +0 -7
  39. package/lib/filter-match.js +7 -22
  40. package/lib/filter-parser.js +37 -101
  41. package/lib/index.d.ts +3 -0
  42. package/lib/index.js +36 -42
  43. package/lib/inherited-collection.js +15 -62
  44. package/lib/inherited-map.js +7 -48
  45. package/lib/listeners/adjacency-list.d.ts +3 -0
  46. package/lib/listeners/adjacency-list.js +91 -0
  47. package/lib/listeners/index.d.ts +2 -0
  48. package/lib/listeners/index.js +12 -0
  49. package/lib/magic-attribute-model.js +58 -114
  50. package/lib/migration.js +7 -28
  51. package/lib/mock-database.d.ts +4 -4
  52. package/lib/mock-database.js +15 -18
  53. package/lib/model-hook.js +4 -35
  54. package/lib/model.js +12 -54
  55. package/lib/operators/array.js +2 -32
  56. package/lib/operators/association.js +0 -6
  57. package/lib/operators/boolean.js +0 -6
  58. package/lib/operators/child-collection.d.ts +2 -0
  59. package/lib/operators/child-collection.js +32 -0
  60. package/lib/operators/date.js +123 -60
  61. package/lib/operators/empty.js +3 -32
  62. package/lib/operators/eq.d.ts +2 -0
  63. package/lib/operators/eq.js +26 -0
  64. package/lib/operators/index.js +4 -7
  65. package/lib/operators/ne.js +5 -5
  66. package/lib/operators/notIn.js +0 -5
  67. package/lib/operators/string.js +0 -11
  68. package/lib/operators/utils.js +0 -6
  69. package/lib/options-parser.d.ts +1 -1
  70. package/lib/options-parser.js +47 -107
  71. package/lib/playground.js +0 -4
  72. package/lib/query-interface/mysql-query-interface.d.ts +11 -0
  73. package/lib/query-interface/mysql-query-interface.js +59 -10
  74. package/lib/query-interface/postgres-query-interface.d.ts +8 -0
  75. package/lib/query-interface/postgres-query-interface.js +70 -12
  76. package/lib/query-interface/query-interface-builder.js +0 -5
  77. package/lib/query-interface/query-interface.d.ts +12 -0
  78. package/lib/query-interface/query-interface.js +33 -3
  79. package/lib/query-interface/sqlite-query-interface.d.ts +11 -0
  80. package/lib/query-interface/sqlite-query-interface.js +61 -10
  81. package/lib/relation-repository/belongs-to-many-repository.js +21 -78
  82. package/lib/relation-repository/belongs-to-repository.js +0 -3
  83. package/lib/relation-repository/hasmany-repository.js +8 -44
  84. package/lib/relation-repository/hasone-repository.js +0 -3
  85. package/lib/relation-repository/multiple-relation-repository.js +14 -68
  86. package/lib/relation-repository/relation-repository.js +5 -42
  87. package/lib/relation-repository/single-relation-repository.js +5 -43
  88. package/lib/repository.d.ts +1 -0
  89. package/lib/repository.js +36 -182
  90. package/lib/sql-parser/index.js +10527 -0
  91. package/lib/sql-parser/sql.pegjs +1297 -0
  92. package/lib/sync-runner.js +19 -54
  93. package/lib/update-associations.js +58 -157
  94. package/lib/update-guard.js +10 -49
  95. package/lib/utils.js +6 -54
  96. package/lib/value-parsers/array-value-parser.js +3 -21
  97. package/lib/value-parsers/base-value-parser.js +0 -13
  98. package/lib/value-parsers/boolean-value-parser.js +4 -10
  99. package/lib/value-parsers/date-value-parser.js +0 -23
  100. package/lib/value-parsers/index.js +0 -10
  101. package/lib/value-parsers/json-value-parser.js +0 -7
  102. package/lib/value-parsers/number-value-parser.js +0 -9
  103. package/lib/value-parsers/string-value-parser.js +3 -20
  104. package/lib/value-parsers/to-many-value-parser.js +1 -42
  105. package/lib/value-parsers/to-one-value-parser.js +0 -14
  106. package/lib/view/field-type-map.d.ts +47 -0
  107. package/lib/view/field-type-map.js +56 -0
  108. package/lib/view/view-inference.d.ts +31 -0
  109. package/lib/view/view-inference.js +92 -0
  110. package/lib/view-collection.d.ts +6 -0
  111. package/lib/view-collection.js +24 -0
  112. package/package.json +4 -4
  113. package/src/__tests__/collection.test.ts +44 -0
  114. package/src/__tests__/fields/date.test.ts +75 -0
  115. package/src/__tests__/fields/sort-field.test.ts +100 -0
  116. package/src/__tests__/filter.test.ts +3 -3
  117. package/src/__tests__/group.test.ts +50 -0
  118. package/src/__tests__/inhertits/collection-inherits.test.ts +114 -0
  119. package/src/__tests__/operator/date-operator.test.ts +244 -98
  120. package/src/__tests__/operator/eq.test.ts +76 -0
  121. package/src/__tests__/operator/ne.test.ts +19 -1
  122. package/src/__tests__/relation-repository/belongs-to-many-repository.test.ts +82 -0
  123. package/src/__tests__/repository/find.test.ts +33 -0
  124. package/src/__tests__/repository.test.ts +88 -0
  125. package/src/__tests__/sql-parser.test.ts +13 -0
  126. package/src/__tests__/tree.test.ts +217 -0
  127. package/src/__tests__/view/list-view.test.ts +34 -0
  128. package/src/__tests__/view/view-collection.test.ts +199 -0
  129. package/src/__tests__/view/view-inference.test.ts +145 -0
  130. package/src/__tests__/view/view-repository.test.ts +67 -0
  131. package/src/collection-group-manager.ts +94 -0
  132. package/src/collection.ts +108 -14
  133. package/src/database-utils/index.ts +1 -0
  134. package/src/database.ts +79 -12
  135. package/src/features/ReferencesMap.ts +3 -2
  136. package/src/fields/belongs-to-many-field.ts +15 -2
  137. package/src/fields/date-field.ts +18 -0
  138. package/src/fields/field.ts +16 -8
  139. package/src/fields/json-field.ts +1 -0
  140. package/src/fields/sort-field.ts +90 -29
  141. package/src/filter-parser.ts +1 -0
  142. package/src/index.ts +3 -1
  143. package/src/listeners/adjacency-list.ts +60 -0
  144. package/src/listeners/index.ts +7 -0
  145. package/src/mock-database.ts +14 -2
  146. package/src/model.ts +4 -0
  147. package/src/operators/child-collection.ts +24 -0
  148. package/src/operators/date.ts +108 -24
  149. package/src/operators/eq.ts +14 -0
  150. package/src/operators/index.ts +2 -0
  151. package/src/operators/ne.ts +12 -7
  152. package/src/options-parser.ts +25 -11
  153. package/src/query-interface/mysql-query-interface.ts +53 -1
  154. package/src/query-interface/postgres-query-interface.ts +84 -3
  155. package/src/query-interface/query-interface.ts +31 -0
  156. package/src/query-interface/sqlite-query-interface.ts +62 -1
  157. package/src/relation-repository/belongs-to-many-repository.ts +20 -1
  158. package/src/relation-repository/hasmany-repository.ts +5 -3
  159. package/src/relation-repository/multiple-relation-repository.ts +9 -1
  160. package/src/repository.ts +6 -13
  161. package/src/sql-parser/index.js +10698 -0
  162. package/src/sql-parser/readme.md +2 -0
  163. package/src/sql-parser/sql.pegjs +1297 -0
  164. package/src/sync-runner.ts +13 -15
  165. package/src/update-associations.ts +26 -22
  166. package/src/view/field-type-map.ts +56 -0
  167. package/src/view/view-inference.ts +106 -0
  168. package/src/view-collection.ts +21 -0
@@ -4,35 +4,24 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.OptionsParser = void 0;
7
-
8
7
  function _sequelize() {
9
8
  const data = require("sequelize");
10
-
11
9
  _sequelize = function _sequelize() {
12
10
  return data;
13
11
  };
14
-
15
12
  return data;
16
13
  }
17
-
18
14
  var _filterParser = _interopRequireDefault(require("./filter-parser"));
19
-
20
15
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
-
22
16
  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; }
23
-
24
17
  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; }
25
-
26
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
27
-
18
+ 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; }
19
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
20
+ 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); }
28
21
  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; } } }; }
29
-
30
22
  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); }
31
-
32
23
  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; }
33
-
34
24
  const debug = require('debug')('noco-database');
35
-
36
25
  class OptionsParser {
37
26
  constructor(options, context) {
38
27
  this.options = void 0;
@@ -54,20 +43,15 @@ class OptionsParser {
54
43
  });
55
44
  this.context = context;
56
45
  }
57
-
58
46
  isAssociation(key) {
59
47
  return this.model.associations[key] !== undefined;
60
48
  }
61
-
62
49
  isAssociationPath(path) {
63
50
  return this.isAssociation(path.split('.')[0]);
64
51
  }
65
-
66
52
  toSequelizeParams() {
67
53
  var _this$options;
68
-
69
54
  const queryParams = this.filterParser.toSequelizeParams();
70
-
71
55
  if ((_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.filterByTk) {
72
56
  queryParams.where = {
73
57
  [_sequelize().Op.and]: [queryParams.where, {
@@ -75,7 +59,6 @@ class OptionsParser {
75
59
  }]
76
60
  };
77
61
  }
78
-
79
62
  return this.parseSort(this.parseFields(queryParams));
80
63
  }
81
64
  /**
@@ -83,36 +66,26 @@ class OptionsParser {
83
66
  * @param filterParams
84
67
  * @protected
85
68
  */
86
-
87
-
88
69
  parseSort(filterParams) {
89
70
  var _this$options2;
90
-
91
71
  let sort = ((_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.sort) || [];
92
-
93
72
  if (typeof sort === 'string') {
94
73
  sort = sort.split(',');
95
74
  }
96
-
97
75
  const orderParams = [];
98
-
99
76
  var _iterator = _createForOfIteratorHelper(sort),
100
- _step;
101
-
77
+ _step;
102
78
  try {
103
79
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
104
80
  const sortKey = _step.value;
105
81
  let direction = sortKey.startsWith('-') ? 'DESC' : 'ASC';
106
82
  let sortField = sortKey.replace('-', '').split('.');
107
-
108
83
  if (this.database.inDialect('postgres', 'sqlite')) {
109
84
  direction = `${direction} NULLS LAST`;
110
- } // handle sort by association
111
-
112
-
85
+ }
86
+ // handle sort by association
113
87
  if (sortField.length > 1) {
114
88
  let associationModel = this.model;
115
-
116
89
  for (let i = 0; i < sortField.length - 1; i++) {
117
90
  const associationKey = sortField[i];
118
91
  sortField[i] = associationModel.associations[associationKey].target;
@@ -122,13 +95,10 @@ class OptionsParser {
122
95
  const rawField = this.model.rawAttributes[sortField[0]];
123
96
  sortField[0] = (rawField === null || rawField === void 0 ? void 0 : rawField.field) || sortField[0];
124
97
  }
125
-
126
98
  sortField.push(direction);
127
-
128
99
  if (this.database.inDialect('mysql')) {
129
100
  orderParams.push([_sequelize().Sequelize.fn('ISNULL', _sequelize().Sequelize.col(`${this.model.name}.${sortField[0]}`))]);
130
101
  }
131
-
132
102
  orderParams.push(sortField);
133
103
  }
134
104
  } catch (err) {
@@ -136,56 +106,54 @@ class OptionsParser {
136
106
  } finally {
137
107
  _iterator.f();
138
108
  }
139
-
140
109
  if (orderParams.length > 0) {
141
110
  return _objectSpread({
142
111
  order: orderParams
143
112
  }, filterParams);
144
113
  }
145
-
146
114
  return filterParams;
147
115
  }
148
-
149
- inheritFromSubQuery() {
150
- return [_sequelize().Sequelize.literal(`(select relname from pg_class where pg_class.oid = "${this.collection.name}".tableoid)`), '__tableName'];
116
+ inheritFromSubQuery(include) {
117
+ include.push([_sequelize().Sequelize.literal(`(select relname from pg_class where pg_class.oid = "${this.collection.name}".tableoid)`), '__tableName']);
118
+ include.push([_sequelize().Sequelize.literal(`
119
+ (SELECT n.nspname
120
+ FROM pg_class c
121
+ JOIN pg_namespace n ON n.oid = c.relnamespace
122
+ WHERE c.oid = "${this.collection.name}".tableoid)
123
+ `), '__schemaName']);
151
124
  }
152
-
153
125
  parseFields(filterParams) {
154
- var _this$options3, _this$options4, _this$options5;
155
-
126
+ var _this$options3, _this$options4, _this$options5, _this$options6;
156
127
  const appends = ((_this$options3 = this.options) === null || _this$options3 === void 0 ? void 0 : _this$options3.appends) || [];
157
128
  const except = [];
129
+ if ((_this$options4 = this.options) === null || _this$options4 === void 0 ? void 0 : _this$options4.attributes) {
130
+ return {
131
+ attributes: this.options.attributes
132
+ };
133
+ }
158
134
  let attributes = {
159
135
  include: [],
160
136
  exclude: []
161
137
  }; // out put all fields by default
162
-
163
138
  if (this.collection.isParent()) {
164
- attributes.include.push(this.inheritFromSubQuery());
139
+ this.inheritFromSubQuery(attributes.include);
165
140
  }
166
-
167
- if ((_this$options4 = this.options) === null || _this$options4 === void 0 ? void 0 : _this$options4.fields) {
141
+ if ((_this$options5 = this.options) === null || _this$options5 === void 0 ? void 0 : _this$options5.fields) {
142
+ attributes = [];
143
+ if (this.collection.isParent()) {
144
+ this.inheritFromSubQuery(attributes);
145
+ }
168
146
  // 将fields拆分为 attributes 和 appends
169
147
  var _iterator2 = _createForOfIteratorHelper(this.options.fields),
170
- _step2;
171
-
148
+ _step2;
172
149
  try {
173
150
  for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
174
151
  const field = _step2.value;
175
-
176
152
  if (this.isAssociationPath(field)) {
177
153
  // field is association field
178
154
  appends.push(field);
179
155
  } else {
180
156
  // field is model attribute, change attributes to array type
181
- if (!Array.isArray(attributes)) {
182
- attributes = [];
183
-
184
- if (this.collection.isParent()) {
185
- attributes.push(this.inheritFromSubQuery());
186
- }
187
- }
188
-
189
157
  attributes.push(field);
190
158
  }
191
159
  }
@@ -195,15 +163,12 @@ class OptionsParser {
195
163
  _iterator2.f();
196
164
  }
197
165
  }
198
-
199
- if ((_this$options5 = this.options) === null || _this$options5 === void 0 ? void 0 : _this$options5.except) {
166
+ if ((_this$options6 = this.options) === null || _this$options6 === void 0 ? void 0 : _this$options6.except) {
200
167
  var _iterator3 = _createForOfIteratorHelper(this.options.except),
201
- _step3;
202
-
168
+ _step3;
203
169
  try {
204
170
  for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
205
171
  const exceptKey = _step3.value;
206
-
207
172
  if (this.isAssociationPath(exceptKey)) {
208
173
  // except association field
209
174
  except.push(exceptKey);
@@ -219,15 +184,12 @@ class OptionsParser {
219
184
  _iterator3.f();
220
185
  }
221
186
  }
222
-
223
187
  return _objectSpread({
224
188
  attributes
225
189
  }, this.parseExcept(except, this.parseAppends(appends, filterParams)));
226
190
  }
227
-
228
191
  parseExcept(except, filterParams) {
229
192
  if (!except) return filterParams;
230
-
231
193
  const setExcept = (queryParams, except) => {
232
194
  // split exceptKey to path form
233
195
  // posts.comments.content => ['posts', 'comments', 'content']
@@ -236,12 +198,10 @@ class OptionsParser {
236
198
  const association = exceptPath[0];
237
199
  const lastLevel = exceptPath.length <= 2;
238
200
  let existIncludeIndex = queryParams['include'].findIndex(include => include['association'] == association);
239
-
240
201
  if (existIncludeIndex == -1) {
241
202
  // if include not exists, ignore this except
242
203
  return;
243
204
  }
244
-
245
205
  if (lastLevel) {
246
206
  // if it not have exclude form
247
207
  if (Array.isArray(queryParams['include'][existIncludeIndex]['attributes'])) {
@@ -250,17 +210,14 @@ class OptionsParser {
250
210
  if (!queryParams['include'][existIncludeIndex]['attributes']['exclude']) {
251
211
  queryParams['include'][existIncludeIndex]['attributes']['exclude'] = [];
252
212
  }
253
-
254
213
  queryParams['include'][existIncludeIndex]['attributes']['exclude'].push(exceptPath[1]);
255
214
  }
256
215
  } else {
257
216
  setExcept(queryParams['include'][existIncludeIndex], exceptPath.filter((_, index) => index !== 0).join('.'));
258
217
  }
259
218
  };
260
-
261
219
  var _iterator4 = _createForOfIteratorHelper(except),
262
- _step4;
263
-
220
+ _step4;
264
221
  try {
265
222
  for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
266
223
  const exceptKey = _step4.value;
@@ -271,10 +228,8 @@ class OptionsParser {
271
228
  } finally {
272
229
  _iterator4.f();
273
230
  }
274
-
275
231
  return filterParams;
276
232
  }
277
-
278
233
  parseAppends(appends, filterParams) {
279
234
  if (!appends) return filterParams;
280
235
  /**
@@ -283,61 +238,52 @@ class OptionsParser {
283
238
  * @param queryParams
284
239
  * @param append
285
240
  */
286
-
287
241
  const setInclude = (model, queryParams, append) => {
288
242
  const appendFields = append.split('.');
289
243
  const appendAssociation = appendFields[0];
290
- const associations = model.associations; // if append length less or equal 2
244
+ const associations = model.associations;
245
+ // if append length less or equal 2
291
246
  // example:
292
247
  // appends: ['posts']
293
248
  // appends: ['posts.title']
294
249
  // All of these can be seen as last level
295
-
296
250
  let lastLevel = false;
297
-
298
251
  if (appendFields.length == 1) {
299
252
  lastLevel = true;
300
253
  }
301
-
302
254
  if (appendFields.length == 2) {
303
255
  const associationModel = associations[appendFields[0]].target;
304
-
305
256
  if (associationModel.rawAttributes[appendFields[1]]) {
306
257
  lastLevel = true;
307
258
  }
308
- } // find association index
309
-
310
-
259
+ }
260
+ // find association index
311
261
  if (queryParams['include'] == undefined) {
312
262
  queryParams['include'] = [];
313
263
  }
314
-
315
- let existIncludeIndex = queryParams['include'].findIndex(include => include['association'] == appendAssociation); // if association not exist, create it
316
-
264
+ let existIncludeIndex = queryParams['include'].findIndex(include => include['association'] == appendAssociation);
265
+ // if association not exist, create it
317
266
  if (existIncludeIndex == -1) {
318
267
  // association not exists
319
268
  queryParams['include'].push({
320
269
  association: appendAssociation
321
270
  });
322
271
  existIncludeIndex = queryParams['include'].length - 1;
323
- } // end appends
272
+ }
273
+ // end appends
324
274
  // without nests association
325
-
326
-
327
275
  if (lastLevel) {
328
276
  // get exist association attributes
329
277
  let attributes = queryParams['include'][existIncludeIndex]['attributes'] || {
330
278
  include: [] // all fields are output by default
331
-
332
- }; // if need set attribute
333
-
279
+ };
280
+ // if need set attribute
334
281
  if (appendFields.length == 2) {
335
282
  if (!Array.isArray(attributes)) {
336
283
  attributes = [];
337
284
  }
338
-
339
- const attributeName = appendFields[1]; // push field to it
340
-
285
+ const attributeName = appendFields[1];
286
+ // push field to it
341
287
  attributes.push(attributeName);
342
288
  } else {
343
289
  // if attributes is empty array, change it to object
@@ -346,21 +292,18 @@ class OptionsParser {
346
292
  include: []
347
293
  };
348
294
  }
349
- } // set new attributes
350
-
351
-
295
+ }
296
+ // set new attributes
352
297
  queryParams['include'][existIncludeIndex] = _objectSpread(_objectSpread({}, queryParams['include'][existIncludeIndex]), {}, {
353
298
  attributes
354
299
  });
355
300
  } else {
356
301
  setInclude(model.associations[queryParams['include'][existIncludeIndex].association].target, queryParams['include'][existIncludeIndex], appendFields.filter((_, index) => index !== 0).join('.'));
357
302
  }
358
- }; // handle every appends
359
-
360
-
303
+ };
304
+ // handle every appends
361
305
  var _iterator5 = _createForOfIteratorHelper(appends),
362
- _step5;
363
-
306
+ _step5;
364
307
  try {
365
308
  for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
366
309
  const append = _step5.value;
@@ -371,11 +314,8 @@ class OptionsParser {
371
314
  } finally {
372
315
  _iterator5.f();
373
316
  }
374
-
375
317
  debug('filter params: %o', filterParams);
376
318
  return filterParams;
377
319
  }
378
-
379
320
  }
380
-
381
321
  exports.OptionsParser = OptionsParser;
package/lib/playground.js CHANGED
@@ -1,17 +1,13 @@
1
1
  "use strict";
2
2
 
3
3
  var _database = require("./database");
4
-
5
4
  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); } }
6
-
7
5
  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); }); }; }
8
-
9
6
  const db = new _database.Database({
10
7
  dialect: 'sqlite',
11
8
  dialectModule: require('sqlite3'),
12
9
  storage: ':memory:'
13
10
  });
14
-
15
11
  _asyncToGenerator(function* () {
16
12
  const User = db.collection({
17
13
  name: 'users',
@@ -4,4 +4,15 @@ import { Transactionable } from 'sequelize';
4
4
  export default class MysqlQueryInterface extends QueryInterface {
5
5
  constructor(db: any);
6
6
  collectionTableExists(collection: Collection, options?: Transactionable): Promise<boolean>;
7
+ listViews(): Promise<[unknown[], unknown]>;
8
+ viewColumnUsage(options: {
9
+ viewName: string;
10
+ schema?: string;
11
+ }): Promise<{
12
+ [view_column_name: string]: {
13
+ column_name: string;
14
+ table_name: string;
15
+ table_schema?: string;
16
+ };
17
+ }>;
7
18
  }
@@ -4,28 +4,28 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
7
  var _queryInterface = _interopRequireDefault(require("./query-interface"));
9
-
8
+ var _sqlParser = _interopRequireDefault(require("../sql-parser"));
10
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
-
10
+ 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; } } }; }
11
+ 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); }
12
+ 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; }
12
13
  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); } }
13
-
14
14
  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); }); }; }
15
-
16
15
  class MysqlQueryInterface extends _queryInterface.default {
17
16
  constructor(db) {
18
17
  super(db);
19
18
  }
20
-
21
19
  collectionTableExists(collection, options) {
22
20
  var _this = this;
23
-
24
21
  return _asyncToGenerator(function* () {
25
22
  const transaction = options === null || options === void 0 ? void 0 : options.transaction;
26
23
  const tableName = collection.model.tableName;
27
24
  const databaseName = _this.db.options.database;
28
- const sql = `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${databaseName}' AND TABLE_NAME = '${tableName}'`;
25
+ const sql = `SELECT TABLE_NAME
26
+ FROM INFORMATION_SCHEMA.TABLES
27
+ WHERE TABLE_SCHEMA = '${databaseName}'
28
+ AND TABLE_NAME = '${tableName}'`;
29
29
  const results = yield _this.db.sequelize.query(sql, {
30
30
  type: 'SELECT',
31
31
  transaction
@@ -33,7 +33,56 @@ class MysqlQueryInterface extends _queryInterface.default {
33
33
  return results.length > 0;
34
34
  })();
35
35
  }
36
-
36
+ listViews() {
37
+ var _this2 = this;
38
+ return _asyncToGenerator(function* () {
39
+ const sql = `SELECT TABLE_NAME as name, VIEW_DEFINITION as definition
40
+ FROM information_schema.views
41
+ WHERE TABLE_SCHEMA = DATABASE()
42
+ ORDER BY TABLE_NAME;`;
43
+ return yield _this2.db.sequelize.query(sql, {
44
+ type: 'SELECT'
45
+ });
46
+ })();
47
+ }
48
+ viewColumnUsage(options) {
49
+ var _this3 = this;
50
+ return _asyncToGenerator(function* () {
51
+ try {
52
+ const viewDefinition = yield _this3.db.sequelize.query(`SHOW CREATE VIEW ${options.viewName}`, {
53
+ type: 'SELECT'
54
+ });
55
+ const createView = viewDefinition[0]['Create View'];
56
+ const regex = /(?<=AS\s)([\s\S]*)/i;
57
+ const match = createView.match(regex);
58
+ const sql = match[0];
59
+ const _sqlParser$parse = _sqlParser.default.parse(sql),
60
+ ast = _sqlParser$parse.ast;
61
+ const columns = ast.columns;
62
+ const results = [];
63
+ var _iterator = _createForOfIteratorHelper(columns),
64
+ _step;
65
+ try {
66
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
67
+ const column = _step.value;
68
+ if (column.expr.type === 'column_ref') {
69
+ results.push([column.as || column.expr.column, {
70
+ column_name: column.expr.column,
71
+ table_name: column.expr.table
72
+ }]);
73
+ }
74
+ }
75
+ } catch (err) {
76
+ _iterator.e(err);
77
+ } finally {
78
+ _iterator.f();
79
+ }
80
+ return Object.fromEntries(results);
81
+ } catch (e) {
82
+ _this3.db.logger.warn(e);
83
+ return {};
84
+ }
85
+ })();
86
+ }
37
87
  }
38
-
39
88
  exports.default = MysqlQueryInterface;
@@ -3,4 +3,12 @@ import { Collection } from '../collection';
3
3
  export default class PostgresQueryInterface extends QueryInterface {
4
4
  constructor(db: any);
5
5
  collectionTableExists(collection: Collection, options?: any): Promise<any>;
6
+ listViews(): Promise<[unknown[], unknown]>;
7
+ viewColumnUsage(options: any): Promise<{
8
+ [view_column_name: string]: {
9
+ column_name: string;
10
+ table_name: string;
11
+ table_schema?: string;
12
+ };
13
+ }>;
6
14
  }
@@ -4,30 +4,30 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
7
  var _queryInterface = _interopRequireDefault(require("./query-interface"));
9
-
8
+ var _sqlParser = _interopRequireDefault(require("../sql-parser"));
10
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
-
10
+ 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; }
11
+ 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; }
12
+ 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; }
13
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
14
+ 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); }
12
15
  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); } }
13
-
14
16
  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); }); }; }
15
-
16
17
  class PostgresQueryInterface extends _queryInterface.default {
17
18
  constructor(db) {
18
19
  super(db);
19
20
  }
20
-
21
21
  collectionTableExists(collection, options) {
22
22
  var _this = this;
23
-
24
23
  return _asyncToGenerator(function* () {
25
24
  const transaction = options === null || options === void 0 ? void 0 : options.transaction;
26
25
  const tableName = collection.model.tableName;
27
26
  const schema = collection.collectionSchema() || 'public';
28
- const sql = `SELECT EXISTS(SELECT 1 FROM information_schema.tables
29
- WHERE table_schema = '${schema}'
30
- AND table_name = '${tableName}')`;
27
+ const sql = `SELECT EXISTS(SELECT 1
28
+ FROM information_schema.tables
29
+ WHERE table_schema = '${schema}'
30
+ AND table_name = '${tableName}')`;
31
31
  const results = yield _this.db.sequelize.query(sql, {
32
32
  type: 'SELECT',
33
33
  transaction
@@ -35,7 +35,65 @@ class PostgresQueryInterface extends _queryInterface.default {
35
35
  return results[0]['exists'];
36
36
  })();
37
37
  }
38
-
38
+ listViews() {
39
+ var _this2 = this;
40
+ return _asyncToGenerator(function* () {
41
+ const sql = `
42
+ SELECT viewname as name, definition, schemaname as schema
43
+ FROM pg_views
44
+ WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
45
+ ORDER BY viewname;
46
+ `;
47
+ return yield _this2.db.sequelize.query(sql, {
48
+ type: 'SELECT'
49
+ });
50
+ })();
51
+ }
52
+ viewColumnUsage(options) {
53
+ var _this3 = this;
54
+ return _asyncToGenerator(function* () {
55
+ const viewName = options.viewName,
56
+ _options$schema = options.schema,
57
+ schema = _options$schema === void 0 ? 'public' : _options$schema;
58
+ const sql = `
59
+ SELECT *
60
+ FROM information_schema.view_column_usage
61
+ WHERE view_schema = '${schema}'
62
+ AND view_name = '${viewName}';
63
+ `;
64
+ const columnUsages = yield _this3.db.sequelize.query(sql, {
65
+ type: 'SELECT'
66
+ });
67
+ const viewDefQuery = yield _this3.db.sequelize.query(`
68
+ select pg_get_viewdef(format('%I.%I', '${schema}', '${viewName}')::regclass, true) as definition
69
+ `, {
70
+ type: 'SELECT'
71
+ });
72
+ const def = viewDefQuery[0]['definition'];
73
+ try {
74
+ const _sqlParser$parse = _sqlParser.default.parse(def),
75
+ ast = _sqlParser$parse.ast;
76
+ const columns = ast[0].columns;
77
+ const usages = columns.map(column => {
78
+ const fieldAlias = column.as || column.expr.column;
79
+ const columnUsage = columnUsages.find(columnUsage => {
80
+ let columnExprTable = column.expr.table;
81
+ // handle column alias
82
+ const from = ast[0].from;
83
+ const findAs = from.find(from => from.as === columnExprTable);
84
+ if (findAs) {
85
+ columnExprTable = findAs.table;
86
+ }
87
+ return columnUsage.column_name === column.expr.column && columnUsage.table_name === columnExprTable;
88
+ });
89
+ return [fieldAlias, columnUsage ? _objectSpread({}, columnUsage) : null];
90
+ }).filter(([, columnUsage]) => columnUsage !== null);
91
+ return Object.fromEntries(usages);
92
+ } catch (e) {
93
+ _this3.db.logger.warn(e);
94
+ return {};
95
+ }
96
+ })();
97
+ }
39
98
  }
40
-
41
99
  exports.default = PostgresQueryInterface;
@@ -4,15 +4,10 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = buildQueryInterface;
7
-
8
7
  var _mysqlQueryInterface = _interopRequireDefault(require("./mysql-query-interface"));
9
-
10
8
  var _postgresQueryInterface = _interopRequireDefault(require("./postgres-query-interface"));
11
-
12
9
  var _sqliteQueryInterface = _interopRequireDefault(require("./sqlite-query-interface"));
13
-
14
10
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
-
16
11
  function buildQueryInterface(db) {
17
12
  const map = {
18
13
  mysql: _mysqlQueryInterface.default,
@@ -6,4 +6,16 @@ export default abstract class QueryInterface {
6
6
  sequelizeQueryInterface: SequelizeQueryInterface;
7
7
  protected constructor(db: Database);
8
8
  abstract collectionTableExists(collection: Collection, options?: Transactionable): Promise<boolean>;
9
+ abstract listViews(): any;
10
+ abstract viewColumnUsage(options: {
11
+ viewName: string;
12
+ schema?: string;
13
+ }): Promise<{
14
+ [view_column_name: string]: {
15
+ column_name: string;
16
+ table_name: string;
17
+ table_schema?: string;
18
+ };
19
+ }>;
20
+ dropAll(options: any): Promise<void>;
9
21
  }