@nocobase/database 0.15.0-alpha.3 → 0.15.0-alpha.5

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.
@@ -1,9 +1,16 @@
1
1
  import { Collection, CollectionOptions } from './collection';
2
2
  import Database from './database';
3
+ import { Model } from './model';
4
+ type CollectionTypeOptions = {
5
+ condition: (options: CollectionOptions) => boolean;
6
+ onSync?: (model: typeof Model, options: any) => Promise<void>;
7
+ };
3
8
  export declare class CollectionFactory {
4
9
  private database;
5
- private collectionTypes;
10
+ collectionTypes: Map<typeof Collection, CollectionTypeOptions>;
6
11
  constructor(database: Database);
7
- registerCollectionType(collectionClass: typeof Collection, condition: (options: CollectionOptions) => boolean): void;
8
- createCollection<T extends Collection>(options: CollectionOptions): T;
12
+ registerCollectionType(collectionClass: typeof Collection, // Using the collection class as the key
13
+ options: CollectionTypeOptions): void;
14
+ createCollection<T extends Collection>(collectionOptions: CollectionOptions): T;
9
15
  }
16
+ export {};
@@ -26,19 +26,20 @@ const _CollectionFactory = class _CollectionFactory {
26
26
  constructor(database) {
27
27
  this.database = database;
28
28
  }
29
- collectionTypes = [];
30
- registerCollectionType(collectionClass, condition) {
31
- this.collectionTypes.push({ ctor: collectionClass, condition });
29
+ // Using a Map with the collection subclass as the key and options as the value
30
+ collectionTypes = /* @__PURE__ */ new Map();
31
+ registerCollectionType(collectionClass, options) {
32
+ this.collectionTypes.set(collectionClass, options);
32
33
  }
33
- createCollection(options) {
34
+ createCollection(collectionOptions) {
34
35
  let klass = import_collection.Collection;
35
- for (const { ctor, condition } of this.collectionTypes) {
36
- if (condition(options)) {
36
+ for (const [ctor, options] of this.collectionTypes) {
37
+ if (options.condition(collectionOptions)) {
37
38
  klass = ctor;
38
39
  break;
39
40
  }
40
41
  }
41
- return new klass(options, {
42
+ return new klass(collectionOptions, {
42
43
  database: this.database
43
44
  });
44
45
  }
package/lib/collection.js CHANGED
@@ -64,10 +64,6 @@ function EnsureAtomicity(target, propertyKey, descriptor) {
64
64
  }
65
65
  const afterRawAttributes = Object.keys(model.rawAttributes);
66
66
  const createdRawAttributes = import_lodash.default.difference(afterRawAttributes, beforeRawAttributes);
67
- console.log({
68
- beforeRawAttributes,
69
- afterRawAttributes
70
- });
71
67
  for (const key of createdRawAttributes) {
72
68
  delete this.model.rawAttributes[key];
73
69
  }
package/lib/database.d.ts CHANGED
@@ -65,6 +65,10 @@ export declare const DialectVersionAccessors: {
65
65
  sql: string;
66
66
  get: (v: string) => string;
67
67
  };
68
+ mariadb: {
69
+ sql: string;
70
+ get: (v: string) => string;
71
+ };
68
72
  postgres: {
69
73
  sql: string;
70
74
  get: (v: string) => string;
@@ -116,6 +120,7 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
116
120
  addMigration(item: MigrationItem): void;
117
121
  addMigrations(options: AddMigrationsOptions): void;
118
122
  inDialect(...dialect: string[]): boolean;
123
+ isMySQLCompatibleDialect(): boolean;
119
124
  /**
120
125
  * Add collection to database
121
126
  * @param options
@@ -151,6 +156,7 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
151
156
  auth(options?: Omit<QueryOptions, 'retry'> & {
152
157
  retry?: number | Pick<QueryOptions, 'retry'>;
153
158
  }): Promise<void>;
159
+ checkVersion(): Promise<boolean>;
154
160
  prepare(): Promise<void>;
155
161
  reconnect(): Promise<void>;
156
162
  closed(): any;
package/lib/database.js CHANGED
@@ -64,6 +64,8 @@ var import_utils2 = require("./utils");
64
64
  var import_value_parsers = require("./value-parsers");
65
65
  var import_view_collection = require("./view-collection");
66
66
  var import_collection_factory = require("./collection-factory");
67
+ var import_chalk = __toESM(require("chalk"));
68
+ var import_helpers = require("./helpers");
67
69
  const DialectVersionAccessors = {
68
70
  sqlite: {
69
71
  sql: "select sqlite_version() as version",
@@ -72,9 +74,13 @@ const DialectVersionAccessors = {
72
74
  mysql: {
73
75
  sql: "select version() as version",
74
76
  get: (v) => {
75
- if (v.toLowerCase().includes("mariadb")) {
76
- return "";
77
- }
77
+ const m = /([\d+.]+)/.exec(v);
78
+ return m[0];
79
+ }
80
+ },
81
+ mariadb: {
82
+ sql: "select version() as version",
83
+ get: (v) => {
78
84
  const m = /([\d+.]+)/.exec(v);
79
85
  return m[0];
80
86
  }
@@ -101,7 +107,11 @@ const _DatabaseVersion = class _DatabaseVersion {
101
107
  return false;
102
108
  }
103
109
  const [result] = await this.db.sequelize.query(accessors[dialect].sql);
104
- return import_semver.default.satisfies(accessors[dialect].get((_a = result == null ? void 0 : result[0]) == null ? void 0 : _a.version), versions[dialect]);
110
+ const versionResult = accessors[dialect].get((_a = result == null ? void 0 : result[0]) == null ? void 0 : _a.version);
111
+ if (import_lodash.default.isPlainObject(versionResult) && versionResult.dialect) {
112
+ return import_semver.default.satisfies(versionResult.version, versions[versionResult.dialect]);
113
+ }
114
+ return import_semver.default.satisfies(versionResult, versions[dialect]);
105
115
  }
106
116
  }
107
117
  return false;
@@ -231,14 +241,20 @@ const _Database = class _Database extends import_events.EventEmitter {
231
241
  return this._instanceId;
232
242
  }
233
243
  registerCollectionType() {
234
- this.collectionFactory.registerCollectionType(import_inherited_collection.InheritedCollection, (options) => {
235
- return options.inherits && import_lodash.default.castArray(options.inherits).length > 0;
244
+ this.collectionFactory.registerCollectionType(import_inherited_collection.InheritedCollection, {
245
+ condition: (options) => {
246
+ return options.inherits && import_lodash.default.castArray(options.inherits).length > 0;
247
+ }
236
248
  });
237
- this.collectionFactory.registerCollectionType(import_view_collection.ViewCollection, (options) => {
238
- return options.viewName || options.view;
249
+ this.collectionFactory.registerCollectionType(import_view_collection.ViewCollection, {
250
+ condition: (options) => {
251
+ return options.viewName || options.view;
252
+ }
239
253
  });
240
- this.collectionFactory.registerCollectionType(import_sql_collection.SqlCollection, (options) => {
241
- return options.sql;
254
+ this.collectionFactory.registerCollectionType(import_sql_collection.SqlCollection, {
255
+ condition: (options) => {
256
+ return options.sql;
257
+ }
242
258
  });
243
259
  }
244
260
  setContext(context) {
@@ -354,6 +370,9 @@ const _Database = class _Database extends import_events.EventEmitter {
354
370
  inDialect(...dialect) {
355
371
  return dialect.includes(this.sequelize.getDialect());
356
372
  }
373
+ isMySQLCompatibleDialect() {
374
+ return this.inDialect("mysql", "mariadb");
375
+ }
357
376
  /**
358
377
  * Add collection to database
359
378
  * @param options
@@ -502,7 +521,7 @@ const _Database = class _Database extends import_events.EventEmitter {
502
521
  return new Field2(options, context);
503
522
  }
504
523
  async sync(options) {
505
- const isMySQL = this.sequelize.getDialect() === "mysql";
524
+ const isMySQL = this.isMySQLCompatibleDialect();
506
525
  if (isMySQL) {
507
526
  await this.sequelize.query("SET FOREIGN_KEY_CHECKS = 0", null);
508
527
  }
@@ -572,7 +591,19 @@ const _Database = class _Database extends import_events.EventEmitter {
572
591
  throw new Error("Connection failed, please check your database connection credentials and try again.");
573
592
  }
574
593
  }
594
+ async checkVersion() {
595
+ return await (0, import_helpers.checkDatabaseVersion)(this);
596
+ }
575
597
  async prepare() {
598
+ if (this.isMySQLCompatibleDialect()) {
599
+ const result = await this.sequelize.query(`SHOW VARIABLES LIKE 'lower_case_table_names'`, { plain: true });
600
+ if ((result == null ? void 0 : result.Value) === "1" && !this.options.underscored) {
601
+ console.log(
602
+ `Your database lower_case_table_names=1, please add ${import_chalk.default.yellow("DB_UNDERSCORED=true")} to the .env file`
603
+ );
604
+ process.exit();
605
+ }
606
+ }
576
607
  if (this.inDialect("postgres") && this.options.schema && this.options.schema != "public") {
577
608
  await this.sequelize.query(`CREATE SCHEMA IF NOT EXISTS "${this.options.schema}"`, null);
578
609
  }
@@ -151,7 +151,7 @@ const _Field = class _Field {
151
151
  sql = `SELECT *
152
152
  from pragma_table_info('${this.collection.model.tableName}')
153
153
  WHERE name = '${this.columnName()}'`;
154
- } else if (this.database.inDialect("mysql")) {
154
+ } else if (this.database.inDialect("mysql", "mariadb")) {
155
155
  sql = `
156
156
  select column_name
157
157
  from INFORMATION_SCHEMA.COLUMNS
@@ -85,6 +85,16 @@ const _HasManyField = class _HasManyField extends import_relation_field.Relation
85
85
  tcoll.addIndex([this.options.foreignKey]);
86
86
  }
87
87
  this.database.referenceMap.addReference(this.reference(association));
88
+ if (this.options.sortable) {
89
+ const targetCollection = database.modelCollection.get(this.TargetModel);
90
+ const sortFieldName = `${this.options.foreignKey}Sort`;
91
+ targetCollection.setField(sortFieldName, {
92
+ type: "sort",
93
+ hidden: true,
94
+ scopeKey: this.options.foreignKey
95
+ });
96
+ this.options.sortBy = sortFieldName;
97
+ }
88
98
  return true;
89
99
  }
90
100
  unbind() {
@@ -87,41 +87,52 @@ const _SortField = class _SortField extends import_field.Field {
87
87
  const doInit = /* @__PURE__ */ __name(async (scopeKey2 = null, scopeValue = null) => {
88
88
  const queryInterface = this.collection.db.sequelize.getQueryInterface();
89
89
  if (scopeKey2) {
90
- const scopeField = this.collection.getField(scopeKey2);
91
- if (!scopeField) {
90
+ const scopeAttribute = this.collection.model.rawAttributes[scopeKey2];
91
+ if (!scopeAttribute) {
92
92
  throw new Error(`can not find scope field ${scopeKey2} for collection ${this.collection.name}`);
93
93
  }
94
- scopeKey2 = this.collection.model.rawAttributes[scopeKey2].field;
94
+ scopeKey2 = scopeAttribute.field;
95
95
  }
96
96
  const quotedOrderField = queryInterface.quoteIdentifier(orderField);
97
- const sortColumnName = this.collection.model.rawAttributes[this.name].field;
98
- const sql = `
99
- WITH ordered_table AS (
100
- SELECT *, ROW_NUMBER() OVER (${scopeKey2 ? `PARTITION BY ${queryInterface.quoteIdentifier(scopeKey2)}` : ""} ORDER BY ${quotedOrderField}) AS new_sequence_number
101
- FROM ${this.collection.quotedTableName()}
102
- ${(() => {
103
- if (scopeKey2 && scopeValue) {
104
- const hasNull = scopeValue.includes(null);
105
- return `WHERE ${queryInterface.quoteIdentifier(scopeKey2)} IN (${scopeValue.filter((v) => v !== null).map((v) => `'${v}'`).join(",")}) ${hasNull ? `OR ${queryInterface.quoteIdentifier(scopeKey2)} IS NULL` : ""} `;
106
- }
107
- return "";
108
- })()}
109
-
110
- )
111
- ${this.collection.db.inDialect("mysql") ? `
112
- UPDATE ${this.collection.quotedTableName()}, ordered_table
113
- SET ${this.collection.quotedTableName()}.${sortColumnName} = ordered_table.new_sequence_number
114
- WHERE ${this.collection.quotedTableName()}.${quotedOrderField} = ordered_table.${quotedOrderField}
115
- ` : `
116
- UPDATE ${this.collection.quotedTableName()}
117
- SET ${queryInterface.quoteIdentifier(sortColumnName)} = ordered_table.new_sequence_number
118
- FROM ordered_table
119
- WHERE ${this.collection.quotedTableName()}.${quotedOrderField} = ${queryInterface.quoteIdentifier(
120
- "ordered_table"
121
- )}.${quotedOrderField};
122
- `}
123
-
124
- `;
97
+ const sortColumnName = queryInterface.quoteIdentifier(this.collection.model.rawAttributes[this.name].field);
98
+ let sql;
99
+ const whereClause = scopeKey2 && scopeValue ? `
100
+ WHERE ${queryInterface.quoteIdentifier(scopeKey2)} IN (${scopeValue.filter((v) => v !== null).map((v) => `'${v}'`).join(", ")})${scopeValue.includes(null) ? ` OR ${queryInterface.quoteIdentifier(scopeKey2)} IS NULL` : ""}` : "";
101
+ if (this.collection.db.inDialect("postgres")) {
102
+ sql = `
103
+ UPDATE ${this.collection.quotedTableName()}
104
+ SET ${sortColumnName} = ordered_table.new_sequence_number
105
+ FROM (
106
+ SELECT *, ROW_NUMBER() OVER (${scopeKey2 ? `PARTITION BY ${queryInterface.quoteIdentifier(scopeKey2)}` : ""} ORDER BY ${quotedOrderField}) AS new_sequence_number
107
+ FROM ${this.collection.quotedTableName()}
108
+ ${whereClause}
109
+ ) AS ordered_table
110
+ WHERE ${this.collection.quotedTableName()}.${quotedOrderField} = ordered_table.${quotedOrderField};
111
+ `;
112
+ } else if (this.collection.db.inDialect("sqlite")) {
113
+ sql = `
114
+ UPDATE ${this.collection.quotedTableName()}
115
+ SET ${sortColumnName} = (
116
+ SELECT new_sequence_number
117
+ FROM (
118
+ SELECT *, ROW_NUMBER() OVER (${scopeKey2 ? `PARTITION BY ${queryInterface.quoteIdentifier(scopeKey2)}` : ""} ORDER BY ${quotedOrderField}) AS new_sequence_number
119
+ FROM ${this.collection.quotedTableName()}
120
+ ${whereClause}
121
+ ) AS ordered_table
122
+ WHERE ${this.collection.quotedTableName()}.${quotedOrderField} = ordered_table.${quotedOrderField}
123
+ );
124
+ `;
125
+ } else if (this.collection.db.inDialect("mysql") || this.collection.db.inDialect("mariadb")) {
126
+ sql = `
127
+ UPDATE ${this.collection.quotedTableName()}
128
+ JOIN (
129
+ SELECT *, ROW_NUMBER() OVER (${scopeKey2 ? `PARTITION BY ${queryInterface.quoteIdentifier(scopeKey2)}` : ""} ORDER BY ${quotedOrderField}) AS new_sequence_number
130
+ FROM ${this.collection.quotedTableName()}
131
+ ${whereClause}
132
+ ) AS ordered_table ON ${this.collection.quotedTableName()}.${quotedOrderField} = ordered_table.${quotedOrderField}
133
+ SET ${this.collection.quotedTableName()}.${sortColumnName} = ordered_table.new_sequence_number;
134
+ `;
135
+ }
125
136
  await this.collection.db.sequelize.query(sql, {
126
137
  transaction
127
138
  });
package/lib/helpers.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- import { IDatabaseOptions } from './database';
1
+ import { Database, IDatabaseOptions } from './database';
2
2
  export declare function parseDatabaseOptionsFromEnv(): Promise<IDatabaseOptions>;
3
+ export declare function checkDatabaseVersion(db: Database): Promise<boolean>;
package/lib/helpers.js CHANGED
@@ -28,10 +28,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var helpers_exports = {};
30
30
  __export(helpers_exports, {
31
+ checkDatabaseVersion: () => checkDatabaseVersion,
31
32
  parseDatabaseOptionsFromEnv: () => parseDatabaseOptionsFromEnv
32
33
  });
33
34
  module.exports = __toCommonJS(helpers_exports);
34
35
  var import_fs = __toESM(require("fs"));
36
+ var import_semver = __toESM(require("semver"));
35
37
  function getEnvValue(key, defaultValue) {
36
38
  return process.env[key] || defaultValue;
37
39
  }
@@ -114,7 +116,57 @@ function customLogger(queryString, queryObject) {
114
116
  }
115
117
  }
116
118
  __name(customLogger, "customLogger");
119
+ const dialectVersionAccessors = {
120
+ sqlite: {
121
+ sql: "select sqlite_version() as version",
122
+ get: (v) => v,
123
+ version: "3.x"
124
+ },
125
+ mysql: {
126
+ sql: "select version() as version",
127
+ get: (v) => {
128
+ const m = /([\d+.]+)/.exec(v);
129
+ return m[0];
130
+ },
131
+ version: ">=8.0.17"
132
+ },
133
+ mariadb: {
134
+ sql: "select version() as version",
135
+ get: (v) => {
136
+ const m = /([\d+.]+)/.exec(v);
137
+ return m[0];
138
+ },
139
+ version: ">=10.9"
140
+ },
141
+ postgres: {
142
+ sql: "select version() as version",
143
+ get: (v) => {
144
+ const m = /([\d+.]+)/.exec(v);
145
+ return import_semver.default.minVersion(m[0]).version;
146
+ },
147
+ version: ">=10"
148
+ }
149
+ };
150
+ async function checkDatabaseVersion(db) {
151
+ var _a;
152
+ const dialect = db.sequelize.getDialect();
153
+ const accessor = dialectVersionAccessors[dialect];
154
+ if (!accessor) {
155
+ throw new Error(`unsupported dialect ${dialect}`);
156
+ }
157
+ const result = await db.sequelize.query(accessor.sql, {
158
+ type: "SELECT"
159
+ });
160
+ const version = accessor.get((_a = result == null ? void 0 : result[0]) == null ? void 0 : _a.version);
161
+ const versionResult = import_semver.default.satisfies(version, accessor.version);
162
+ if (!versionResult) {
163
+ throw new Error(`to use ${dialect}, please ensure the version is ${accessor.version}`);
164
+ }
165
+ return true;
166
+ }
167
+ __name(checkDatabaseVersion, "checkDatabaseVersion");
117
168
  // Annotate the CommonJS export names for ESM import in node:
118
169
  0 && (module.exports = {
170
+ checkDatabaseVersion,
119
171
  parseDatabaseOptionsFromEnv
120
172
  });
package/lib/model.d.ts CHANGED
@@ -10,6 +10,7 @@ export declare class Model<TModelAttributes extends {} = any, TCreationAttribute
10
10
  [key: string]: any;
11
11
  protected _changedWithAssociations: Set<unknown>;
12
12
  protected _previousDataValuesWithAssociations: {};
13
+ static sync(options: any): Promise<any>;
13
14
  toChangedWithAssociations(): void;
14
15
  changedWithAssociations(key?: string, value?: any): boolean | unknown[] | this;
15
16
  clearChangedWithAssociations(): void;
@@ -17,6 +18,5 @@ export declare class Model<TModelAttributes extends {} = any, TCreationAttribute
17
18
  private hiddenObjKey;
18
19
  private sortAssociations;
19
20
  private sortArray;
20
- static sync(options: any): Promise<any>;
21
21
  }
22
22
  export {};
package/lib/model.js CHANGED
@@ -43,6 +43,54 @@ const _ = import_lodash.default;
43
43
  const _Model = class _Model extends import_sequelize.Model {
44
44
  _changedWithAssociations = /* @__PURE__ */ new Set();
45
45
  _previousDataValuesWithAssociations = {};
46
+ static async sync(options) {
47
+ var _a;
48
+ if (this.collection.isView()) {
49
+ return;
50
+ }
51
+ if (this.collection.options.sync === false) {
52
+ return;
53
+ }
54
+ const collectionSyncOptions = (_a = this.database.collectionFactory.collectionTypes.get(this.collection.constructor)) == null ? void 0 : _a.onSync;
55
+ if (collectionSyncOptions) {
56
+ await collectionSyncOptions(this, options);
57
+ return;
58
+ }
59
+ const model = this;
60
+ const _schema = model._schema;
61
+ if (_schema && _schema != "public") {
62
+ await this.sequelize.query(`CREATE SCHEMA IF NOT EXISTS "${_schema}";`, {
63
+ raw: true,
64
+ transaction: options == null ? void 0 : options.transaction
65
+ });
66
+ }
67
+ if (Object.keys(model.tableAttributes).length === 0) {
68
+ if (this.database.inDialect("sqlite", "mysql", "mariadb")) {
69
+ console.error(`Zero-column tables aren't supported in ${this.database.sequelize.getDialect()}`);
70
+ return;
71
+ }
72
+ const queryInterface = this.sequelize.queryInterface;
73
+ if (!queryInterface.patched) {
74
+ const oldDescribeTable = queryInterface.describeTable;
75
+ queryInterface.describeTable = async function(...args) {
76
+ try {
77
+ return await oldDescribeTable.call(this, ...args);
78
+ } catch (err) {
79
+ if (err.message.includes("No description found for")) {
80
+ return [];
81
+ } else {
82
+ throw err;
83
+ }
84
+ }
85
+ };
86
+ queryInterface.patched = true;
87
+ }
88
+ }
89
+ if (this.collection.isInherited()) {
90
+ return import_sync_runner.SyncRunner.syncInheritModel(model, options);
91
+ }
92
+ return import_sequelize.Model.sync.call(this, options);
93
+ }
46
94
  // TODO
47
95
  toChangedWithAssociations() {
48
96
  this._changedWithAssociations = /* @__PURE__ */ new Set([...this._changedWithAssociations, ...this._changed]);
@@ -137,48 +185,6 @@ const _Model = class _Model extends import_sequelize.Model {
137
185
  });
138
186
  return import_lodash.default.orderBy(data, orderItems, orderDirections);
139
187
  }
140
- static async sync(options) {
141
- if (this.collection.isView()) {
142
- return;
143
- }
144
- if (this.collection.options.sync === false) {
145
- return;
146
- }
147
- const model = this;
148
- const _schema = model._schema;
149
- if (_schema && _schema != "public") {
150
- await this.sequelize.query(`CREATE SCHEMA IF NOT EXISTS "${_schema}";`, {
151
- raw: true,
152
- transaction: options == null ? void 0 : options.transaction
153
- });
154
- }
155
- if (Object.keys(model.tableAttributes).length === 0) {
156
- if (this.database.inDialect("sqlite", "mysql")) {
157
- console.error(`Zero-column tables aren't supported in ${this.database.sequelize.getDialect()}`);
158
- return;
159
- }
160
- const queryInterface = this.sequelize.queryInterface;
161
- if (!queryInterface.patched) {
162
- const oldDescribeTable = queryInterface.describeTable;
163
- queryInterface.describeTable = async function(...args) {
164
- try {
165
- return await oldDescribeTable.call(this, ...args);
166
- } catch (err) {
167
- if (err.message.includes("No description found for")) {
168
- return [];
169
- } else {
170
- throw err;
171
- }
172
- }
173
- };
174
- queryInterface.patched = true;
175
- }
176
- }
177
- if (this.collection.isInherited()) {
178
- return import_sync_runner.SyncRunner.syncInheritModel(model, options);
179
- }
180
- return import_sequelize.Model.sync.call(this, options);
181
- }
182
188
  };
183
189
  __name(_Model, "Model");
184
190
  __publicField(_Model, "database");
@@ -30,7 +30,7 @@ const isPg = /* @__PURE__ */ __name((ctx) => {
30
30
  return getDialect(ctx) === "postgres";
31
31
  }, "isPg");
32
32
  const isMySQL = /* @__PURE__ */ __name((ctx) => {
33
- return getDialect(ctx) === "mysql";
33
+ return getDialect(ctx) === "mysql" || getDialect(ctx) === "mariadb";
34
34
  }, "isMySQL");
35
35
  // Annotate the CommonJS export names for ESM import in node:
36
36
  0 && (module.exports = {
@@ -132,7 +132,7 @@ const _OptionsParser = class _OptionsParser {
132
132
  sortField[0] = (rawField == null ? void 0 : rawField.field) || sortField[0];
133
133
  }
134
134
  sortField.push(direction);
135
- if (this.database.inDialect("mysql")) {
135
+ if (this.database.isMySQLCompatibleDialect()) {
136
136
  orderParams.push([import_sequelize.Sequelize.fn("ISNULL", import_sequelize.Sequelize.col(`${this.model.name}.${sortField[0]}`))]);
137
137
  }
138
138
  orderParams.push(sortField);
@@ -17,4 +17,8 @@ export default class MysqlQueryInterface extends QueryInterface {
17
17
  }>;
18
18
  parseSQL(sql: string): any;
19
19
  viewDef(viewName: string): Promise<string>;
20
+ showTableDefinition(tableInfo: {
21
+ name: string;
22
+ schema?: string;
23
+ }): Promise<any>;
20
24
  }
@@ -88,6 +88,12 @@ const _MysqlQueryInterface = class _MysqlQueryInterface extends import_query_int
88
88
  const sql = match[0];
89
89
  return sql;
90
90
  }
91
+ async showTableDefinition(tableInfo) {
92
+ const { name } = tableInfo;
93
+ const sql = `SHOW CREATE TABLE ${name}`;
94
+ const results = await this.db.sequelize.query(sql, { type: "SELECT" });
95
+ return results[0]["Create Table"];
96
+ }
91
97
  };
92
98
  __name(_MysqlQueryInterface, "MysqlQueryInterface");
93
99
  let MysqlQueryInterface = _MysqlQueryInterface;
@@ -13,4 +13,8 @@ export default class PostgresQueryInterface extends QueryInterface {
13
13
  table_schema?: string;
14
14
  };
15
15
  }>;
16
+ showTableDefinition(tableInfo: {
17
+ name: string;
18
+ schema?: string;
19
+ }): Promise<any>;
16
20
  }
@@ -108,6 +108,33 @@ const _PostgresQueryInterface = class _PostgresQueryInterface extends import_que
108
108
  return {};
109
109
  }
110
110
  }
111
+ async showTableDefinition(tableInfo) {
112
+ const showFunc = `
113
+ CREATE OR REPLACE FUNCTION show_create_table(p_schema text, p_table_name text)
114
+ RETURNS text AS
115
+ $BODY$
116
+ SELECT 'CREATE TABLE ' || p_schema || '.' || p_table_name || ' (' || E'\\n' || '' ||
117
+ string_agg(column_list.column_expr, ', ' || E'\\n' || '') ||
118
+ '' || E'\\n' || ');'
119
+ FROM (
120
+ SELECT ' ' || column_name || ' ' || data_type ||
121
+ coalesce('(' || character_maximum_length || ')', '') ||
122
+ case when is_nullable = 'YES' then '' else ' NOT NULL' end as column_expr
123
+ FROM information_schema.columns
124
+ WHERE table_schema = p_schema AND table_name = p_table_name
125
+ ORDER BY ordinal_position) column_list;
126
+ $BODY$
127
+ LANGUAGE SQL STABLE;
128
+ `;
129
+ await this.db.sequelize.query(showFunc, { type: "RAW" });
130
+ const res = await this.db.sequelize.query(
131
+ `SELECT show_create_table('${tableInfo.schema}', '${tableInfo.name || "public"}')`,
132
+ {
133
+ type: "SELECT"
134
+ }
135
+ );
136
+ return res[0]["show_create_table"];
137
+ }
111
138
  };
112
139
  __name(_PostgresQueryInterface, "PostgresQueryInterface");
113
140
  let PostgresQueryInterface = _PostgresQueryInterface;
@@ -37,6 +37,7 @@ var import_sqlite_query_interface = __toESM(require("./sqlite-query-interface"))
37
37
  function buildQueryInterface(db) {
38
38
  const map = {
39
39
  mysql: import_mysql_query_interface.default,
40
+ mariadb: import_mysql_query_interface.default,
40
41
  postgres: import_postgres_query_interface.default,
41
42
  sqlite: import_sqlite_query_interface.default
42
43
  };
@@ -19,5 +19,9 @@ export default abstract class QueryInterface {
19
19
  };
20
20
  }>;
21
21
  abstract parseSQL(sql: string): any;
22
+ abstract showTableDefinition(tableInfo: {
23
+ name: string;
24
+ schema?: string;
25
+ }): Promise<any>;
22
26
  dropAll(options: any): Promise<void>;
23
27
  }
@@ -16,4 +16,8 @@ export default class SqliteQueryInterface extends QueryInterface {
16
16
  }>;
17
17
  parseSQL(sql: string): any;
18
18
  viewDef(viewName: string): Promise<string>;
19
+ showTableDefinition(tableInfo: {
20
+ name: string;
21
+ schema?: string;
22
+ }): Promise<any>;
19
23
  }
@@ -98,6 +98,9 @@ const _SqliteQueryInterface = class _SqliteQueryInterface extends import_query_i
98
98
  const sql = match[0];
99
99
  return sql;
100
100
  }
101
+ showTableDefinition(tableInfo) {
102
+ return Promise.resolve(void 0);
103
+ }
101
104
  };
102
105
  __name(_SqliteQueryInterface, "SqliteQueryInterface");
103
106
  let SqliteQueryInterface = _SqliteQueryInterface;
@@ -45,5 +45,19 @@ declare const _default: {
45
45
  numeric: string;
46
46
  json: string[];
47
47
  };
48
+ mariadb: {
49
+ varchar: string;
50
+ text: string;
51
+ int: string;
52
+ integer: string;
53
+ bigint: string;
54
+ float: string;
55
+ double: string;
56
+ boolean: string;
57
+ tinyint: string;
58
+ datetime: string;
59
+ timestamp: string;
60
+ json: string[];
61
+ };
48
62
  };
49
63
  export default _default;
@@ -66,4 +66,4 @@ const sqlite = {
66
66
  numeric: "decimal",
67
67
  json: ["json", "array"]
68
68
  };
69
- var field_type_map_default = { postgres, mysql, sqlite };
69
+ var field_type_map_default = { postgres, mysql, sqlite, mariadb: mysql };
@@ -14,9 +14,9 @@ export declare class ViewFieldInference {
14
14
  viewSchema?: string;
15
15
  }): Promise<InferredFieldResult>;
16
16
  static inferToFieldType(options: {
17
- db: Database;
18
17
  name: string;
19
18
  type: string;
19
+ dialect: string;
20
20
  }): {
21
21
  possibleTypes: string[];
22
22
  type?: undefined;
@@ -99,15 +99,21 @@ const _ViewFieldInference = class _ViewFieldInference {
99
99
  }
100
100
  }
101
101
  if (!inferResult.type) {
102
- Object.assign(inferResult, this.inferToFieldType({ db, name, type: column.type }));
102
+ Object.assign(
103
+ inferResult,
104
+ this.inferToFieldType({
105
+ dialect: db.sequelize.getDialect(),
106
+ name,
107
+ type: column.type
108
+ })
109
+ );
103
110
  }
104
111
  rawFields.push([name, inferResult]);
105
112
  }
106
113
  return Object.fromEntries(rawFields);
107
114
  }
108
115
  static inferToFieldType(options) {
109
- const { db } = options;
110
- const dialect = db.sequelize.getDialect();
116
+ const { dialect } = options;
111
117
  const fieldTypeMap = import_field_type_map.default[dialect];
112
118
  if (!options.type) {
113
119
  return {
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@nocobase/database",
3
- "version": "0.15.0-alpha.3",
3
+ "version": "0.15.0-alpha.5",
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/logger": "0.15.0-alpha.3",
10
- "@nocobase/utils": "0.15.0-alpha.3",
9
+ "@nocobase/logger": "0.15.0-alpha.5",
10
+ "@nocobase/utils": "0.15.0-alpha.5",
11
11
  "async-mutex": "^0.3.2",
12
12
  "cron-parser": "4.4.0",
13
13
  "dayjs": "^1.11.8",
@@ -33,5 +33,5 @@
33
33
  "url": "git+https://github.com/nocobase/nocobase.git",
34
34
  "directory": "packages/database"
35
35
  },
36
- "gitHead": "8f39868bd613a465efb20123094ebbc2390c1eef"
36
+ "gitHead": "4713b1a887dad4dadf27b65e3b3e2a46c6986cbf"
37
37
  }