@nocobase/database 0.21.0-alpha.1 → 0.21.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/collection.js CHANGED
@@ -260,9 +260,6 @@ const _Collection = class _Collection extends import_events.EventEmitter {
260
260
  `Field type conflict: cannot set "${name}" on "${this.name}" to ${options.type}, parent "${name}" type is ${oldField.options.type}`
261
261
  );
262
262
  }
263
- if (this.options.autoGenId !== false && options.primaryKey) {
264
- this.model.removeAttribute("id");
265
- }
266
263
  this.removeField(name);
267
264
  this.fields.set(name, field);
268
265
  this.emit("field.afterAdd", field);
package/lib/database.js CHANGED
@@ -183,7 +183,13 @@ const _Database = class _Database extends import_events.EventEmitter {
183
183
  opts.timezone = "+00:00";
184
184
  }
185
185
  if (options.dialect === "postgres") {
186
- require("pg").defaults.parseInt8 = true;
186
+ const types = require("pg").types;
187
+ types.setTypeParser(types.builtins.INT8, function(val) {
188
+ if (val <= Number.MAX_SAFE_INTEGER) {
189
+ return Number(val);
190
+ }
191
+ return val;
192
+ });
187
193
  }
188
194
  this.options = opts;
189
195
  const sequelizeOptions = this.sequelizeOptions(this.options);
@@ -21,6 +21,7 @@ __export(must_have_filter_decorator_exports, {
21
21
  default: () => must_have_filter_decorator_default
22
22
  });
23
23
  module.exports = __toCommonJS(must_have_filter_decorator_exports);
24
+ var import_utils = require("@nocobase/utils");
24
25
  const mustHaveFilter = /* @__PURE__ */ __name(() => (target, propertyKey, descriptor) => {
25
26
  const oldValue = descriptor.value;
26
27
  descriptor.value = function(...args) {
@@ -28,7 +29,7 @@ const mustHaveFilter = /* @__PURE__ */ __name(() => (target, propertyKey, descri
28
29
  if (Array.isArray(options.values)) {
29
30
  return oldValue.apply(this, args);
30
31
  }
31
- if (!(options == null ? void 0 : options.filter) && !(options == null ? void 0 : options.filterByTk) && !(options == null ? void 0 : options.forceUpdate)) {
32
+ if (!(0, import_utils.isValidFilter)(options == null ? void 0 : options.filter) && !(options == null ? void 0 : options.filterByTk) && !(options == null ? void 0 : options.forceUpdate)) {
32
33
  throw new Error(`must provide filter or filterByTk for ${propertyKey} call, or set forceUpdate to true`);
33
34
  }
34
35
  return oldValue.apply(this, args);
@@ -10,4 +10,5 @@ export interface NanoidFieldOptions extends BaseColumnFieldOptions {
10
10
  type: 'nanoid';
11
11
  size?: number;
12
12
  customAlphabet?: string;
13
+ autoFill?: boolean;
13
14
  }
@@ -30,10 +30,10 @@ const _NanoidField = class _NanoidField extends import_field.Field {
30
30
  return import_sequelize.DataTypes.STRING;
31
31
  }
32
32
  init() {
33
- const { name, size, customAlphabet: customAlphabetOptions } = this.options;
33
+ const { name, size, customAlphabet: customAlphabetOptions, autoFill } = this.options;
34
34
  this.listener = async (instance) => {
35
35
  const value = instance.get(name);
36
- if (!value) {
36
+ if (!value && autoFill !== false) {
37
37
  const nanoIdFunc = customAlphabetOptions ? (0, import_nanoid.customAlphabet)(customAlphabetOptions) : import_nanoid.nanoid;
38
38
  instance.set(name, nanoIdFunc(size || DEFAULT_SIZE));
39
39
  }
@@ -1,9 +1,12 @@
1
1
  import { DataTypes } from 'sequelize';
2
- import { BaseColumnFieldOptions, Field, FieldContext } from './field';
2
+ import { BaseColumnFieldOptions, Field } from './field';
3
3
  export declare class UuidField extends Field {
4
- constructor(options?: any, context?: FieldContext);
5
4
  get dataType(): DataTypes.AbstractDataTypeConstructor;
5
+ init(): void;
6
+ bind(): void;
7
+ unbind(): void;
6
8
  }
7
9
  export interface UUIDFieldOptions extends BaseColumnFieldOptions {
8
10
  type: 'uuid';
11
+ autoFill?: boolean;
9
12
  }
@@ -23,19 +23,30 @@ __export(uuid_field_exports, {
23
23
  module.exports = __toCommonJS(uuid_field_exports);
24
24
  var import_sequelize = require("sequelize");
25
25
  var import_field = require("./field");
26
+ var import_uuid = require("uuid");
26
27
  const _UuidField = class _UuidField extends import_field.Field {
27
- constructor(options, context) {
28
- super(
29
- {
30
- defaultValue: new import_sequelize.DataTypes.UUIDV4(),
31
- ...options
32
- },
33
- context
34
- );
35
- }
36
28
  get dataType() {
37
29
  return import_sequelize.DataTypes.UUID;
38
30
  }
31
+ init() {
32
+ const { name, autoFill } = this.options;
33
+ this.listener = async (instance) => {
34
+ const value = instance.get(name);
35
+ if (!value && autoFill !== false) {
36
+ instance.set(name, (0, import_uuid.v4)());
37
+ }
38
+ };
39
+ }
40
+ bind() {
41
+ super.bind();
42
+ this.on("beforeCreate", this.listener);
43
+ this.on("beforeUpdate", this.listener);
44
+ }
45
+ unbind() {
46
+ super.unbind();
47
+ this.off("beforeCreate", this.listener);
48
+ this.off("beforeUpdate", this.listener);
49
+ }
39
50
  };
40
51
  __name(_UuidField, "UuidField");
41
52
  let UuidField = _UuidField;
package/lib/repository.js CHANGED
@@ -44,6 +44,7 @@ module.exports = __toCommonJS(repository_exports);
44
44
  var import_flat = require("flat");
45
45
  var import_lodash = __toESM(require("lodash"));
46
46
  var import_sequelize = require("sequelize");
47
+ var import_utils = require("@nocobase/utils");
47
48
  var import_must_have_filter_decorator = __toESM(require("./decorators/must-have-filter-decorator"));
48
49
  var import_target_collection_decorator = __toESM(require("./decorators/target-collection-decorator"));
49
50
  var import_transaction_decorator = require("./decorators/transaction-decorator");
@@ -469,7 +470,7 @@ const _Repository = class _Repository {
469
470
  transaction: transaction2
470
471
  });
471
472
  }
472
- if (options.filter) {
473
+ if (options.filter && (0, import_utils.isValidFilter)(options.filter)) {
473
474
  if (this.collection.model.primaryKeyAttributes.length !== 1 && !import_lodash.default.get(this.collection.options, "filterTargetKey")) {
474
475
  const queryOptions = {
475
476
  ...this.buildQueryOptions(options)
@@ -5,6 +5,7 @@ export declare class SyncRunner {
5
5
  private readonly collection;
6
6
  private readonly database;
7
7
  private tableDescMap;
8
+ private uniqueAttributes;
8
9
  constructor(model: typeof Model);
9
10
  get tableName(): string | {
10
11
  tableName: string;
@@ -17,6 +18,8 @@ export declare class SyncRunner {
17
18
  [attribute: string]: import("sequelize").ModelAttributeColumnOptions<SequelizeModel<any, any>>;
18
19
  };
19
20
  runSync(options: any): Promise<any>;
21
+ handleUniqueFieldBeforeSync(beforeColumns: any, options: any): Promise<void>;
22
+ handlePrimaryKeyBeforeSync(columns: any, options: any): Promise<void>;
20
23
  handlePrimaryKey(columns: any, options: any): Promise<void>;
21
24
  handleDefaultValues(columns: any, options: any): Promise<void>;
22
25
  handleUniqueIndex(options: any): Promise<void>;
@@ -34,6 +34,7 @@ const _SyncRunner = class _SyncRunner {
34
34
  collection;
35
35
  database;
36
36
  tableDescMap = {};
37
+ uniqueAttributes = [];
37
38
  get tableName() {
38
39
  return this.model.getTableName();
39
40
  }
@@ -68,6 +69,15 @@ const _SyncRunner = class _SyncRunner {
68
69
  }
69
70
  throw e;
70
71
  }
72
+ try {
73
+ const beforeColumns = await this.queryInterface.describeTable(this.tableName, options);
74
+ await this.handlePrimaryKeyBeforeSync(beforeColumns, options);
75
+ await this.handleUniqueFieldBeforeSync(beforeColumns, options);
76
+ } catch (e) {
77
+ if (!e.message.includes("No description found")) {
78
+ throw e;
79
+ }
80
+ }
71
81
  const syncResult = await this.performSync(options);
72
82
  const columns = await this.queryInterface.describeTable(this.tableName, options);
73
83
  await this.handlePrimaryKey(columns, options);
@@ -75,10 +85,34 @@ const _SyncRunner = class _SyncRunner {
75
85
  await this.handleUniqueIndex(options);
76
86
  return syncResult;
77
87
  }
78
- async handlePrimaryKey(columns, options) {
79
- if (!this.database.inDialect("postgres")) {
88
+ async handleUniqueFieldBeforeSync(beforeColumns, options) {
89
+ if (!this.database.inDialect("sqlite")) {
80
90
  return;
81
91
  }
92
+ const newAttributes = Object.keys(this.rawAttributes).filter((key) => {
93
+ return !Object.keys(beforeColumns).includes(this.rawAttributes[key].field) && this.rawAttributes[key].unique;
94
+ });
95
+ this.uniqueAttributes = newAttributes;
96
+ for (const newAttribute of newAttributes) {
97
+ this.rawAttributes[newAttribute].unique = false;
98
+ }
99
+ }
100
+ async handlePrimaryKeyBeforeSync(columns, options) {
101
+ const columnsBePrimaryKey = Object.keys(columns).filter((key) => {
102
+ return columns[key].primaryKey == true;
103
+ }).sort();
104
+ const columnsWillBePrimaryKey = Object.keys(this.rawAttributes).filter((key) => {
105
+ return this.rawAttributes[key].primaryKey == true;
106
+ }).map((key) => {
107
+ return this.rawAttributes[key].field;
108
+ }).sort();
109
+ if (columnsBePrimaryKey.length == 1 && !columnsWillBePrimaryKey.includes(columnsBePrimaryKey[0])) {
110
+ if (this.database.inDialect("mariadb", "mysql")) {
111
+ await this.sequelize.query(`ALTER TABLE ${this.collection.quotedTableName()} DROP PRIMARY KEY;`, options);
112
+ }
113
+ }
114
+ }
115
+ async handlePrimaryKey(columns, options) {
82
116
  try {
83
117
  const columnsBePrimaryKey = Object.keys(columns).filter((key) => {
84
118
  return columns[key].primaryKey == true;
@@ -91,18 +125,26 @@ const _SyncRunner = class _SyncRunner {
91
125
  if (columnsWillBePrimaryKey.length == 0) {
92
126
  return;
93
127
  }
94
- if (JSON.stringify(columnsBePrimaryKey) != JSON.stringify(columnsWillBePrimaryKey)) {
95
- await this.queryInterface.addConstraint(this.tableName, {
96
- type: "primary key",
97
- fields: columnsWillBePrimaryKey,
98
- name: `${this.collection.tableName()}_${columnsWillBePrimaryKey.join("_")}_pk`,
99
- transaction: options == null ? void 0 : options.transaction
100
- });
128
+ if (columnsWillBePrimaryKey.length == 1 && JSON.stringify(columnsBePrimaryKey) != JSON.stringify(columnsWillBePrimaryKey)) {
129
+ if (this.database.inDialect("mariadb", "mysql")) {
130
+ await this.sequelize.query(
131
+ `ALTER TABLE ${this.collection.quotedTableName()} ADD PRIMARY KEY (${columnsWillBePrimaryKey[0]});`,
132
+ options
133
+ );
134
+ } else {
135
+ await this.queryInterface.addConstraint(this.tableName, {
136
+ type: "primary key",
137
+ fields: columnsWillBePrimaryKey,
138
+ name: `${this.collection.tableName()}_${columnsWillBePrimaryKey.join("_")}_pk`,
139
+ transaction: options == null ? void 0 : options.transaction
140
+ });
141
+ }
101
142
  }
102
143
  } catch (e) {
103
144
  if (e.message.includes("No description found")) {
104
145
  return;
105
146
  }
147
+ throw e;
106
148
  }
107
149
  }
108
150
  async handleDefaultValues(columns, options) {
@@ -154,6 +196,9 @@ const _SyncRunner = class _SyncRunner {
154
196
  }
155
197
  }
156
198
  async handleUniqueIndex(options) {
199
+ for (const uniqueAttribute of this.uniqueAttributes) {
200
+ this.rawAttributes[uniqueAttribute].unique = true;
201
+ }
157
202
  const existsIndexes = await this.queryInterface.showIndex(this.collection.getTableNameWithSchema(), options);
158
203
  const existsUniqueIndexes = existsIndexes.filter((index) => index.unique);
159
204
  const uniqueAttributes = Object.keys(this.rawAttributes).filter((key) => {
@@ -190,7 +235,8 @@ const _SyncRunner = class _SyncRunner {
190
235
  if (!indexExists) {
191
236
  await this.queryInterface.addIndex(this.tableName, [this.rawAttributes[uniqueAttribute].field], {
192
237
  unique: true,
193
- transaction: options == null ? void 0 : options.transaction
238
+ transaction: options == null ? void 0 : options.transaction,
239
+ name: `${this.collection.tableName()}_${this.rawAttributes[uniqueAttribute].field}_uk`
194
240
  });
195
241
  }
196
242
  }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@nocobase/database",
3
- "version": "0.21.0-alpha.1",
3
+ "version": "0.21.0-alpha.2",
4
4
  "description": "",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
7
7
  "license": "Apache-2.0",
8
8
  "dependencies": {
9
- "@nocobase/logger": "0.21.0-alpha.1",
10
- "@nocobase/utils": "0.21.0-alpha.1",
9
+ "@nocobase/logger": "0.21.0-alpha.2",
10
+ "@nocobase/utils": "0.21.0-alpha.2",
11
11
  "async-mutex": "^0.3.2",
12
12
  "chalk": "^4.1.1",
13
13
  "cron-parser": "4.4.0",
@@ -25,7 +25,8 @@
25
25
  "qs": "^6.11.2",
26
26
  "semver": "^7.3.7",
27
27
  "sequelize": "^6.26.0",
28
- "umzug": "^3.1.1"
28
+ "umzug": "^3.1.1",
29
+ "uuid": "^9.0.1"
29
30
  },
30
31
  "devDependencies": {
31
32
  "@types/glob": "^7.2.0"
@@ -35,5 +36,5 @@
35
36
  "url": "git+https://github.com/nocobase/nocobase.git",
36
37
  "directory": "packages/database"
37
38
  },
38
- "gitHead": "afd2f3d1341b85ea9daa7b2667dd4ace1fafb7ff"
39
+ "gitHead": "90628f2e2da846208fb2d7966ddb4e467d187ffb"
39
40
  }