@nocobase/database 0.9.0-alpha.2 → 0.9.1-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.
Files changed (125) hide show
  1. package/lib/collection-importer.js +1 -1
  2. package/lib/collection.d.ts +9 -2
  3. package/lib/collection.js +153 -63
  4. package/lib/database-utils/index.d.ts +8 -0
  5. package/lib/database-utils/index.js +59 -0
  6. package/lib/database.d.ts +32 -3
  7. package/lib/database.js +237 -64
  8. package/lib/fields/array-field.d.ts +1 -1
  9. package/lib/fields/array-field.js +2 -2
  10. package/lib/fields/belongs-to-many-field.js +8 -3
  11. package/lib/fields/field.d.ts +1 -0
  12. package/lib/fields/field.js +37 -15
  13. package/lib/fields/has-one-field.d.ts +1 -1
  14. package/lib/fields/has-one-field.js +9 -5
  15. package/lib/fields/number-field.d.ts +9 -6
  16. package/lib/fields/number-field.js +8 -6
  17. package/lib/fields/sort-field.js +15 -1
  18. package/lib/filter-parser.js +1 -1
  19. package/lib/index.d.ts +6 -4
  20. package/lib/index.js +59 -36
  21. package/lib/mock-database.d.ts +2 -0
  22. package/lib/mock-database.js +3 -1
  23. package/lib/model.js +10 -1
  24. package/lib/options-parser.js +3 -0
  25. package/lib/query-interface/mysql-query-interface.d.ts +7 -0
  26. package/lib/query-interface/mysql-query-interface.js +39 -0
  27. package/lib/query-interface/postgres-query-interface.d.ts +6 -0
  28. package/lib/query-interface/postgres-query-interface.js +41 -0
  29. package/lib/query-interface/query-interface-builder.d.ts +2 -0
  30. package/lib/query-interface/query-interface-builder.js +23 -0
  31. package/lib/query-interface/query-interface.d.ts +9 -0
  32. package/lib/query-interface/query-interface.js +18 -0
  33. package/lib/query-interface/sqlite-query-interface.d.ts +6 -0
  34. package/lib/query-interface/sqlite-query-interface.js +38 -0
  35. package/lib/relation-repository/belongs-to-many-repository.js +4 -2
  36. package/lib/relation-repository/multiple-relation-repository.js +2 -0
  37. package/lib/relation-repository/single-relation-repository.js +1 -0
  38. package/lib/repository.js +5 -2
  39. package/lib/sync-runner.d.ts +1 -1
  40. package/lib/sync-runner.js +29 -22
  41. package/lib/types.d.ts +7 -1
  42. package/lib/update-associations.js +17 -3
  43. package/lib/update-guard.d.ts +1 -0
  44. package/lib/update-guard.js +6 -0
  45. package/lib/utils.d.ts +5 -0
  46. package/lib/utils.js +78 -0
  47. package/lib/value-parsers/array-value-parser.d.ts +8 -0
  48. package/lib/value-parsers/array-value-parser.js +76 -0
  49. package/lib/value-parsers/base-value-parser.d.ts +12 -0
  50. package/lib/value-parsers/base-value-parser.js +59 -0
  51. package/lib/value-parsers/boolean-value-parser.d.ts +4 -0
  52. package/lib/value-parsers/boolean-value-parser.js +46 -0
  53. package/lib/value-parsers/date-value-parser.d.ts +5 -0
  54. package/lib/value-parsers/date-value-parser.js +91 -0
  55. package/lib/value-parsers/index.d.ts +12 -0
  56. package/lib/value-parsers/index.js +102 -0
  57. package/lib/value-parsers/json-value-parser.d.ts +4 -0
  58. package/lib/value-parsers/json-value-parser.js +37 -0
  59. package/lib/value-parsers/number-value-parser.d.ts +4 -0
  60. package/lib/value-parsers/number-value-parser.js +49 -0
  61. package/lib/value-parsers/string-value-parser.d.ts +8 -0
  62. package/lib/value-parsers/string-value-parser.js +76 -0
  63. package/lib/value-parsers/to-many-value-parser.d.ts +13 -0
  64. package/lib/value-parsers/to-many-value-parser.js +169 -0
  65. package/lib/value-parsers/to-one-value-parser.d.ts +4 -0
  66. package/lib/value-parsers/to-one-value-parser.js +49 -0
  67. package/package.json +5 -3
  68. package/src/__tests__/bigint.test.ts +1 -1
  69. package/src/__tests__/collection-importer.test.ts +13 -1
  70. package/src/__tests__/collection.test.ts +19 -9
  71. package/src/__tests__/database.test.ts +32 -0
  72. package/src/__tests__/fields/sort-field.test.ts +23 -0
  73. package/src/__tests__/filter.test.ts +60 -0
  74. package/src/__tests__/inhertits/collection-inherits.test.ts +7 -5
  75. package/src/__tests__/percent2float.test.ts +14 -0
  76. package/src/__tests__/postgres/schema.test.ts +120 -0
  77. package/src/__tests__/underscored-options.test.ts +207 -0
  78. package/src/__tests__/update-associations-through.test.ts +73 -0
  79. package/src/__tests__/value-parsers/base.test.ts +20 -0
  80. package/src/__tests__/value-parsers/date.test.ts +67 -0
  81. package/src/__tests__/value-parsers/number.test.ts +46 -0
  82. package/src/__tests__/value-parsers/to-many.test.ts +206 -0
  83. package/src/__tests__/value-parsers/to-one.test.ts +60 -0
  84. package/src/collection-importer.ts +2 -2
  85. package/src/collection.ts +115 -17
  86. package/src/database-utils/index.ts +38 -0
  87. package/src/database.ts +188 -36
  88. package/src/fields/array-field.ts +1 -1
  89. package/src/fields/belongs-to-field.ts +1 -1
  90. package/src/fields/belongs-to-many-field.ts +8 -3
  91. package/src/fields/field.ts +48 -17
  92. package/src/fields/has-many-field.ts +1 -1
  93. package/src/fields/has-one-field.ts +11 -7
  94. package/src/fields/number-field.ts +10 -6
  95. package/src/fields/sort-field.ts +13 -1
  96. package/src/filter-parser.ts +1 -1
  97. package/src/index.ts +7 -4
  98. package/src/inherited-collection.ts +1 -0
  99. package/src/mock-database.ts +3 -1
  100. package/src/model.ts +11 -2
  101. package/src/options-parser.ts +5 -0
  102. package/src/query-interface/mysql-query-interface.ts +20 -0
  103. package/src/query-interface/postgres-query-interface.ts +22 -0
  104. package/src/query-interface/query-interface-builder.ts +14 -0
  105. package/src/query-interface/query-interface.ts +12 -0
  106. package/src/query-interface/sqlite-query-interface.ts +18 -0
  107. package/src/relation-repository/belongs-to-many-repository.ts +4 -2
  108. package/src/relation-repository/multiple-relation-repository.ts +4 -0
  109. package/src/relation-repository/single-relation-repository.ts +2 -0
  110. package/src/repository.ts +8 -3
  111. package/src/sync-runner.ts +35 -24
  112. package/src/types.ts +12 -1
  113. package/src/update-associations.ts +12 -5
  114. package/src/update-guard.ts +6 -0
  115. package/src/utils.ts +95 -0
  116. package/src/value-parsers/array-value-parser.ts +30 -0
  117. package/src/value-parsers/base-value-parser.ts +40 -0
  118. package/src/value-parsers/boolean-value-parser.ts +29 -0
  119. package/src/value-parsers/date-value-parser.ts +38 -0
  120. package/src/value-parsers/index.ts +46 -0
  121. package/src/value-parsers/json-value-parser.ts +19 -0
  122. package/src/value-parsers/number-value-parser.ts +29 -0
  123. package/src/value-parsers/string-value-parser.ts +31 -0
  124. package/src/value-parsers/to-many-value-parser.ts +85 -0
  125. package/src/value-parsers/to-one-value-parser.ts +20 -0
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _queryInterface = _interopRequireDefault(require("./query-interface"));
9
+
10
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
+
12
+ 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); } }
13
+
14
+ 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); }); }; }
15
+
16
+ class SqliteQueryInterface extends _queryInterface.default {
17
+ constructor(db) {
18
+ super(db);
19
+ }
20
+
21
+ collectionTableExists(collection, options) {
22
+ var _this = this;
23
+
24
+ return _asyncToGenerator(function* () {
25
+ const transaction = options === null || options === void 0 ? void 0 : options.transaction;
26
+ const tableName = collection.model.tableName;
27
+ const sql = `SELECT name FROM sqlite_master WHERE type='table' AND name='${tableName}';`;
28
+ const results = yield _this.db.sequelize.query(sql, {
29
+ type: 'SELECT',
30
+ transaction
31
+ });
32
+ return results.length > 0;
33
+ })();
34
+ }
35
+
36
+ }
37
+
38
+ exports.default = SqliteQueryInterface;
@@ -97,13 +97,15 @@ class BelongsToManyRepository extends _multipleRelationRepository.MultipleRelati
97
97
  const transaction = yield _this2.getTransaction(options);
98
98
  const association = _this2.association;
99
99
 
100
+ const throughModel = _this2.throughModel();
101
+
100
102
  const instancesToIds = instances => {
101
103
  return instances.map(instance => instance.get(_this2.targetKey()));
102
104
  }; // Through Table
103
105
 
104
106
 
105
107
  const throughTableWhere = [{
106
- [association.foreignKey]: _this2.sourceKeyValue
108
+ [throughModel.rawAttributes[association.foreignKey].field]: _this2.sourceKeyValue
107
109
  }];
108
110
  let ids;
109
111
 
@@ -130,7 +132,7 @@ class BelongsToManyRepository extends _multipleRelationRepository.MultipleRelati
130
132
  }
131
133
 
132
134
  throughTableWhere.push({
133
- [association.otherKey]: {
135
+ [throughModel.rawAttributes[association.otherKey].field]: {
134
136
  [_sequelize().Op.in]: ids
135
137
  }
136
138
  }); // delete through table data
@@ -75,6 +75,7 @@ class MultipleRelationRepository extends _relationRepository.RelationRepository
75
75
  const getAccessor = _this.accessors().get;
76
76
 
77
77
  const sourceModel = yield _this.getSourceModel(transaction);
78
+ if (!sourceModel) return [];
78
79
 
79
80
  if (findOptions.include && findOptions.include.length > 0) {
80
81
  const ids = (yield sourceModel[getAccessor](_objectSpread(_objectSpread({}, findOptions), {}, {
@@ -139,6 +140,7 @@ class MultipleRelationRepository extends _relationRepository.RelationRepository
139
140
  return _asyncToGenerator(function* () {
140
141
  const transaction = yield _this3.getTransaction(options);
141
142
  const sourceModel = yield _this3.getSourceModel(transaction);
143
+ if (!sourceModel) return 0;
142
144
 
143
145
  const queryOptions = _this3.buildQueryOptions(options);
144
146
 
@@ -80,6 +80,7 @@ class SingleRelationRepository extends _relationRepository.RelationRepository {
80
80
  const getAccessor = _this3.accessors().get;
81
81
 
82
82
  const sourceModel = yield _this3.getSourceModel(transaction);
83
+ if (!sourceModel) return null;
83
84
 
84
85
  if ((findOptions === null || findOptions === void 0 ? void 0 : (_findOptions$include = findOptions.include) === null || _findOptions$include === void 0 ? void 0 : _findOptions$include.length) > 0) {
85
86
  const templateModel = yield sourceModel[getAccessor](_objectSpread(_objectSpread({}, findOptions), {}, {
package/lib/repository.js CHANGED
@@ -350,7 +350,8 @@ class Repository {
350
350
  const transaction = yield _this5.getTransaction(options);
351
351
 
352
352
  const guard = _updateGuard.UpdateGuard.fromOptions(_this5.model, _objectSpread(_objectSpread({}, options), {}, {
353
- action: 'create'
353
+ action: 'create',
354
+ underscored: _this5.collection.options.underscored
354
355
  }));
355
356
 
356
357
  const values = guard.sanitize(options.values || {});
@@ -436,7 +437,9 @@ class Repository {
436
437
 
437
438
  const transaction = yield _this7.getTransaction(options);
438
439
 
439
- const guard = _updateGuard.UpdateGuard.fromOptions(_this7.model, options);
440
+ const guard = _updateGuard.UpdateGuard.fromOptions(_this7.model, _objectSpread(_objectSpread({}, options), {}, {
441
+ underscored: _this7.collection.options.underscored
442
+ }));
440
443
 
441
444
  const values = guard.sanitize(options.values);
442
445
 
@@ -1,4 +1,4 @@
1
1
  export declare class SyncRunner {
2
2
  static syncInheritModel(model: any, options: any): Promise<void>;
3
- static createTable(tableName: any, attributes: any, options: any, model: any, parentTables: any): Promise<any>;
3
+ static createTable(tableName: any, attributes: any, options: any, model: any, parents: any): Promise<any>;
4
4
  }
@@ -54,8 +54,7 @@ class SyncRunner {
54
54
  throw new Error(`Inherit model ${inheritedCollection.name} can't be created without parents, parents option is ${_lodash().default.castArray(inheritedCollection.options.inherits).join(', ')}`);
55
55
  }
56
56
 
57
- const parentTables = parents.map(parent => parent.model.tableName);
58
- const tableName = model.getTableName();
57
+ const tableName = inheritedCollection.addSchemaTableName();
59
58
  const attributes = model.tableAttributes;
60
59
 
61
60
  const childAttributes = _lodash().default.pickBy(attributes, value => {
@@ -63,17 +62,20 @@ class SyncRunner {
63
62
  });
64
63
 
65
64
  let maxSequenceVal = 0;
66
- let maxSequenceName;
65
+ let maxSequenceName; // find max sequence
67
66
 
68
67
  if (childAttributes.id && childAttributes.id.autoIncrement) {
69
- var _iterator = _createForOfIteratorHelper(parentTables),
68
+ var _iterator = _createForOfIteratorHelper(parents),
70
69
  _step;
71
70
 
72
71
  try {
73
72
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
74
73
  const parent = _step.value;
75
- const sequenceNameResult = yield queryInterface.sequelize.query(`SELECT column_default FROM information_schema.columns WHERE
76
- table_name='${parent}' and "column_name" = 'id';`, {
74
+ const sequenceNameResult = yield queryInterface.sequelize.query(`SELECT column_default
75
+ FROM information_schema.columns
76
+ WHERE table_name = '${parent.model.tableName}'
77
+ and table_schema = '${parent.collectionSchema()}'
78
+ and "column_name" = 'id';`, {
77
79
  transaction
78
80
  });
79
81
 
@@ -87,10 +89,11 @@ class SyncRunner {
87
89
  throw new Error(`Can't find sequence name of ${parent}`);
88
90
  }
89
91
 
90
- const regex = new RegExp(/nextval\('("?\w+"?)\'.*\)/);
92
+ const regex = new RegExp(/nextval\('(.*)'::regclass\)/);
91
93
  const match = regex.exec(columnDefault);
92
94
  const sequenceName = match[1];
93
- const sequenceCurrentValResult = yield queryInterface.sequelize.query(`select last_value from ${sequenceName}`, {
95
+ const sequenceCurrentValResult = yield queryInterface.sequelize.query(`select last_value
96
+ from ${sequenceName}`, {
94
97
  transaction
95
98
  });
96
99
  const sequenceCurrentVal = parseInt(sequenceCurrentValResult[0][0]['last_value']);
@@ -107,22 +110,21 @@ class SyncRunner {
107
110
  }
108
111
  }
109
112
 
110
- yield _this.createTable(tableName, childAttributes, options, model, parentTables);
113
+ yield _this.createTable(tableName, childAttributes, options, model, parents); // if we have max sequence, set it to child table
111
114
 
112
115
  if (maxSequenceName) {
113
- const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map(parent => db.getCollection(parent).model.tableName);
116
+ const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map(parent => db.getCollection(parent).addSchemaTableName());
114
117
  const sequenceTables = [...parentsDeep, tableName];
115
118
 
116
119
  for (var _i = 0, _sequenceTables = sequenceTables; _i < _sequenceTables.length; _i++) {
117
120
  const sequenceTable = _sequenceTables[_i];
118
- const queryName = Boolean(sequenceTable.match(/[A-Z]/)) ? `"${sequenceTable}"` : sequenceTable;
119
- const idColumnQuery = yield queryInterface.sequelize.query(`
120
- SELECT true
121
- FROM pg_attribute
122
- WHERE attrelid = '${queryName}'::regclass -- cast to a registered class (table)
123
- AND attname = 'id'
124
- AND NOT attisdropped
125
- `, {
121
+ const tableName = sequenceTable.tableName;
122
+ const schemaName = sequenceTable.schema;
123
+ const queryName = Boolean(tableName.match(/[A-Z]/)) && !tableName.includes(`"`) ? `"${tableName}"` : tableName;
124
+ const idColumnQuery = yield queryInterface.sequelize.query(`SELECT column_name
125
+ FROM information_schema.columns
126
+ WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schemaName}';
127
+ `, {
126
128
  transaction
127
129
  });
128
130
 
@@ -130,7 +132,8 @@ AND NOT attisdropped
130
132
  continue;
131
133
  }
132
134
 
133
- yield queryInterface.sequelize.query(`alter table "${sequenceTable}" alter column id set default nextval('${maxSequenceName}')`, {
135
+ yield queryInterface.sequelize.query(`alter table ${db.utils.quoteTable(sequenceTable)}
136
+ alter column id set default nextval('${maxSequenceName}')`, {
134
137
  transaction
135
138
  });
136
139
  }
@@ -139,7 +142,9 @@ AND NOT attisdropped
139
142
  if (options.alter) {
140
143
  const columns = yield queryInterface.describeTable(tableName, options);
141
144
 
142
- for (const columnName in childAttributes) {
145
+ for (const attribute in childAttributes) {
146
+ const columnName = childAttributes[attribute].field;
147
+
143
148
  if (!columns[columnName]) {
144
149
  yield queryInterface.addColumn(tableName, columnName, childAttributes[columnName], options);
145
150
  }
@@ -148,7 +153,7 @@ AND NOT attisdropped
148
153
  })();
149
154
  }
150
155
 
151
- static createTable(tableName, attributes, options, model, parentTables) {
156
+ static createTable(tableName, attributes, options, model, parents) {
152
157
  return _asyncToGenerator(function* () {
153
158
  let sql = '';
154
159
  options = _objectSpread({}, options);
@@ -171,7 +176,9 @@ AND NOT attisdropped
171
176
  table: tableName,
172
177
  context: 'createTable'
173
178
  });
174
- sql = `${queryGenerator.createTableQuery(tableName, attributes, options)}`.replace(';', ` INHERITS (${parentTables.map(t => `"${t}"`).join(', ')});`);
179
+ sql = `${queryGenerator.createTableQuery(tableName, attributes, options)}`.replace(';', ` INHERITS (${parents.map(t => {
180
+ return t.addSchemaTableName();
181
+ }).join(', ')});`);
175
182
  return yield model.sequelize.query(sql, options);
176
183
  })();
177
184
  }
package/lib/types.d.ts CHANGED
@@ -13,6 +13,9 @@ export declare type ModelDestroyEventType = 'beforeDestroy' | 'afterDestroy';
13
13
  export declare type ModelCreateWithAssociationsEventType = 'afterCreateWithAssociations';
14
14
  export declare type ModelUpdateWithAssociationsEventType = 'afterUpdateWithAssociations';
15
15
  export declare type ModelSaveWithAssociationsEventType = 'afterSaveWithAssociations';
16
+ export declare type ModelBulkCreateEvnetType = 'beforeBulkCreate' | 'afterBulkCreate';
17
+ export declare type ModelBulkUpdateEvnetType = 'beforeBulkUpdate' | 'afterBulkUpdate';
18
+ export declare type ModelBulkDestroyEvnetType = 'beforeBulkDestroy' | 'afterBulkDestroy';
16
19
  export declare type ModelValidateEventTypes = ModelValidateEventType | `${CollectionNameType}.${ModelValidateEventType}`;
17
20
  export declare type ModelCreateEventTypes = ModelCreateEventType | `${CollectionNameType}.${ModelCreateEventType}`;
18
21
  export declare type ModelUpdateEventTypes = ModelUpdateEventType | `${CollectionNameType}.${ModelUpdateEventType}`;
@@ -21,7 +24,10 @@ export declare type ModelDestroyEventTypes = ModelDestroyEventType | `${Collecti
21
24
  export declare type ModelCreateWithAssociationsEventTypes = ModelCreateWithAssociationsEventType | `${CollectionNameType}.${ModelCreateWithAssociationsEventType}`;
22
25
  export declare type ModelUpdateWithAssociationsEventTypes = ModelUpdateWithAssociationsEventType | `${CollectionNameType}.${ModelUpdateWithAssociationsEventType}`;
23
26
  export declare type ModelSaveWithAssociationsEventTypes = ModelSaveWithAssociationsEventType | `${CollectionNameType}.${ModelSaveWithAssociationsEventType}`;
24
- export declare type ModelEventTypes = ModelSyncEventType | ModelValidateEventTypes | ModelCreateEventTypes | ModelUpdateEventTypes | ModelSaveEventTypes | ModelDestroyEventTypes | ModelCreateWithAssociationsEventTypes | ModelUpdateWithAssociationsEventTypes | ModelSaveWithAssociationsEventTypes;
27
+ export declare type ModelBulkCreateEvnetTypes = ModelBulkCreateEvnetType | `${CollectionNameType}.${ModelBulkCreateEvnetType}`;
28
+ export declare type ModelBulkUpdateEvnetTypes = ModelBulkUpdateEvnetType | `${CollectionNameType}.${ModelBulkUpdateEvnetType}`;
29
+ export declare type ModelBulkDestroyEvnetTypes = ModelBulkDestroyEvnetType | `${CollectionNameType}.${ModelBulkDestroyEvnetType}`;
30
+ export declare type ModelEventTypes = ModelSyncEventType | ModelValidateEventTypes | ModelCreateEventTypes | ModelUpdateEventTypes | ModelSaveEventTypes | ModelDestroyEventTypes | ModelCreateWithAssociationsEventTypes | ModelUpdateWithAssociationsEventTypes | ModelSaveWithAssociationsEventTypes | ModelBulkCreateEvnetTypes | ModelBulkUpdateEvnetTypes | ModelBulkDestroyEvnetTypes;
25
31
  export declare type DatabaseBeforeDefineCollectionEventType = 'beforeDefineCollection';
26
32
  export declare type DatabaseAfterDefineCollectionEventType = 'afterDefineCollection';
27
33
  export declare type DatabaseBeforeRemoveCollectionEventType = 'beforeRemoveCollection';
@@ -463,7 +463,8 @@ function _updateMultipleAssociation() {
463
463
  if (isStringOrNumber(value)) {
464
464
  yield model[setAccessor](value, {
465
465
  transaction,
466
- context
466
+ context,
467
+ individualHooks: true
467
468
  });
468
469
  return;
469
470
  }
@@ -476,6 +477,8 @@ function _updateMultipleAssociation() {
476
477
 
477
478
  const list2 = []; // to be added
478
479
 
480
+ const created = [];
481
+
479
482
  var _iterator3 = _createForOfIteratorHelper(value),
480
483
  _step3;
481
484
 
@@ -494,6 +497,13 @@ function _updateMultipleAssociation() {
494
497
  } else if (item.sequelize) {
495
498
  list1.push(item);
496
499
  } else if (typeof item === 'object') {
500
+ const targetKey = association.targetKey || 'id';
501
+
502
+ if (item[targetKey]) {
503
+ created.push(item[targetKey]);
504
+ list1.push(item[targetKey]);
505
+ }
506
+
497
507
  list2.push(item);
498
508
  }
499
509
  } // associate targets in lists1
@@ -506,7 +516,8 @@ function _updateMultipleAssociation() {
506
516
 
507
517
  yield model[setAccessor](list1, {
508
518
  transaction,
509
- context
519
+ context,
520
+ individualHooks: true
510
521
  });
511
522
  const list3 = [];
512
523
 
@@ -544,7 +555,10 @@ function _updateMultipleAssociation() {
544
555
  }
545
556
 
546
557
  const addAccessor = association.accessors.add;
547
- yield model[addAccessor](item[pk], accessorOptions);
558
+
559
+ if (!created.includes(item[pk])) {
560
+ yield model[addAccessor](item[pk], accessorOptions);
561
+ }
548
562
 
549
563
  if (!recursive) {
550
564
  continue;
@@ -8,6 +8,7 @@ declare type UpdateAction = 'create' | 'update';
8
8
  export declare class UpdateGuard {
9
9
  model: ModelStatic<any>;
10
10
  action: UpdateAction;
11
+ underscored: boolean;
11
12
  private associationKeysToBeUpdate;
12
13
  private blackList;
13
14
  private whiteList;
@@ -23,6 +23,7 @@ class UpdateGuard {
23
23
  constructor() {
24
24
  this.model = void 0;
25
25
  this.action = void 0;
26
+ this.underscored = void 0;
26
27
  this.associationKeysToBeUpdate = void 0;
27
28
  this.blackList = void 0;
28
29
  this.whiteList = void 0;
@@ -164,6 +165,11 @@ class UpdateGuard {
164
165
  guard.setBlackList(options.blacklist);
165
166
  guard.setAction(_lodash().default.get(options, 'action', 'update'));
166
167
  guard.setAssociationKeysToBeUpdate(options.updateAssociationValues);
168
+
169
+ if (options.underscored) {
170
+ guard.underscored = options.underscored;
171
+ }
172
+
167
173
  return guard;
168
174
  }
169
175
 
package/lib/utils.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import Database from './database';
1
2
  import { Model } from './model';
2
3
  declare type HandleAppendsQueryOptions = {
3
4
  templateModel: any;
@@ -6,4 +7,8 @@ declare type HandleAppendsQueryOptions = {
6
7
  export declare function handleAppendsQuery(options: HandleAppendsQueryOptions): Promise<Model<any, any>[]>;
7
8
  export declare function md5(value: string): string;
8
9
  export declare function checkIdentifier(value: string): void;
10
+ export declare function getTableName(collectionName: string, options: any): any;
11
+ export declare function snakeCase(name: string): any;
12
+ export declare function patchSequelizeQueryInterface(db: Database): void;
13
+ export declare function percent2float(value: string): number;
9
14
  export {};
package/lib/utils.js CHANGED
@@ -4,8 +4,12 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.checkIdentifier = checkIdentifier;
7
+ exports.getTableName = getTableName;
7
8
  exports.handleAppendsQuery = handleAppendsQuery;
8
9
  exports.md5 = md5;
10
+ exports.patchSequelizeQueryInterface = patchSequelizeQueryInterface;
11
+ exports.percent2float = percent2float;
12
+ exports.snakeCase = snakeCase;
9
13
 
10
14
  function _crypto() {
11
15
  const data = _interopRequireDefault(require("crypto"));
@@ -19,6 +23,16 @@ function _crypto() {
19
23
 
20
24
  var _identifierError = require("./errors/identifier-error");
21
25
 
26
+ function _lodash() {
27
+ const data = _interopRequireDefault(require("lodash"));
28
+
29
+ _lodash = function _lodash() {
30
+ return data;
31
+ };
32
+
33
+ return data;
34
+ }
35
+
22
36
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
37
 
24
38
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
@@ -128,4 +142,68 @@ function checkIdentifier(value) {
128
142
  if (value.length > MAX_IDENTIFIER_LENGTH) {
129
143
  throw new _identifierError.IdentifierError(`Identifier ${value} is too long`);
130
144
  }
145
+ }
146
+
147
+ function getTableName(collectionName, options) {
148
+ return options.underscored ? snakeCase(collectionName) : collectionName;
149
+ }
150
+
151
+ function snakeCase(name) {
152
+ return require('sequelize').Utils.underscore(name);
153
+ }
154
+
155
+ function patchShowConstraintsQuery(queryGenerator, db) {
156
+ queryGenerator.showConstraintsQuery = (tableName, constraintName) => {
157
+ const lines = ['SELECT constraint_catalog AS "constraintCatalog",', 'constraint_schema AS "constraintSchema",', 'constraint_name AS "constraintName",', 'table_catalog AS "tableCatalog",', 'table_schema AS "tableSchema",', 'table_name AS "tableName",', 'constraint_type AS "constraintType",', 'is_deferrable AS "isDeferrable",', 'initially_deferred AS "initiallyDeferred"', 'from INFORMATION_SCHEMA.table_constraints', `WHERE table_name='${_lodash().default.isPlainObject(tableName) ? tableName.tableName : tableName}'`];
158
+
159
+ if (!constraintName) {
160
+ lines.push(`AND constraint_name='${constraintName}'`);
161
+ }
162
+
163
+ if (_lodash().default.isPlainObject(tableName) && tableName.schema) {
164
+ lines.push(`AND table_schema='${tableName.schema}'`);
165
+ }
166
+
167
+ return lines.join(' ');
168
+ };
169
+ }
170
+
171
+ function patchDescribeTableQuery(queryGenerator) {
172
+ const describeTableQuery = function describeTableQuery(tableName, schema) {
173
+ schema = schema || this.options.schema || 'public';
174
+ return 'SELECT ' + 'pk.constraint_type as "Constraint",' + 'c.column_name as "Field", ' + 'c.column_default as "Default",' + 'c.is_nullable as "Null", ' + "(CASE WHEN c.udt_name = 'hstore' THEN c.udt_name ELSE c.data_type END) || (CASE WHEN c.character_maximum_length IS NOT NULL THEN '(' || c.character_maximum_length || ')' ELSE '' END) as \"Type\", " + '(SELECT array_agg(e.enumlabel) FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON t.oid=e.enumtypid WHERE t.typname=c.udt_name) AS "special", ' + '(SELECT pgd.description FROM pg_catalog.pg_statio_all_tables AS st INNER JOIN pg_catalog.pg_description pgd on (pgd.objoid=st.relid) WHERE c.ordinal_position=pgd.objsubid AND c.table_name=st.relname AND st.schemaname = c.table_schema) AS "Comment" ' + 'FROM information_schema.columns c ' + 'LEFT JOIN (SELECT tc.table_schema, tc.table_name, ' + 'cu.column_name, tc.constraint_type ' + 'FROM information_schema.TABLE_CONSTRAINTS tc ' + 'JOIN information_schema.KEY_COLUMN_USAGE cu ' + 'ON tc.table_schema=cu.table_schema and tc.table_name=cu.table_name ' + 'and tc.constraint_name=cu.constraint_name ' + "and tc.constraint_type='PRIMARY KEY') pk " + 'ON pk.table_schema=c.table_schema ' + 'AND pk.table_name=c.table_name ' + 'AND pk.column_name=c.column_name ' + `WHERE c.table_name = ${this.escape(tableName)} AND c.table_schema = ${this.escape(schema)}`;
175
+ };
176
+
177
+ queryGenerator.describeTableQuery = describeTableQuery.bind(queryGenerator);
178
+ }
179
+
180
+ function patchSequelizeQueryInterface(db) {
181
+ if (db.inDialect('postgres')) {
182
+ //@ts-ignore
183
+ const queryGenerator = db.sequelize.dialect.queryGenerator;
184
+ patchShowConstraintsQuery(queryGenerator, db);
185
+ patchDescribeTableQuery(queryGenerator);
186
+ }
187
+ }
188
+
189
+ function percent2float(value) {
190
+ if (!value.endsWith('%')) {
191
+ return NaN;
192
+ }
193
+
194
+ let val = value.substring(0, value.length - 1);
195
+
196
+ if (isNaN(+val)) {
197
+ return NaN;
198
+ }
199
+
200
+ const index = value.indexOf('.');
201
+
202
+ if (index === -1) {
203
+ return parseFloat(value) / 100;
204
+ }
205
+
206
+ const repeat = value.length - index - 2;
207
+ const v = parseInt('1' + '0'.repeat(repeat));
208
+ return parseFloat(value) * v / (100 * v);
131
209
  }
@@ -0,0 +1,8 @@
1
+ import { BaseValueParser } from './base-value-parser';
2
+ export declare class ArrayValueParser extends BaseValueParser {
3
+ setValue(value: any): Promise<void>;
4
+ getOptions(): {
5
+ map: Map<any, any>;
6
+ set: Set<unknown>;
7
+ };
8
+ }
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ArrayValueParser = void 0;
7
+
8
+ var _baseValueParser = require("./base-value-parser");
9
+
10
+ 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; } } }; }
11
+
12
+ 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); }
13
+
14
+ 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; }
15
+
16
+ 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); } }
17
+
18
+ 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); }); }; }
19
+
20
+ class ArrayValueParser extends _baseValueParser.BaseValueParser {
21
+ setValue(value) {
22
+ var _this = this;
23
+
24
+ return _asyncToGenerator(function* () {
25
+ const _this$getOptions = _this.getOptions(),
26
+ map = _this$getOptions.map,
27
+ set = _this$getOptions.set;
28
+
29
+ const values = _this.toArr(value);
30
+
31
+ if (set.size > 0) {
32
+ const filtered = values.map(v => map.has(v) ? map.get(v) : v).filter(v => set.has(v));
33
+
34
+ if (values.length === filtered.length) {
35
+ _this.value = filtered;
36
+ } else {
37
+ _this.errors.push(`No matching option found - ${JSON.stringify(value)}`);
38
+ }
39
+ } else {
40
+ _this.value = values;
41
+ }
42
+ })();
43
+ }
44
+
45
+ getOptions() {
46
+ var _this$field$options, _this$field$options$u;
47
+
48
+ const options = ((_this$field$options = this.field.options) === null || _this$field$options === void 0 ? void 0 : (_this$field$options$u = _this$field$options['uiSchema']) === null || _this$field$options$u === void 0 ? void 0 : _this$field$options$u.enum) || [];
49
+ const map = new Map();
50
+ const set = new Set();
51
+
52
+ var _iterator = _createForOfIteratorHelper(options),
53
+ _step;
54
+
55
+ try {
56
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
57
+ const option = _step.value;
58
+ set.add(option.value);
59
+ set.add(option.label);
60
+ map.set(option.label, option.value);
61
+ }
62
+ } catch (err) {
63
+ _iterator.e(err);
64
+ } finally {
65
+ _iterator.f();
66
+ }
67
+
68
+ return {
69
+ map,
70
+ set
71
+ };
72
+ }
73
+
74
+ }
75
+
76
+ exports.ArrayValueParser = ArrayValueParser;
@@ -0,0 +1,12 @@
1
+ export declare class BaseValueParser {
2
+ ctx: any;
3
+ field: any;
4
+ value: any;
5
+ errors: string[];
6
+ constructor(field: any, ctx: any);
7
+ trim(value: any): any;
8
+ toArr(value: any, splitter?: string): any[];
9
+ toString(): any;
10
+ getValue(): any;
11
+ setValue(value: any): Promise<void>;
12
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.BaseValueParser = void 0;
7
+
8
+ 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); } }
9
+
10
+ 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); }); }; }
11
+
12
+ class BaseValueParser {
13
+ constructor(field, ctx) {
14
+ this.ctx = void 0;
15
+ this.field = void 0;
16
+ this.value = void 0;
17
+ this.errors = [];
18
+ this.field = field;
19
+ this.ctx = ctx;
20
+ this.value = null;
21
+ }
22
+
23
+ trim(value) {
24
+ return typeof value === 'string' ? value.trim() : value;
25
+ }
26
+
27
+ toArr(value, splitter) {
28
+ let values = [];
29
+
30
+ if (!value) {
31
+ values = [];
32
+ } else if (typeof value === 'string') {
33
+ values = value.split(splitter || /,|,|、/);
34
+ } else if (Array.isArray(value)) {
35
+ values = value;
36
+ }
37
+
38
+ return values.map(v => this.trim(v)).filter(Boolean);
39
+ }
40
+
41
+ toString() {
42
+ return this.value;
43
+ }
44
+
45
+ getValue() {
46
+ return this.value;
47
+ }
48
+
49
+ setValue(value) {
50
+ var _this = this;
51
+
52
+ return _asyncToGenerator(function* () {
53
+ _this.value = value;
54
+ })();
55
+ }
56
+
57
+ }
58
+
59
+ exports.BaseValueParser = BaseValueParser;
@@ -0,0 +1,4 @@
1
+ import { BaseValueParser } from './base-value-parser';
2
+ export declare class BooleanValueParser extends BaseValueParser {
3
+ setValue(value: any): Promise<void>;
4
+ }