@nocobase/database 0.7.6-alpha.2 → 0.8.0-alpha.4
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 +1 -1
- package/lib/collection.js +1 -0
- package/lib/database.d.ts +17 -2
- package/lib/database.js +53 -41
- package/lib/features/ReferencesMap.d.ts +15 -0
- package/lib/features/ReferencesMap.js +60 -0
- package/lib/features/referential-integrity-check.d.ts +8 -0
- package/lib/features/referential-integrity-check.js +89 -0
- package/lib/fields/belongs-to-field.d.ts +2 -0
- package/lib/fields/belongs-to-field.js +16 -2
- package/lib/fields/belongs-to-many-field.d.ts +1 -0
- package/lib/fields/belongs-to-many-field.js +8 -2
- package/lib/fields/context-field.d.ts +2 -1
- package/lib/fields/context-field.js +12 -8
- package/lib/fields/field.d.ts +2 -1
- package/lib/fields/field.js +1 -0
- package/lib/fields/formula-field.js +1 -1
- package/lib/fields/has-many-field.d.ts +2 -0
- package/lib/fields/has-many-field.js +19 -1
- package/lib/fields/has-one-field.d.ts +2 -0
- package/lib/fields/has-one-field.js +16 -2
- package/lib/filter-parser.js +5 -3
- package/lib/model.d.ts +1 -0
- package/lib/options-parser.js +3 -2
- package/lib/relation-repository/belongs-to-many-repository.d.ts +3 -3
- package/lib/relation-repository/hasmany-repository.d.ts +2 -2
- package/lib/relation-repository/hasone-repository.d.ts +2 -4
- package/lib/relation-repository/multiple-relation-repository.d.ts +2 -5
- package/lib/relation-repository/relation-repository.js +2 -2
- package/lib/relation-repository/single-relation-repository.d.ts +1 -1
- package/lib/repository.d.ts +25 -15
- package/lib/repository.js +3 -1
- package/lib/types.d.ts +43 -0
- package/lib/types.js +5 -0
- package/package.json +3 -3
- package/src/__tests__/fields/belongs-to-field.test.ts +112 -4
- package/src/__tests__/fields/has-many-field.test.ts +83 -0
- package/src/__tests__/relation-repository/hasone-repository.test.ts +3 -3
- package/src/__tests__/repository/find.test.ts +10 -0
- package/src/collection.ts +3 -1
- package/src/database.ts +64 -15
- package/src/features/ReferencesMap.ts +64 -0
- package/src/features/referential-integrity-check.ts +61 -0
- package/src/fields/belongs-to-field.ts +21 -1
- package/src/fields/belongs-to-many-field.ts +6 -0
- package/src/fields/context-field.ts +5 -7
- package/src/fields/field.ts +4 -3
- package/src/fields/formula-field.ts +4 -4
- package/src/fields/has-many-field.ts +25 -2
- package/src/fields/has-one-field.ts +22 -2
- package/src/filter-parser.ts +5 -1
- package/src/model.ts +1 -0
- package/src/options-parser.ts +4 -2
- package/src/relation-repository/belongs-to-many-repository.ts +3 -3
- package/src/relation-repository/hasmany-repository.ts +8 -5
- package/src/relation-repository/hasone-repository.ts +2 -4
- package/src/relation-repository/multiple-relation-repository.ts +3 -4
- package/src/relation-repository/relation-repository.ts +1 -1
- package/src/relation-repository/single-relation-repository.ts +1 -1
- package/src/repository.ts +41 -19
- package/src/types.ts +64 -0
package/lib/collection.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export declare class Collection<TModelAttributes extends {} = any, TCreationAttr
|
|
|
41
41
|
get filterTargetKey(): string;
|
|
42
42
|
get name(): string;
|
|
43
43
|
get db(): Database;
|
|
44
|
-
constructor(options: CollectionOptions, context
|
|
44
|
+
constructor(options: CollectionOptions, context: CollectionContext);
|
|
45
45
|
private checkOptions;
|
|
46
46
|
private sequelizeModelOptions;
|
|
47
47
|
/**
|
package/lib/collection.js
CHANGED
|
@@ -102,6 +102,7 @@ class Collection extends _events().EventEmitter {
|
|
|
102
102
|
this.options = options;
|
|
103
103
|
this.bindFieldEventListener();
|
|
104
104
|
this.modelInit();
|
|
105
|
+
this.db.modelCollection.set(this.model, this);
|
|
105
106
|
this.setFields(options.fields);
|
|
106
107
|
this.setRepository(options.repository);
|
|
107
108
|
this.setSortable(options.sortable);
|
package/lib/database.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ import { Model } from './model';
|
|
|
13
13
|
import { ModelHook } from './model-hook';
|
|
14
14
|
import { RelationRepository } from './relation-repository/relation-repository';
|
|
15
15
|
import { Repository } from './repository';
|
|
16
|
+
import { AfterDefineCollectionListener, BeforeDefineCollectionListener, CreateListener, CreateWithAssociationsListener, DatabaseAfterDefineCollectionEventType, DatabaseAfterRemoveCollectionEventType, DatabaseBeforeDefineCollectionEventType, DatabaseBeforeRemoveCollectionEventType, DestroyListener, EventType, ModelCreateEventTypes, ModelCreateWithAssociationsEventTypes, ModelDestroyEventTypes, ModelSaveEventTypes, ModelSaveWithAssociationsEventTypes, ModelUpdateEventTypes, ModelUpdateWithAssociationsEventTypes, ModelValidateEventTypes, RemoveCollectionListener, SaveListener, SaveWithAssociationsListener, SyncListener, UpdateListener, UpdateWithAssociationsListener, ValidateListener } from './types';
|
|
17
|
+
import ReferencesMap from './features/ReferencesMap';
|
|
16
18
|
export interface MergeOptions extends merge.Options {
|
|
17
19
|
}
|
|
18
20
|
export interface PendingOptions {
|
|
@@ -60,6 +62,7 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
|
60
62
|
collections: Map<string, Collection<any, any>>;
|
|
61
63
|
pendingFields: Map<string, FieldTypes.RelationField[]>;
|
|
62
64
|
modelCollection: Map<ModelCtor<any>, Collection<any, any>>;
|
|
65
|
+
referenceMap: ReferencesMap;
|
|
63
66
|
modelHook: ModelHook;
|
|
64
67
|
version: DatabaseVersion;
|
|
65
68
|
delayCollectionExtend: Map<string, {
|
|
@@ -67,10 +70,10 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
|
67
70
|
mergeOptions?: any;
|
|
68
71
|
}[]>;
|
|
69
72
|
constructor(options: DatabaseOptions);
|
|
73
|
+
initListener(): void;
|
|
70
74
|
addMigration(item: MigrationItem): void;
|
|
71
75
|
addMigrations(options: AddMigrationsOptions): void;
|
|
72
76
|
inDialect(...dialect: string[]): boolean;
|
|
73
|
-
private requireModule;
|
|
74
77
|
/**
|
|
75
78
|
* Add collection to database
|
|
76
79
|
* @param options
|
|
@@ -105,7 +108,19 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
|
105
108
|
reconnect(): Promise<void>;
|
|
106
109
|
closed(): any;
|
|
107
110
|
close(): Promise<void>;
|
|
108
|
-
on(event:
|
|
111
|
+
on(event: EventType, listener: any): this;
|
|
112
|
+
on(event: ModelValidateEventTypes, listener: SyncListener): this;
|
|
113
|
+
on(event: ModelValidateEventTypes, listener: ValidateListener): this;
|
|
114
|
+
on(event: ModelCreateEventTypes, listener: CreateListener): this;
|
|
115
|
+
on(event: ModelUpdateEventTypes, listener: UpdateListener): this;
|
|
116
|
+
on(event: ModelSaveEventTypes, listener: SaveListener): this;
|
|
117
|
+
on(event: ModelDestroyEventTypes, listener: DestroyListener): this;
|
|
118
|
+
on(event: ModelCreateWithAssociationsEventTypes, listener: CreateWithAssociationsListener): this;
|
|
119
|
+
on(event: ModelUpdateWithAssociationsEventTypes, listener: UpdateWithAssociationsListener): this;
|
|
120
|
+
on(event: ModelSaveWithAssociationsEventTypes, listener: SaveWithAssociationsListener): this;
|
|
121
|
+
on(event: DatabaseBeforeDefineCollectionEventType, listener: BeforeDefineCollectionListener): this;
|
|
122
|
+
on(event: DatabaseAfterDefineCollectionEventType, listener: AfterDefineCollectionListener): this;
|
|
123
|
+
on(event: DatabaseBeforeRemoveCollectionEventType | DatabaseAfterRemoveCollectionEventType, listener: RemoveCollectionListener): this;
|
|
109
124
|
extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): void;
|
|
110
125
|
import(options: {
|
|
111
126
|
directory: string;
|
package/lib/database.js
CHANGED
|
@@ -98,6 +98,10 @@ var _modelHook = require("./model-hook");
|
|
|
98
98
|
|
|
99
99
|
var _operators = _interopRequireDefault(require("./operators"));
|
|
100
100
|
|
|
101
|
+
var _referentialIntegrityCheck = require("./features/referential-integrity-check");
|
|
102
|
+
|
|
103
|
+
var _ReferencesMap = _interopRequireDefault(require("./features/ReferencesMap"));
|
|
104
|
+
|
|
101
105
|
const _excluded = ["drop"],
|
|
102
106
|
_excluded2 = ["retry"];
|
|
103
107
|
|
|
@@ -192,7 +196,8 @@ class DatabaseVersion {
|
|
|
192
196
|
|
|
193
197
|
class Database extends _events().EventEmitter {
|
|
194
198
|
constructor(options) {
|
|
195
|
-
super();
|
|
199
|
+
super(); // this.setMaxListeners(100);
|
|
200
|
+
|
|
196
201
|
this.sequelize = void 0;
|
|
197
202
|
this.migrator = void 0;
|
|
198
203
|
this.migrations = void 0;
|
|
@@ -204,6 +209,7 @@ class Database extends _events().EventEmitter {
|
|
|
204
209
|
this.collections = new Map();
|
|
205
210
|
this.pendingFields = new Map();
|
|
206
211
|
this.modelCollection = new Map();
|
|
212
|
+
this.referenceMap = new _ReferencesMap.default();
|
|
207
213
|
this.modelHook = void 0;
|
|
208
214
|
this.version = void 0;
|
|
209
215
|
this.delayCollectionExtend = new Map();
|
|
@@ -285,6 +291,12 @@ class Database extends _events().EventEmitter {
|
|
|
285
291
|
opts.tableName = `${this.options.tablePrefix}${opts.tableName || opts.modelName || opts.name.plural}`;
|
|
286
292
|
}
|
|
287
293
|
});
|
|
294
|
+
this.initListener();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
initListener() {
|
|
298
|
+
var _this2 = this;
|
|
299
|
+
|
|
288
300
|
this.on('afterCreate', /*#__PURE__*/function () {
|
|
289
301
|
var _ref = _asyncToGenerator(function* (instance) {
|
|
290
302
|
var _instance$toChangedWi;
|
|
@@ -307,6 +319,19 @@ class Database extends _events().EventEmitter {
|
|
|
307
319
|
return _ref2.apply(this, arguments);
|
|
308
320
|
};
|
|
309
321
|
}());
|
|
322
|
+
this.on('beforeDestroy', /*#__PURE__*/function () {
|
|
323
|
+
var _ref3 = _asyncToGenerator(function* (instance, options) {
|
|
324
|
+
yield (0, _referentialIntegrityCheck.referentialIntegrityCheck)({
|
|
325
|
+
db: _this2,
|
|
326
|
+
referencedInstance: instance,
|
|
327
|
+
transaction: options.transaction
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
return function (_x3, _x4) {
|
|
332
|
+
return _ref3.apply(this, arguments);
|
|
333
|
+
};
|
|
334
|
+
}());
|
|
310
335
|
}
|
|
311
336
|
|
|
312
337
|
addMigration(item) {
|
|
@@ -335,7 +360,7 @@ class Database extends _events().EventEmitter {
|
|
|
335
360
|
filename = filename.substring(0, filename.lastIndexOf('.')) || filename;
|
|
336
361
|
this.migrations.add({
|
|
337
362
|
name: namespace ? `${namespace}/${filename}` : filename,
|
|
338
|
-
migration:
|
|
363
|
+
migration: (0, _utils().requireModule)(file),
|
|
339
364
|
context
|
|
340
365
|
});
|
|
341
366
|
}
|
|
@@ -349,18 +374,6 @@ class Database extends _events().EventEmitter {
|
|
|
349
374
|
inDialect(...dialect) {
|
|
350
375
|
return dialect.includes(this.sequelize.getDialect());
|
|
351
376
|
}
|
|
352
|
-
|
|
353
|
-
requireModule(module) {
|
|
354
|
-
if (typeof module === 'string') {
|
|
355
|
-
module = require(module);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (typeof module !== 'object') {
|
|
359
|
-
return module;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return module.__esModule ? module.default : module;
|
|
363
|
-
}
|
|
364
377
|
/**
|
|
365
378
|
* Add collection to database
|
|
366
379
|
* @param options
|
|
@@ -373,7 +386,6 @@ class Database extends _events().EventEmitter {
|
|
|
373
386
|
database: this
|
|
374
387
|
});
|
|
375
388
|
this.collections.set(collection.name, collection);
|
|
376
|
-
this.modelCollection.set(collection.model, collection);
|
|
377
389
|
this.emit('afterDefineCollection', collection);
|
|
378
390
|
return collection;
|
|
379
391
|
}
|
|
@@ -514,19 +526,19 @@ class Database extends _events().EventEmitter {
|
|
|
514
526
|
}
|
|
515
527
|
|
|
516
528
|
sync(options) {
|
|
517
|
-
var
|
|
529
|
+
var _this3 = this;
|
|
518
530
|
|
|
519
531
|
return _asyncToGenerator(function* () {
|
|
520
|
-
const isMySQL =
|
|
532
|
+
const isMySQL = _this3.sequelize.getDialect() === 'mysql';
|
|
521
533
|
|
|
522
534
|
if (isMySQL) {
|
|
523
|
-
yield
|
|
535
|
+
yield _this3.sequelize.query('SET FOREIGN_KEY_CHECKS = 0', null);
|
|
524
536
|
}
|
|
525
537
|
|
|
526
|
-
const result = yield
|
|
538
|
+
const result = yield _this3.sequelize.sync(options);
|
|
527
539
|
|
|
528
540
|
if (isMySQL) {
|
|
529
|
-
yield
|
|
541
|
+
yield _this3.sequelize.query('SET FOREIGN_KEY_CHECKS = 1', null);
|
|
530
542
|
}
|
|
531
543
|
|
|
532
544
|
return result;
|
|
@@ -534,26 +546,26 @@ class Database extends _events().EventEmitter {
|
|
|
534
546
|
}
|
|
535
547
|
|
|
536
548
|
clean(options) {
|
|
537
|
-
var
|
|
549
|
+
var _this4 = this;
|
|
538
550
|
|
|
539
551
|
return _asyncToGenerator(function* () {
|
|
540
552
|
const drop = options.drop,
|
|
541
553
|
others = _objectWithoutProperties(options, _excluded);
|
|
542
554
|
|
|
543
555
|
if (drop) {
|
|
544
|
-
yield
|
|
556
|
+
yield _this4.sequelize.getQueryInterface().dropAllTables(others);
|
|
545
557
|
}
|
|
546
558
|
})();
|
|
547
559
|
}
|
|
548
560
|
|
|
549
561
|
collectionExistsInDb(name, options) {
|
|
550
|
-
var
|
|
562
|
+
var _this5 = this;
|
|
551
563
|
|
|
552
564
|
return _asyncToGenerator(function* () {
|
|
553
|
-
const tables = yield
|
|
565
|
+
const tables = yield _this5.sequelize.getQueryInterface().showAllTables({
|
|
554
566
|
transaction: options === null || options === void 0 ? void 0 : options.transaction
|
|
555
567
|
});
|
|
556
|
-
return !!tables.find(table => table === `${
|
|
568
|
+
return !!tables.find(table => table === `${_this5.getTablePrefix()}${name}`);
|
|
557
569
|
})();
|
|
558
570
|
}
|
|
559
571
|
|
|
@@ -562,7 +574,7 @@ class Database extends _events().EventEmitter {
|
|
|
562
574
|
}
|
|
563
575
|
|
|
564
576
|
auth(options = {}) {
|
|
565
|
-
var
|
|
577
|
+
var _this6 = this;
|
|
566
578
|
|
|
567
579
|
return _asyncToGenerator(function* () {
|
|
568
580
|
const _options$retry = options.retry,
|
|
@@ -574,9 +586,9 @@ class Database extends _events().EventEmitter {
|
|
|
574
586
|
let count = 1;
|
|
575
587
|
|
|
576
588
|
const authenticate = /*#__PURE__*/function () {
|
|
577
|
-
var
|
|
589
|
+
var _ref4 = _asyncToGenerator(function* () {
|
|
578
590
|
try {
|
|
579
|
-
yield
|
|
591
|
+
yield _this6.sequelize.authenticate(others);
|
|
580
592
|
console.log('Connection has been established successfully.');
|
|
581
593
|
return true;
|
|
582
594
|
} catch (error) {
|
|
@@ -592,7 +604,7 @@ class Database extends _events().EventEmitter {
|
|
|
592
604
|
});
|
|
593
605
|
|
|
594
606
|
return function authenticate() {
|
|
595
|
-
return
|
|
607
|
+
return _ref4.apply(this, arguments);
|
|
596
608
|
};
|
|
597
609
|
}();
|
|
598
610
|
|
|
@@ -601,21 +613,21 @@ class Database extends _events().EventEmitter {
|
|
|
601
613
|
}
|
|
602
614
|
|
|
603
615
|
reconnect() {
|
|
604
|
-
var
|
|
616
|
+
var _this7 = this;
|
|
605
617
|
|
|
606
618
|
return _asyncToGenerator(function* () {
|
|
607
|
-
if (
|
|
619
|
+
if (_this7.isSqliteMemory()) {
|
|
608
620
|
return;
|
|
609
621
|
} // @ts-ignore
|
|
610
622
|
|
|
611
623
|
|
|
612
|
-
const ConnectionManager =
|
|
624
|
+
const ConnectionManager = _this7.sequelize.dialect.connectionManager.constructor; // @ts-ignore
|
|
613
625
|
|
|
614
|
-
const connectionManager = new ConnectionManager(
|
|
626
|
+
const connectionManager = new ConnectionManager(_this7.sequelize.dialect, _this7.sequelize); // @ts-ignore
|
|
615
627
|
|
|
616
|
-
|
|
628
|
+
_this7.sequelize.dialect.connectionManager = connectionManager; // @ts-ignore
|
|
617
629
|
|
|
618
|
-
|
|
630
|
+
_this7.sequelize.connectionManager = connectionManager;
|
|
619
631
|
})();
|
|
620
632
|
}
|
|
621
633
|
|
|
@@ -625,14 +637,14 @@ class Database extends _events().EventEmitter {
|
|
|
625
637
|
}
|
|
626
638
|
|
|
627
639
|
close() {
|
|
628
|
-
var
|
|
640
|
+
var _this8 = this;
|
|
629
641
|
|
|
630
642
|
return _asyncToGenerator(function* () {
|
|
631
|
-
if (
|
|
643
|
+
if (_this8.isSqliteMemory()) {
|
|
632
644
|
return;
|
|
633
645
|
}
|
|
634
646
|
|
|
635
|
-
return
|
|
647
|
+
return _this8.sequelize.close();
|
|
636
648
|
})();
|
|
637
649
|
}
|
|
638
650
|
|
|
@@ -664,7 +676,7 @@ class Database extends _events().EventEmitter {
|
|
|
664
676
|
}
|
|
665
677
|
|
|
666
678
|
import(options) {
|
|
667
|
-
var
|
|
679
|
+
var _this9 = this;
|
|
668
680
|
|
|
669
681
|
return _asyncToGenerator(function* () {
|
|
670
682
|
const reader = new _collectionImporter.ImporterReader(options.directory, options.extensions);
|
|
@@ -679,9 +691,9 @@ class Database extends _events().EventEmitter {
|
|
|
679
691
|
const module = _step2.value;
|
|
680
692
|
|
|
681
693
|
if (module.extend) {
|
|
682
|
-
|
|
694
|
+
_this9.extendCollection(module.collectionOptions, module.mergeOptions);
|
|
683
695
|
} else {
|
|
684
|
-
const collection =
|
|
696
|
+
const collection = _this9.collection(module);
|
|
685
697
|
|
|
686
698
|
result.set(collection.name, collection);
|
|
687
699
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface Reference {
|
|
2
|
+
sourceCollectionName: string;
|
|
3
|
+
sourceField: string;
|
|
4
|
+
targetField: string;
|
|
5
|
+
targetCollectionName: string;
|
|
6
|
+
onDelete: string;
|
|
7
|
+
}
|
|
8
|
+
declare class ReferencesMap {
|
|
9
|
+
protected map: Map<string, Reference[]>;
|
|
10
|
+
addReference(reference: Reference): void;
|
|
11
|
+
getReferences(collectionName: any): Reference[];
|
|
12
|
+
existReference(reference: Reference): Reference;
|
|
13
|
+
removeReference(reference: Reference): void;
|
|
14
|
+
}
|
|
15
|
+
export default ReferencesMap;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
class ReferencesMap {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.map = new Map();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
addReference(reference) {
|
|
14
|
+
const existReference = this.existReference(reference);
|
|
15
|
+
|
|
16
|
+
if (existReference) {
|
|
17
|
+
if (reference.onDelete && existReference.onDelete !== reference.onDelete) {
|
|
18
|
+
throw new Error(`On Delete Conflict, exist reference ${JSON.stringify(existReference)}, new reference ${JSON.stringify(reference)}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!reference.onDelete) {
|
|
25
|
+
reference.onDelete = 'SET NULL';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.map.set(reference.targetCollectionName, [...(this.map.get(reference.targetCollectionName) || []), reference]);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getReferences(collectionName) {
|
|
32
|
+
return this.map.get(collectionName);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
existReference(reference) {
|
|
36
|
+
const references = this.map.get(reference.targetCollectionName);
|
|
37
|
+
|
|
38
|
+
if (!references) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const keys = Object.keys(reference).filter(k => k !== 'onDelete');
|
|
43
|
+
return references.find(ref => keys.every(key => ref[key] === reference[key]));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
removeReference(reference) {
|
|
47
|
+
const references = this.map.get(reference.targetCollectionName);
|
|
48
|
+
|
|
49
|
+
if (!references) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const keys = Object.keys(reference);
|
|
54
|
+
this.map.set(reference.targetCollectionName, references.filter(ref => !keys.every(key => ref[key] === reference[key])));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var _default = ReferencesMap;
|
|
60
|
+
exports.default = _default;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import Database from '../database';
|
|
2
|
+
import { Model, Transactionable } from 'sequelize';
|
|
3
|
+
interface ReferentialIntegrityCheckOptions extends Transactionable {
|
|
4
|
+
db: Database;
|
|
5
|
+
referencedInstance: Model;
|
|
6
|
+
}
|
|
7
|
+
export declare function referentialIntegrityCheck(options: ReferentialIntegrityCheckOptions): Promise<void>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.referentialIntegrityCheck = referentialIntegrityCheck;
|
|
7
|
+
|
|
8
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
9
|
+
|
|
10
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
11
|
+
|
|
12
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
13
|
+
|
|
14
|
+
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); } }
|
|
15
|
+
|
|
16
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
17
|
+
|
|
18
|
+
function referentialIntegrityCheck(_x) {
|
|
19
|
+
return _referentialIntegrityCheck.apply(this, arguments);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function _referentialIntegrityCheck() {
|
|
23
|
+
_referentialIntegrityCheck = _asyncToGenerator(function* (options) {
|
|
24
|
+
const referencedInstance = options.referencedInstance,
|
|
25
|
+
db = options.db,
|
|
26
|
+
transaction = options.transaction; // @ts-ignore
|
|
27
|
+
|
|
28
|
+
const collection = db.modelCollection.get(referencedInstance.constructor);
|
|
29
|
+
const collectionName = collection.name;
|
|
30
|
+
const references = db.referenceMap.getReferences(collectionName);
|
|
31
|
+
|
|
32
|
+
if (!references) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var _iterator = _createForOfIteratorHelper(references),
|
|
37
|
+
_step;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
41
|
+
const reference = _step.value;
|
|
42
|
+
const sourceCollectionName = reference.sourceCollectionName,
|
|
43
|
+
sourceField = reference.sourceField,
|
|
44
|
+
targetField = reference.targetField,
|
|
45
|
+
onDelete = reference.onDelete;
|
|
46
|
+
const sourceCollection = db.collections.get(sourceCollectionName);
|
|
47
|
+
const sourceRepository = sourceCollection.repository;
|
|
48
|
+
const filter = {
|
|
49
|
+
[sourceField]: referencedInstance[targetField]
|
|
50
|
+
};
|
|
51
|
+
const referencingExists = yield sourceRepository.count({
|
|
52
|
+
filter,
|
|
53
|
+
transaction
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (!referencingExists) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (onDelete === 'RESTRICT') {
|
|
61
|
+
throw new Error('RESTRICT');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (onDelete === 'CASCADE') {
|
|
65
|
+
yield sourceRepository.destroy({
|
|
66
|
+
filter: filter,
|
|
67
|
+
transaction
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (onDelete === 'SET NULL') {
|
|
72
|
+
yield sourceRepository.update({
|
|
73
|
+
filter,
|
|
74
|
+
values: {
|
|
75
|
+
[sourceField]: null
|
|
76
|
+
},
|
|
77
|
+
hooks: false,
|
|
78
|
+
transaction
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
_iterator.e(err);
|
|
84
|
+
} finally {
|
|
85
|
+
_iterator.f();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
return _referentialIntegrityCheck.apply(this, arguments);
|
|
89
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { BelongsToOptions as SequelizeBelongsToOptions } from 'sequelize';
|
|
2
2
|
import { BaseRelationFieldOptions, RelationField } from './relation-field';
|
|
3
|
+
import { Reference } from '../features/ReferencesMap';
|
|
3
4
|
export declare class BelongsToField extends RelationField {
|
|
4
5
|
static type: string;
|
|
5
6
|
get target(): any;
|
|
7
|
+
reference(association: any): Reference;
|
|
6
8
|
bind(): boolean;
|
|
7
9
|
unbind(): void;
|
|
8
10
|
}
|
|
@@ -43,6 +43,17 @@ class BelongsToField extends _relationField.RelationField {
|
|
|
43
43
|
return target || _sequelize().Utils.pluralize(name);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
reference(association) {
|
|
47
|
+
const targetKey = association.targetKey;
|
|
48
|
+
return {
|
|
49
|
+
sourceCollectionName: this.database.modelCollection.get(association.source).name,
|
|
50
|
+
sourceField: association.foreignKey,
|
|
51
|
+
targetField: targetKey,
|
|
52
|
+
targetCollectionName: this.database.modelCollection.get(association.target).name,
|
|
53
|
+
onDelete: this.options.onDelete
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
46
57
|
bind() {
|
|
47
58
|
const _this$context = this.context,
|
|
48
59
|
database = _this$context.database,
|
|
@@ -63,7 +74,7 @@ class BelongsToField extends _relationField.RelationField {
|
|
|
63
74
|
const association = collection.model.belongsTo(Target, _objectSpread({
|
|
64
75
|
as: this.name,
|
|
65
76
|
constraints: false
|
|
66
|
-
}, (0, _lodash().omit)(this.options, ['name', 'type', 'target']))); // inverse relation
|
|
77
|
+
}, (0, _lodash().omit)(this.options, ['name', 'type', 'target', 'onDelete']))); // inverse relation
|
|
67
78
|
// this.TargetModel.hasMany(collection.model);
|
|
68
79
|
// 建立关系之后从 pending 列表中删除
|
|
69
80
|
|
|
@@ -86,6 +97,7 @@ class BelongsToField extends _relationField.RelationField {
|
|
|
86
97
|
}
|
|
87
98
|
|
|
88
99
|
this.collection.addIndex([this.options.foreignKey]);
|
|
100
|
+
this.database.referenceMap.addReference(this.reference(association));
|
|
89
101
|
return true;
|
|
90
102
|
}
|
|
91
103
|
|
|
@@ -105,8 +117,10 @@ class BelongsToField extends _relationField.RelationField {
|
|
|
105
117
|
|
|
106
118
|
if (!field1 && !field2) {
|
|
107
119
|
collection.model.removeAttribute(foreignKey);
|
|
108
|
-
}
|
|
120
|
+
}
|
|
109
121
|
|
|
122
|
+
const association = collection.model.associations[this.name];
|
|
123
|
+
this.database.referenceMap.removeReference(this.reference(association)); // 删掉 model 的关联字段
|
|
110
124
|
|
|
111
125
|
delete collection.model.associations[this.name]; // @ts-ignore
|
|
112
126
|
|
|
@@ -2,6 +2,7 @@ import { BelongsToManyOptions as SequelizeBelongsToManyOptions } from 'sequelize
|
|
|
2
2
|
import { MultipleRelationFieldOptions, RelationField } from './relation-field';
|
|
3
3
|
export declare class BelongsToManyField extends RelationField {
|
|
4
4
|
get through(): any;
|
|
5
|
+
get otherKey(): any;
|
|
5
6
|
bind(): boolean;
|
|
6
7
|
unbind(): void;
|
|
7
8
|
}
|
|
@@ -40,6 +40,10 @@ class BelongsToManyField extends _relationField.RelationField {
|
|
|
40
40
|
return this.options.through || _sequelize().Utils.camelize([this.context.collection.model.name, this.target].map(name => name.toLowerCase()).sort().join('_'));
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
get otherKey() {
|
|
44
|
+
return this.options.otherKey;
|
|
45
|
+
}
|
|
46
|
+
|
|
43
47
|
bind() {
|
|
44
48
|
const _this$context = this.context,
|
|
45
49
|
database = _this$context.database,
|
|
@@ -58,7 +62,8 @@ class BelongsToManyField extends _relationField.RelationField {
|
|
|
58
62
|
Through = database.getCollection(through);
|
|
59
63
|
} else {
|
|
60
64
|
Through = database.collection({
|
|
61
|
-
name: through
|
|
65
|
+
name: through // timestamps: false,
|
|
66
|
+
|
|
62
67
|
});
|
|
63
68
|
Object.defineProperty(Through.model, 'isThrough', {
|
|
64
69
|
value: true
|
|
@@ -106,7 +111,8 @@ class BelongsToManyField extends _relationField.RelationField {
|
|
|
106
111
|
unbind() {
|
|
107
112
|
const _this$context2 = this.context,
|
|
108
113
|
database = _this$context2.database,
|
|
109
|
-
collection = _this$context2.collection;
|
|
114
|
+
collection = _this$context2.collection;
|
|
115
|
+
const Through = database.getCollection(this.through); // 如果关系字段还没建立就删除了,也同步删除待建立关联的关系字段
|
|
110
116
|
|
|
111
117
|
database.removePendingField(this); // 删掉 model 的关联字段
|
|
112
118
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { Model } from '../model';
|
|
1
2
|
import { BaseColumnFieldOptions, Field } from './field';
|
|
2
3
|
export declare class ContextField extends Field {
|
|
3
4
|
get dataType(): any;
|
|
4
|
-
|
|
5
|
+
listener: (model: Model, options: any) => Promise<void>;
|
|
5
6
|
bind(): void;
|
|
6
7
|
unbind(): void;
|
|
7
8
|
}
|
|
@@ -34,18 +34,17 @@ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try
|
|
|
34
34
|
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); }); }; }
|
|
35
35
|
|
|
36
36
|
class ContextField extends _field.Field {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return _sequelize().DataTypes[type.toUpperCase()] || _sequelize().DataTypes.STRING;
|
|
40
|
-
}
|
|
37
|
+
constructor(...args) {
|
|
38
|
+
var _this;
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
name = _this$options.name,
|
|
45
|
-
dataIndex = _this$options.dataIndex;
|
|
40
|
+
super(...args);
|
|
41
|
+
_this = this;
|
|
46
42
|
|
|
47
43
|
this.listener = /*#__PURE__*/function () {
|
|
48
44
|
var _ref = _asyncToGenerator(function* (model, options) {
|
|
45
|
+
const _this$options = _this.options,
|
|
46
|
+
name = _this$options.name,
|
|
47
|
+
dataIndex = _this$options.dataIndex;
|
|
49
48
|
const context = options.context;
|
|
50
49
|
model.set(name, _lodash().default.get(context, dataIndex));
|
|
51
50
|
model.changed(name, true);
|
|
@@ -57,6 +56,11 @@ class ContextField extends _field.Field {
|
|
|
57
56
|
}();
|
|
58
57
|
}
|
|
59
58
|
|
|
59
|
+
get dataType() {
|
|
60
|
+
const type = this.options.dataType || 'string';
|
|
61
|
+
return _sequelize().DataTypes[type.toUpperCase()] || _sequelize().DataTypes.STRING;
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
bind() {
|
|
61
65
|
super.bind();
|
|
62
66
|
const createOnly = this.options.createOnly;
|
package/lib/fields/field.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DataType, ModelAttributeColumnOptions, ModelIndexesOptions, QueryInterfaceOptions, SyncOptions, Transactionable } from 'sequelize';
|
|
2
2
|
import { Collection } from '../collection';
|
|
3
3
|
import { Database } from '../database';
|
|
4
|
+
import { ModelEventTypes } from '../types';
|
|
4
5
|
export interface FieldContext {
|
|
5
6
|
database: Database;
|
|
6
7
|
collection: Collection;
|
|
@@ -26,7 +27,7 @@ export declare abstract class Field {
|
|
|
26
27
|
constructor(options?: any, context?: FieldContext);
|
|
27
28
|
sync(syncOptions: SyncOptions): Promise<void>;
|
|
28
29
|
init(): void;
|
|
29
|
-
on(eventName:
|
|
30
|
+
on(eventName: ModelEventTypes, listener: (...args: any[]) => void): this;
|
|
30
31
|
off(eventName: string, listener: (...args: any[]) => void): this;
|
|
31
32
|
get(name: string): any;
|
|
32
33
|
remove(): void | Field;
|