@nocobase/database 0.8.1-alpha.4 → 0.9.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/database.d.ts +2 -0
- package/lib/database.js +39 -7
- package/lib/fields/index.d.ts +3 -5
- package/lib/fields/index.js +13 -26
- package/lib/model.js +2 -1
- package/lib/repository.js +6 -2
- package/package.json +3 -9
- package/src/__tests__/collection.test.ts +2 -2
- package/src/database.ts +38 -7
- package/src/fields/field.ts +2 -2
- package/src/fields/index.ts +3 -6
- package/src/model.ts +2 -1
- package/src/repository.ts +13 -5
- package/lib/fields/formula-field.d.ts +0 -19
- package/lib/fields/formula-field.js +0 -197
- package/src/__tests__/fields/formula-field.test.ts +0 -69
- package/src/fields/formula-field.ts +0 -106
package/lib/database.d.ts
CHANGED
|
@@ -68,6 +68,7 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
|
68
68
|
tableNameCollectionMap: Map<string, Collection<any, any>>;
|
|
69
69
|
referenceMap: ReferencesMap;
|
|
70
70
|
inheritanceMap: InheritanceMap;
|
|
71
|
+
importedFrom: Map<string, string[]>;
|
|
71
72
|
modelHook: ModelHook;
|
|
72
73
|
version: DatabaseVersion;
|
|
73
74
|
delayCollectionExtend: Map<string, {
|
|
@@ -130,6 +131,7 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
|
130
131
|
extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): void;
|
|
131
132
|
import(options: {
|
|
132
133
|
directory: string;
|
|
134
|
+
from?: string;
|
|
133
135
|
extensions?: ImportFileExtension[];
|
|
134
136
|
}): Promise<Map<string, Collection>>;
|
|
135
137
|
emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
|
package/lib/database.js
CHANGED
|
@@ -215,6 +215,7 @@ class Database extends _events().EventEmitter {
|
|
|
215
215
|
this.tableNameCollectionMap = new Map();
|
|
216
216
|
this.referenceMap = new _ReferencesMap.default();
|
|
217
217
|
this.inheritanceMap = new _inheritedMap.default();
|
|
218
|
+
this.importedFrom = new Map();
|
|
218
219
|
this.modelHook = void 0;
|
|
219
220
|
this.version = void 0;
|
|
220
221
|
this.delayCollectionExtend = new Map();
|
|
@@ -296,6 +297,15 @@ class Database extends _events().EventEmitter {
|
|
|
296
297
|
sequelize: this.sequelize
|
|
297
298
|
}))
|
|
298
299
|
});
|
|
300
|
+
this.collection({
|
|
301
|
+
name: 'migrations',
|
|
302
|
+
autoGenId: false,
|
|
303
|
+
timestamps: false,
|
|
304
|
+
fields: [{
|
|
305
|
+
type: 'string',
|
|
306
|
+
name: 'name'
|
|
307
|
+
}]
|
|
308
|
+
});
|
|
299
309
|
this.sequelize.beforeDefine((model, opts) => {
|
|
300
310
|
if (this.options.tablePrefix) {
|
|
301
311
|
opts.tableName = `${this.options.tablePrefix}${opts.tableName || opts.modelName || opts.name.plural}`;
|
|
@@ -430,7 +440,25 @@ class Database extends _events().EventEmitter {
|
|
|
430
440
|
|
|
431
441
|
|
|
432
442
|
getCollection(name) {
|
|
433
|
-
|
|
443
|
+
if (!name) {
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const _name$split = name.split('.'),
|
|
448
|
+
_name$split2 = _slicedToArray(_name$split, 2),
|
|
449
|
+
collectionName = _name$split2[0],
|
|
450
|
+
associationName = _name$split2[1];
|
|
451
|
+
|
|
452
|
+
let collection = this.collections.get(collectionName);
|
|
453
|
+
|
|
454
|
+
if (associationName) {
|
|
455
|
+
var _collection$getField;
|
|
456
|
+
|
|
457
|
+
const target = (_collection$getField = collection.getField(associationName)) === null || _collection$getField === void 0 ? void 0 : _collection$getField.target;
|
|
458
|
+
return target ? this.collections.get(target) : null;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return collection;
|
|
434
462
|
}
|
|
435
463
|
|
|
436
464
|
hasCollection(name) {
|
|
@@ -458,13 +486,13 @@ class Database extends _events().EventEmitter {
|
|
|
458
486
|
getRepository(name, relationId) {
|
|
459
487
|
var _this$getCollection;
|
|
460
488
|
|
|
461
|
-
|
|
462
|
-
|
|
489
|
+
const _name$split3 = name.split('.'),
|
|
490
|
+
_name$split4 = _slicedToArray(_name$split3, 2),
|
|
491
|
+
collection = _name$split4[0],
|
|
492
|
+
relation = _name$split4[1];
|
|
463
493
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
collection = _name$split2[0],
|
|
467
|
-
relation = _name$split2[1];
|
|
494
|
+
if (relation) {
|
|
495
|
+
var _this$getRepository, _this$getRepository$r;
|
|
468
496
|
|
|
469
497
|
return (_this$getRepository = this.getRepository(collection)) === null || _this$getRepository === void 0 ? void 0 : (_this$getRepository$r = _this$getRepository.relation(relation)) === null || _this$getRepository$r === void 0 ? void 0 : _this$getRepository$r.of(relationId);
|
|
470
498
|
}
|
|
@@ -726,6 +754,10 @@ class Database extends _events().EventEmitter {
|
|
|
726
754
|
} else {
|
|
727
755
|
const collection = _this9.collection(module);
|
|
728
756
|
|
|
757
|
+
if (options.from) {
|
|
758
|
+
_this9.importedFrom.set(options.from, [...(_this9.importedFrom.get(options.from) || []), collection.name]);
|
|
759
|
+
}
|
|
760
|
+
|
|
729
761
|
result.set(collection.name, collection);
|
|
730
762
|
}
|
|
731
763
|
}
|
package/lib/fields/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { JsonbFieldOptions, JsonFieldOptions } from './json-field';
|
|
|
11
11
|
import { DecimalFieldOptions, DoubleFieldOptions, FloatFieldOptions, IntegerFieldOptions, RealFieldOptions } from './number-field';
|
|
12
12
|
import { PasswordFieldOptions } from './password-field';
|
|
13
13
|
import { RadioFieldOptions } from './radio-field';
|
|
14
|
+
import { SetFieldOptions } from './set-field';
|
|
14
15
|
import { SortFieldOptions } from './sort-field';
|
|
15
16
|
import { StringFieldOptions } from './string-field';
|
|
16
17
|
import { TextFieldOptions } from './text-field';
|
|
@@ -18,10 +19,7 @@ import { TimeFieldOptions } from './time-field';
|
|
|
18
19
|
import { UidFieldOptions } from './uid-field';
|
|
19
20
|
import { UUIDFieldOptions } from './uuid-field';
|
|
20
21
|
import { VirtualFieldOptions } from './virtual-field';
|
|
21
|
-
import { FormulaFieldOptions } from './formula-field';
|
|
22
|
-
import { SetFieldOptions } from './set-field';
|
|
23
22
|
export * from './array-field';
|
|
24
|
-
export * from './set-field';
|
|
25
23
|
export * from './belongs-to-field';
|
|
26
24
|
export * from './belongs-to-many-field';
|
|
27
25
|
export * from './boolean-field';
|
|
@@ -35,6 +33,7 @@ export * from './number-field';
|
|
|
35
33
|
export * from './password-field';
|
|
36
34
|
export * from './radio-field';
|
|
37
35
|
export * from './relation-field';
|
|
36
|
+
export * from './set-field';
|
|
38
37
|
export * from './sort-field';
|
|
39
38
|
export * from './string-field';
|
|
40
39
|
export * from './text-field';
|
|
@@ -42,5 +41,4 @@ export * from './time-field';
|
|
|
42
41
|
export * from './uid-field';
|
|
43
42
|
export * from './uuid-field';
|
|
44
43
|
export * from './virtual-field';
|
|
45
|
-
export
|
|
46
|
-
export declare type FieldOptions = BaseFieldOptions | StringFieldOptions | IntegerFieldOptions | FloatFieldOptions | DecimalFieldOptions | DoubleFieldOptions | RealFieldOptions | JsonFieldOptions | JsonbFieldOptions | BooleanFieldOptions | RadioFieldOptions | SortFieldOptions | TextFieldOptions | VirtualFieldOptions | FormulaFieldOptions | ArrayFieldOptions | SetFieldOptions | TimeFieldOptions | DateFieldOptions | UidFieldOptions | UUIDFieldOptions | PasswordFieldOptions | ContextFieldOptions | BelongsToFieldOptions | HasOneFieldOptions | HasManyFieldOptions | BelongsToManyFieldOptions;
|
|
44
|
+
export declare type FieldOptions = BaseFieldOptions | StringFieldOptions | IntegerFieldOptions | FloatFieldOptions | DecimalFieldOptions | DoubleFieldOptions | RealFieldOptions | JsonFieldOptions | JsonbFieldOptions | BooleanFieldOptions | RadioFieldOptions | SortFieldOptions | TextFieldOptions | VirtualFieldOptions | ArrayFieldOptions | SetFieldOptions | TimeFieldOptions | DateFieldOptions | UidFieldOptions | UUIDFieldOptions | PasswordFieldOptions | ContextFieldOptions | BelongsToFieldOptions | HasOneFieldOptions | HasManyFieldOptions | BelongsToManyFieldOptions;
|
package/lib/fields/index.js
CHANGED
|
@@ -17,19 +17,6 @@ Object.keys(_arrayField).forEach(function (key) {
|
|
|
17
17
|
});
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
var _setField = require("./set-field");
|
|
21
|
-
|
|
22
|
-
Object.keys(_setField).forEach(function (key) {
|
|
23
|
-
if (key === "default" || key === "__esModule") return;
|
|
24
|
-
if (key in exports && exports[key] === _setField[key]) return;
|
|
25
|
-
Object.defineProperty(exports, key, {
|
|
26
|
-
enumerable: true,
|
|
27
|
-
get: function get() {
|
|
28
|
-
return _setField[key];
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
20
|
var _belongsToField = require("./belongs-to-field");
|
|
34
21
|
|
|
35
22
|
Object.keys(_belongsToField).forEach(function (key) {
|
|
@@ -199,6 +186,19 @@ Object.keys(_relationField).forEach(function (key) {
|
|
|
199
186
|
});
|
|
200
187
|
});
|
|
201
188
|
|
|
189
|
+
var _setField = require("./set-field");
|
|
190
|
+
|
|
191
|
+
Object.keys(_setField).forEach(function (key) {
|
|
192
|
+
if (key === "default" || key === "__esModule") return;
|
|
193
|
+
if (key in exports && exports[key] === _setField[key]) return;
|
|
194
|
+
Object.defineProperty(exports, key, {
|
|
195
|
+
enumerable: true,
|
|
196
|
+
get: function get() {
|
|
197
|
+
return _setField[key];
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
202
|
var _sortField = require("./sort-field");
|
|
203
203
|
|
|
204
204
|
Object.keys(_sortField).forEach(function (key) {
|
|
@@ -288,17 +288,4 @@ Object.keys(_virtualField).forEach(function (key) {
|
|
|
288
288
|
return _virtualField[key];
|
|
289
289
|
}
|
|
290
290
|
});
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
var _formulaField = require("./formula-field");
|
|
294
|
-
|
|
295
|
-
Object.keys(_formulaField).forEach(function (key) {
|
|
296
|
-
if (key === "default" || key === "__esModule") return;
|
|
297
|
-
if (key in exports && exports[key] === _formulaField[key]) return;
|
|
298
|
-
Object.defineProperty(exports, key, {
|
|
299
|
-
enumerable: true,
|
|
300
|
-
get: function get() {
|
|
301
|
-
return _formulaField[key];
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
291
|
});
|
package/lib/model.js
CHANGED
|
@@ -173,7 +173,8 @@ class Model extends _sequelize().Model {
|
|
|
173
173
|
|
|
174
174
|
if (Object.keys(model.tableAttributes).length === 0) {
|
|
175
175
|
if (_this.database.inDialect('sqlite', 'mysql')) {
|
|
176
|
-
|
|
176
|
+
console.error(`Zero-column tables aren't supported in ${_this.database.sequelize.getDialect()}`);
|
|
177
|
+
return;
|
|
177
178
|
} // @ts-ignore
|
|
178
179
|
|
|
179
180
|
|
package/lib/repository.js
CHANGED
|
@@ -119,6 +119,10 @@ class RelationRepositoryBuilder {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
of(id) {
|
|
122
|
+
if (!this.association) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
122
126
|
const klass = this.builder()[this.association.associationType];
|
|
123
127
|
return new klass(this.collection, this.associationName, id);
|
|
124
128
|
}
|
|
@@ -262,9 +266,9 @@ class Repository {
|
|
|
262
266
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
263
267
|
const row = _step.value;
|
|
264
268
|
|
|
265
|
-
const rowCollectionName = _this2.database.tableNameCollectionMap.get(row.get('__tableName')).name;
|
|
269
|
+
const rowCollectionName = _this2.database.tableNameCollectionMap.get(options.raw ? row['__tableName'] : row.get('__tableName')).name;
|
|
266
270
|
|
|
267
|
-
row.set('__collection', rowCollectionName, {
|
|
271
|
+
options.raw ? row['__collection'] = rowCollectionName : row.set('__collection', rowCollectionName, {
|
|
268
272
|
raw: true
|
|
269
273
|
});
|
|
270
274
|
}
|
package/package.json
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/database",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-alpha.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
|
-
"licenses": [
|
|
9
|
-
{
|
|
10
|
-
"type": "Apache-2.0",
|
|
11
|
-
"url": "http://www.apache.org/licenses/LICENSE-2.0"
|
|
12
|
-
}
|
|
13
|
-
],
|
|
14
8
|
"dependencies": {
|
|
15
|
-
"@nocobase/utils": "0.
|
|
9
|
+
"@nocobase/utils": "0.9.0-alpha.2",
|
|
16
10
|
"async-mutex": "^0.3.2",
|
|
17
11
|
"cron-parser": "4.4.0",
|
|
18
12
|
"deepmerge": "^4.2.2",
|
|
@@ -32,5 +26,5 @@
|
|
|
32
26
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
33
27
|
"directory": "packages/database"
|
|
34
28
|
},
|
|
35
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "b8f76ad38e60e677c5bb4aab0a4cdb28d98a0f49"
|
|
36
30
|
}
|
|
@@ -19,7 +19,7 @@ describe('collection', () => {
|
|
|
19
19
|
await db.close();
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
it('should throw error when create empty collection in sqlite and mysql', async () => {
|
|
22
|
+
it('should not throw error when create empty collection in sqlite and mysql', async () => {
|
|
23
23
|
if (!db.inDialect('sqlite', 'mysql')) {
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
@@ -44,7 +44,7 @@ describe('collection', () => {
|
|
|
44
44
|
error = e;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
expect(error
|
|
47
|
+
expect(error).toBeUndefined();
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
pgOnly()('can create empty collection', async () => {
|
package/src/database.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
Sequelize,
|
|
16
16
|
SyncOptions,
|
|
17
17
|
Transactionable,
|
|
18
|
-
Utils
|
|
18
|
+
Utils
|
|
19
19
|
} from 'sequelize';
|
|
20
20
|
import { SequelizeStorage, Umzug } from 'umzug';
|
|
21
21
|
import { Collection, CollectionOptions, RepositoryType } from './collection';
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
SyncListener,
|
|
59
59
|
UpdateListener,
|
|
60
60
|
UpdateWithAssociationsListener,
|
|
61
|
-
ValidateListener
|
|
61
|
+
ValidateListener
|
|
62
62
|
} from './types';
|
|
63
63
|
|
|
64
64
|
export interface MergeOptions extends merge.Options {}
|
|
@@ -158,6 +158,8 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
158
158
|
referenceMap = new ReferencesMap();
|
|
159
159
|
inheritanceMap = new InheritanceMap();
|
|
160
160
|
|
|
161
|
+
importedFrom = new Map<string, Array<string>>();
|
|
162
|
+
|
|
161
163
|
modelHook: ModelHook;
|
|
162
164
|
version: DatabaseVersion;
|
|
163
165
|
|
|
@@ -232,6 +234,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
232
234
|
};
|
|
233
235
|
|
|
234
236
|
this.migrations = new Migrations(context);
|
|
237
|
+
|
|
235
238
|
this.migrator = new Umzug({
|
|
236
239
|
logger: migratorOptions.logger || console,
|
|
237
240
|
migrations: this.migrations.callback(),
|
|
@@ -243,6 +246,13 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
243
246
|
}),
|
|
244
247
|
});
|
|
245
248
|
|
|
249
|
+
this.collection({
|
|
250
|
+
name: 'migrations',
|
|
251
|
+
autoGenId: false,
|
|
252
|
+
timestamps: false,
|
|
253
|
+
fields: [{ type: 'string', name: 'name' }],
|
|
254
|
+
});
|
|
255
|
+
|
|
246
256
|
this.sequelize.beforeDefine((model, opts) => {
|
|
247
257
|
if (this.options.tablePrefix) {
|
|
248
258
|
opts.tableName = `${this.options.tablePrefix}${opts.tableName || opts.modelName || opts.name.plural}`;
|
|
@@ -346,7 +356,19 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
346
356
|
* @param name
|
|
347
357
|
*/
|
|
348
358
|
getCollection(name: string): Collection {
|
|
349
|
-
|
|
359
|
+
if (!name) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const [collectionName, associationName] = name.split('.');
|
|
364
|
+
let collection = this.collections.get(collectionName);
|
|
365
|
+
|
|
366
|
+
if (associationName) {
|
|
367
|
+
const target = collection.getField(associationName)?.target;
|
|
368
|
+
return target ? this.collections.get(target) : null;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return collection;
|
|
350
372
|
}
|
|
351
373
|
|
|
352
374
|
hasCollection(name: string): boolean {
|
|
@@ -379,11 +401,10 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
379
401
|
getRepository<R extends ArrayFieldRepository>(name: string, relationId: string | number): R;
|
|
380
402
|
|
|
381
403
|
getRepository<R extends RelationRepository>(name: string, relationId?: string | number): Repository | R {
|
|
382
|
-
|
|
383
|
-
|
|
404
|
+
const [collection, relation] = name.split('.');
|
|
405
|
+
if (relation) {
|
|
384
406
|
return this.getRepository(collection)?.relation(relation)?.of(relationId) as R;
|
|
385
407
|
}
|
|
386
|
-
|
|
387
408
|
return this.getCollection(name)?.repository;
|
|
388
409
|
}
|
|
389
410
|
|
|
@@ -447,6 +468,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
447
468
|
|
|
448
469
|
buildField(options, context: FieldContext) {
|
|
449
470
|
const { type } = options;
|
|
471
|
+
|
|
450
472
|
const Field = this.fieldTypes.get(type);
|
|
451
473
|
|
|
452
474
|
if (!Field) {
|
|
@@ -578,7 +600,11 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
578
600
|
}
|
|
579
601
|
}
|
|
580
602
|
|
|
581
|
-
async import(options: {
|
|
603
|
+
async import(options: {
|
|
604
|
+
directory: string;
|
|
605
|
+
from?: string;
|
|
606
|
+
extensions?: ImportFileExtension[];
|
|
607
|
+
}): Promise<Map<string, Collection>> {
|
|
582
608
|
const reader = new ImporterReader(options.directory, options.extensions);
|
|
583
609
|
const modules = await reader.read();
|
|
584
610
|
const result = new Map<string, Collection>();
|
|
@@ -588,6 +614,11 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
588
614
|
this.extendCollection(module.collectionOptions, module.mergeOptions);
|
|
589
615
|
} else {
|
|
590
616
|
const collection = this.collection(module);
|
|
617
|
+
|
|
618
|
+
if (options.from) {
|
|
619
|
+
this.importedFrom.set(options.from, [...(this.importedFrom.get(options.from) || []), collection.name]);
|
|
620
|
+
}
|
|
621
|
+
|
|
591
622
|
result.set(collection.name, collection);
|
|
592
623
|
}
|
|
593
624
|
}
|
package/src/fields/field.ts
CHANGED
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
ModelIndexesOptions,
|
|
7
7
|
QueryInterfaceOptions,
|
|
8
8
|
SyncOptions,
|
|
9
|
-
Transactionable
|
|
9
|
+
Transactionable
|
|
10
10
|
} from 'sequelize';
|
|
11
11
|
import { Collection } from '../collection';
|
|
12
12
|
import { Database } from '../database';
|
|
13
|
-
import { ModelEventTypes } from '../types';
|
|
14
13
|
import { InheritedCollection } from '../inherited-collection';
|
|
14
|
+
import { ModelEventTypes } from '../types';
|
|
15
15
|
|
|
16
16
|
export interface FieldContext {
|
|
17
17
|
database: Database;
|
package/src/fields/index.ts
CHANGED
|
@@ -13,10 +13,11 @@ import {
|
|
|
13
13
|
DoubleFieldOptions,
|
|
14
14
|
FloatFieldOptions,
|
|
15
15
|
IntegerFieldOptions,
|
|
16
|
-
RealFieldOptions
|
|
16
|
+
RealFieldOptions
|
|
17
17
|
} from './number-field';
|
|
18
18
|
import { PasswordFieldOptions } from './password-field';
|
|
19
19
|
import { RadioFieldOptions } from './radio-field';
|
|
20
|
+
import { SetFieldOptions } from './set-field';
|
|
20
21
|
import { SortFieldOptions } from './sort-field';
|
|
21
22
|
import { StringFieldOptions } from './string-field';
|
|
22
23
|
import { TextFieldOptions } from './text-field';
|
|
@@ -24,11 +25,8 @@ import { TimeFieldOptions } from './time-field';
|
|
|
24
25
|
import { UidFieldOptions } from './uid-field';
|
|
25
26
|
import { UUIDFieldOptions } from './uuid-field';
|
|
26
27
|
import { VirtualFieldOptions } from './virtual-field';
|
|
27
|
-
import { FormulaFieldOptions } from './formula-field';
|
|
28
|
-
import { SetFieldOptions } from './set-field';
|
|
29
28
|
|
|
30
29
|
export * from './array-field';
|
|
31
|
-
export * from './set-field';
|
|
32
30
|
export * from './belongs-to-field';
|
|
33
31
|
export * from './belongs-to-many-field';
|
|
34
32
|
export * from './boolean-field';
|
|
@@ -42,6 +40,7 @@ export * from './number-field';
|
|
|
42
40
|
export * from './password-field';
|
|
43
41
|
export * from './radio-field';
|
|
44
42
|
export * from './relation-field';
|
|
43
|
+
export * from './set-field';
|
|
45
44
|
export * from './sort-field';
|
|
46
45
|
export * from './string-field';
|
|
47
46
|
export * from './text-field';
|
|
@@ -49,7 +48,6 @@ export * from './time-field';
|
|
|
49
48
|
export * from './uid-field';
|
|
50
49
|
export * from './uuid-field';
|
|
51
50
|
export * from './virtual-field';
|
|
52
|
-
export * from './formula-field';
|
|
53
51
|
|
|
54
52
|
export type FieldOptions =
|
|
55
53
|
| BaseFieldOptions
|
|
@@ -66,7 +64,6 @@ export type FieldOptions =
|
|
|
66
64
|
| SortFieldOptions
|
|
67
65
|
| TextFieldOptions
|
|
68
66
|
| VirtualFieldOptions
|
|
69
|
-
| FormulaFieldOptions
|
|
70
67
|
| ArrayFieldOptions
|
|
71
68
|
| SetFieldOptions
|
|
72
69
|
| TimeFieldOptions
|
package/src/model.ts
CHANGED
|
@@ -156,7 +156,8 @@ export class Model<TModelAttributes extends {} = any, TCreationAttributes extend
|
|
|
156
156
|
// fix sequelize sync with model that not have any column
|
|
157
157
|
if (Object.keys(model.tableAttributes).length === 0) {
|
|
158
158
|
if (this.database.inDialect('sqlite', 'mysql')) {
|
|
159
|
-
|
|
159
|
+
console.error(`Zero-column tables aren't supported in ${this.database.sequelize.getDialect()}`);
|
|
160
|
+
return;
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
// @ts-ignore
|
package/src/repository.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
Op,
|
|
12
12
|
Transactionable,
|
|
13
13
|
UpdateOptions as SequelizeUpdateOptions,
|
|
14
|
-
WhereOperators
|
|
14
|
+
WhereOperators
|
|
15
15
|
} from 'sequelize';
|
|
16
16
|
import { Collection } from './collection';
|
|
17
17
|
import { Database } from './database';
|
|
@@ -193,6 +193,9 @@ class RelationRepositoryBuilder<R extends RelationRepository> {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
of(id: string | number): R {
|
|
196
|
+
if (!this.association) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
196
199
|
const klass = this.builder()[this.association.associationType];
|
|
197
200
|
return new klass(this.collection, this.associationName, id);
|
|
198
201
|
}
|
|
@@ -335,10 +338,15 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
|
|
|
335
338
|
|
|
336
339
|
if (this.collection.isParent()) {
|
|
337
340
|
for (const row of rows) {
|
|
338
|
-
const rowCollectionName = this.database.tableNameCollectionMap.get(
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
341
|
+
const rowCollectionName = this.database.tableNameCollectionMap.get(
|
|
342
|
+
options.raw ? row['__tableName'] : row.get('__tableName'),
|
|
343
|
+
).name;
|
|
344
|
+
|
|
345
|
+
options.raw
|
|
346
|
+
? (row['__collection'] = rowCollectionName)
|
|
347
|
+
: row.set('__collection', rowCollectionName, {
|
|
348
|
+
raw: true,
|
|
349
|
+
});
|
|
342
350
|
}
|
|
343
351
|
}
|
|
344
352
|
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { DataTypes } from 'sequelize';
|
|
2
|
-
import { BaseColumnFieldOptions, Field } from './field';
|
|
3
|
-
export declare class FormulaField extends Field {
|
|
4
|
-
get dataType(): DataTypes.FloatDataTypeConstructor;
|
|
5
|
-
caculate(expression: any, scope: any): any;
|
|
6
|
-
initFieldData: ({ transaction }: {
|
|
7
|
-
transaction: any;
|
|
8
|
-
}) => Promise<void>;
|
|
9
|
-
caculateField: (instance: any) => Promise<void>;
|
|
10
|
-
updateFieldData: (instance: any, { transaction }: {
|
|
11
|
-
transaction: any;
|
|
12
|
-
}) => Promise<void>;
|
|
13
|
-
bind(): void;
|
|
14
|
-
unbind(): void;
|
|
15
|
-
}
|
|
16
|
-
export interface FormulaFieldOptions extends BaseColumnFieldOptions {
|
|
17
|
-
type: 'formula';
|
|
18
|
-
expression: string;
|
|
19
|
-
}
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.FormulaField = void 0;
|
|
7
|
-
|
|
8
|
-
function _sequelize() {
|
|
9
|
-
const data = require("sequelize");
|
|
10
|
-
|
|
11
|
-
_sequelize = function _sequelize() {
|
|
12
|
-
return data;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
return data;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
var _field = require("./field");
|
|
19
|
-
|
|
20
|
-
function math() {
|
|
21
|
-
const data = _interopRequireWildcard(require("mathjs"));
|
|
22
|
-
|
|
23
|
-
math = function math() {
|
|
24
|
-
return data;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
return data;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
31
|
-
|
|
32
|
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
33
|
-
|
|
34
|
-
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; } } }; }
|
|
35
|
-
|
|
36
|
-
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); }
|
|
37
|
-
|
|
38
|
-
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; }
|
|
39
|
-
|
|
40
|
-
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); } }
|
|
41
|
-
|
|
42
|
-
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); }); }; }
|
|
43
|
-
|
|
44
|
-
class FormulaField extends _field.Field {
|
|
45
|
-
constructor(...args) {
|
|
46
|
-
var _this;
|
|
47
|
-
|
|
48
|
-
super(...args);
|
|
49
|
-
_this = this;
|
|
50
|
-
|
|
51
|
-
this.initFieldData = /*#__PURE__*/function () {
|
|
52
|
-
var _ref = _asyncToGenerator(function* ({
|
|
53
|
-
transaction
|
|
54
|
-
}) {
|
|
55
|
-
const _this$options = _this.options,
|
|
56
|
-
expression = _this$options.expression,
|
|
57
|
-
name = _this$options.name;
|
|
58
|
-
const records = yield _this.collection.repository.find({
|
|
59
|
-
order: [_this.collection.model.primaryKeyAttribute],
|
|
60
|
-
transaction
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
var _iterator = _createForOfIteratorHelper(records),
|
|
64
|
-
_step;
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
68
|
-
const record = _step.value;
|
|
69
|
-
const scope = record.toJSON();
|
|
70
|
-
|
|
71
|
-
const result = _this.caculate(expression, scope);
|
|
72
|
-
|
|
73
|
-
if (result) {
|
|
74
|
-
yield record.update({
|
|
75
|
-
[name]: result
|
|
76
|
-
}, {
|
|
77
|
-
transaction,
|
|
78
|
-
silent: true,
|
|
79
|
-
hooks: false
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
} catch (err) {
|
|
84
|
-
_iterator.e(err);
|
|
85
|
-
} finally {
|
|
86
|
-
_iterator.f();
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
return function (_x) {
|
|
91
|
-
return _ref.apply(this, arguments);
|
|
92
|
-
};
|
|
93
|
-
}();
|
|
94
|
-
|
|
95
|
-
this.caculateField = /*#__PURE__*/function () {
|
|
96
|
-
var _ref2 = _asyncToGenerator(function* (instance) {
|
|
97
|
-
const _this$options2 = _this.options,
|
|
98
|
-
expression = _this$options2.expression,
|
|
99
|
-
name = _this$options2.name;
|
|
100
|
-
const scope = instance.toJSON();
|
|
101
|
-
let result;
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
result = math().evaluate(expression, scope);
|
|
105
|
-
result = math().round(result, 9);
|
|
106
|
-
} catch (_unused) {}
|
|
107
|
-
|
|
108
|
-
if (result === 0 || result) {
|
|
109
|
-
instance.set(name, result);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
return function (_x2) {
|
|
114
|
-
return _ref2.apply(this, arguments);
|
|
115
|
-
};
|
|
116
|
-
}();
|
|
117
|
-
|
|
118
|
-
this.updateFieldData = /*#__PURE__*/function () {
|
|
119
|
-
var _ref3 = _asyncToGenerator(function* (instance, {
|
|
120
|
-
transaction
|
|
121
|
-
}) {
|
|
122
|
-
if (_this.collection.name === instance.collectionName && instance.name === _this.options.name) {
|
|
123
|
-
_this.options = Object.assign(_this.options, instance.options);
|
|
124
|
-
const _this$options3 = _this.options,
|
|
125
|
-
name = _this$options3.name,
|
|
126
|
-
expression = _this$options3.expression;
|
|
127
|
-
const records = yield _this.collection.repository.find({
|
|
128
|
-
order: [_this.collection.model.primaryKeyAttribute],
|
|
129
|
-
transaction
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
var _iterator2 = _createForOfIteratorHelper(records),
|
|
133
|
-
_step2;
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
137
|
-
const record = _step2.value;
|
|
138
|
-
const scope = record.toJSON();
|
|
139
|
-
|
|
140
|
-
const result = _this.caculate(expression, scope);
|
|
141
|
-
|
|
142
|
-
yield record.update({
|
|
143
|
-
[name]: result
|
|
144
|
-
}, {
|
|
145
|
-
transaction,
|
|
146
|
-
silent: true,
|
|
147
|
-
hooks: false
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
} catch (err) {
|
|
151
|
-
_iterator2.e(err);
|
|
152
|
-
} finally {
|
|
153
|
-
_iterator2.f();
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
return function (_x3, _x4) {
|
|
159
|
-
return _ref3.apply(this, arguments);
|
|
160
|
-
};
|
|
161
|
-
}();
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
get dataType() {
|
|
165
|
-
return _sequelize().DataTypes.FLOAT;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
caculate(expression, scope) {
|
|
169
|
-
let result = null;
|
|
170
|
-
|
|
171
|
-
try {
|
|
172
|
-
result = math().evaluate(expression, scope);
|
|
173
|
-
result = math().round(result, 9);
|
|
174
|
-
} catch (_unused2) {}
|
|
175
|
-
|
|
176
|
-
return result;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
bind() {
|
|
180
|
-
super.bind();
|
|
181
|
-
this.on('afterSync', this.initFieldData); // TODO: should not depends on fields table (which is defined by other plugin)
|
|
182
|
-
|
|
183
|
-
this.database.on('fields.afterUpdate', this.updateFieldData);
|
|
184
|
-
this.on('beforeSave', this.caculateField);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
unbind() {
|
|
188
|
-
super.unbind();
|
|
189
|
-
this.off('beforeSave', this.caculateField); // TODO: should not depends on fields table
|
|
190
|
-
|
|
191
|
-
this.database.off('fields.afterUpdate', this.updateFieldData);
|
|
192
|
-
this.off('afterSync', this.initFieldData);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
exports.FormulaField = FormulaField;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { mockDatabase } from '..';
|
|
2
|
-
import { Database } from '../../database';
|
|
3
|
-
import { FormulaField } from '../../fields';
|
|
4
|
-
|
|
5
|
-
describe('formula field', () => {
|
|
6
|
-
let db: Database;
|
|
7
|
-
|
|
8
|
-
beforeEach(async () => {
|
|
9
|
-
db = mockDatabase();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
afterEach(async () => {
|
|
13
|
-
await db.close();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('add formula field with old table, already has data.', async () => {
|
|
17
|
-
const Test = db.collection({
|
|
18
|
-
name: 'tests',
|
|
19
|
-
fields: [
|
|
20
|
-
{ type: 'float', name: 'price' },
|
|
21
|
-
{ type: 'float', name: 'count' },
|
|
22
|
-
],
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
await db.sync();
|
|
26
|
-
|
|
27
|
-
const test = await Test.model.create<any>({
|
|
28
|
-
price: '1.2',
|
|
29
|
-
count: '2',
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const expression = 'price*count';
|
|
33
|
-
const field = Test.addField('sum', { type: 'formula', expression });
|
|
34
|
-
|
|
35
|
-
await field.sync({});
|
|
36
|
-
|
|
37
|
-
const updatedTest = await Test.model.findByPk(test.id);
|
|
38
|
-
const sum = updatedTest.get('sum');
|
|
39
|
-
|
|
40
|
-
const sumField = Test.getField<FormulaField>('sum');
|
|
41
|
-
expect(sum).toEqual(sumField.caculate(expression, updatedTest.toJSON()));
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('auto set formula field with create or update data', async () => {
|
|
45
|
-
const expression = 'price*count';
|
|
46
|
-
const Test = db.collection({
|
|
47
|
-
name: 'tests',
|
|
48
|
-
fields: [
|
|
49
|
-
{ type: 'float', name: 'price' },
|
|
50
|
-
{ type: 'float', name: 'count' },
|
|
51
|
-
{ name: 'sum', type: 'formula', expression },
|
|
52
|
-
],
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
await db.sync();
|
|
56
|
-
|
|
57
|
-
const test = await Test.model.create<any>({
|
|
58
|
-
price: '1.2',
|
|
59
|
-
count: '2',
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const sumField = Test.getField<FormulaField>('sum');
|
|
63
|
-
expect(test.get('sum')).toEqual(sumField.caculate(expression, test.toJSON()));
|
|
64
|
-
|
|
65
|
-
test.set('count', '6');
|
|
66
|
-
await test.save();
|
|
67
|
-
expect(test.get('sum')).toEqual(sumField.caculate(expression, test.toJSON()));
|
|
68
|
-
});
|
|
69
|
-
});
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { DataTypes } from 'sequelize';
|
|
2
|
-
import { BaseColumnFieldOptions, Field } from './field';
|
|
3
|
-
import * as math from 'mathjs';
|
|
4
|
-
|
|
5
|
-
export class FormulaField extends Field {
|
|
6
|
-
get dataType() {
|
|
7
|
-
return DataTypes.FLOAT;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
caculate(expression, scope) {
|
|
11
|
-
let result = null;
|
|
12
|
-
try {
|
|
13
|
-
result = math.evaluate(expression, scope);
|
|
14
|
-
result = math.round(result, 9);
|
|
15
|
-
} catch {}
|
|
16
|
-
return result;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
initFieldData = async ({ transaction }) => {
|
|
20
|
-
const { expression, name } = this.options;
|
|
21
|
-
|
|
22
|
-
const records = await this.collection.repository.find({
|
|
23
|
-
order: [this.collection.model.primaryKeyAttribute],
|
|
24
|
-
transaction,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
for (const record of records) {
|
|
28
|
-
const scope = record.toJSON();
|
|
29
|
-
const result = this.caculate(expression, scope);
|
|
30
|
-
if (result) {
|
|
31
|
-
await record.update(
|
|
32
|
-
{
|
|
33
|
-
[name]: result,
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
transaction,
|
|
37
|
-
silent: true,
|
|
38
|
-
hooks: false,
|
|
39
|
-
},
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
caculateField = async (instance) => {
|
|
46
|
-
const { expression, name } = this.options;
|
|
47
|
-
const scope = instance.toJSON();
|
|
48
|
-
let result;
|
|
49
|
-
try {
|
|
50
|
-
result = math.evaluate(expression, scope);
|
|
51
|
-
result = math.round(result, 9);
|
|
52
|
-
} catch {}
|
|
53
|
-
if (result === 0 || result) {
|
|
54
|
-
instance.set(name, result);
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
updateFieldData = async (instance, { transaction }) => {
|
|
59
|
-
if (this.collection.name === instance.collectionName && instance.name === this.options.name) {
|
|
60
|
-
this.options = Object.assign(this.options, instance.options);
|
|
61
|
-
const { name, expression } = this.options;
|
|
62
|
-
|
|
63
|
-
const records = await this.collection.repository.find({
|
|
64
|
-
order: [this.collection.model.primaryKeyAttribute],
|
|
65
|
-
transaction,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
for (const record of records) {
|
|
69
|
-
const scope = record.toJSON();
|
|
70
|
-
const result = this.caculate(expression, scope);
|
|
71
|
-
await record.update(
|
|
72
|
-
{
|
|
73
|
-
[name]: result,
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
transaction,
|
|
77
|
-
silent: true,
|
|
78
|
-
hooks: false,
|
|
79
|
-
},
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
bind() {
|
|
86
|
-
super.bind();
|
|
87
|
-
this.on('afterSync', this.initFieldData);
|
|
88
|
-
// TODO: should not depends on fields table (which is defined by other plugin)
|
|
89
|
-
this.database.on('fields.afterUpdate', this.updateFieldData);
|
|
90
|
-
this.on('beforeSave', this.caculateField);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
unbind() {
|
|
94
|
-
super.unbind();
|
|
95
|
-
this.off('beforeSave', this.caculateField);
|
|
96
|
-
// TODO: should not depends on fields table
|
|
97
|
-
this.database.off('fields.afterUpdate', this.updateFieldData);
|
|
98
|
-
this.off('afterSync', this.initFieldData);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export interface FormulaFieldOptions extends BaseColumnFieldOptions {
|
|
103
|
-
type: 'formula';
|
|
104
|
-
|
|
105
|
-
expression: string;
|
|
106
|
-
}
|