@nocobase/database 0.7.1-alpha.7 → 0.7.2-alpha.3
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 -1
- package/lib/database.js +107 -75
- 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;
|
|
@@ -78,7 +84,6 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
|
78
84
|
getCollection(name: string): Collection;
|
|
79
85
|
hasCollection(name: string): boolean;
|
|
80
86
|
removeCollection(name: string): Collection<any, any>;
|
|
81
|
-
getCollectionFieldByPath(path: string): FieldTypes.Field;
|
|
82
87
|
getModel<M extends Model>(name: string): ModelCtor<M>;
|
|
83
88
|
getRepository<R extends Repository>(name: string): R;
|
|
84
89
|
getRepository<R extends RelationRepository>(name: string, relationId: string | number): R;
|
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,15 +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
|
|
106
|
-
|
|
107
|
-
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); }); }; }
|
|
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; } } }; }
|
|
108
116
|
|
|
109
|
-
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; }
|
|
110
118
|
|
|
111
|
-
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; }
|
|
112
120
|
|
|
113
|
-
function
|
|
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; }
|
|
114
122
|
|
|
115
123
|
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
116
124
|
|
|
@@ -124,11 +132,63 @@ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Sy
|
|
|
124
132
|
|
|
125
133
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
126
134
|
|
|
127
|
-
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); } }
|
|
128
136
|
|
|
129
|
-
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); }); }; }
|
|
130
138
|
|
|
131
|
-
|
|
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
|
+
}
|
|
132
192
|
|
|
133
193
|
class Database extends _events().EventEmitter {
|
|
134
194
|
constructor(options) {
|
|
@@ -145,7 +205,9 @@ class Database extends _events().EventEmitter {
|
|
|
145
205
|
this.pendingFields = new Map();
|
|
146
206
|
this.modelCollection = new Map();
|
|
147
207
|
this.modelHook = void 0;
|
|
208
|
+
this.version = void 0;
|
|
148
209
|
this.delayCollectionExtend = new Map();
|
|
210
|
+
this.version = new DatabaseVersion(this);
|
|
149
211
|
|
|
150
212
|
const opts = _objectSpread({
|
|
151
213
|
sync: {
|
|
@@ -182,8 +244,8 @@ class Database extends _events().EventEmitter {
|
|
|
182
244
|
});
|
|
183
245
|
}); // register database field types
|
|
184
246
|
|
|
185
|
-
for (var
|
|
186
|
-
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),
|
|
187
249
|
name = _Object$entries$_i[0],
|
|
188
250
|
field = _Object$entries$_i[1];
|
|
189
251
|
|
|
@@ -319,36 +381,6 @@ class Database extends _events().EventEmitter {
|
|
|
319
381
|
return collection;
|
|
320
382
|
}
|
|
321
383
|
|
|
322
|
-
getCollectionFieldByPath(path) {
|
|
323
|
-
const _path$split = path.split('.'),
|
|
324
|
-
_path$split2 = _toArray(_path$split),
|
|
325
|
-
collectionName = _path$split2[0],
|
|
326
|
-
fieldName = _path$split2[1],
|
|
327
|
-
others = _path$split2.slice(2);
|
|
328
|
-
|
|
329
|
-
const collection = this.getCollection(collectionName);
|
|
330
|
-
|
|
331
|
-
if (!collection) {
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
const field = collection.getField(fieldName);
|
|
336
|
-
|
|
337
|
-
if (others.length === 0) {
|
|
338
|
-
return field;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (field.target) {
|
|
342
|
-
const target = this.getCollection(field.target);
|
|
343
|
-
|
|
344
|
-
if (!target) {
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
return target.getField(others[0]);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
384
|
getModel(name) {
|
|
353
385
|
return this.getCollection(name).model;
|
|
354
386
|
}
|
|
@@ -388,8 +420,8 @@ class Database extends _events().EventEmitter {
|
|
|
388
420
|
}
|
|
389
421
|
|
|
390
422
|
registerFieldTypes(fieldTypes) {
|
|
391
|
-
for (var
|
|
392
|
-
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),
|
|
393
425
|
type = _Object$entries2$_i[0],
|
|
394
426
|
fieldType = _Object$entries2$_i[1];
|
|
395
427
|
|
|
@@ -398,8 +430,8 @@ class Database extends _events().EventEmitter {
|
|
|
398
430
|
}
|
|
399
431
|
|
|
400
432
|
registerModels(models) {
|
|
401
|
-
for (var
|
|
402
|
-
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),
|
|
403
435
|
type = _Object$entries3$_i[0],
|
|
404
436
|
schemaType = _Object$entries3$_i[1];
|
|
405
437
|
|
|
@@ -408,8 +440,8 @@ class Database extends _events().EventEmitter {
|
|
|
408
440
|
}
|
|
409
441
|
|
|
410
442
|
registerRepositories(repositories) {
|
|
411
|
-
for (var
|
|
412
|
-
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),
|
|
413
445
|
type = _Object$entries4$_i[0],
|
|
414
446
|
schemaType = _Object$entries4$_i[1];
|
|
415
447
|
|
|
@@ -434,8 +466,8 @@ class Database extends _events().EventEmitter {
|
|
|
434
466
|
}
|
|
435
467
|
|
|
436
468
|
registerOperators(operators) {
|
|
437
|
-
for (var
|
|
438
|
-
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),
|
|
439
471
|
key = _Object$entries5$_i[0],
|
|
440
472
|
operator = _Object$entries5$_i[1];
|
|
441
473
|
|
|
@@ -455,19 +487,19 @@ class Database extends _events().EventEmitter {
|
|
|
455
487
|
}
|
|
456
488
|
|
|
457
489
|
sync(options) {
|
|
458
|
-
var
|
|
490
|
+
var _this2 = this;
|
|
459
491
|
|
|
460
492
|
return _asyncToGenerator(function* () {
|
|
461
|
-
const isMySQL =
|
|
493
|
+
const isMySQL = _this2.sequelize.getDialect() === 'mysql';
|
|
462
494
|
|
|
463
495
|
if (isMySQL) {
|
|
464
|
-
yield
|
|
496
|
+
yield _this2.sequelize.query('SET FOREIGN_KEY_CHECKS = 0', null);
|
|
465
497
|
}
|
|
466
498
|
|
|
467
|
-
const result = yield
|
|
499
|
+
const result = yield _this2.sequelize.sync(options);
|
|
468
500
|
|
|
469
501
|
if (isMySQL) {
|
|
470
|
-
yield
|
|
502
|
+
yield _this2.sequelize.query('SET FOREIGN_KEY_CHECKS = 1', null);
|
|
471
503
|
}
|
|
472
504
|
|
|
473
505
|
return result;
|
|
@@ -475,26 +507,26 @@ class Database extends _events().EventEmitter {
|
|
|
475
507
|
}
|
|
476
508
|
|
|
477
509
|
clean(options) {
|
|
478
|
-
var
|
|
510
|
+
var _this3 = this;
|
|
479
511
|
|
|
480
512
|
return _asyncToGenerator(function* () {
|
|
481
513
|
const drop = options.drop,
|
|
482
514
|
others = _objectWithoutProperties(options, _excluded);
|
|
483
515
|
|
|
484
516
|
if (drop) {
|
|
485
|
-
yield
|
|
517
|
+
yield _this3.sequelize.getQueryInterface().dropAllTables(others);
|
|
486
518
|
}
|
|
487
519
|
})();
|
|
488
520
|
}
|
|
489
521
|
|
|
490
522
|
collectionExistsInDb(name, options) {
|
|
491
|
-
var
|
|
523
|
+
var _this4 = this;
|
|
492
524
|
|
|
493
525
|
return _asyncToGenerator(function* () {
|
|
494
|
-
const tables = yield
|
|
526
|
+
const tables = yield _this4.sequelize.getQueryInterface().showAllTables({
|
|
495
527
|
transaction: options === null || options === void 0 ? void 0 : options.transaction
|
|
496
528
|
});
|
|
497
|
-
return !!tables.find(table => table === `${
|
|
529
|
+
return !!tables.find(table => table === `${_this4.getTablePrefix()}${name}`);
|
|
498
530
|
})();
|
|
499
531
|
}
|
|
500
532
|
|
|
@@ -503,7 +535,7 @@ class Database extends _events().EventEmitter {
|
|
|
503
535
|
}
|
|
504
536
|
|
|
505
537
|
auth(options = {}) {
|
|
506
|
-
var
|
|
538
|
+
var _this5 = this;
|
|
507
539
|
|
|
508
540
|
return _asyncToGenerator(function* () {
|
|
509
541
|
const _options$retry = options.retry,
|
|
@@ -517,7 +549,7 @@ class Database extends _events().EventEmitter {
|
|
|
517
549
|
const authenticate = /*#__PURE__*/function () {
|
|
518
550
|
var _ref = _asyncToGenerator(function* () {
|
|
519
551
|
try {
|
|
520
|
-
yield
|
|
552
|
+
yield _this5.sequelize.authenticate(others);
|
|
521
553
|
console.log('Connection has been established successfully.');
|
|
522
554
|
return true;
|
|
523
555
|
} catch (error) {
|
|
@@ -542,21 +574,21 @@ class Database extends _events().EventEmitter {
|
|
|
542
574
|
}
|
|
543
575
|
|
|
544
576
|
reconnect() {
|
|
545
|
-
var
|
|
577
|
+
var _this6 = this;
|
|
546
578
|
|
|
547
579
|
return _asyncToGenerator(function* () {
|
|
548
|
-
if (
|
|
580
|
+
if (_this6.isSqliteMemory()) {
|
|
549
581
|
return;
|
|
550
582
|
} // @ts-ignore
|
|
551
583
|
|
|
552
584
|
|
|
553
|
-
const ConnectionManager =
|
|
585
|
+
const ConnectionManager = _this6.sequelize.dialect.connectionManager.constructor; // @ts-ignore
|
|
554
586
|
|
|
555
|
-
const connectionManager = new ConnectionManager(
|
|
587
|
+
const connectionManager = new ConnectionManager(_this6.sequelize.dialect, _this6.sequelize); // @ts-ignore
|
|
556
588
|
|
|
557
|
-
|
|
589
|
+
_this6.sequelize.dialect.connectionManager = connectionManager; // @ts-ignore
|
|
558
590
|
|
|
559
|
-
|
|
591
|
+
_this6.sequelize.connectionManager = connectionManager;
|
|
560
592
|
})();
|
|
561
593
|
}
|
|
562
594
|
|
|
@@ -566,14 +598,14 @@ class Database extends _events().EventEmitter {
|
|
|
566
598
|
}
|
|
567
599
|
|
|
568
600
|
close() {
|
|
569
|
-
var
|
|
601
|
+
var _this7 = this;
|
|
570
602
|
|
|
571
603
|
return _asyncToGenerator(function* () {
|
|
572
|
-
if (
|
|
604
|
+
if (_this7.isSqliteMemory()) {
|
|
573
605
|
return;
|
|
574
606
|
}
|
|
575
607
|
|
|
576
|
-
return
|
|
608
|
+
return _this7.sequelize.close();
|
|
577
609
|
})();
|
|
578
610
|
}
|
|
579
611
|
|
|
@@ -590,7 +622,7 @@ class Database extends _events().EventEmitter {
|
|
|
590
622
|
}
|
|
591
623
|
|
|
592
624
|
import(options) {
|
|
593
|
-
var
|
|
625
|
+
var _this8 = this;
|
|
594
626
|
|
|
595
627
|
return _asyncToGenerator(function* () {
|
|
596
628
|
const reader = new _collectionImporter.ImporterReader(options.directory, options.extensions);
|
|
@@ -607,17 +639,17 @@ class Database extends _events().EventEmitter {
|
|
|
607
639
|
if (module.extend) {
|
|
608
640
|
const collectionName = module.collectionOptions.name;
|
|
609
641
|
|
|
610
|
-
const existCollection =
|
|
642
|
+
const existCollection = _this8.getCollection(collectionName);
|
|
611
643
|
|
|
612
644
|
if (existCollection) {
|
|
613
645
|
existCollection.updateOptions(module.collectionOptions, module.mergeOptions);
|
|
614
646
|
} else {
|
|
615
|
-
const existDelayExtends =
|
|
647
|
+
const existDelayExtends = _this8.delayCollectionExtend.get(collectionName) || [];
|
|
616
648
|
|
|
617
|
-
|
|
649
|
+
_this8.delayCollectionExtend.set(collectionName, [...existDelayExtends, module]);
|
|
618
650
|
}
|
|
619
651
|
} else {
|
|
620
|
-
const collection =
|
|
652
|
+
const collection = _this8.collection(module);
|
|
621
653
|
|
|
622
654
|
result.set(collection.name, collection);
|
|
623
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.3",
|
|
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.3",
|
|
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": "7ab5ec36f6408dd2fab545970a08679e8c2820e5"
|
|
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
|
}
|