@nocobase/database 0.9.1-alpha.1 → 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 (38) hide show
  1. package/lib/collection.d.ts +2 -1
  2. package/lib/collection.js +20 -4
  3. package/lib/database.d.ts +6 -0
  4. package/lib/database.js +14 -4
  5. package/lib/fields/belongs-to-many-field.js +8 -2
  6. package/lib/fields/field.js +2 -2
  7. package/lib/filter-parser.js +1 -1
  8. package/lib/query-interface/mysql-query-interface.d.ts +7 -0
  9. package/lib/query-interface/mysql-query-interface.js +39 -0
  10. package/lib/query-interface/postgres-query-interface.d.ts +6 -0
  11. package/lib/query-interface/postgres-query-interface.js +41 -0
  12. package/lib/query-interface/query-interface-builder.d.ts +2 -0
  13. package/lib/query-interface/query-interface-builder.js +23 -0
  14. package/lib/query-interface/query-interface.d.ts +9 -0
  15. package/lib/query-interface/query-interface.js +18 -0
  16. package/lib/query-interface/sqlite-query-interface.d.ts +6 -0
  17. package/lib/query-interface/sqlite-query-interface.js +38 -0
  18. package/lib/relation-repository/multiple-relation-repository.js +2 -0
  19. package/lib/relation-repository/single-relation-repository.js +1 -0
  20. package/lib/sync-runner.d.ts +1 -1
  21. package/lib/sync-runner.js +16 -19
  22. package/lib/utils.js +13 -3
  23. package/package.json +4 -3
  24. package/src/__tests__/filter.test.ts +60 -0
  25. package/src/collection.ts +20 -4
  26. package/src/database.ts +19 -5
  27. package/src/fields/belongs-to-many-field.ts +8 -2
  28. package/src/fields/field.ts +5 -3
  29. package/src/filter-parser.ts +1 -1
  30. package/src/query-interface/mysql-query-interface.ts +20 -0
  31. package/src/query-interface/postgres-query-interface.ts +22 -0
  32. package/src/query-interface/query-interface-builder.ts +14 -0
  33. package/src/query-interface/query-interface.ts +12 -0
  34. package/src/query-interface/sqlite-query-interface.ts +18 -0
  35. package/src/relation-repository/multiple-relation-repository.ts +4 -0
  36. package/src/relation-repository/single-relation-repository.ts +2 -0
  37. package/src/sync-runner.ts +19 -22
  38. package/src/utils.ts +4 -3
@@ -65,7 +65,7 @@ export declare class Collection<TModelAttributes extends {} = any, TCreationAttr
65
65
  resetFields(): void;
66
66
  remove(): void;
67
67
  removeFromDb(options?: QueryInterfaceDropTableOptions): Promise<void>;
68
- existsInDb(options?: Transactionable): Promise<boolean>;
68
+ existsInDb(options?: Transactionable): any;
69
69
  removeField(name: string): void | Field;
70
70
  /**
71
71
  * TODO
@@ -91,4 +91,5 @@ export declare class Collection<TModelAttributes extends {} = any, TCreationAttr
91
91
  isParent(): boolean;
92
92
  addSchemaTableName(): any;
93
93
  quotedTableName(): any;
94
+ collectionSchema(): string;
94
95
  }
package/lib/collection.js CHANGED
@@ -396,7 +396,7 @@ class Collection extends _events().EventEmitter {
396
396
  })) {
397
397
  const queryInterface = _this.db.sequelize.getQueryInterface();
398
398
 
399
- yield queryInterface.dropTable(_this.model.tableName, options);
399
+ yield queryInterface.dropTable(_this.addSchemaTableName(), options);
400
400
  }
401
401
 
402
402
  _this.remove();
@@ -407,7 +407,7 @@ class Collection extends _events().EventEmitter {
407
407
  var _this2 = this;
408
408
 
409
409
  return _asyncToGenerator(function* () {
410
- return _this2.db.collectionExistsInDb(_this2.name, options);
410
+ return _this2.db.queryInterface.collectionTableExists(_this2, options);
411
411
  })();
412
412
  }
413
413
 
@@ -659,8 +659,8 @@ class Collection extends _events().EventEmitter {
659
659
  addSchemaTableName() {
660
660
  const tableName = this.model.tableName;
661
661
 
662
- if (this.options.schema) {
663
- return this.db.utils.addSchema(tableName, this.options.schema);
662
+ if (this.collectionSchema()) {
663
+ return this.db.utils.addSchema(tableName, this.collectionSchema());
664
664
  }
665
665
 
666
666
  return tableName;
@@ -670,6 +670,22 @@ class Collection extends _events().EventEmitter {
670
670
  return this.db.utils.quoteTable(this.addSchemaTableName());
671
671
  }
672
672
 
673
+ collectionSchema() {
674
+ if (this.options.schema) {
675
+ return this.options.schema;
676
+ }
677
+
678
+ if (this.db.options.schema) {
679
+ return this.db.options.schema;
680
+ }
681
+
682
+ if (this.db.inDialect('postgres')) {
683
+ return 'public';
684
+ }
685
+
686
+ return undefined;
687
+ }
688
+
673
689
  }
674
690
 
675
691
  exports.Collection = Collection;
package/lib/database.d.ts CHANGED
@@ -19,6 +19,8 @@ import { Repository } from './repository';
19
19
  import { AfterDefineCollectionListener, BeforeDefineCollectionListener, CreateListener, CreateWithAssociationsListener, DatabaseAfterDefineCollectionEventType, DatabaseAfterRemoveCollectionEventType, DatabaseBeforeDefineCollectionEventType, DatabaseBeforeRemoveCollectionEventType, DestroyListener, EventType, ModelCreateEventTypes, ModelCreateWithAssociationsEventTypes, ModelDestroyEventTypes, ModelSaveEventTypes, ModelSaveWithAssociationsEventTypes, ModelUpdateEventTypes, ModelUpdateWithAssociationsEventTypes, ModelValidateEventTypes, RemoveCollectionListener, SaveListener, SaveWithAssociationsListener, SyncListener, UpdateListener, UpdateWithAssociationsListener, ValidateListener } from './types';
20
20
  import DatabaseUtils from './database-utils';
21
21
  import { BaseValueParser } from './value-parsers';
22
+ import QueryInterface from './query-interface/query-interface';
23
+ import { Logger } from '@nocobase/logger';
22
24
  export interface MergeOptions extends merge.Options {
23
25
  }
24
26
  export interface PendingOptions {
@@ -84,6 +86,7 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
84
86
  pendingFields: Map<string, FieldTypes.RelationField[]>;
85
87
  modelCollection: Map<ModelStatic<any>, Collection<any, any>>;
86
88
  tableNameCollectionMap: Map<string, Collection<any, any>>;
89
+ queryInterface: QueryInterface;
87
90
  utils: DatabaseUtils;
88
91
  referenceMap: ReferencesMap;
89
92
  inheritanceMap: InheritanceMap;
@@ -94,11 +97,14 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
94
97
  collectionOptions: CollectionOptions;
95
98
  mergeOptions?: any;
96
99
  }[]>;
100
+ logger: Logger;
97
101
  constructor(options: DatabaseOptions);
102
+ setLogger(logger: Logger): void;
98
103
  initListener(): void;
99
104
  addMigration(item: MigrationItem): void;
100
105
  addMigrations(options: AddMigrationsOptions): void;
101
106
  inDialect(...dialect: string[]): boolean;
107
+ escapeId(identifier: string): string;
102
108
  /**
103
109
  * Add collection to database
104
110
  * @param options
package/lib/database.js CHANGED
@@ -112,6 +112,8 @@ var _databaseUtils = _interopRequireDefault(require("./database-utils"));
112
112
 
113
113
  var _valueParsers = require("./value-parsers");
114
114
 
115
+ var _queryInterfaceBuilder = _interopRequireDefault(require("./query-interface/query-interface-builder"));
116
+
115
117
  const _excluded = ["drop"],
116
118
  _excluded2 = ["retry"];
117
119
 
@@ -231,6 +233,7 @@ class Database extends _events().EventEmitter {
231
233
  this.pendingFields = new Map();
232
234
  this.modelCollection = new Map();
233
235
  this.tableNameCollectionMap = new Map();
236
+ this.queryInterface = void 0;
234
237
  this.utils = new _databaseUtils.default(this);
235
238
  this.referenceMap = new _ReferencesMap.default();
236
239
  this.inheritanceMap = new _inheritedMap.default();
@@ -238,6 +241,7 @@ class Database extends _events().EventEmitter {
238
241
  this.modelHook = void 0;
239
242
  this.version = void 0;
240
243
  this.delayCollectionExtend = new Map();
244
+ this.logger = void 0;
241
245
  this.version = new DatabaseVersion(this);
242
246
 
243
247
  const opts = _objectSpread({
@@ -268,6 +272,7 @@ class Database extends _events().EventEmitter {
268
272
 
269
273
  this.options = opts;
270
274
  this.sequelize = new (_sequelize().Sequelize)(opts);
275
+ this.queryInterface = (0, _queryInterfaceBuilder.default)(this);
271
276
  this.collections = new Map();
272
277
  this.modelHook = new _modelHook.ModelHook(this);
273
278
  this.on('afterDefineCollection', collection => {
@@ -337,6 +342,10 @@ class Database extends _events().EventEmitter {
337
342
  (0, _utils2.patchSequelizeQueryInterface)(this);
338
343
  }
339
344
 
345
+ setLogger(logger) {
346
+ this.logger = logger;
347
+ }
348
+
340
349
  initListener() {
341
350
  var _this2 = this;
342
351
 
@@ -464,6 +473,10 @@ class Database extends _events().EventEmitter {
464
473
  inDialect(...dialect) {
465
474
  return dialect.includes(this.sequelize.getDialect());
466
475
  }
476
+
477
+ escapeId(identifier) {
478
+ return this.inDialect('mysql') ? `\`${identifier}\`` : `"${identifier}"`;
479
+ }
467
480
  /**
468
481
  * Add collection to database
469
482
  * @param options
@@ -773,10 +786,7 @@ class Database extends _events().EventEmitter {
773
786
  return false;
774
787
  }
775
788
 
776
- const tables = yield _this5.sequelize.getQueryInterface().showAllTables({
777
- transaction: options === null || options === void 0 ? void 0 : options.transaction
778
- });
779
- return tables.includes(_this5.getCollection(name).model.tableName);
789
+ return yield _this5.queryInterface.collectionTableExists(collection, options);
780
790
  })();
781
791
  }
782
792
 
@@ -73,9 +73,15 @@ class BelongsToManyField extends _relationField.RelationField {
73
73
  if (database.hasCollection(through)) {
74
74
  Through = database.getCollection(through);
75
75
  } else {
76
- Through = database.collection({
76
+ const throughCollectionOptions = {
77
77
  name: through
78
- });
78
+ };
79
+
80
+ if (this.collection.collectionSchema()) {
81
+ throughCollectionOptions['schema'] = this.collection.collectionSchema();
82
+ }
83
+
84
+ Through = database.collection(throughCollectionOptions);
79
85
  Object.defineProperty(Through.model, 'isThrough', {
80
86
  value: true
81
87
  });
@@ -184,7 +184,7 @@ class Field {
184
184
  })) && columnReferencesCount == 1) {
185
185
  const queryInterface = _this2.database.sequelize.getQueryInterface();
186
186
 
187
- yield queryInterface.removeColumn(_this2.collection.model.tableName, _this2.columnName(), options);
187
+ yield queryInterface.removeColumn(_this2.collection.addSchemaTableName(), _this2.columnName(), options);
188
188
  }
189
189
 
190
190
  _this2.remove();
@@ -212,7 +212,7 @@ class Field {
212
212
  sql = `
213
213
  select column_name
214
214
  from INFORMATION_SCHEMA.COLUMNS
215
- where TABLE_NAME='${_this3.collection.model.tableName}' AND column_name='${_this3.columnName()}'
215
+ where TABLE_NAME='${_this3.collection.model.tableName}' AND column_name='${_this3.columnName()}' AND table_schema='${_this3.collection.collectionSchema() || 'public'}'
216
216
  `;
217
217
  }
218
218
 
@@ -215,7 +215,7 @@ class FilterParser {
215
215
  origins.push(attr); // if it is target model attribute
216
216
 
217
217
  if (target.rawAttributes[attr]) {
218
- associationKeys.push(attr);
218
+ associationKeys.push(target.rawAttributes[attr].field || attr);
219
219
  target = null;
220
220
  } else if (target.associations[attr]) {
221
221
  // if it is target model association (nested association filter)
@@ -0,0 +1,7 @@
1
+ import QueryInterface from './query-interface';
2
+ import { Collection } from '../collection';
3
+ import { Transactionable } from 'sequelize';
4
+ export default class MysqlQueryInterface extends QueryInterface {
5
+ constructor(db: any);
6
+ collectionTableExists(collection: Collection, options?: Transactionable): Promise<boolean>;
7
+ }
@@ -0,0 +1,39 @@
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 MysqlQueryInterface 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 databaseName = _this.db.options.database;
28
+ const sql = `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${databaseName}' AND TABLE_NAME = '${tableName}'`;
29
+ const results = yield _this.db.sequelize.query(sql, {
30
+ type: 'SELECT',
31
+ transaction
32
+ });
33
+ return results.length > 0;
34
+ })();
35
+ }
36
+
37
+ }
38
+
39
+ exports.default = MysqlQueryInterface;
@@ -0,0 +1,6 @@
1
+ import QueryInterface from './query-interface';
2
+ import { Collection } from '../collection';
3
+ export default class PostgresQueryInterface extends QueryInterface {
4
+ constructor(db: any);
5
+ collectionTableExists(collection: Collection, options?: any): Promise<any>;
6
+ }
@@ -0,0 +1,41 @@
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 PostgresQueryInterface 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 schema = collection.collectionSchema() || 'public';
28
+ const sql = `SELECT EXISTS(SELECT 1 FROM information_schema.tables
29
+ WHERE table_schema = '${schema}'
30
+ AND table_name = '${tableName}')`;
31
+ const results = yield _this.db.sequelize.query(sql, {
32
+ type: 'SELECT',
33
+ transaction
34
+ });
35
+ return results[0]['exists'];
36
+ })();
37
+ }
38
+
39
+ }
40
+
41
+ exports.default = PostgresQueryInterface;
@@ -0,0 +1,2 @@
1
+ import Database from '../database';
2
+ export default function buildQueryInterface(db: Database): any;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = buildQueryInterface;
7
+
8
+ var _mysqlQueryInterface = _interopRequireDefault(require("./mysql-query-interface"));
9
+
10
+ var _postgresQueryInterface = _interopRequireDefault(require("./postgres-query-interface"));
11
+
12
+ var _sqliteQueryInterface = _interopRequireDefault(require("./sqlite-query-interface"));
13
+
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+
16
+ function buildQueryInterface(db) {
17
+ const map = {
18
+ mysql: _mysqlQueryInterface.default,
19
+ postgres: _postgresQueryInterface.default,
20
+ sqlite: _sqliteQueryInterface.default
21
+ };
22
+ return new map[db.options.dialect](db);
23
+ }
@@ -0,0 +1,9 @@
1
+ import Database from '../database';
2
+ import { Collection } from '../collection';
3
+ import { QueryInterface as SequelizeQueryInterface, Transactionable } from 'sequelize';
4
+ export default abstract class QueryInterface {
5
+ db: Database;
6
+ sequelizeQueryInterface: SequelizeQueryInterface;
7
+ protected constructor(db: Database);
8
+ abstract collectionTableExists(collection: Collection, options?: Transactionable): Promise<boolean>;
9
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ class QueryInterface {
9
+ constructor(db) {
10
+ this.db = void 0;
11
+ this.sequelizeQueryInterface = void 0;
12
+ this.db = db;
13
+ this.sequelizeQueryInterface = db.sequelize.getQueryInterface();
14
+ }
15
+
16
+ }
17
+
18
+ exports.default = QueryInterface;
@@ -0,0 +1,6 @@
1
+ import QueryInterface from './query-interface';
2
+ import { Collection } from '../collection';
3
+ export default class SqliteQueryInterface extends QueryInterface {
4
+ constructor(db: any);
5
+ collectionTableExists(collection: Collection, options?: any): Promise<boolean>;
6
+ }
@@ -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;
@@ -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), {}, {
@@ -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, db: any): Promise<any>;
3
+ static createTable(tableName: any, attributes: any, options: any, model: any, parents: any): Promise<any>;
4
4
  }
@@ -41,7 +41,6 @@ class SyncRunner {
41
41
  const transaction = options.transaction;
42
42
  const inheritedCollection = model.collection;
43
43
  const db = inheritedCollection.context.database;
44
- const schemaName = db.options.schema || 'public';
45
44
  const dialect = db.sequelize.getDialect();
46
45
  const queryInterface = db.sequelize.getQueryInterface();
47
46
 
@@ -55,10 +54,7 @@ class SyncRunner {
55
54
  throw new Error(`Inherit model ${inheritedCollection.name} can't be created without parents, parents option is ${_lodash().default.castArray(inheritedCollection.options.inherits).join(', ')}`);
56
55
  }
57
56
 
58
- const parentTables = parents.map(parent => parent.model.tableName);
59
- const tableName = model.tableName;
60
- const schemaTableName = db.utils.addSchema(tableName);
61
- const quoteTableName = db.utils.quoteTable(tableName);
57
+ const tableName = inheritedCollection.addSchemaTableName();
62
58
  const attributes = model.tableAttributes;
63
59
 
64
60
  const childAttributes = _lodash().default.pickBy(attributes, value => {
@@ -66,10 +62,10 @@ class SyncRunner {
66
62
  });
67
63
 
68
64
  let maxSequenceVal = 0;
69
- let maxSequenceName;
65
+ let maxSequenceName; // find max sequence
70
66
 
71
67
  if (childAttributes.id && childAttributes.id.autoIncrement) {
72
- var _iterator = _createForOfIteratorHelper(parentTables),
68
+ var _iterator = _createForOfIteratorHelper(parents),
73
69
  _step;
74
70
 
75
71
  try {
@@ -77,8 +73,8 @@ class SyncRunner {
77
73
  const parent = _step.value;
78
74
  const sequenceNameResult = yield queryInterface.sequelize.query(`SELECT column_default
79
75
  FROM information_schema.columns
80
- WHERE table_name = '${parent}'
81
- and table_schema = '${schemaName}'
76
+ WHERE table_name = '${parent.model.tableName}'
77
+ and table_schema = '${parent.collectionSchema()}'
82
78
  and "column_name" = 'id';`, {
83
79
  transaction
84
80
  });
@@ -114,17 +110,18 @@ class SyncRunner {
114
110
  }
115
111
  }
116
112
 
117
- yield _this.createTable(schemaTableName, childAttributes, options, model, parentTables, db);
113
+ yield _this.createTable(tableName, childAttributes, options, model, parents); // if we have max sequence, set it to child table
118
114
 
119
115
  if (maxSequenceName) {
120
- const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map(parent => db.getCollection(parent).model.tableName);
121
- const sequenceTables = [...parentsDeep, tableName.toString()];
116
+ const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map(parent => db.getCollection(parent).addSchemaTableName());
117
+ const sequenceTables = [...parentsDeep, tableName];
122
118
 
123
119
  for (var _i = 0, _sequenceTables = sequenceTables; _i < _sequenceTables.length; _i++) {
124
120
  const sequenceTable = _sequenceTables[_i];
125
- const queryName = Boolean(sequenceTable.match(/[A-Z]/)) && !sequenceTable.includes(`"`) ? `"${sequenceTable}"` : sequenceTable;
126
- const idColumnQuery = yield queryInterface.sequelize.query(`
127
- SELECT column_name
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
128
125
  FROM information_schema.columns
129
126
  WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schemaName}';
130
127
  `, {
@@ -135,7 +132,7 @@ WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schem
135
132
  continue;
136
133
  }
137
134
 
138
- yield queryInterface.sequelize.query(`alter table "${schemaName}"."${sequenceTable}"
135
+ yield queryInterface.sequelize.query(`alter table ${db.utils.quoteTable(sequenceTable)}
139
136
  alter column id set default nextval('${maxSequenceName}')`, {
140
137
  transaction
141
138
  });
@@ -156,7 +153,7 @@ WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schem
156
153
  })();
157
154
  }
158
155
 
159
- static createTable(tableName, attributes, options, model, parentTables, db) {
156
+ static createTable(tableName, attributes, options, model, parents) {
160
157
  return _asyncToGenerator(function* () {
161
158
  let sql = '';
162
159
  options = _objectSpread({}, options);
@@ -179,8 +176,8 @@ WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schem
179
176
  table: tableName,
180
177
  context: 'createTable'
181
178
  });
182
- sql = `${queryGenerator.createTableQuery(tableName, attributes, options)}`.replace(';', ` INHERITS (${parentTables.map(t => {
183
- return db.utils.quoteTable(db.utils.addSchema(t, db.options.schema));
179
+ sql = `${queryGenerator.createTableQuery(tableName, attributes, options)}`.replace(';', ` INHERITS (${parents.map(t => {
180
+ return t.addSchemaTableName();
184
181
  }).join(', ')});`);
185
182
  return yield model.sequelize.query(sql, options);
186
183
  })();
package/lib/utils.js CHANGED
@@ -23,6 +23,16 @@ function _crypto() {
23
23
 
24
24
  var _identifierError = require("./errors/identifier-error");
25
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
+
26
36
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27
37
 
28
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; }
@@ -144,14 +154,14 @@ function snakeCase(name) {
144
154
 
145
155
  function patchShowConstraintsQuery(queryGenerator, db) {
146
156
  queryGenerator.showConstraintsQuery = (tableName, constraintName) => {
147
- 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='${tableName}'`];
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}'`];
148
158
 
149
159
  if (!constraintName) {
150
160
  lines.push(`AND constraint_name='${constraintName}'`);
151
161
  }
152
162
 
153
- if (db.options.schema && db.options.schema !== 'public') {
154
- lines.push(`AND table_schema='${db.options.schema}'`);
163
+ if (_lodash().default.isPlainObject(tableName) && tableName.schema) {
164
+ lines.push(`AND table_schema='${tableName.schema}'`);
155
165
  }
156
166
 
157
167
  return lines.join(' ');
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@nocobase/database",
3
- "version": "0.9.1-alpha.1",
3
+ "version": "0.9.1-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
8
  "dependencies": {
9
- "@nocobase/utils": "0.9.1-alpha.1",
9
+ "@nocobase/logger": "0.9.1-alpha.2",
10
+ "@nocobase/utils": "0.9.1-alpha.2",
10
11
  "async-mutex": "^0.3.2",
11
12
  "cron-parser": "4.4.0",
12
13
  "deepmerge": "^4.2.2",
@@ -27,5 +28,5 @@
27
28
  "url": "git+https://github.com/nocobase/nocobase.git",
28
29
  "directory": "packages/database"
29
30
  },
30
- "gitHead": "56cb184b00dc383b853015d525bf6e79dea92169"
31
+ "gitHead": "d588a68eca4feed4642a4cb317301011266fe5c9"
31
32
  }
@@ -0,0 +1,60 @@
1
+ import Database from '../database';
2
+ import { mockDatabase } from '../mock-database';
3
+
4
+ describe('filter', () => {
5
+ let db: Database;
6
+
7
+ beforeEach(async () => {
8
+ db = mockDatabase();
9
+
10
+ await db.clean({ drop: true });
11
+ });
12
+
13
+ afterEach(async () => {
14
+ await db.close();
15
+ });
16
+
17
+ it('should filter by association field', async () => {
18
+ const UserCollection = db.collection({
19
+ name: 'users',
20
+ fields: [
21
+ { type: 'string', name: 'name' },
22
+ { type: 'hasMany', name: 'posts' },
23
+ ],
24
+ });
25
+
26
+ const PostCollection = db.collection({
27
+ name: 'posts',
28
+ fields: [
29
+ { type: 'string', name: 'title' },
30
+ { type: 'belongsTo', name: 'user' },
31
+ ],
32
+ });
33
+
34
+ await db.sync();
35
+
36
+ const user = await UserCollection.repository.create({
37
+ values: {
38
+ name: 'John',
39
+ posts: [
40
+ {
41
+ title: 'p1',
42
+ },
43
+ {
44
+ title: 'p2',
45
+ },
46
+ ],
47
+ },
48
+ });
49
+
50
+ const response = await UserCollection.repository.find({
51
+ filter: {
52
+ 'posts.createdAt': {
53
+ $dateOn: user.get('createdAt'),
54
+ },
55
+ },
56
+ });
57
+
58
+ expect(response).toHaveLength(1);
59
+ });
60
+ });
package/src/collection.ts CHANGED
@@ -308,13 +308,13 @@ export class Collection<
308
308
  })
309
309
  ) {
310
310
  const queryInterface = this.db.sequelize.getQueryInterface();
311
- await queryInterface.dropTable(this.model.tableName, options);
311
+ await queryInterface.dropTable(this.addSchemaTableName(), options);
312
312
  }
313
313
  this.remove();
314
314
  }
315
315
 
316
316
  async existsInDb(options?: Transactionable) {
317
- return this.db.collectionExistsInDb(this.name, options);
317
+ return this.db.queryInterface.collectionTableExists(this, options);
318
318
  }
319
319
 
320
320
  removeField(name: string): void | Field {
@@ -542,8 +542,8 @@ export class Collection<
542
542
  public addSchemaTableName() {
543
543
  const tableName = this.model.tableName;
544
544
 
545
- if (this.options.schema) {
546
- return this.db.utils.addSchema(tableName, this.options.schema);
545
+ if (this.collectionSchema()) {
546
+ return this.db.utils.addSchema(tableName, this.collectionSchema());
547
547
  }
548
548
 
549
549
  return tableName;
@@ -552,4 +552,20 @@ export class Collection<
552
552
  public quotedTableName() {
553
553
  return this.db.utils.quoteTable(this.addSchemaTableName());
554
554
  }
555
+
556
+ public collectionSchema() {
557
+ if (this.options.schema) {
558
+ return this.options.schema;
559
+ }
560
+
561
+ if (this.db.options.schema) {
562
+ return this.db.options.schema;
563
+ }
564
+
565
+ if (this.db.inDialect('postgres')) {
566
+ return 'public';
567
+ }
568
+
569
+ return undefined;
570
+ }
555
571
  }
package/src/database.ts CHANGED
@@ -64,6 +64,9 @@ import { patchSequelizeQueryInterface, snakeCase } from './utils';
64
64
 
65
65
  import DatabaseUtils from './database-utils';
66
66
  import { BaseValueParser, registerFieldValueParsers } from './value-parsers';
67
+ import buildQueryInterface from './query-interface/query-interface-builder';
68
+ import QueryInterface from './query-interface/query-interface';
69
+ import { Logger } from '@nocobase/logger';
67
70
 
68
71
  export interface MergeOptions extends merge.Options {}
69
72
 
@@ -166,6 +169,8 @@ export class Database extends EventEmitter implements AsyncEmitter {
166
169
  modelCollection = new Map<ModelStatic<any>, Collection>();
167
170
  tableNameCollectionMap = new Map<string, Collection>();
168
171
 
172
+ queryInterface: QueryInterface;
173
+
169
174
  utils = new DatabaseUtils(this);
170
175
  referenceMap = new ReferencesMap();
171
176
  inheritanceMap = new InheritanceMap();
@@ -177,6 +182,8 @@ export class Database extends EventEmitter implements AsyncEmitter {
177
182
 
178
183
  delayCollectionExtend = new Map<string, { collectionOptions: CollectionOptions; mergeOptions?: any }[]>();
179
184
 
185
+ logger: Logger;
186
+
180
187
  constructor(options: DatabaseOptions) {
181
188
  super();
182
189
 
@@ -212,6 +219,8 @@ export class Database extends EventEmitter implements AsyncEmitter {
212
219
 
213
220
  this.sequelize = new Sequelize(opts);
214
221
 
222
+ this.queryInterface = buildQueryInterface(this);
223
+
215
224
  this.collections = new Map();
216
225
  this.modelHook = new ModelHook(this);
217
226
 
@@ -280,6 +289,10 @@ export class Database extends EventEmitter implements AsyncEmitter {
280
289
  patchSequelizeQueryInterface(this);
281
290
  }
282
291
 
292
+ setLogger(logger: Logger) {
293
+ this.logger = logger;
294
+ }
295
+
283
296
  initListener() {
284
297
  this.on('beforeDefine', (model, options) => {
285
298
  if (this.options.underscored) {
@@ -374,6 +387,10 @@ export class Database extends EventEmitter implements AsyncEmitter {
374
387
  return dialect.includes(this.sequelize.getDialect());
375
388
  }
376
389
 
390
+ escapeId(identifier: string) {
391
+ return this.inDialect('mysql') ? `\`${identifier}\`` : `"${identifier}"`;
392
+ }
393
+
377
394
  /**
378
395
  * Add collection to database
379
396
  * @param options
@@ -627,15 +644,12 @@ export class Database extends EventEmitter implements AsyncEmitter {
627
644
 
628
645
  async collectionExistsInDb(name: string, options?: Transactionable) {
629
646
  const collection = this.getCollection(name);
647
+
630
648
  if (!collection) {
631
649
  return false;
632
650
  }
633
651
 
634
- const tables = await this.sequelize.getQueryInterface().showAllTables({
635
- transaction: options?.transaction,
636
- });
637
-
638
- return tables.includes(this.getCollection(name).model.tableName);
652
+ return await this.queryInterface.collectionTableExists(collection, options);
639
653
  }
640
654
 
641
655
  public isSqliteMemory() {
@@ -55,9 +55,15 @@ export class BelongsToManyField extends RelationField {
55
55
  if (database.hasCollection(through)) {
56
56
  Through = database.getCollection(through);
57
57
  } else {
58
- Through = database.collection({
58
+ const throughCollectionOptions = {
59
59
  name: through,
60
- });
60
+ };
61
+
62
+ if (this.collection.collectionSchema()) {
63
+ throughCollectionOptions['schema'] = this.collection.collectionSchema();
64
+ }
65
+
66
+ Through = database.collection(throughCollectionOptions);
61
67
 
62
68
  Object.defineProperty(Through.model, 'isThrough', { value: true });
63
69
  }
@@ -6,7 +6,7 @@ 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';
@@ -169,7 +169,7 @@ export abstract class Field {
169
169
  columnReferencesCount == 1
170
170
  ) {
171
171
  const queryInterface = this.database.sequelize.getQueryInterface();
172
- await queryInterface.removeColumn(this.collection.model.tableName, this.columnName(), options);
172
+ await queryInterface.removeColumn(this.collection.addSchemaTableName(), this.columnName(), options);
173
173
  }
174
174
 
175
175
  this.remove();
@@ -194,7 +194,9 @@ export abstract class Field {
194
194
  sql = `
195
195
  select column_name
196
196
  from INFORMATION_SCHEMA.COLUMNS
197
- where TABLE_NAME='${this.collection.model.tableName}' AND column_name='${this.columnName()}'
197
+ where TABLE_NAME='${
198
+ this.collection.model.tableName
199
+ }' AND column_name='${this.columnName()}' AND table_schema='${this.collection.collectionSchema() || 'public'}'
198
200
  `;
199
201
  }
200
202
  const [rows] = await this.database.sequelize.query(sql, opts);
@@ -178,7 +178,7 @@ export default class FilterParser {
178
178
  origins.push(attr);
179
179
  // if it is target model attribute
180
180
  if (target.rawAttributes[attr]) {
181
- associationKeys.push(attr);
181
+ associationKeys.push(target.rawAttributes[attr].field || attr);
182
182
  target = null;
183
183
  } else if (target.associations[attr]) {
184
184
  // if it is target model association (nested association filter)
@@ -0,0 +1,20 @@
1
+ import QueryInterface from './query-interface';
2
+ import { Collection } from '../collection';
3
+ import { Transactionable } from 'sequelize';
4
+
5
+ export default class MysqlQueryInterface extends QueryInterface {
6
+ constructor(db) {
7
+ super(db);
8
+ }
9
+
10
+ async collectionTableExists(collection: Collection, options?: Transactionable) {
11
+ const transaction = options?.transaction;
12
+
13
+ const tableName = collection.model.tableName;
14
+ const databaseName = this.db.options.database;
15
+ const sql = `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${databaseName}' AND TABLE_NAME = '${tableName}'`;
16
+
17
+ const results = await this.db.sequelize.query(sql, { type: 'SELECT', transaction });
18
+ return results.length > 0;
19
+ }
20
+ }
@@ -0,0 +1,22 @@
1
+ import QueryInterface from './query-interface';
2
+ import { Collection } from '../collection';
3
+
4
+ export default class PostgresQueryInterface extends QueryInterface {
5
+ constructor(db) {
6
+ super(db);
7
+ }
8
+
9
+ async collectionTableExists(collection: Collection, options?) {
10
+ const transaction = options?.transaction;
11
+
12
+ const tableName = collection.model.tableName;
13
+ const schema = collection.collectionSchema() || 'public';
14
+
15
+ const sql = `SELECT EXISTS(SELECT 1 FROM information_schema.tables
16
+ WHERE table_schema = '${schema}'
17
+ AND table_name = '${tableName}')`;
18
+
19
+ const results = await this.db.sequelize.query(sql, { type: 'SELECT', transaction });
20
+ return results[0]['exists'];
21
+ }
22
+ }
@@ -0,0 +1,14 @@
1
+ import Database from '../database';
2
+ import MysqlQueryInterface from './mysql-query-interface';
3
+ import PostgresQueryInterface from './postgres-query-interface';
4
+ import SqliteQueryInterface from './sqlite-query-interface';
5
+
6
+ export default function buildQueryInterface(db: Database) {
7
+ const map = {
8
+ mysql: MysqlQueryInterface,
9
+ postgres: PostgresQueryInterface,
10
+ sqlite: SqliteQueryInterface,
11
+ };
12
+
13
+ return new map[db.options.dialect](db);
14
+ }
@@ -0,0 +1,12 @@
1
+ import Database from '../database';
2
+ import { Collection } from '../collection';
3
+ import { QueryInterface as SequelizeQueryInterface, Transactionable } from 'sequelize';
4
+
5
+ export default abstract class QueryInterface {
6
+ sequelizeQueryInterface: SequelizeQueryInterface;
7
+ protected constructor(public db: Database) {
8
+ this.sequelizeQueryInterface = db.sequelize.getQueryInterface();
9
+ }
10
+
11
+ abstract collectionTableExists(collection: Collection, options?: Transactionable): Promise<boolean>;
12
+ }
@@ -0,0 +1,18 @@
1
+ import QueryInterface from './query-interface';
2
+ import { Collection } from '../collection';
3
+
4
+ export default class SqliteQueryInterface extends QueryInterface {
5
+ constructor(db) {
6
+ super(db);
7
+ }
8
+
9
+ async collectionTableExists(collection: Collection, options?) {
10
+ const transaction = options?.transaction;
11
+
12
+ const tableName = collection.model.tableName;
13
+
14
+ const sql = `SELECT name FROM sqlite_master WHERE type='table' AND name='${tableName}';`;
15
+ const results = await this.db.sequelize.query(sql, { type: 'SELECT', transaction });
16
+ return results.length > 0;
17
+ }
18
+ }
@@ -42,6 +42,8 @@ export abstract class MultipleRelationRepository extends RelationRepository {
42
42
  const getAccessor = this.accessors().get;
43
43
  const sourceModel = await this.getSourceModel(transaction);
44
44
 
45
+ if (!sourceModel) return [];
46
+
45
47
  if (findOptions.include && findOptions.include.length > 0) {
46
48
  const ids = (
47
49
  await sourceModel[getAccessor]({
@@ -103,6 +105,8 @@ export abstract class MultipleRelationRepository extends RelationRepository {
103
105
  const transaction = await this.getTransaction(options);
104
106
 
105
107
  const sourceModel = await this.getSourceModel(transaction);
108
+ if (!sourceModel) return 0;
109
+
106
110
  const queryOptions = this.buildQueryOptions(options);
107
111
 
108
112
  const count = await sourceModel[this.accessors().get]({
@@ -54,6 +54,8 @@ export abstract class SingleRelationRepository extends RelationRepository {
54
54
  const getAccessor = this.accessors().get;
55
55
  const sourceModel = await this.getSourceModel(transaction);
56
56
 
57
+ if (!sourceModel) return null;
58
+
57
59
  if (findOptions?.include?.length > 0) {
58
60
  const templateModel = await sourceModel[getAccessor]({
59
61
  ...findOptions,
@@ -7,7 +7,6 @@ export class SyncRunner {
7
7
 
8
8
  const inheritedCollection = model.collection as InheritedCollection;
9
9
  const db = inheritedCollection.context.database;
10
- const schemaName = db.options.schema || 'public';
11
10
 
12
11
  const dialect = db.sequelize.getDialect();
13
12
 
@@ -27,12 +26,7 @@ export class SyncRunner {
27
26
  );
28
27
  }
29
28
 
30
- const parentTables = parents.map((parent) => parent.model.tableName);
31
-
32
- const tableName = model.tableName;
33
-
34
- const schemaTableName = db.utils.addSchema(tableName);
35
- const quoteTableName = db.utils.quoteTable(tableName);
29
+ const tableName = inheritedCollection.addSchemaTableName();
36
30
 
37
31
  const attributes = model.tableAttributes;
38
32
 
@@ -43,13 +37,14 @@ export class SyncRunner {
43
37
  let maxSequenceVal = 0;
44
38
  let maxSequenceName;
45
39
 
40
+ // find max sequence
46
41
  if (childAttributes.id && childAttributes.id.autoIncrement) {
47
- for (const parent of parentTables) {
42
+ for (const parent of parents) {
48
43
  const sequenceNameResult = await queryInterface.sequelize.query(
49
44
  `SELECT column_default
50
45
  FROM information_schema.columns
51
- WHERE table_name = '${parent}'
52
- and table_schema = '${schemaName}'
46
+ WHERE table_name = '${parent.model.tableName}'
47
+ and table_schema = '${parent.collectionSchema()}'
53
48
  and "column_name" = 'id';`,
54
49
  {
55
50
  transaction,
@@ -88,22 +83,24 @@ export class SyncRunner {
88
83
  }
89
84
  }
90
85
 
91
- await this.createTable(schemaTableName, childAttributes, options, model, parentTables, db);
86
+ await this.createTable(tableName, childAttributes, options, model, parents);
92
87
 
88
+ // if we have max sequence, set it to child table
93
89
  if (maxSequenceName) {
94
- const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map(
95
- (parent) => db.getCollection(parent).model.tableName,
90
+ const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map((parent) =>
91
+ db.getCollection(parent).addSchemaTableName(),
96
92
  );
97
93
 
98
- const sequenceTables = [...parentsDeep, tableName.toString()];
94
+ const sequenceTables = [...parentsDeep, tableName];
99
95
 
100
96
  for (const sequenceTable of sequenceTables) {
101
- const queryName =
102
- Boolean(sequenceTable.match(/[A-Z]/)) && !sequenceTable.includes(`"`) ? `"${sequenceTable}"` : sequenceTable;
97
+ const tableName = sequenceTable.tableName;
98
+ const schemaName = sequenceTable.schema;
99
+
100
+ const queryName = Boolean(tableName.match(/[A-Z]/)) && !tableName.includes(`"`) ? `"${tableName}"` : tableName;
103
101
 
104
102
  const idColumnQuery = await queryInterface.sequelize.query(
105
- `
106
- SELECT column_name
103
+ `SELECT column_name
107
104
  FROM information_schema.columns
108
105
  WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schemaName}';
109
106
  `,
@@ -117,7 +114,7 @@ WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schem
117
114
  }
118
115
 
119
116
  await queryInterface.sequelize.query(
120
- `alter table "${schemaName}"."${sequenceTable}"
117
+ `alter table ${db.utils.quoteTable(sequenceTable)}
121
118
  alter column id set default nextval('${maxSequenceName}')`,
122
119
  {
123
120
  transaction,
@@ -139,7 +136,7 @@ WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schem
139
136
  }
140
137
  }
141
138
 
142
- static async createTable(tableName, attributes, options, model, parentTables, db) {
139
+ static async createTable(tableName, attributes, options, model, parents) {
143
140
  let sql = '';
144
141
 
145
142
  options = { ...options };
@@ -164,9 +161,9 @@ WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schem
164
161
 
165
162
  sql = `${queryGenerator.createTableQuery(tableName, attributes, options)}`.replace(
166
163
  ';',
167
- ` INHERITS (${parentTables
164
+ ` INHERITS (${parents
168
165
  .map((t) => {
169
- return db.utils.quoteTable(db.utils.addSchema(t, db.options.schema));
166
+ return t.addSchemaTableName();
170
167
  })
171
168
  .join(', ')});`,
172
169
  );
package/src/utils.ts CHANGED
@@ -2,6 +2,7 @@ import crypto from 'crypto';
2
2
  import Database from './database';
3
3
  import { IdentifierError } from './errors/identifier-error';
4
4
  import { Model } from './model';
5
+ import lodash from 'lodash';
5
6
 
6
7
  type HandleAppendsQueryOptions = {
7
8
  templateModel: any;
@@ -96,15 +97,15 @@ function patchShowConstraintsQuery(queryGenerator, db) {
96
97
  'is_deferrable AS "isDeferrable",',
97
98
  'initially_deferred AS "initiallyDeferred"',
98
99
  'from INFORMATION_SCHEMA.table_constraints',
99
- `WHERE table_name='${tableName}'`,
100
+ `WHERE table_name='${lodash.isPlainObject(tableName) ? tableName.tableName : tableName}'`,
100
101
  ];
101
102
 
102
103
  if (!constraintName) {
103
104
  lines.push(`AND constraint_name='${constraintName}'`);
104
105
  }
105
106
 
106
- if (db.options.schema && db.options.schema !== 'public') {
107
- lines.push(`AND table_schema='${db.options.schema}'`);
107
+ if (lodash.isPlainObject(tableName) && tableName.schema) {
108
+ lines.push(`AND table_schema='${tableName.schema}'`);
108
109
  }
109
110
 
110
111
  return lines.join(' ');