@nocobase/database 0.19.0-alpha.9 → 0.20.0-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 +5 -1
- package/lib/collection.js +35 -10
- package/lib/database.js +7 -1
- package/lib/eager-loading/eager-loading-tree.js +5 -0
- package/lib/errors/zero-column-table-error.d.ts +2 -0
- package/lib/errors/zero-column-table-error.js +31 -0
- package/lib/fields/array-field.js +4 -1
- package/lib/fields/belongs-to-field.d.ts +1 -0
- package/lib/fields/belongs-to-field.js +36 -1
- package/lib/fields/belongs-to-many-field.d.ts +5 -1
- package/lib/fields/belongs-to-many-field.js +57 -1
- package/lib/fields/date-field.d.ts +1 -0
- package/lib/fields/date-field.js +13 -0
- package/lib/fields/has-many-field.d.ts +1 -0
- package/lib/fields/has-many-field.js +25 -0
- package/lib/fields/has-one-field.d.ts +1 -0
- package/lib/fields/has-one-field.js +25 -0
- package/lib/fields/relation-field.d.ts +1 -0
- package/lib/fields/relation-field.js +13 -0
- package/lib/inherited-collection.d.ts +4 -3
- package/lib/inherited-collection.js +32 -22
- package/lib/inherited-sync-runner.d.ts +4 -0
- package/lib/inherited-sync-runner.js +175 -0
- package/lib/mock-database.js +1 -1
- package/lib/model.d.ts +1 -0
- package/lib/model.js +5 -46
- package/lib/sync-runner.d.ts +28 -2
- package/lib/sync-runner.js +229 -117
- package/lib/update-associations.js +44 -7
- package/lib/view/field-type-map.d.ts +13 -13
- package/lib/view/field-type-map.js +14 -14
- package/package.json +4 -4
package/lib/collection.d.ts
CHANGED
|
@@ -84,14 +84,18 @@ export declare class Collection<TModelAttributes extends {} = any, TCreationAttr
|
|
|
84
84
|
findField(callback: (field: Field) => boolean): any;
|
|
85
85
|
hasField(name: string): boolean;
|
|
86
86
|
getField<F extends Field>(name: string): F;
|
|
87
|
+
getFields(): any[];
|
|
87
88
|
addField(name: string, options: FieldOptions): Field;
|
|
88
89
|
checkFieldType(name: string, options: FieldOptions): void;
|
|
90
|
+
correctOptions(options: any): void;
|
|
89
91
|
setField(name: string, options: FieldOptions): Field;
|
|
90
92
|
setFields(fields: FieldOptions[], resetFields?: boolean): void;
|
|
91
93
|
resetFields(): void;
|
|
92
94
|
remove(): Collection<any, any>;
|
|
93
95
|
removeFieldFromDb(name: string, options?: QueryInterfaceOptions): Promise<void>;
|
|
94
|
-
removeFromDb(options?: QueryInterfaceDropTableOptions
|
|
96
|
+
removeFromDb(options?: QueryInterfaceDropTableOptions & {
|
|
97
|
+
dropCollection?: boolean;
|
|
98
|
+
}): Promise<Collection<any, any>>;
|
|
95
99
|
existsInDb(options?: Transactionable): Promise<boolean>;
|
|
96
100
|
removeField(name: string): void | Field;
|
|
97
101
|
/**
|
package/lib/collection.js
CHANGED
|
@@ -96,11 +96,15 @@ const _Collection = class _Collection extends import_events.EventEmitter {
|
|
|
96
96
|
this.setSortable(options.sortable);
|
|
97
97
|
}
|
|
98
98
|
get filterTargetKey() {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
var _a;
|
|
100
|
+
const targetKey = (_a = this.options) == null ? void 0 : _a.filterTargetKey;
|
|
101
|
+
if (targetKey && this.model.getAttributes()[targetKey]) {
|
|
102
|
+
return targetKey;
|
|
102
103
|
}
|
|
103
|
-
|
|
104
|
+
if (this.model.primaryKeyAttributes.length > 1) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return this.model.primaryKeyAttribute;
|
|
104
108
|
}
|
|
105
109
|
get name() {
|
|
106
110
|
return this.options.name;
|
|
@@ -187,6 +191,9 @@ const _Collection = class _Collection extends import_events.EventEmitter {
|
|
|
187
191
|
getField(name) {
|
|
188
192
|
return this.fields.get(name);
|
|
189
193
|
}
|
|
194
|
+
getFields() {
|
|
195
|
+
return [...this.fields.values()];
|
|
196
|
+
}
|
|
190
197
|
addField(name, options) {
|
|
191
198
|
return this.setField(name, options);
|
|
192
199
|
}
|
|
@@ -211,6 +218,11 @@ const _Collection = class _Collection extends import_events.EventEmitter {
|
|
|
211
218
|
throw new Error(`fields with same column must be of the same type ${JSON.stringify(options)}`);
|
|
212
219
|
}
|
|
213
220
|
}
|
|
221
|
+
correctOptions(options) {
|
|
222
|
+
if (options.primaryKey && options.autoIncrement) {
|
|
223
|
+
delete options.defaultValue;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
214
226
|
setField(name, options) {
|
|
215
227
|
(0, import_utils.checkIdentifier)(name);
|
|
216
228
|
this.checkFieldType(name, options);
|
|
@@ -233,6 +245,7 @@ const _Collection = class _Collection extends import_events.EventEmitter {
|
|
|
233
245
|
}
|
|
234
246
|
}
|
|
235
247
|
}
|
|
248
|
+
this.correctOptions(options);
|
|
236
249
|
this.emit("field.beforeAdd", name, options, { collection: this });
|
|
237
250
|
const field = database.buildField(
|
|
238
251
|
{ name, ...options },
|
|
@@ -253,6 +266,10 @@ const _Collection = class _Collection extends import_events.EventEmitter {
|
|
|
253
266
|
this.removeField(name);
|
|
254
267
|
this.fields.set(name, field);
|
|
255
268
|
this.emit("field.afterAdd", field);
|
|
269
|
+
this.db.emit("field.afterAdd", {
|
|
270
|
+
collection: this,
|
|
271
|
+
field
|
|
272
|
+
});
|
|
256
273
|
if (this.isParent()) {
|
|
257
274
|
for (const child of this.context.database.inheritanceMap.getChildren(this.name, {
|
|
258
275
|
deep: false
|
|
@@ -306,9 +323,6 @@ const _Collection = class _Collection extends import_events.EventEmitter {
|
|
|
306
323
|
field.remove();
|
|
307
324
|
return;
|
|
308
325
|
}
|
|
309
|
-
if (this.model.primaryKeyAttributes.includes(this.name)) {
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
326
|
if (this.model.options.timestamps !== false) {
|
|
313
327
|
let timestampsFields = ["createdAt", "updatedAt", "deletedAt"];
|
|
314
328
|
if (this.db.options.underscored) {
|
|
@@ -341,8 +355,17 @@ const _Collection = class _Collection extends import_events.EventEmitter {
|
|
|
341
355
|
if (await field.existsInDb({
|
|
342
356
|
transaction: options == null ? void 0 : options.transaction
|
|
343
357
|
}) && columnReferencesCount == 1) {
|
|
344
|
-
const
|
|
345
|
-
|
|
358
|
+
const columns = await this.model.sequelize.getQueryInterface().describeTable(this.getTableNameWithSchema(), options);
|
|
359
|
+
if (Object.keys(columns).length == 1) {
|
|
360
|
+
await this.removeFromDb({
|
|
361
|
+
...options,
|
|
362
|
+
cascade: true,
|
|
363
|
+
dropCollection: false
|
|
364
|
+
});
|
|
365
|
+
} else {
|
|
366
|
+
const queryInterface = this.db.sequelize.getQueryInterface();
|
|
367
|
+
await queryInterface.removeColumn(this.getTableNameWithSchema(), field.columnName(), options);
|
|
368
|
+
}
|
|
346
369
|
}
|
|
347
370
|
field.remove();
|
|
348
371
|
}
|
|
@@ -353,7 +376,9 @@ const _Collection = class _Collection extends import_events.EventEmitter {
|
|
|
353
376
|
const queryInterface = this.db.sequelize.getQueryInterface();
|
|
354
377
|
await queryInterface.dropTable(this.getTableNameWithSchema(), options);
|
|
355
378
|
}
|
|
356
|
-
|
|
379
|
+
if ((options == null ? void 0 : options.dropCollection) !== false) {
|
|
380
|
+
return this.remove();
|
|
381
|
+
}
|
|
357
382
|
}
|
|
358
383
|
async existsInDb(options) {
|
|
359
384
|
return this.db.queryInterface.collectionTableExists(this, options);
|
package/lib/database.js
CHANGED
|
@@ -220,6 +220,9 @@ const _Database = class _Database extends import_events.EventEmitter {
|
|
|
220
220
|
this.migrations = new import_migration.Migrations(context);
|
|
221
221
|
this.sequelize.beforeDefine((model, opts2) => {
|
|
222
222
|
if (this.options.tablePrefix) {
|
|
223
|
+
if (opts2.tableName && opts2.tableName.startsWith(this.options.tablePrefix)) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
223
226
|
opts2.tableName = `${this.options.tablePrefix}${opts2.tableName || opts2.modelName || opts2.name.plural}`;
|
|
224
227
|
}
|
|
225
228
|
});
|
|
@@ -445,7 +448,7 @@ const _Database = class _Database extends import_events.EventEmitter {
|
|
|
445
448
|
return collection;
|
|
446
449
|
}
|
|
447
450
|
hasCollection(name) {
|
|
448
|
-
return this.
|
|
451
|
+
return !!this.getCollection(name);
|
|
449
452
|
}
|
|
450
453
|
removeCollection(name) {
|
|
451
454
|
const collection = this.collections.get(name);
|
|
@@ -536,6 +539,9 @@ const _Database = class _Database extends import_events.EventEmitter {
|
|
|
536
539
|
if (options.field && collection.options.underscored && !collection.isView()) {
|
|
537
540
|
options.field = (0, import_utils2.snakeCase)(options.field);
|
|
538
541
|
}
|
|
542
|
+
if (Object.prototype.hasOwnProperty.call(options, "defaultValue") && options.defaultValue === null) {
|
|
543
|
+
delete options.defaultValue;
|
|
544
|
+
}
|
|
539
545
|
return new Field2(options, context);
|
|
540
546
|
}
|
|
541
547
|
async sync(options) {
|
|
@@ -91,6 +91,11 @@ const _EagerLoadingTree = class _EagerLoadingTree {
|
|
|
91
91
|
continue;
|
|
92
92
|
}
|
|
93
93
|
const association = import_lodash.default.isString(include.association) ? eagerLoadingTreeParent.model.associations[include.association] : include.association;
|
|
94
|
+
if (!association) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Association "${include.association}" not found in model "${eagerLoadingTreeParent.model.name}"`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
94
99
|
const associationType = association.associationType;
|
|
95
100
|
const child = buildNode({
|
|
96
101
|
model: association.target,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var zero_column_table_error_exports = {};
|
|
20
|
+
__export(zero_column_table_error_exports, {
|
|
21
|
+
ZeroColumnTableError: () => ZeroColumnTableError
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(zero_column_table_error_exports);
|
|
24
|
+
const _ZeroColumnTableError = class _ZeroColumnTableError extends Error {
|
|
25
|
+
};
|
|
26
|
+
__name(_ZeroColumnTableError, "ZeroColumnTableError");
|
|
27
|
+
let ZeroColumnTableError = _ZeroColumnTableError;
|
|
28
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
29
|
+
0 && (module.exports = {
|
|
30
|
+
ZeroColumnTableError
|
|
31
|
+
});
|
|
@@ -31,8 +31,11 @@ const _ArrayField = class _ArrayField extends import_field.Field {
|
|
|
31
31
|
return import_sequelize.DataTypes.JSON;
|
|
32
32
|
}
|
|
33
33
|
sortValue = (model) => {
|
|
34
|
-
|
|
34
|
+
let oldValue = model.get(this.options.name);
|
|
35
35
|
if (oldValue) {
|
|
36
|
+
if (typeof oldValue === "string") {
|
|
37
|
+
oldValue = JSON.parse(oldValue);
|
|
38
|
+
}
|
|
36
39
|
const newValue = oldValue.sort();
|
|
37
40
|
model.set(this.options.name, newValue);
|
|
38
41
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
7
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
8
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
@@ -16,6 +18,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
18
|
}
|
|
17
19
|
return to;
|
|
18
20
|
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
19
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
30
|
var __publicField = (obj, key, value) => {
|
|
21
31
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -26,7 +36,7 @@ __export(belongs_to_field_exports, {
|
|
|
26
36
|
BelongsToField: () => BelongsToField
|
|
27
37
|
});
|
|
28
38
|
module.exports = __toCommonJS(belongs_to_field_exports);
|
|
29
|
-
var import_lodash = require("lodash");
|
|
39
|
+
var import_lodash = __toESM(require("lodash"));
|
|
30
40
|
var import_sequelize = require("sequelize");
|
|
31
41
|
var import_utils = require("../utils");
|
|
32
42
|
var import_relation_field = require("./relation-field");
|
|
@@ -51,6 +61,27 @@ const _BelongsToField = class _BelongsToField extends import_relation_field.Rela
|
|
|
51
61
|
reference(association) {
|
|
52
62
|
return _BelongsToField.toReference(this.database, association, this.options.onDelete);
|
|
53
63
|
}
|
|
64
|
+
checkAssociationKeys() {
|
|
65
|
+
let { foreignKey, targetKey } = this.options;
|
|
66
|
+
if (!targetKey) {
|
|
67
|
+
targetKey = this.TargetModel.primaryKeyAttribute;
|
|
68
|
+
}
|
|
69
|
+
if (!foreignKey) {
|
|
70
|
+
foreignKey = import_lodash.default.camelCase(`${this.name}_${targetKey}`);
|
|
71
|
+
}
|
|
72
|
+
const targetKeyAttribute = this.TargetModel.rawAttributes[targetKey];
|
|
73
|
+
const foreignKeyAttribute = this.collection.model.rawAttributes[foreignKey];
|
|
74
|
+
if (!foreignKeyAttribute || !targetKeyAttribute) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const foreignKeyType = foreignKeyAttribute.type.constructor.toString();
|
|
78
|
+
const targetKeyType = targetKeyAttribute.type.constructor.toString();
|
|
79
|
+
if (!this.keyPairsTypeMatched(foreignKeyType, targetKeyType)) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Foreign key "${foreignKey}" type "${foreignKeyType}" does not match target key "${targetKey}" type "${targetKeyType}" in belongs to relation "${this.name}" of collection "${this.collection.name}"`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
54
85
|
bind() {
|
|
55
86
|
const { database, collection } = this.context;
|
|
56
87
|
const Target = this.TargetModel;
|
|
@@ -58,6 +89,7 @@ const _BelongsToField = class _BelongsToField extends import_relation_field.Rela
|
|
|
58
89
|
database.addPendingField(this);
|
|
59
90
|
return false;
|
|
60
91
|
}
|
|
92
|
+
this.checkAssociationKeys();
|
|
61
93
|
if (collection.model.associations[this.name]) {
|
|
62
94
|
delete collection.model.associations[this.name];
|
|
63
95
|
}
|
|
@@ -70,6 +102,9 @@ const _BelongsToField = class _BelongsToField extends import_relation_field.Rela
|
|
|
70
102
|
if (!this.options.foreignKey) {
|
|
71
103
|
this.options.foreignKey = association.foreignKey;
|
|
72
104
|
}
|
|
105
|
+
if (!this.options.targetKey) {
|
|
106
|
+
this.options.targetKey = association.targetKey;
|
|
107
|
+
}
|
|
73
108
|
try {
|
|
74
109
|
(0, import_utils.checkIdentifier)(this.options.foreignKey);
|
|
75
110
|
} catch (error) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BelongsToManyOptions as SequelizeBelongsToManyOptions } from 'sequelize';
|
|
1
|
+
import { AssociationScope, BelongsToManyOptions as SequelizeBelongsToManyOptions } from 'sequelize';
|
|
2
2
|
import { Reference } from '../features/ReferencesMap';
|
|
3
3
|
import { MultipleRelationFieldOptions, RelationField } from './relation-field';
|
|
4
4
|
export declare class BelongsToManyField extends RelationField {
|
|
@@ -6,6 +6,7 @@ export declare class BelongsToManyField extends RelationField {
|
|
|
6
6
|
get through(): any;
|
|
7
7
|
get otherKey(): any;
|
|
8
8
|
references(association: any): Reference[];
|
|
9
|
+
checkAssociationKeys(database: any): void;
|
|
9
10
|
bind(): boolean;
|
|
10
11
|
unbind(): void;
|
|
11
12
|
}
|
|
@@ -13,4 +14,7 @@ export interface BelongsToManyFieldOptions extends MultipleRelationFieldOptions,
|
|
|
13
14
|
type: 'belongsToMany';
|
|
14
15
|
target?: string;
|
|
15
16
|
through?: string;
|
|
17
|
+
throughScope?: AssociationScope;
|
|
18
|
+
throughUnique?: boolean;
|
|
19
|
+
throughParanoid?: boolean;
|
|
16
20
|
}
|
|
@@ -54,6 +54,47 @@ const _BelongsToManyField = class _BelongsToManyField extends import_relation_fi
|
|
|
54
54
|
import_belongs_to_field.BelongsToField.toReference(db, sourceAssociation, onDelete)
|
|
55
55
|
];
|
|
56
56
|
}
|
|
57
|
+
checkAssociationKeys(database) {
|
|
58
|
+
let { foreignKey, sourceKey, otherKey, targetKey } = this.options;
|
|
59
|
+
const through = this.through;
|
|
60
|
+
const throughCollection = database.getCollection(through);
|
|
61
|
+
if (!throughCollection) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!sourceKey) {
|
|
65
|
+
sourceKey = this.collection.model.primaryKeyAttribute;
|
|
66
|
+
}
|
|
67
|
+
if (!foreignKey) {
|
|
68
|
+
foreignKey = import_sequelize.Utils.camelize([import_sequelize.Utils.singularize(this.collection.model.name), sourceKey].join("_"));
|
|
69
|
+
}
|
|
70
|
+
if (!targetKey) {
|
|
71
|
+
targetKey = this.TargetModel.primaryKeyAttribute;
|
|
72
|
+
}
|
|
73
|
+
if (!otherKey) {
|
|
74
|
+
otherKey = import_sequelize.Utils.camelize([import_sequelize.Utils.singularize(this.TargetModel.name), targetKey].join("_"));
|
|
75
|
+
}
|
|
76
|
+
const foreignKeyAttribute = throughCollection.model.rawAttributes[foreignKey];
|
|
77
|
+
const otherKeyAttribute = throughCollection.model.rawAttributes[otherKey];
|
|
78
|
+
const sourceKeyAttribute = this.collection.model.rawAttributes[sourceKey];
|
|
79
|
+
const targetKeyAttribute = this.TargetModel.rawAttributes[targetKey];
|
|
80
|
+
if (!foreignKeyAttribute || !otherKeyAttribute || !sourceKeyAttribute || !targetKeyAttribute) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const foreignKeyType = foreignKeyAttribute.type.constructor.toString();
|
|
84
|
+
const otherKeyType = otherKeyAttribute.type.constructor.toString();
|
|
85
|
+
const sourceKeyType = sourceKeyAttribute.type.constructor.toString();
|
|
86
|
+
const targetKeyType = targetKeyAttribute.type.constructor.toString();
|
|
87
|
+
if (!this.keyPairsTypeMatched(foreignKeyType, sourceKeyType)) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Foreign key "${foreignKey}" type "${foreignKeyType}" does not match source key "${sourceKey}" type "${sourceKeyType}" in belongs to many relation "${this.name}" of collection "${this.collection.name}"`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (!this.keyPairsTypeMatched(otherKeyType, targetKeyType)) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Other key "${otherKey}" type "${otherKeyType}" does not match target key "${targetKey}" type "${targetKeyType}" in belongs to many relation "${this.name}" of collection "${this.collection.name}"`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
57
98
|
bind() {
|
|
58
99
|
const { database, collection } = this.context;
|
|
59
100
|
const Target = this.TargetModel;
|
|
@@ -61,6 +102,13 @@ const _BelongsToManyField = class _BelongsToManyField extends import_relation_fi
|
|
|
61
102
|
database.addPendingField(this);
|
|
62
103
|
return false;
|
|
63
104
|
}
|
|
105
|
+
if (!this.collection.model.primaryKeyAttribute) {
|
|
106
|
+
throw new Error(`Collection model ${this.collection.model.name} has no primary key attribute`);
|
|
107
|
+
}
|
|
108
|
+
if (!Target.primaryKeyAttribute) {
|
|
109
|
+
throw new Error(`Target model ${Target.name} has no primary key attribute`);
|
|
110
|
+
}
|
|
111
|
+
this.checkAssociationKeys(database);
|
|
64
112
|
const through = this.through;
|
|
65
113
|
let Through;
|
|
66
114
|
if (database.hasCollection(through)) {
|
|
@@ -85,7 +133,12 @@ const _BelongsToManyField = class _BelongsToManyField extends import_relation_fi
|
|
|
85
133
|
constraints: false,
|
|
86
134
|
...(0, import_lodash.omit)(this.options, ["name", "type", "target"]),
|
|
87
135
|
as: this.name,
|
|
88
|
-
through:
|
|
136
|
+
through: {
|
|
137
|
+
model: Through.model,
|
|
138
|
+
scope: this.options.throughScope,
|
|
139
|
+
paranoid: this.options.throughParanoid,
|
|
140
|
+
unique: this.options.throughUnique
|
|
141
|
+
}
|
|
89
142
|
};
|
|
90
143
|
const association = collection.model.belongsToMany(Target, belongsToManyOptions);
|
|
91
144
|
database.removePendingField(this);
|
|
@@ -98,6 +151,9 @@ const _BelongsToManyField = class _BelongsToManyField extends import_relation_fi
|
|
|
98
151
|
if (!this.options.otherKey) {
|
|
99
152
|
this.options.otherKey = association.otherKey;
|
|
100
153
|
}
|
|
154
|
+
if (!this.options.targetKey) {
|
|
155
|
+
this.options.targetKey = association.targetKey;
|
|
156
|
+
}
|
|
101
157
|
try {
|
|
102
158
|
(0, import_utils.checkIdentifier)(this.options.foreignKey);
|
|
103
159
|
(0, import_utils.checkIdentifier)(this.options.otherKey);
|
package/lib/fields/date-field.js
CHANGED
|
@@ -42,6 +42,19 @@ const _DateField = class _DateField extends import_field.Field {
|
|
|
42
42
|
const props = this.getProps();
|
|
43
43
|
return props.gmt;
|
|
44
44
|
}
|
|
45
|
+
bind() {
|
|
46
|
+
super.bind();
|
|
47
|
+
if (this.options.interface === "createdAt") {
|
|
48
|
+
const { model } = this.context.collection;
|
|
49
|
+
model._timestampAttributes.createdAt = this.name;
|
|
50
|
+
model.refreshAttributes();
|
|
51
|
+
}
|
|
52
|
+
if (this.options.interface === "updatedAt") {
|
|
53
|
+
const { model } = this.context.collection;
|
|
54
|
+
model._timestampAttributes.updatedAt = this.name;
|
|
55
|
+
model.refreshAttributes();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
45
58
|
};
|
|
46
59
|
__name(_DateField, "DateField");
|
|
47
60
|
let DateField = _DateField;
|
|
@@ -46,6 +46,27 @@ const _HasManyField = class _HasManyField extends import_relation_field.Relation
|
|
|
46
46
|
onDelete: this.options.onDelete
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
+
checkAssociationKeys() {
|
|
50
|
+
let { foreignKey, sourceKey } = this.options;
|
|
51
|
+
if (!sourceKey) {
|
|
52
|
+
sourceKey = this.collection.model.primaryKeyAttribute;
|
|
53
|
+
}
|
|
54
|
+
if (!foreignKey) {
|
|
55
|
+
foreignKey = import_sequelize.Utils.camelize([import_sequelize.Utils.singularize(this.name), this.collection.model.primaryKeyAttribute].join("_"));
|
|
56
|
+
}
|
|
57
|
+
const foreignKeyAttribute = this.TargetModel.rawAttributes[foreignKey];
|
|
58
|
+
const sourceKeyAttribute = this.collection.model.rawAttributes[sourceKey];
|
|
59
|
+
if (!foreignKeyAttribute || !sourceKeyAttribute) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const foreignKeyType = foreignKeyAttribute.type.constructor.toString();
|
|
63
|
+
const sourceKeyType = sourceKeyAttribute.type.constructor.toString();
|
|
64
|
+
if (!this.keyPairsTypeMatched(foreignKeyType, sourceKeyType)) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Foreign key "${foreignKey}" type "${foreignKeyType}" does not match source key "${sourceKey}" type "${sourceKeyType}" in has many relation "${this.name}" of collection "${this.collection.name}"`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
49
70
|
bind() {
|
|
50
71
|
const { database, collection } = this.context;
|
|
51
72
|
const Target = this.TargetModel;
|
|
@@ -53,6 +74,7 @@ const _HasManyField = class _HasManyField extends import_relation_field.Relation
|
|
|
53
74
|
database.addPendingField(this);
|
|
54
75
|
return false;
|
|
55
76
|
}
|
|
77
|
+
this.checkAssociationKeys();
|
|
56
78
|
if (collection.model.associations[this.name]) {
|
|
57
79
|
delete collection.model.associations[this.name];
|
|
58
80
|
}
|
|
@@ -66,6 +88,9 @@ const _HasManyField = class _HasManyField extends import_relation_field.Relation
|
|
|
66
88
|
if (!this.options.foreignKey) {
|
|
67
89
|
this.options.foreignKey = association.foreignKey;
|
|
68
90
|
}
|
|
91
|
+
if (!this.options.sourceKey) {
|
|
92
|
+
this.options.sourceKey = association.sourceKey;
|
|
93
|
+
}
|
|
69
94
|
try {
|
|
70
95
|
(0, import_utils.checkIdentifier)(this.options.foreignKey);
|
|
71
96
|
} catch (error) {
|
|
@@ -53,6 +53,27 @@ const _HasOneField = class _HasOneField extends import_relation_field.RelationFi
|
|
|
53
53
|
onDelete: this.options.onDelete
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
|
+
checkAssociationKeys() {
|
|
57
|
+
let { foreignKey, sourceKey } = this.options;
|
|
58
|
+
if (!sourceKey) {
|
|
59
|
+
sourceKey = this.collection.model.primaryKeyAttribute;
|
|
60
|
+
}
|
|
61
|
+
if (!foreignKey) {
|
|
62
|
+
foreignKey = import_sequelize.Utils.camelize([import_sequelize.Utils.singularize(this.name), this.collection.model.primaryKeyAttribute].join("_"));
|
|
63
|
+
}
|
|
64
|
+
const foreignKeyAttribute = this.TargetModel.rawAttributes[foreignKey];
|
|
65
|
+
const sourceKeyAttribute = this.collection.model.rawAttributes[sourceKey];
|
|
66
|
+
if (!foreignKeyAttribute || !sourceKeyAttribute) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const foreignKeyType = foreignKeyAttribute.type.constructor.toString();
|
|
70
|
+
const sourceKeyType = sourceKeyAttribute.type.constructor.toString();
|
|
71
|
+
if (!this.keyPairsTypeMatched(foreignKeyType, sourceKeyType)) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`Foreign key "${foreignKey}" type "${foreignKeyType}" does not match source key "${sourceKey}" type "${sourceKeyType}" in has one relation "${this.name}" of collection "${this.collection.name}"`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
56
77
|
bind() {
|
|
57
78
|
const { database, collection } = this.context;
|
|
58
79
|
const Target = this.TargetModel;
|
|
@@ -60,6 +81,7 @@ const _HasOneField = class _HasOneField extends import_relation_field.RelationFi
|
|
|
60
81
|
database.addPendingField(this);
|
|
61
82
|
return false;
|
|
62
83
|
}
|
|
84
|
+
this.checkAssociationKeys();
|
|
63
85
|
const association = collection.model.hasOne(Target, {
|
|
64
86
|
constraints: false,
|
|
65
87
|
...(0, import_lodash.omit)(this.options, ["name", "type", "target", "onDelete"]),
|
|
@@ -70,6 +92,9 @@ const _HasOneField = class _HasOneField extends import_relation_field.RelationFi
|
|
|
70
92
|
if (!this.options.foreignKey) {
|
|
71
93
|
this.options.foreignKey = association.foreignKey;
|
|
72
94
|
}
|
|
95
|
+
if (!this.options.sourceKey) {
|
|
96
|
+
this.options.sourceKey = association.sourceKey;
|
|
97
|
+
}
|
|
73
98
|
try {
|
|
74
99
|
(0, import_utils.checkIdentifier)(this.options.foreignKey);
|
|
75
100
|
} catch (error) {
|
|
@@ -16,5 +16,6 @@ export declare abstract class RelationField extends Field {
|
|
|
16
16
|
* @constructor
|
|
17
17
|
*/
|
|
18
18
|
get TargetModel(): import("sequelize").ModelCtor<import("sequelize").Model<any, any>>;
|
|
19
|
+
keyPairsTypeMatched(type1: any, type2: any): boolean;
|
|
19
20
|
protected clearAccessors(): void;
|
|
20
21
|
}
|
|
@@ -46,6 +46,19 @@ const _RelationField = class _RelationField extends import_field.Field {
|
|
|
46
46
|
get TargetModel() {
|
|
47
47
|
return this.context.database.sequelize.models[this.target];
|
|
48
48
|
}
|
|
49
|
+
keyPairsTypeMatched(type1, type2) {
|
|
50
|
+
type1 = type1.toLowerCase();
|
|
51
|
+
type2 = type2.toLowerCase();
|
|
52
|
+
const numberTypeGroups = ["integer", "bigint", "decimal", "float", "real", "double", "smallint", "tinyint"];
|
|
53
|
+
const stringTypeGroups = ["string", "char", "text"];
|
|
54
|
+
if (numberTypeGroups.includes(type1) && numberTypeGroups.includes(type2)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if (stringTypeGroups.includes(type1) && stringTypeGroups.includes(type2)) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return type1 === type2;
|
|
61
|
+
}
|
|
49
62
|
clearAccessors() {
|
|
50
63
|
const { collection } = this.context;
|
|
51
64
|
const association = collection.model.associations[this.name];
|
|
@@ -3,11 +3,12 @@ import { Collection, CollectionContext, CollectionOptions } from './collection';
|
|
|
3
3
|
export declare class InheritedCollection extends Collection {
|
|
4
4
|
parents?: Collection[];
|
|
5
5
|
constructor(options: CollectionOptions, context: CollectionContext);
|
|
6
|
-
protected bindParents(): void;
|
|
7
|
-
protected setParents(inherits: string | string[]): void;
|
|
8
|
-
protected setParentFields(): void;
|
|
9
6
|
getParents(): Collection<any, any>[];
|
|
7
|
+
getFlatParents(): any[];
|
|
10
8
|
parentFields(): Map<string, Field>;
|
|
11
9
|
parentAttributes(): {};
|
|
12
10
|
isInherited(): boolean;
|
|
11
|
+
protected bindParents(): void;
|
|
12
|
+
protected setParents(inherits: string | string[]): void;
|
|
13
|
+
protected setParentFields(): void;
|
|
13
14
|
}
|
|
@@ -57,31 +57,18 @@ const _InheritedCollection = class _InheritedCollection extends import_collectio
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
|
|
61
|
-
this.
|
|
62
|
-
this.setParentFields();
|
|
63
|
-
this.setFields(this.options.fields, false);
|
|
64
|
-
this.db.inheritanceMap.setInheritance(this.name, this.options.inherits);
|
|
60
|
+
getParents() {
|
|
61
|
+
return this.parents;
|
|
65
62
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
|
|
63
|
+
getFlatParents() {
|
|
64
|
+
const parents = [];
|
|
65
|
+
for (const parent of this.parents) {
|
|
66
|
+
if (parent.isInherited()) {
|
|
67
|
+
parents.push(...parent.getFlatParents());
|
|
71
68
|
}
|
|
72
|
-
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
setParentFields() {
|
|
76
|
-
for (const [name, fieldOptions] of this.parentFields()) {
|
|
77
|
-
this.setField(name, {
|
|
78
|
-
...fieldOptions,
|
|
79
|
-
inherit: true
|
|
80
|
-
});
|
|
69
|
+
parents.push(parent);
|
|
81
70
|
}
|
|
82
|
-
|
|
83
|
-
getParents() {
|
|
84
|
-
return this.parents;
|
|
71
|
+
return parents;
|
|
85
72
|
}
|
|
86
73
|
parentFields() {
|
|
87
74
|
const fields = /* @__PURE__ */ new Map();
|
|
@@ -112,6 +99,29 @@ const _InheritedCollection = class _InheritedCollection extends import_collectio
|
|
|
112
99
|
isInherited() {
|
|
113
100
|
return true;
|
|
114
101
|
}
|
|
102
|
+
bindParents() {
|
|
103
|
+
this.setParents(this.options.inherits);
|
|
104
|
+
this.setParentFields();
|
|
105
|
+
this.setFields(this.options.fields, false);
|
|
106
|
+
this.db.inheritanceMap.setInheritance(this.name, this.options.inherits);
|
|
107
|
+
}
|
|
108
|
+
setParents(inherits) {
|
|
109
|
+
this.parents = import_lodash.default.castArray(inherits).map((name) => {
|
|
110
|
+
const existCollection = this.db.collections.get(name);
|
|
111
|
+
if (!existCollection) {
|
|
112
|
+
throw new ParentCollectionNotFound(name);
|
|
113
|
+
}
|
|
114
|
+
return existCollection;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
setParentFields() {
|
|
118
|
+
for (const [name, fieldOptions] of this.parentFields()) {
|
|
119
|
+
this.setField(name, {
|
|
120
|
+
...fieldOptions,
|
|
121
|
+
inherit: true
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
115
125
|
};
|
|
116
126
|
__name(_InheritedCollection, "InheritedCollection");
|
|
117
127
|
let InheritedCollection = _InheritedCollection;
|