@nocobase/database 0.10.0-alpha.4 → 0.10.1-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/fields/uid-field.js +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +11 -2
- package/lib/operators/child-collection.js +28 -6
- package/lib/repository.js +8 -8
- package/lib/update-associations.js +6 -2
- package/package.json +4 -4
- package/src/__tests__/inhertits/collection-inherits.test.ts +51 -5
- package/src/__tests__/update-associations.test.ts +179 -0
- package/src/fields/uid-field.ts +1 -1
- package/src/filter-parser.ts +1 -0
- package/src/index.ts +1 -0
- package/src/operators/child-collection.ts +26 -7
- package/src/repository.ts +2 -2
- package/src/update-associations.ts +6 -1
package/lib/fields/uid-field.js
CHANGED
|
@@ -31,7 +31,7 @@ class UidField extends _field.Field {
|
|
|
31
31
|
_this$options$prefix = _this$options.prefix,
|
|
32
32
|
prefix = _this$options$prefix === void 0 ? '' : _this$options$prefix,
|
|
33
33
|
pattern = _this$options.pattern;
|
|
34
|
-
const re = new RegExp(pattern || '^[A-Za-z0-
|
|
34
|
+
const re = new RegExp(pattern || '^[A-Za-z0-9_][A-Za-z0-9_-]*$');
|
|
35
35
|
this.listener = /*#__PURE__*/function () {
|
|
36
36
|
var _ref = _asyncToGenerator(function* (instance) {
|
|
37
37
|
const value = instance.get(name);
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -6,7 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
var _exportNames = {
|
|
7
7
|
DataTypes: true,
|
|
8
8
|
Op: true,
|
|
9
|
-
snakeCase: true
|
|
9
|
+
snakeCase: true,
|
|
10
|
+
FilterParser: true
|
|
10
11
|
};
|
|
11
12
|
Object.defineProperty(exports, "DataTypes", {
|
|
12
13
|
enumerable: true,
|
|
@@ -14,6 +15,12 @@ Object.defineProperty(exports, "DataTypes", {
|
|
|
14
15
|
return _sequelize().DataTypes;
|
|
15
16
|
}
|
|
16
17
|
});
|
|
18
|
+
Object.defineProperty(exports, "FilterParser", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function get() {
|
|
21
|
+
return _filterParser.default;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
17
24
|
Object.defineProperty(exports, "Op", {
|
|
18
25
|
enumerable: true,
|
|
19
26
|
get: function get() {
|
|
@@ -303,4 +310,6 @@ Object.keys(_viewInference).forEach(function (key) {
|
|
|
303
310
|
return _viewInference[key];
|
|
304
311
|
}
|
|
305
312
|
});
|
|
306
|
-
});
|
|
313
|
+
});
|
|
314
|
+
var _filterParser = _interopRequireDefault(require("./filter-parser"));
|
|
315
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -4,6 +4,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
+
function _lodash() {
|
|
8
|
+
const data = _interopRequireDefault(require("lodash"));
|
|
9
|
+
_lodash = function _lodash() {
|
|
10
|
+
return data;
|
|
11
|
+
};
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
7
14
|
function _sequelize() {
|
|
8
15
|
const data = require("sequelize");
|
|
9
16
|
_sequelize = function _sequelize() {
|
|
@@ -11,22 +18,37 @@ function _sequelize() {
|
|
|
11
18
|
};
|
|
12
19
|
return data;
|
|
13
20
|
}
|
|
21
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
22
|
const mapVal = (values, db) => values.map(v => {
|
|
15
23
|
const collection = db.getCollection(v);
|
|
16
24
|
return _sequelize().Sequelize.literal(`'${collection.tableNameAsString()}'::regclass`);
|
|
17
25
|
});
|
|
26
|
+
const filterItems = (values, db) => {
|
|
27
|
+
return _lodash().default.castArray(values).map(v => {
|
|
28
|
+
const collection = db.getCollection(v);
|
|
29
|
+
if (!collection) return null;
|
|
30
|
+
return `'${collection.tableNameAsString()}'::regclass`;
|
|
31
|
+
}).filter(Boolean);
|
|
32
|
+
};
|
|
33
|
+
const joinValues = items => items.join(', ');
|
|
18
34
|
var _default = {
|
|
19
35
|
$childIn(values, ctx) {
|
|
20
36
|
const db = ctx.db;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
37
|
+
const items = filterItems(values, db);
|
|
38
|
+
if (items.length) {
|
|
39
|
+
return _sequelize().Sequelize.literal(`"${ctx.model.name}"."tableoid" IN (${joinValues(items)})`);
|
|
40
|
+
} else {
|
|
41
|
+
return _sequelize().Sequelize.literal(`1 = 2`);
|
|
42
|
+
}
|
|
24
43
|
},
|
|
25
44
|
$childNotIn(values, ctx) {
|
|
26
45
|
const db = ctx.db;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
46
|
+
const items = filterItems(values, db);
|
|
47
|
+
if (items.length) {
|
|
48
|
+
return _sequelize().Sequelize.literal(`"${ctx.model.name}"."tableoid" NOT IN (${joinValues(items)})`);
|
|
49
|
+
} else {
|
|
50
|
+
return _sequelize().Sequelize.literal(`1 = 1`);
|
|
51
|
+
}
|
|
30
52
|
}
|
|
31
53
|
};
|
|
32
54
|
exports.default = _default;
|
package/lib/repository.js
CHANGED
|
@@ -4,6 +4,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.Repository = void 0;
|
|
7
|
+
function _flat() {
|
|
8
|
+
const data = require("flat");
|
|
9
|
+
_flat = function _flat() {
|
|
10
|
+
return data;
|
|
11
|
+
};
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
7
14
|
function _lodash() {
|
|
8
15
|
const data = _interopRequireDefault(require("lodash"));
|
|
9
16
|
_lodash = function _lodash() {
|
|
@@ -20,6 +27,7 @@ function _sequelize() {
|
|
|
20
27
|
}
|
|
21
28
|
var _mustHaveFilterDecorator = _interopRequireDefault(require("./decorators/must-have-filter-decorator"));
|
|
22
29
|
var _transactionDecorator = require("./decorators/transaction-decorator");
|
|
30
|
+
var _eagerLoadingTree = require("./eager-loading/eager-loading-tree");
|
|
23
31
|
var _arrayFieldRepository = require("./field-repository/array-field-repository");
|
|
24
32
|
var _fields = require("./fields");
|
|
25
33
|
var _filterParser = _interopRequireDefault(require("./filter-parser"));
|
|
@@ -30,14 +38,6 @@ var _hasmanyRepository = require("./relation-repository/hasmany-repository");
|
|
|
30
38
|
var _hasoneRepository = require("./relation-repository/hasone-repository");
|
|
31
39
|
var _updateAssociations = require("./update-associations");
|
|
32
40
|
var _updateGuard = require("./update-guard");
|
|
33
|
-
var _eagerLoadingTree = require("./eager-loading/eager-loading-tree");
|
|
34
|
-
function _flat() {
|
|
35
|
-
const data = require("flat");
|
|
36
|
-
_flat = function _flat() {
|
|
37
|
-
return data;
|
|
38
|
-
};
|
|
39
|
-
return data;
|
|
40
|
-
}
|
|
41
41
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
42
42
|
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
43
43
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
@@ -12,8 +12,6 @@ exports.updateModelByValues = updateModelByValues;
|
|
|
12
12
|
exports.updateMultipleAssociation = updateMultipleAssociation;
|
|
13
13
|
exports.updateSingleAssociation = updateSingleAssociation;
|
|
14
14
|
exports.updateThroughTableValue = updateThroughTableValue;
|
|
15
|
-
var _model = require("./model");
|
|
16
|
-
var _updateGuard = require("./update-guard");
|
|
17
15
|
function _lodash() {
|
|
18
16
|
const data = _interopRequireDefault(require("lodash"));
|
|
19
17
|
_lodash = function _lodash() {
|
|
@@ -21,6 +19,8 @@ function _lodash() {
|
|
|
21
19
|
};
|
|
22
20
|
return data;
|
|
23
21
|
}
|
|
22
|
+
var _model = require("./model");
|
|
23
|
+
var _updateGuard = require("./update-guard");
|
|
24
24
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
25
|
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; }
|
|
26
26
|
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; }
|
|
@@ -367,6 +367,10 @@ function _updateMultipleAssociation() {
|
|
|
367
367
|
if (!association) {
|
|
368
368
|
return false;
|
|
369
369
|
}
|
|
370
|
+
// @ts-ignore skip update association if through model is a view
|
|
371
|
+
if (association.through && association.through.model.options.view) {
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
370
374
|
if (!['undefined', 'string', 'number', 'object'].includes(typeof value)) {
|
|
371
375
|
return false;
|
|
372
376
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/database",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1-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.10.
|
|
10
|
-
"@nocobase/utils": "0.10.
|
|
9
|
+
"@nocobase/logger": "0.10.1-alpha.1",
|
|
10
|
+
"@nocobase/utils": "0.10.1-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": "8f415f5e0ee2e72d681f9ab16af5911b52c374a9"
|
|
32
32
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { BelongsToManyRepository } from '@nocobase/database';
|
|
1
2
|
import Database from '../../database';
|
|
2
3
|
import { InheritedCollection } from '../../inherited-collection';
|
|
3
4
|
import { mockDatabase } from '../index';
|
|
4
|
-
import { BelongsToManyRepository } from '@nocobase/database';
|
|
5
5
|
import pgOnly from './helper';
|
|
6
6
|
|
|
7
7
|
pgOnly()('collection inherits', () => {
|
|
@@ -182,9 +182,17 @@ pgOnly()('collection inherits', () => {
|
|
|
182
182
|
});
|
|
183
183
|
|
|
184
184
|
it('should list data filtered by child type', async () => {
|
|
185
|
+
const assocs = db.collection({
|
|
186
|
+
name: 'assocs',
|
|
187
|
+
fields: [{ name: 'name', type: 'string' }],
|
|
188
|
+
});
|
|
189
|
+
|
|
185
190
|
const rootCollection = db.collection({
|
|
186
191
|
name: 'root',
|
|
187
|
-
fields: [
|
|
192
|
+
fields: [
|
|
193
|
+
{ name: 'name', type: 'string' },
|
|
194
|
+
{ name: 'assocs', type: 'hasMany', target: 'assocs' },
|
|
195
|
+
],
|
|
188
196
|
});
|
|
189
197
|
|
|
190
198
|
const child1Collection = db.collection({
|
|
@@ -202,11 +210,29 @@ pgOnly()('collection inherits', () => {
|
|
|
202
210
|
await rootCollection.repository.create({
|
|
203
211
|
values: {
|
|
204
212
|
name: 'root1',
|
|
213
|
+
assocs: [
|
|
214
|
+
{
|
|
215
|
+
name: 'assoc1',
|
|
216
|
+
},
|
|
217
|
+
],
|
|
205
218
|
},
|
|
206
219
|
});
|
|
207
220
|
|
|
208
221
|
await child1Collection.repository.create({
|
|
209
|
-
values: [
|
|
222
|
+
values: [
|
|
223
|
+
{
|
|
224
|
+
name: 'child1-1',
|
|
225
|
+
assocs: [
|
|
226
|
+
{
|
|
227
|
+
name: 'child-assoc1-1',
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: 'child1-2',
|
|
233
|
+
assocs: [{ name: 'child-assoc1-2' }],
|
|
234
|
+
},
|
|
235
|
+
],
|
|
210
236
|
});
|
|
211
237
|
|
|
212
238
|
await child2Collection.repository.create({
|
|
@@ -215,18 +241,38 @@ pgOnly()('collection inherits', () => {
|
|
|
215
241
|
|
|
216
242
|
const records = await rootCollection.repository.find({
|
|
217
243
|
filter: {
|
|
218
|
-
'
|
|
244
|
+
'__collection.$childIn': [child1Collection.name],
|
|
219
245
|
},
|
|
246
|
+
appends: ['assocs'],
|
|
220
247
|
});
|
|
221
248
|
|
|
222
249
|
expect(records.every((r) => r.get('__collection') === child1Collection.name)).toBe(true);
|
|
223
250
|
|
|
224
251
|
const records2 = await rootCollection.repository.find({
|
|
225
252
|
filter: {
|
|
226
|
-
'
|
|
253
|
+
'__collection.$childNotIn': [child1Collection.name],
|
|
227
254
|
},
|
|
228
255
|
});
|
|
229
256
|
expect(records2.every((r) => r.get('__collection') !== child1Collection.name)).toBe(true);
|
|
257
|
+
|
|
258
|
+
const recordsWithFilter = await rootCollection.repository.find({
|
|
259
|
+
filter: {
|
|
260
|
+
'__collection.$childIn': [child1Collection.name],
|
|
261
|
+
assocs: {
|
|
262
|
+
name: 'child-assoc1-1',
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
expect(recordsWithFilter.every((r) => r.get('__collection') == child1Collection.name)).toBe(true);
|
|
268
|
+
|
|
269
|
+
const filterWithUndefined = await rootCollection.repository.find({
|
|
270
|
+
filter: {
|
|
271
|
+
'__collection.$childIn': 'undefined',
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
expect(filterWithUndefined).toHaveLength(0);
|
|
230
276
|
});
|
|
231
277
|
|
|
232
278
|
it('should list collection name in relation repository', async () => {
|
|
@@ -3,6 +3,185 @@ import { Database } from '../database';
|
|
|
3
3
|
import { updateAssociations } from '../update-associations';
|
|
4
4
|
import { mockDatabase } from './';
|
|
5
5
|
|
|
6
|
+
describe('update belongs to many with view as through table', () => {
|
|
7
|
+
let db: Database;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
db = mockDatabase({
|
|
10
|
+
tablePrefix: '',
|
|
11
|
+
});
|
|
12
|
+
await db.clean({
|
|
13
|
+
drop: true,
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
await db.close();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should not update through table', async () => {
|
|
22
|
+
const Order = db.collection({
|
|
23
|
+
name: 'orders',
|
|
24
|
+
fields: [
|
|
25
|
+
{
|
|
26
|
+
type: 'string',
|
|
27
|
+
name: 'name',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: 'hasMany',
|
|
31
|
+
name: 'orderItems',
|
|
32
|
+
foreignKey: 'order_id',
|
|
33
|
+
target: 'orderItems',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const OrderItem = db.collection({
|
|
39
|
+
name: 'orderItems',
|
|
40
|
+
timestamps: false,
|
|
41
|
+
fields: [
|
|
42
|
+
{
|
|
43
|
+
type: 'integer',
|
|
44
|
+
name: 'count',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
type: 'belongsTo',
|
|
48
|
+
name: 'item',
|
|
49
|
+
target: 'items',
|
|
50
|
+
foreignKey: 'item_id',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'belongsTo',
|
|
54
|
+
name: 'order',
|
|
55
|
+
target: 'orders',
|
|
56
|
+
foreignKey: 'order_id',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const Item = db.collection({
|
|
62
|
+
name: 'items',
|
|
63
|
+
fields: [{ name: 'name', type: 'string' }],
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
await db.sync();
|
|
67
|
+
|
|
68
|
+
const viewName = 'order_item_view';
|
|
69
|
+
|
|
70
|
+
const dropViewSQL = `DROP VIEW IF EXISTS ${viewName}`;
|
|
71
|
+
await db.sequelize.query(dropViewSQL);
|
|
72
|
+
|
|
73
|
+
const viewSQL = `CREATE VIEW ${viewName} as SELECT orders.*, items.name as item_name FROM ${OrderItem.quotedTableName()} as orders INNER JOIN ${Item.quotedTableName()} as items ON orders.item_id = items.id`;
|
|
74
|
+
|
|
75
|
+
await db.sequelize.query(viewSQL);
|
|
76
|
+
|
|
77
|
+
const OrderItemView = db.collection({
|
|
78
|
+
name: viewName,
|
|
79
|
+
view: true,
|
|
80
|
+
schema: db.inDialect('postgres') ? 'public' : undefined,
|
|
81
|
+
fields: [
|
|
82
|
+
{
|
|
83
|
+
type: 'bigInt',
|
|
84
|
+
name: 'order_id',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
type: 'bigInt',
|
|
88
|
+
name: 'item_id',
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
await db.sync();
|
|
94
|
+
|
|
95
|
+
Order.setField('items', {
|
|
96
|
+
type: 'belongsToMany',
|
|
97
|
+
target: 'orderItems',
|
|
98
|
+
through: viewName,
|
|
99
|
+
foreignKey: 'order_id',
|
|
100
|
+
otherKey: 'item_id',
|
|
101
|
+
sourceKey: 'id',
|
|
102
|
+
targetKey: 'id',
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await db.sync();
|
|
106
|
+
|
|
107
|
+
const order1 = await db.getRepository('orders').create({
|
|
108
|
+
values: {
|
|
109
|
+
name: 'order1',
|
|
110
|
+
orderItems: [
|
|
111
|
+
{
|
|
112
|
+
count: 1,
|
|
113
|
+
item: {
|
|
114
|
+
name: 'item1',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
count: 2,
|
|
119
|
+
item: {
|
|
120
|
+
name: 'item2',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const item1 = await db.getRepository('items').findOne({
|
|
128
|
+
filter: {
|
|
129
|
+
name: 'item1',
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const item2 = await db.getRepository('items').findOne({
|
|
134
|
+
filter: {
|
|
135
|
+
name: 'item2',
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await db.getRepository('orders').update({
|
|
140
|
+
filterByTk: order1.get('id'),
|
|
141
|
+
values: {
|
|
142
|
+
name: 'order1',
|
|
143
|
+
orderItems: [
|
|
144
|
+
{
|
|
145
|
+
count: 1,
|
|
146
|
+
item: {
|
|
147
|
+
id: item1.get('id'),
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
count: 2,
|
|
152
|
+
item: {
|
|
153
|
+
id: item2.get('id'),
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
count: 3,
|
|
158
|
+
item: {
|
|
159
|
+
name: 'item3',
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
items: [
|
|
164
|
+
{
|
|
165
|
+
id: item1.get('id'),
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: item2.get('id'),
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const order1AfterUpdate = await db.getRepository('orders').findOne({
|
|
175
|
+
filter: {
|
|
176
|
+
name: 'order1',
|
|
177
|
+
},
|
|
178
|
+
appends: ['items'],
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
expect(order1AfterUpdate.get('items').length).toBe(3);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
6
185
|
describe('update associations', () => {
|
|
7
186
|
describe('belongsTo', () => {
|
|
8
187
|
let db: Database;
|
package/src/fields/uid-field.ts
CHANGED
|
@@ -9,7 +9,7 @@ export class UidField extends Field {
|
|
|
9
9
|
|
|
10
10
|
init() {
|
|
11
11
|
const { name, prefix = '', pattern } = this.options;
|
|
12
|
-
const re = new RegExp(pattern || '^[A-Za-z0-
|
|
12
|
+
const re = new RegExp(pattern || '^[A-Za-z0-9_][A-Za-z0-9_-]*$');
|
|
13
13
|
this.listener = async (instance) => {
|
|
14
14
|
const value = instance.get(name);
|
|
15
15
|
if (!value) {
|
package/src/filter-parser.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import lodash from 'lodash';
|
|
2
|
+
import { Sequelize } from 'sequelize';
|
|
2
3
|
|
|
3
4
|
const mapVal = (values, db) =>
|
|
4
5
|
values.map((v) => {
|
|
@@ -6,19 +7,37 @@ const mapVal = (values, db) =>
|
|
|
6
7
|
return Sequelize.literal(`'${collection.tableNameAsString()}'::regclass`);
|
|
7
8
|
});
|
|
8
9
|
|
|
10
|
+
const filterItems = (values, db) => {
|
|
11
|
+
return lodash
|
|
12
|
+
.castArray(values)
|
|
13
|
+
.map((v) => {
|
|
14
|
+
const collection = db.getCollection(v);
|
|
15
|
+
if (!collection) return null;
|
|
16
|
+
return `'${collection.tableNameAsString()}'::regclass`;
|
|
17
|
+
})
|
|
18
|
+
.filter(Boolean);
|
|
19
|
+
};
|
|
20
|
+
const joinValues = (items) => items.join(', ');
|
|
9
21
|
export default {
|
|
10
22
|
$childIn(values, ctx: any) {
|
|
11
23
|
const db = ctx.db;
|
|
24
|
+
const items = filterItems(values, db);
|
|
12
25
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
26
|
+
if (items.length) {
|
|
27
|
+
return Sequelize.literal(`"${ctx.model.name}"."tableoid" IN (${joinValues(items)})`);
|
|
28
|
+
} else {
|
|
29
|
+
return Sequelize.literal(`1 = 2`);
|
|
30
|
+
}
|
|
16
31
|
},
|
|
32
|
+
|
|
17
33
|
$childNotIn(values, ctx: any) {
|
|
18
34
|
const db = ctx.db;
|
|
35
|
+
const items = filterItems(values, db);
|
|
19
36
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
37
|
+
if (items.length) {
|
|
38
|
+
return Sequelize.literal(`"${ctx.model.name}"."tableoid" NOT IN (${joinValues(items)})`);
|
|
39
|
+
} else {
|
|
40
|
+
return Sequelize.literal(`1 = 1`);
|
|
41
|
+
}
|
|
23
42
|
},
|
|
24
43
|
} as Record<string, any>;
|
package/src/repository.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { flatten } from 'flat';
|
|
1
2
|
import lodash from 'lodash';
|
|
2
3
|
import {
|
|
3
4
|
Association,
|
|
@@ -18,6 +19,7 @@ import { Collection } from './collection';
|
|
|
18
19
|
import { Database } from './database';
|
|
19
20
|
import mustHaveFilter from './decorators/must-have-filter-decorator';
|
|
20
21
|
import { transactionWrapperBuilder } from './decorators/transaction-decorator';
|
|
22
|
+
import { EagerLoadingTree } from './eager-loading/eager-loading-tree';
|
|
21
23
|
import { ArrayFieldRepository } from './field-repository/array-field-repository';
|
|
22
24
|
import { ArrayField, RelationField } from './fields';
|
|
23
25
|
import FilterParser from './filter-parser';
|
|
@@ -31,8 +33,6 @@ import { HasOneRepository } from './relation-repository/hasone-repository';
|
|
|
31
33
|
import { RelationRepository } from './relation-repository/relation-repository';
|
|
32
34
|
import { updateAssociations, updateModelByValues } from './update-associations';
|
|
33
35
|
import { UpdateGuard } from './update-guard';
|
|
34
|
-
import { EagerLoadingTree } from './eager-loading/eager-loading-tree';
|
|
35
|
-
import { flatten } from 'flat';
|
|
36
36
|
|
|
37
37
|
const debug = require('debug')('noco-database');
|
|
38
38
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import lodash from 'lodash';
|
|
1
2
|
import {
|
|
2
3
|
Association,
|
|
3
4
|
BelongsTo,
|
|
@@ -10,7 +11,6 @@ import {
|
|
|
10
11
|
} from 'sequelize';
|
|
11
12
|
import { Model } from './model';
|
|
12
13
|
import { UpdateGuard } from './update-guard';
|
|
13
|
-
import lodash from 'lodash';
|
|
14
14
|
|
|
15
15
|
function isUndefinedOrNull(value: any) {
|
|
16
16
|
return typeof value === 'undefined' || value === null;
|
|
@@ -377,6 +377,11 @@ export async function updateMultipleAssociation(
|
|
|
377
377
|
return false;
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
+
// @ts-ignore skip update association if through model is a view
|
|
381
|
+
if (association.through && association.through.model.options.view) {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
|
|
380
385
|
if (!['undefined', 'string', 'number', 'object'].includes(typeof value)) {
|
|
381
386
|
return false;
|
|
382
387
|
}
|