@nocobase/database 0.7.1-alpha.6 → 0.7.2-alpha.2
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.d.ts +2 -0
- package/lib/collection.js +92 -0
- package/lib/database.d.ts +6 -0
- package/lib/database.js +108 -42
- package/lib/fields/belongs-to-field.js +4 -2
- package/lib/fields/belongs-to-many-field.js +5 -1
- package/lib/fields/field.js +8 -0
- package/lib/fields/has-many-field.js +17 -3
- package/lib/fields/has-one-field.js +16 -2
- package/lib/relation-repository/relation-repository.d.ts +1 -0
- package/lib/relation-repository/relation-repository.js +4 -0
- package/package.json +4 -3
- package/src/__tests__/collection.test.ts +16 -0
- package/src/__tests__/update-associations.test.ts +13 -9
- package/src/collection.ts +69 -1
- package/src/database.ts +44 -0
- package/src/fields/belongs-to-field.ts +3 -1
- package/src/fields/belongs-to-many-field.ts +3 -0
- package/src/fields/field.ts +6 -0
- package/src/fields/has-many-field.ts +15 -6
- package/src/fields/has-one-field.ts +12 -1
- package/src/relation-repository/relation-repository.ts +4 -0
package/lib/collection.d.ts
CHANGED
|
@@ -73,5 +73,7 @@ export declare class Collection<TModelAttributes extends {} = any, TCreationAttr
|
|
|
73
73
|
* @param options
|
|
74
74
|
*/
|
|
75
75
|
updateField(name: string, options: FieldOptions): void;
|
|
76
|
+
addIndex(index: any): void;
|
|
77
|
+
removeIndex(fields: any): void;
|
|
76
78
|
sync(syncOptions?: SyncOptions): Promise<void>;
|
|
77
79
|
}
|
package/lib/collection.js
CHANGED
|
@@ -35,6 +35,16 @@ function _lodash() {
|
|
|
35
35
|
return data;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
function _sequelize() {
|
|
39
|
+
const data = require("sequelize");
|
|
40
|
+
|
|
41
|
+
_sequelize = function _sequelize() {
|
|
42
|
+
return data;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
|
|
38
48
|
var _model = require("./model");
|
|
39
49
|
|
|
40
50
|
var _repository = require("./repository");
|
|
@@ -356,6 +366,88 @@ class Collection extends _events().EventEmitter {
|
|
|
356
366
|
this.setField(options.name || name, options);
|
|
357
367
|
}
|
|
358
368
|
|
|
369
|
+
addIndex(index) {
|
|
370
|
+
if (!index) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
let indexes = this.model.options.indexes || [];
|
|
375
|
+
let indexName = [];
|
|
376
|
+
let indexItem;
|
|
377
|
+
|
|
378
|
+
if (typeof index === 'string') {
|
|
379
|
+
indexItem = {
|
|
380
|
+
fields: [index]
|
|
381
|
+
};
|
|
382
|
+
indexName = [index];
|
|
383
|
+
} else if (Array.isArray(index)) {
|
|
384
|
+
indexItem = {
|
|
385
|
+
fields: index
|
|
386
|
+
};
|
|
387
|
+
indexName = index;
|
|
388
|
+
} else if (index === null || index === void 0 ? void 0 : index.fields) {
|
|
389
|
+
indexItem = index;
|
|
390
|
+
indexName = index.fields;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (_lodash().default.isEqual(this.model.primaryKeyAttributes, indexName)) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const name = this.model.primaryKeyAttributes.join(',');
|
|
398
|
+
|
|
399
|
+
if (name.startsWith(`${indexName.join(',')},`)) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
var _iterator3 = _createForOfIteratorHelper(indexes),
|
|
404
|
+
_step3;
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
408
|
+
const item = _step3.value;
|
|
409
|
+
|
|
410
|
+
if (_lodash().default.isEqual(item.fields, indexName)) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const name = item.fields.join(',');
|
|
415
|
+
|
|
416
|
+
if (name.startsWith(`${indexName.join(',')},`)) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
} catch (err) {
|
|
421
|
+
_iterator3.e(err);
|
|
422
|
+
} finally {
|
|
423
|
+
_iterator3.f();
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (!indexItem) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
indexes.push(indexItem);
|
|
431
|
+
this.model.options.indexes = indexes;
|
|
432
|
+
const tableName = this.model.getTableName(); // @ts-ignore
|
|
433
|
+
|
|
434
|
+
this.model._indexes = this.model.options.indexes // @ts-ignore
|
|
435
|
+
.map(index => _sequelize().Utils.nameIndex(this.model._conformIndex(index), tableName));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
removeIndex(fields) {
|
|
439
|
+
if (!fields) {
|
|
440
|
+
return;
|
|
441
|
+
} // @ts-ignore
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
const indexes = this.model._indexes; // @ts-ignore
|
|
445
|
+
|
|
446
|
+
this.model._indexes = indexes.filter(item => {
|
|
447
|
+
return !_lodash().default.isEqual(item.fields, fields);
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
|
|
359
451
|
sync(syncOptions) {
|
|
360
452
|
var _this3 = this;
|
|
361
453
|
|
package/lib/database.d.ts
CHANGED
|
@@ -43,6 +43,11 @@ export declare type AddMigrationsOptions = {
|
|
|
43
43
|
directory: string;
|
|
44
44
|
};
|
|
45
45
|
declare type OperatorFunc = (value: any, ctx?: RegisterOperatorsContext) => any;
|
|
46
|
+
declare class DatabaseVersion {
|
|
47
|
+
db: Database;
|
|
48
|
+
constructor(db: Database);
|
|
49
|
+
satisfies(versions: any): Promise<boolean>;
|
|
50
|
+
}
|
|
46
51
|
export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
47
52
|
sequelize: Sequelize;
|
|
48
53
|
migrator: Umzug;
|
|
@@ -56,6 +61,7 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
|
56
61
|
pendingFields: Map<string, FieldTypes.RelationField[]>;
|
|
57
62
|
modelCollection: Map<ModelCtor<any>, Collection<any, any>>;
|
|
58
63
|
modelHook: ModelHook;
|
|
64
|
+
version: DatabaseVersion;
|
|
59
65
|
delayCollectionExtend: Map<string, {
|
|
60
66
|
collectionOptions: CollectionOptions;
|
|
61
67
|
mergeOptions?: any;
|
package/lib/database.js
CHANGED
|
@@ -57,6 +57,16 @@ function _path() {
|
|
|
57
57
|
return data;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
function _semver() {
|
|
61
|
+
const data = _interopRequireDefault(require("semver"));
|
|
62
|
+
|
|
63
|
+
_semver = function _semver() {
|
|
64
|
+
return data;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return data;
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
function _sequelize() {
|
|
61
71
|
const data = require("sequelize");
|
|
62
72
|
|
|
@@ -102,11 +112,13 @@ function _objectWithoutProperties(source, excluded) { if (source == null) return
|
|
|
102
112
|
|
|
103
113
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
104
114
|
|
|
105
|
-
function
|
|
115
|
+
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(_e2) { throw _e2; }, 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(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
106
116
|
|
|
107
|
-
function
|
|
117
|
+
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; }
|
|
108
118
|
|
|
109
|
-
function
|
|
119
|
+
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; }
|
|
120
|
+
|
|
121
|
+
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; }
|
|
110
122
|
|
|
111
123
|
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
112
124
|
|
|
@@ -120,11 +132,63 @@ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Sy
|
|
|
120
132
|
|
|
121
133
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
122
134
|
|
|
123
|
-
function
|
|
135
|
+
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); } }
|
|
124
136
|
|
|
125
|
-
function
|
|
137
|
+
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); }); }; }
|
|
126
138
|
|
|
127
|
-
|
|
139
|
+
class DatabaseVersion {
|
|
140
|
+
constructor(db) {
|
|
141
|
+
this.db = void 0;
|
|
142
|
+
this.db = db;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
satisfies(versions) {
|
|
146
|
+
var _this = this;
|
|
147
|
+
|
|
148
|
+
return _asyncToGenerator(function* () {
|
|
149
|
+
const dialects = {
|
|
150
|
+
sqlite: {
|
|
151
|
+
sql: 'select sqlite_version() as version',
|
|
152
|
+
get: v => v
|
|
153
|
+
},
|
|
154
|
+
mysql: {
|
|
155
|
+
sql: 'select version() as version',
|
|
156
|
+
get: v => v
|
|
157
|
+
},
|
|
158
|
+
postgres: {
|
|
159
|
+
sql: 'select version() as version',
|
|
160
|
+
get: v => {
|
|
161
|
+
const keys = v.split(' ');
|
|
162
|
+
keys.shift();
|
|
163
|
+
return _semver().default.minVersion(keys.shift()).version;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
for (var _i = 0, _Object$keys = Object.keys(dialects); _i < _Object$keys.length; _i++) {
|
|
169
|
+
const dialect = _Object$keys[_i];
|
|
170
|
+
|
|
171
|
+
if (_this.db.inDialect(dialect)) {
|
|
172
|
+
var _result$, _result$2;
|
|
173
|
+
|
|
174
|
+
if (!(versions === null || versions === void 0 ? void 0 : versions[dialect])) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const _yield$_this$db$seque = yield _this.db.sequelize.query(dialects[dialect].sql),
|
|
179
|
+
_yield$_this$db$seque2 = _slicedToArray(_yield$_this$db$seque, 1),
|
|
180
|
+
result = _yield$_this$db$seque2[0];
|
|
181
|
+
|
|
182
|
+
console.log(`db version: ${dialects[dialect].get(result === null || result === void 0 ? void 0 : (_result$ = result[0]) === null || _result$ === void 0 ? void 0 : _result$.version)}`);
|
|
183
|
+
return _semver().default.satisfies(dialects[dialect].get(result === null || result === void 0 ? void 0 : (_result$2 = result[0]) === null || _result$2 === void 0 ? void 0 : _result$2.version), versions[dialect]);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return false;
|
|
188
|
+
})();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
}
|
|
128
192
|
|
|
129
193
|
class Database extends _events().EventEmitter {
|
|
130
194
|
constructor(options) {
|
|
@@ -141,7 +205,9 @@ class Database extends _events().EventEmitter {
|
|
|
141
205
|
this.pendingFields = new Map();
|
|
142
206
|
this.modelCollection = new Map();
|
|
143
207
|
this.modelHook = void 0;
|
|
208
|
+
this.version = void 0;
|
|
144
209
|
this.delayCollectionExtend = new Map();
|
|
210
|
+
this.version = new DatabaseVersion(this);
|
|
145
211
|
|
|
146
212
|
const opts = _objectSpread({
|
|
147
213
|
sync: {
|
|
@@ -178,8 +244,8 @@ class Database extends _events().EventEmitter {
|
|
|
178
244
|
});
|
|
179
245
|
}); // register database field types
|
|
180
246
|
|
|
181
|
-
for (var
|
|
182
|
-
const _Object$entries$_i = _slicedToArray(_Object$entries[
|
|
247
|
+
for (var _i2 = 0, _Object$entries = Object.entries(FieldTypes); _i2 < _Object$entries.length; _i2++) {
|
|
248
|
+
const _Object$entries$_i = _slicedToArray(_Object$entries[_i2], 2),
|
|
183
249
|
name = _Object$entries$_i[0],
|
|
184
250
|
field = _Object$entries$_i[1];
|
|
185
251
|
|
|
@@ -354,8 +420,8 @@ class Database extends _events().EventEmitter {
|
|
|
354
420
|
}
|
|
355
421
|
|
|
356
422
|
registerFieldTypes(fieldTypes) {
|
|
357
|
-
for (var
|
|
358
|
-
const _Object$entries2$_i = _slicedToArray(_Object$entries2[
|
|
423
|
+
for (var _i3 = 0, _Object$entries2 = Object.entries(fieldTypes); _i3 < _Object$entries2.length; _i3++) {
|
|
424
|
+
const _Object$entries2$_i = _slicedToArray(_Object$entries2[_i3], 2),
|
|
359
425
|
type = _Object$entries2$_i[0],
|
|
360
426
|
fieldType = _Object$entries2$_i[1];
|
|
361
427
|
|
|
@@ -364,8 +430,8 @@ class Database extends _events().EventEmitter {
|
|
|
364
430
|
}
|
|
365
431
|
|
|
366
432
|
registerModels(models) {
|
|
367
|
-
for (var
|
|
368
|
-
const _Object$entries3$_i = _slicedToArray(_Object$entries3[
|
|
433
|
+
for (var _i4 = 0, _Object$entries3 = Object.entries(models); _i4 < _Object$entries3.length; _i4++) {
|
|
434
|
+
const _Object$entries3$_i = _slicedToArray(_Object$entries3[_i4], 2),
|
|
369
435
|
type = _Object$entries3$_i[0],
|
|
370
436
|
schemaType = _Object$entries3$_i[1];
|
|
371
437
|
|
|
@@ -374,8 +440,8 @@ class Database extends _events().EventEmitter {
|
|
|
374
440
|
}
|
|
375
441
|
|
|
376
442
|
registerRepositories(repositories) {
|
|
377
|
-
for (var
|
|
378
|
-
const _Object$entries4$_i = _slicedToArray(_Object$entries4[
|
|
443
|
+
for (var _i5 = 0, _Object$entries4 = Object.entries(repositories); _i5 < _Object$entries4.length; _i5++) {
|
|
444
|
+
const _Object$entries4$_i = _slicedToArray(_Object$entries4[_i5], 2),
|
|
379
445
|
type = _Object$entries4$_i[0],
|
|
380
446
|
schemaType = _Object$entries4$_i[1];
|
|
381
447
|
|
|
@@ -400,8 +466,8 @@ class Database extends _events().EventEmitter {
|
|
|
400
466
|
}
|
|
401
467
|
|
|
402
468
|
registerOperators(operators) {
|
|
403
|
-
for (var
|
|
404
|
-
const _Object$entries5$_i = _slicedToArray(_Object$entries5[
|
|
469
|
+
for (var _i6 = 0, _Object$entries5 = Object.entries(operators); _i6 < _Object$entries5.length; _i6++) {
|
|
470
|
+
const _Object$entries5$_i = _slicedToArray(_Object$entries5[_i6], 2),
|
|
405
471
|
key = _Object$entries5$_i[0],
|
|
406
472
|
operator = _Object$entries5$_i[1];
|
|
407
473
|
|
|
@@ -421,19 +487,19 @@ class Database extends _events().EventEmitter {
|
|
|
421
487
|
}
|
|
422
488
|
|
|
423
489
|
sync(options) {
|
|
424
|
-
var
|
|
490
|
+
var _this2 = this;
|
|
425
491
|
|
|
426
492
|
return _asyncToGenerator(function* () {
|
|
427
|
-
const isMySQL =
|
|
493
|
+
const isMySQL = _this2.sequelize.getDialect() === 'mysql';
|
|
428
494
|
|
|
429
495
|
if (isMySQL) {
|
|
430
|
-
yield
|
|
496
|
+
yield _this2.sequelize.query('SET FOREIGN_KEY_CHECKS = 0', null);
|
|
431
497
|
}
|
|
432
498
|
|
|
433
|
-
const result = yield
|
|
499
|
+
const result = yield _this2.sequelize.sync(options);
|
|
434
500
|
|
|
435
501
|
if (isMySQL) {
|
|
436
|
-
yield
|
|
502
|
+
yield _this2.sequelize.query('SET FOREIGN_KEY_CHECKS = 1', null);
|
|
437
503
|
}
|
|
438
504
|
|
|
439
505
|
return result;
|
|
@@ -441,26 +507,26 @@ class Database extends _events().EventEmitter {
|
|
|
441
507
|
}
|
|
442
508
|
|
|
443
509
|
clean(options) {
|
|
444
|
-
var
|
|
510
|
+
var _this3 = this;
|
|
445
511
|
|
|
446
512
|
return _asyncToGenerator(function* () {
|
|
447
513
|
const drop = options.drop,
|
|
448
514
|
others = _objectWithoutProperties(options, _excluded);
|
|
449
515
|
|
|
450
516
|
if (drop) {
|
|
451
|
-
yield
|
|
517
|
+
yield _this3.sequelize.getQueryInterface().dropAllTables(others);
|
|
452
518
|
}
|
|
453
519
|
})();
|
|
454
520
|
}
|
|
455
521
|
|
|
456
522
|
collectionExistsInDb(name, options) {
|
|
457
|
-
var
|
|
523
|
+
var _this4 = this;
|
|
458
524
|
|
|
459
525
|
return _asyncToGenerator(function* () {
|
|
460
|
-
const tables = yield
|
|
526
|
+
const tables = yield _this4.sequelize.getQueryInterface().showAllTables({
|
|
461
527
|
transaction: options === null || options === void 0 ? void 0 : options.transaction
|
|
462
528
|
});
|
|
463
|
-
return !!tables.find(table => table === `${
|
|
529
|
+
return !!tables.find(table => table === `${_this4.getTablePrefix()}${name}`);
|
|
464
530
|
})();
|
|
465
531
|
}
|
|
466
532
|
|
|
@@ -469,7 +535,7 @@ class Database extends _events().EventEmitter {
|
|
|
469
535
|
}
|
|
470
536
|
|
|
471
537
|
auth(options = {}) {
|
|
472
|
-
var
|
|
538
|
+
var _this5 = this;
|
|
473
539
|
|
|
474
540
|
return _asyncToGenerator(function* () {
|
|
475
541
|
const _options$retry = options.retry,
|
|
@@ -483,7 +549,7 @@ class Database extends _events().EventEmitter {
|
|
|
483
549
|
const authenticate = /*#__PURE__*/function () {
|
|
484
550
|
var _ref = _asyncToGenerator(function* () {
|
|
485
551
|
try {
|
|
486
|
-
yield
|
|
552
|
+
yield _this5.sequelize.authenticate(others);
|
|
487
553
|
console.log('Connection has been established successfully.');
|
|
488
554
|
return true;
|
|
489
555
|
} catch (error) {
|
|
@@ -508,21 +574,21 @@ class Database extends _events().EventEmitter {
|
|
|
508
574
|
}
|
|
509
575
|
|
|
510
576
|
reconnect() {
|
|
511
|
-
var
|
|
577
|
+
var _this6 = this;
|
|
512
578
|
|
|
513
579
|
return _asyncToGenerator(function* () {
|
|
514
|
-
if (
|
|
580
|
+
if (_this6.isSqliteMemory()) {
|
|
515
581
|
return;
|
|
516
582
|
} // @ts-ignore
|
|
517
583
|
|
|
518
584
|
|
|
519
|
-
const ConnectionManager =
|
|
585
|
+
const ConnectionManager = _this6.sequelize.dialect.connectionManager.constructor; // @ts-ignore
|
|
520
586
|
|
|
521
|
-
const connectionManager = new ConnectionManager(
|
|
587
|
+
const connectionManager = new ConnectionManager(_this6.sequelize.dialect, _this6.sequelize); // @ts-ignore
|
|
522
588
|
|
|
523
|
-
|
|
589
|
+
_this6.sequelize.dialect.connectionManager = connectionManager; // @ts-ignore
|
|
524
590
|
|
|
525
|
-
|
|
591
|
+
_this6.sequelize.connectionManager = connectionManager;
|
|
526
592
|
})();
|
|
527
593
|
}
|
|
528
594
|
|
|
@@ -532,14 +598,14 @@ class Database extends _events().EventEmitter {
|
|
|
532
598
|
}
|
|
533
599
|
|
|
534
600
|
close() {
|
|
535
|
-
var
|
|
601
|
+
var _this7 = this;
|
|
536
602
|
|
|
537
603
|
return _asyncToGenerator(function* () {
|
|
538
|
-
if (
|
|
604
|
+
if (_this7.isSqliteMemory()) {
|
|
539
605
|
return;
|
|
540
606
|
}
|
|
541
607
|
|
|
542
|
-
return
|
|
608
|
+
return _this7.sequelize.close();
|
|
543
609
|
})();
|
|
544
610
|
}
|
|
545
611
|
|
|
@@ -556,7 +622,7 @@ class Database extends _events().EventEmitter {
|
|
|
556
622
|
}
|
|
557
623
|
|
|
558
624
|
import(options) {
|
|
559
|
-
var
|
|
625
|
+
var _this8 = this;
|
|
560
626
|
|
|
561
627
|
return _asyncToGenerator(function* () {
|
|
562
628
|
const reader = new _collectionImporter.ImporterReader(options.directory, options.extensions);
|
|
@@ -573,17 +639,17 @@ class Database extends _events().EventEmitter {
|
|
|
573
639
|
if (module.extend) {
|
|
574
640
|
const collectionName = module.collectionOptions.name;
|
|
575
641
|
|
|
576
|
-
const existCollection =
|
|
642
|
+
const existCollection = _this8.getCollection(collectionName);
|
|
577
643
|
|
|
578
644
|
if (existCollection) {
|
|
579
645
|
existCollection.updateOptions(module.collectionOptions, module.mergeOptions);
|
|
580
646
|
} else {
|
|
581
|
-
const existDelayExtends =
|
|
647
|
+
const existDelayExtends = _this8.delayCollectionExtend.get(collectionName) || [];
|
|
582
648
|
|
|
583
|
-
|
|
649
|
+
_this8.delayCollectionExtend.set(collectionName, [...existDelayExtends, module]);
|
|
584
650
|
}
|
|
585
651
|
} else {
|
|
586
|
-
const collection =
|
|
652
|
+
const collection = _this8.collection(module);
|
|
587
653
|
|
|
588
654
|
result.set(collection.name, collection);
|
|
589
655
|
}
|
|
@@ -59,7 +59,8 @@ class BelongsToField extends _relationField.RelationField {
|
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
const association = collection.model.belongsTo(Target, _objectSpread({
|
|
62
|
-
as: this.name
|
|
62
|
+
as: this.name,
|
|
63
|
+
constraints: false
|
|
63
64
|
}, (0, _lodash().omit)(this.options, ['name', 'type', 'target']))); // inverse relation
|
|
64
65
|
// this.TargetModel.hasMany(collection.model);
|
|
65
66
|
// 建立关系之后从 pending 列表中删除
|
|
@@ -75,6 +76,7 @@ class BelongsToField extends _relationField.RelationField {
|
|
|
75
76
|
this.options.sourceKey = association.sourceKey;
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
this.collection.addIndex([this.options.foreignKey]);
|
|
78
80
|
return true;
|
|
79
81
|
}
|
|
80
82
|
|
|
@@ -99,7 +101,7 @@ class BelongsToField extends _relationField.RelationField {
|
|
|
99
101
|
|
|
100
102
|
delete collection.model.associations[this.name]; // @ts-ignore
|
|
101
103
|
|
|
102
|
-
collection.model.refreshAttributes();
|
|
104
|
+
collection.model.refreshAttributes(); // this.collection.removeIndex([this.options.foreignKey]);
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
}
|
|
@@ -63,7 +63,9 @@ class BelongsToManyField extends _relationField.RelationField {
|
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const association = collection.model.belongsToMany(Target, _objectSpread(_objectSpread({
|
|
66
|
+
const association = collection.model.belongsToMany(Target, _objectSpread(_objectSpread({
|
|
67
|
+
constraints: false
|
|
68
|
+
}, (0, _lodash().omit)(this.options, ['name', 'type', 'target'])), {}, {
|
|
67
69
|
as: this.name,
|
|
68
70
|
through: Through.model
|
|
69
71
|
})); // 建立关系之后从 pending 列表中删除
|
|
@@ -86,6 +88,8 @@ class BelongsToManyField extends _relationField.RelationField {
|
|
|
86
88
|
this.options.through = this.through;
|
|
87
89
|
}
|
|
88
90
|
|
|
91
|
+
Through.addIndex([this.options.foreignKey]);
|
|
92
|
+
Through.addIndex([this.options.otherKey]);
|
|
89
93
|
return true;
|
|
90
94
|
}
|
|
91
95
|
|
package/lib/fields/field.js
CHANGED
|
@@ -209,11 +209,19 @@ class Field {
|
|
|
209
209
|
model.rawAttributes[this.name] = this.toSequelize(); // @ts-ignore
|
|
210
210
|
|
|
211
211
|
model.refreshAttributes();
|
|
212
|
+
|
|
213
|
+
if (this.options.index) {
|
|
214
|
+
this.context.collection.addIndex([this.name]);
|
|
215
|
+
}
|
|
212
216
|
}
|
|
213
217
|
|
|
214
218
|
unbind() {
|
|
215
219
|
const model = this.context.collection.model;
|
|
216
220
|
model.removeAttribute(this.name);
|
|
221
|
+
|
|
222
|
+
if (this.options.index) {
|
|
223
|
+
this.context.collection.removeIndex([this.name]);
|
|
224
|
+
}
|
|
217
225
|
}
|
|
218
226
|
|
|
219
227
|
toSequelize() {
|
|
@@ -58,10 +58,12 @@ class HasManyField extends _relationField.RelationField {
|
|
|
58
58
|
delete collection.model.associations[this.name];
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const association = collection.model.hasMany(Target, _objectSpread({
|
|
61
|
+
const association = collection.model.hasMany(Target, _objectSpread(_objectSpread({
|
|
62
|
+
constraints: false
|
|
63
|
+
}, (0, _lodash().omit)(this.options, ['name', 'type', 'target'])), {}, {
|
|
62
64
|
as: this.name,
|
|
63
65
|
foreignKey: this.foreignKey
|
|
64
|
-
}
|
|
66
|
+
})); // inverse relation
|
|
65
67
|
// this.TargetModel.belongsTo(collection.model);
|
|
66
68
|
// 建立关系之后从 pending 列表中删除
|
|
67
69
|
|
|
@@ -76,6 +78,18 @@ class HasManyField extends _relationField.RelationField {
|
|
|
76
78
|
this.options.sourceKey = association.sourceKey;
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
let tcoll;
|
|
82
|
+
|
|
83
|
+
if (this.target === collection.name) {
|
|
84
|
+
tcoll = collection;
|
|
85
|
+
} else {
|
|
86
|
+
tcoll = database.getCollection(this.target);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (tcoll) {
|
|
90
|
+
tcoll.addIndex([this.options.foreignKey]);
|
|
91
|
+
}
|
|
92
|
+
|
|
79
93
|
return true;
|
|
80
94
|
}
|
|
81
95
|
|
|
@@ -86,7 +100,7 @@ class HasManyField extends _relationField.RelationField {
|
|
|
86
100
|
|
|
87
101
|
database.removePendingField(this); // 如果关系表内没有显式的创建外键字段,删除关系时,外键也删除掉
|
|
88
102
|
|
|
89
|
-
const tcoll = database.
|
|
103
|
+
const tcoll = database.getCollection(this.target);
|
|
90
104
|
const foreignKey = this.options.foreignKey;
|
|
91
105
|
const field = tcoll.findField(field => {
|
|
92
106
|
if (field.name === foreignKey) {
|
|
@@ -61,10 +61,12 @@ class HasOneField extends _relationField.RelationField {
|
|
|
61
61
|
return false;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const association = collection.model.hasOne(Target, _objectSpread({
|
|
64
|
+
const association = collection.model.hasOne(Target, _objectSpread(_objectSpread({
|
|
65
|
+
constraints: false
|
|
66
|
+
}, (0, _lodash().omit)(this.options, ['name', 'type', 'target'])), {}, {
|
|
65
67
|
as: this.name,
|
|
66
68
|
foreignKey: this.foreignKey
|
|
67
|
-
}
|
|
69
|
+
})); // 建立关系之后从 pending 列表中删除
|
|
68
70
|
|
|
69
71
|
database.removePendingField(this);
|
|
70
72
|
|
|
@@ -77,6 +79,18 @@ class HasOneField extends _relationField.RelationField {
|
|
|
77
79
|
this.options.sourceKey = association.sourceKey;
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
let tcoll;
|
|
83
|
+
|
|
84
|
+
if (this.target === collection.name) {
|
|
85
|
+
tcoll = collection;
|
|
86
|
+
} else {
|
|
87
|
+
tcoll = database.getCollection(this.target);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (tcoll) {
|
|
91
|
+
tcoll.addIndex([this.options.foreignKey]);
|
|
92
|
+
}
|
|
93
|
+
|
|
80
94
|
return true;
|
|
81
95
|
}
|
|
82
96
|
|
|
@@ -16,6 +16,7 @@ export declare abstract class RelationRepository {
|
|
|
16
16
|
sourceInstance: Model;
|
|
17
17
|
db: Database;
|
|
18
18
|
constructor(sourceCollection: Collection, association: string, sourceKeyValue: string | number);
|
|
19
|
+
get collection(): Collection<any, any>;
|
|
19
20
|
targetKey(): any;
|
|
20
21
|
protected accessors(): import("sequelize").SingleAssociationAccessors | import("sequelize").MultiAssociationAccessors;
|
|
21
22
|
create(options?: CreateOptions): Promise<any>;
|
|
@@ -71,6 +71,10 @@ class RelationRepository {
|
|
|
71
71
|
this.targetCollection = this.sourceCollection.context.database.modelCollection.get(this.targetModel);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
get collection() {
|
|
75
|
+
return this.db.getCollection(this.targetModel.name);
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
targetKey() {
|
|
75
79
|
return this.associationField.targetKey;
|
|
76
80
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/database",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2-alpha.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
}
|
|
13
13
|
],
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@nocobase/utils": "0.7.
|
|
15
|
+
"@nocobase/utils": "0.7.2-alpha.2",
|
|
16
16
|
"async-mutex": "^0.3.2",
|
|
17
17
|
"deepmerge": "^4.2.2",
|
|
18
18
|
"flat": "^5.0.2",
|
|
19
19
|
"glob": "^7.1.6",
|
|
20
20
|
"mathjs": "^10.6.1",
|
|
21
|
+
"semver": "^7.3.7",
|
|
21
22
|
"sequelize": "^6.9.0",
|
|
22
23
|
"umzug": "^3.1.1"
|
|
23
24
|
},
|
|
@@ -29,5 +30,5 @@
|
|
|
29
30
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
30
31
|
"directory": "packages/database"
|
|
31
32
|
},
|
|
32
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "a0cc50154cc292248ef107c95a24bcc0c7a586fa"
|
|
33
34
|
}
|
|
@@ -13,6 +13,22 @@ describe('collection', () => {
|
|
|
13
13
|
await db.close();
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
+
test.skip('indexes', async () => {
|
|
17
|
+
await db.clean({ drop: true });
|
|
18
|
+
const collection = db.collection({
|
|
19
|
+
name: 'test',
|
|
20
|
+
fields: [
|
|
21
|
+
{
|
|
22
|
+
type: 'string',
|
|
23
|
+
name: 'name',
|
|
24
|
+
index: true,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
collection.removeField('name');
|
|
29
|
+
await db.sync();
|
|
30
|
+
});
|
|
31
|
+
|
|
16
32
|
test('removeFromDb', async () => {
|
|
17
33
|
await db.clean({ drop: true });
|
|
18
34
|
const collection = db.collection({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Collection } from '../collection';
|
|
2
2
|
import { Database } from '../database';
|
|
3
|
-
import {
|
|
3
|
+
import { updateAssociations } from '../update-associations';
|
|
4
4
|
import { mockDatabase } from './';
|
|
5
5
|
|
|
6
6
|
describe('update associations', () => {
|
|
@@ -356,13 +356,14 @@ describe('update associations', () => {
|
|
|
356
356
|
});
|
|
357
357
|
|
|
358
358
|
describe('belongsToMany', () => {
|
|
359
|
-
let db;
|
|
360
|
-
let Post;
|
|
361
|
-
let Tag;
|
|
362
|
-
let PostTag;
|
|
359
|
+
let db: Database;
|
|
360
|
+
let Post: Collection;
|
|
361
|
+
let Tag: Collection;
|
|
362
|
+
let PostTag: Collection;
|
|
363
363
|
|
|
364
364
|
beforeEach(async () => {
|
|
365
365
|
db = mockDatabase();
|
|
366
|
+
await db.clean({ drop: true });
|
|
366
367
|
PostTag = db.collection({
|
|
367
368
|
name: 'posts_tags',
|
|
368
369
|
fields: [{ type: 'string', name: 'tagged_at' }],
|
|
@@ -389,7 +390,7 @@ describe('update associations', () => {
|
|
|
389
390
|
afterEach(async () => {
|
|
390
391
|
await db.close();
|
|
391
392
|
});
|
|
392
|
-
test('set through value', async () => {
|
|
393
|
+
test.only('set through value', async () => {
|
|
393
394
|
const p1 = await Post.repository.create({
|
|
394
395
|
values: {
|
|
395
396
|
title: 'hello',
|
|
@@ -404,9 +405,12 @@ describe('update associations', () => {
|
|
|
404
405
|
],
|
|
405
406
|
},
|
|
406
407
|
});
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
408
|
+
const count = await PostTag.repository.count({
|
|
409
|
+
filter: {
|
|
410
|
+
tagged_at: '123',
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
expect(count).toEqual(1);
|
|
410
414
|
});
|
|
411
415
|
});
|
|
412
416
|
});
|
package/src/collection.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import merge from 'deepmerge';
|
|
2
2
|
import { EventEmitter } from 'events';
|
|
3
3
|
import { default as lodash, default as _ } from 'lodash';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
ModelCtor,
|
|
6
|
+
ModelOptions,
|
|
7
|
+
QueryInterfaceDropTableOptions,
|
|
8
|
+
SyncOptions,
|
|
9
|
+
Transactionable,
|
|
10
|
+
Utils
|
|
11
|
+
} from 'sequelize';
|
|
5
12
|
import { Database } from './database';
|
|
6
13
|
import { Field, FieldOptions } from './fields';
|
|
7
14
|
import { Model } from './model';
|
|
@@ -278,6 +285,67 @@ export class Collection<
|
|
|
278
285
|
this.setField(options.name || name, options);
|
|
279
286
|
}
|
|
280
287
|
|
|
288
|
+
addIndex(index: any) {
|
|
289
|
+
if (!index) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
let indexes: any = this.model.options.indexes || [];
|
|
293
|
+
let indexName = [];
|
|
294
|
+
let indexItem;
|
|
295
|
+
if (typeof index === 'string') {
|
|
296
|
+
indexItem = {
|
|
297
|
+
fields: [index],
|
|
298
|
+
};
|
|
299
|
+
indexName = [index];
|
|
300
|
+
} else if (Array.isArray(index)) {
|
|
301
|
+
indexItem = {
|
|
302
|
+
fields: index,
|
|
303
|
+
};
|
|
304
|
+
indexName = index;
|
|
305
|
+
} else if (index?.fields) {
|
|
306
|
+
indexItem = index;
|
|
307
|
+
indexName = index.fields;
|
|
308
|
+
}
|
|
309
|
+
if (lodash.isEqual(this.model.primaryKeyAttributes, indexName)) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const name: string = this.model.primaryKeyAttributes.join(',');
|
|
313
|
+
if (name.startsWith(`${indexName.join(',')},`)) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
for (const item of indexes) {
|
|
317
|
+
if (lodash.isEqual(item.fields, indexName)) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const name: string = item.fields.join(',');
|
|
321
|
+
if (name.startsWith(`${indexName.join(',')},`)) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (!indexItem) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
indexes.push(indexItem);
|
|
329
|
+
this.model.options.indexes = indexes;
|
|
330
|
+
const tableName = this.model.getTableName();
|
|
331
|
+
// @ts-ignore
|
|
332
|
+
this.model._indexes = this.model.options.indexes
|
|
333
|
+
// @ts-ignore
|
|
334
|
+
.map((index) => Utils.nameIndex(this.model._conformIndex(index), tableName));
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
removeIndex(fields: any) {
|
|
338
|
+
if (!fields) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
// @ts-ignore
|
|
342
|
+
const indexes: any[] = this.model._indexes;
|
|
343
|
+
// @ts-ignore
|
|
344
|
+
this.model._indexes = indexes.filter((item) => {
|
|
345
|
+
return !lodash.isEqual(item.fields, fields);
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
281
349
|
async sync(syncOptions?: SyncOptions) {
|
|
282
350
|
const modelNames = [this.model.name];
|
|
283
351
|
|
package/src/database.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { EventEmitter } from 'events';
|
|
|
4
4
|
import glob from 'glob';
|
|
5
5
|
import lodash from 'lodash';
|
|
6
6
|
import { basename, isAbsolute, resolve } from 'path';
|
|
7
|
+
import semver from 'semver';
|
|
7
8
|
import {
|
|
8
9
|
ModelCtor,
|
|
9
10
|
Op,
|
|
@@ -65,6 +66,46 @@ export type AddMigrationsOptions = {
|
|
|
65
66
|
|
|
66
67
|
type OperatorFunc = (value: any, ctx?: RegisterOperatorsContext) => any;
|
|
67
68
|
|
|
69
|
+
class DatabaseVersion {
|
|
70
|
+
db: Database;
|
|
71
|
+
|
|
72
|
+
constructor(db: Database) {
|
|
73
|
+
this.db = db;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async satisfies(versions) {
|
|
77
|
+
const dialects = {
|
|
78
|
+
sqlite: {
|
|
79
|
+
sql: 'select sqlite_version() as version',
|
|
80
|
+
get: (v) => v,
|
|
81
|
+
},
|
|
82
|
+
mysql: {
|
|
83
|
+
sql: 'select version() as version',
|
|
84
|
+
get: (v) => v,
|
|
85
|
+
},
|
|
86
|
+
postgres: {
|
|
87
|
+
sql: 'select version() as version',
|
|
88
|
+
get: (v) => {
|
|
89
|
+
const keys = v.split(' ');
|
|
90
|
+
keys.shift();
|
|
91
|
+
return semver.minVersion(keys.shift()).version;
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
for (const dialect of Object.keys(dialects)) {
|
|
96
|
+
if (this.db.inDialect(dialect)) {
|
|
97
|
+
if (!versions?.[dialect]) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
const [result] = (await this.db.sequelize.query(dialects[dialect].sql)) as any;
|
|
101
|
+
console.log(`db version: ${dialects[dialect].get(result?.[0]?.version)}`);
|
|
102
|
+
return semver.satisfies(dialects[dialect].get(result?.[0]?.version), versions[dialect]);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
68
109
|
export class Database extends EventEmitter implements AsyncEmitter {
|
|
69
110
|
sequelize: Sequelize;
|
|
70
111
|
migrator: Umzug;
|
|
@@ -79,12 +120,15 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
79
120
|
modelCollection = new Map<ModelCtor<any>, Collection>();
|
|
80
121
|
|
|
81
122
|
modelHook: ModelHook;
|
|
123
|
+
version: DatabaseVersion;
|
|
82
124
|
|
|
83
125
|
delayCollectionExtend = new Map<string, { collectionOptions: CollectionOptions; mergeOptions?: any }[]>();
|
|
84
126
|
|
|
85
127
|
constructor(options: DatabaseOptions) {
|
|
86
128
|
super();
|
|
87
129
|
|
|
130
|
+
this.version = new DatabaseVersion(this);
|
|
131
|
+
|
|
88
132
|
const opts = {
|
|
89
133
|
sync: {
|
|
90
134
|
alter: {
|
|
@@ -28,6 +28,7 @@ export class BelongsToField extends RelationField {
|
|
|
28
28
|
// define relation on sequelize model
|
|
29
29
|
const association = collection.model.belongsTo(Target, {
|
|
30
30
|
as: this.name,
|
|
31
|
+
constraints: false,
|
|
31
32
|
...omit(this.options, ['name', 'type', 'target']),
|
|
32
33
|
});
|
|
33
34
|
|
|
@@ -45,7 +46,7 @@ export class BelongsToField extends RelationField {
|
|
|
45
46
|
// @ts-ignore
|
|
46
47
|
this.options.sourceKey = association.sourceKey;
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
+
this.collection.addIndex([this.options.foreignKey]);
|
|
49
50
|
return true;
|
|
50
51
|
}
|
|
51
52
|
|
|
@@ -67,6 +68,7 @@ export class BelongsToField extends RelationField {
|
|
|
67
68
|
delete collection.model.associations[this.name];
|
|
68
69
|
// @ts-ignore
|
|
69
70
|
collection.model.refreshAttributes();
|
|
71
|
+
// this.collection.removeIndex([this.options.foreignKey]);
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
74
|
|
|
@@ -37,6 +37,7 @@ export class BelongsToManyField extends RelationField {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
const association = collection.model.belongsToMany(Target, {
|
|
40
|
+
constraints: false,
|
|
40
41
|
...omit(this.options, ['name', 'type', 'target']),
|
|
41
42
|
as: this.name,
|
|
42
43
|
through: Through.model,
|
|
@@ -57,6 +58,8 @@ export class BelongsToManyField extends RelationField {
|
|
|
57
58
|
if (!this.options.through) {
|
|
58
59
|
this.options.through = this.through;
|
|
59
60
|
}
|
|
61
|
+
Through.addIndex([this.options.foreignKey]);
|
|
62
|
+
Through.addIndex([this.options.otherKey]);
|
|
60
63
|
return true;
|
|
61
64
|
}
|
|
62
65
|
|
package/src/fields/field.ts
CHANGED
|
@@ -171,11 +171,17 @@ export abstract class Field {
|
|
|
171
171
|
model.rawAttributes[this.name] = this.toSequelize();
|
|
172
172
|
// @ts-ignore
|
|
173
173
|
model.refreshAttributes();
|
|
174
|
+
if (this.options.index) {
|
|
175
|
+
this.context.collection.addIndex([this.name]);
|
|
176
|
+
}
|
|
174
177
|
}
|
|
175
178
|
|
|
176
179
|
unbind() {
|
|
177
180
|
const { model } = this.context.collection;
|
|
178
181
|
model.removeAttribute(this.name);
|
|
182
|
+
if (this.options.index) {
|
|
183
|
+
this.context.collection.removeIndex([this.name]);
|
|
184
|
+
}
|
|
179
185
|
}
|
|
180
186
|
|
|
181
187
|
toSequelize(): any {
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
ForeignKeyOptions,
|
|
6
6
|
HasManyOptions,
|
|
7
7
|
HasManyOptions as SequelizeHasManyOptions,
|
|
8
|
-
Utils
|
|
8
|
+
Utils
|
|
9
9
|
} from 'sequelize';
|
|
10
|
-
|
|
11
|
-
import {
|
|
10
|
+
import { Collection } from '../collection';
|
|
11
|
+
import { MultipleRelationFieldOptions, RelationField } from './relation-field';
|
|
12
12
|
|
|
13
13
|
export interface HasManyFieldOptions extends HasManyOptions {
|
|
14
14
|
/**
|
|
@@ -93,11 +93,11 @@ export class HasManyField extends RelationField {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
const association = collection.model.hasMany(Target, {
|
|
96
|
+
constraints: false,
|
|
97
|
+
...omit(this.options, ['name', 'type', 'target']),
|
|
96
98
|
as: this.name,
|
|
97
99
|
foreignKey: this.foreignKey,
|
|
98
|
-
...omit(this.options, ['name', 'type', 'target']),
|
|
99
100
|
});
|
|
100
|
-
|
|
101
101
|
// inverse relation
|
|
102
102
|
// this.TargetModel.belongsTo(collection.model);
|
|
103
103
|
|
|
@@ -111,6 +111,15 @@ export class HasManyField extends RelationField {
|
|
|
111
111
|
// @ts-ignore
|
|
112
112
|
this.options.sourceKey = association.sourceKey;
|
|
113
113
|
}
|
|
114
|
+
let tcoll: Collection;
|
|
115
|
+
if (this.target === collection.name) {
|
|
116
|
+
tcoll = collection;
|
|
117
|
+
} else {
|
|
118
|
+
tcoll = database.getCollection(this.target);
|
|
119
|
+
}
|
|
120
|
+
if (tcoll) {
|
|
121
|
+
tcoll.addIndex([this.options.foreignKey]);
|
|
122
|
+
}
|
|
114
123
|
return true;
|
|
115
124
|
}
|
|
116
125
|
|
|
@@ -119,7 +128,7 @@ export class HasManyField extends RelationField {
|
|
|
119
128
|
// 如果关系字段还没建立就删除了,也同步删除待建立关联的关系字段
|
|
120
129
|
database.removePendingField(this);
|
|
121
130
|
// 如果关系表内没有显式的创建外键字段,删除关系时,外键也删除掉
|
|
122
|
-
const tcoll = database.
|
|
131
|
+
const tcoll = database.getCollection(this.target);
|
|
123
132
|
const foreignKey = this.options.foreignKey;
|
|
124
133
|
const field = tcoll.findField((field) => {
|
|
125
134
|
if (field.name === foreignKey) {
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
HasOneOptions as SequelizeHasOneOptions,
|
|
8
8
|
Utils
|
|
9
9
|
} from 'sequelize';
|
|
10
|
+
import { Collection } from '../collection';
|
|
10
11
|
import { BaseRelationFieldOptions, RelationField } from './relation-field';
|
|
11
12
|
|
|
12
13
|
export interface HasOneFieldOptions extends HasOneOptions {
|
|
@@ -92,9 +93,10 @@ export class HasOneField extends RelationField {
|
|
|
92
93
|
return false;
|
|
93
94
|
}
|
|
94
95
|
const association = collection.model.hasOne(Target, {
|
|
96
|
+
constraints: false,
|
|
97
|
+
...omit(this.options, ['name', 'type', 'target']),
|
|
95
98
|
as: this.name,
|
|
96
99
|
foreignKey: this.foreignKey,
|
|
97
|
-
...omit(this.options, ['name', 'type', 'target']),
|
|
98
100
|
});
|
|
99
101
|
// 建立关系之后从 pending 列表中删除
|
|
100
102
|
database.removePendingField(this);
|
|
@@ -105,6 +107,15 @@ export class HasOneField extends RelationField {
|
|
|
105
107
|
// @ts-ignore
|
|
106
108
|
this.options.sourceKey = association.sourceKey;
|
|
107
109
|
}
|
|
110
|
+
let tcoll: Collection;
|
|
111
|
+
if (this.target === collection.name) {
|
|
112
|
+
tcoll = collection;
|
|
113
|
+
} else {
|
|
114
|
+
tcoll = database.getCollection(this.target);
|
|
115
|
+
}
|
|
116
|
+
if (tcoll) {
|
|
117
|
+
tcoll.addIndex([this.options.foreignKey]);
|
|
118
|
+
}
|
|
108
119
|
return true;
|
|
109
120
|
}
|
|
110
121
|
|
|
@@ -40,6 +40,10 @@ export abstract class RelationRepository {
|
|
|
40
40
|
this.targetCollection = this.sourceCollection.context.database.modelCollection.get(this.targetModel);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
get collection() {
|
|
44
|
+
return this.db.getCollection(this.targetModel.name);
|
|
45
|
+
}
|
|
46
|
+
|
|
43
47
|
targetKey() {
|
|
44
48
|
return this.associationField.targetKey;
|
|
45
49
|
}
|