@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 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
- return this.collections.get(name);
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
- if (relationId) {
462
- var _this$getRepository, _this$getRepository$r;
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
- const _name$split = name.split('.'),
465
- _name$split2 = _slicedToArray(_name$split, 2),
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
  }
@@ -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 * from './formula-field';
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;
@@ -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
- throw new Error(`Zero-column tables aren't supported in ${_this.database.sequelize.getDialect()}`);
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.8.1-alpha.4",
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.8.1-alpha.4",
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": "22ccdf7bd7fcbd16aeefd5250db237a4bd1ccff1"
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.message.includes("Zero-column tables aren't supported in")).toBeTruthy();
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
- return this.collections.get(name);
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
- if (relationId) {
383
- const [collection, relation] = name.split('.');
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: { directory: string; extensions?: ImportFileExtension[] }): Promise<Map<string, Collection>> {
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
  }
@@ -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;
@@ -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
- throw new Error(`Zero-column tables aren't supported in ${this.database.sequelize.getDialect()}`);
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(row.get('__tableName')).name;
339
- row.set('__collection', rowCollectionName, {
340
- raw: true,
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
- }