@nocobase/database 1.9.0-beta.5 → 1.9.0-beta.7

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.
@@ -44,6 +44,7 @@ var import_lodash = __toESM(require("lodash"));
44
44
  var import_sequelize = require("sequelize");
45
45
  var import_append_child_collection_name_after_repository_find = require("../listeners/append-child-collection-name-after-repository-find");
46
46
  var import_options_parser = require("../options-parser");
47
+ var import_utils = require("../utils");
47
48
  const pushAttribute = /* @__PURE__ */ __name((node, attribute) => {
48
49
  if (import_lodash.default.isArray(node.attributes) && !node.attributes.includes(attribute)) {
49
50
  node.attributes.push(attribute);
@@ -85,25 +86,6 @@ const queryParentSQL = /* @__PURE__ */ __name((options) => {
85
86
  )
86
87
  SELECT ${q(targetKeyField)} AS ${q(targetKey)}, ${q(foreignKeyField)} AS ${q(foreignKey)} FROM cte`;
87
88
  }, "queryParentSQL");
88
- const processIncludes = /* @__PURE__ */ __name((includes, model, parentAs = "") => {
89
- includes.forEach((include, index) => {
90
- const association = model.associations[include.association];
91
- if (association == null ? void 0 : association.generateInclude) {
92
- includes[index] = {
93
- ...include,
94
- ...association.generateInclude(parentAs)
95
- };
96
- }
97
- if (include.include && Array.isArray(include.include) && include.include.length > 0) {
98
- const nextModel = association == null ? void 0 : association.target;
99
- if (!nextModel) {
100
- return;
101
- }
102
- processIncludes(include.include, nextModel, parentAs ? `${parentAs}->${association.as}` : association.as);
103
- }
104
- });
105
- return includes;
106
- }, "processIncludes");
107
89
  const _EagerLoadingTree = class _EagerLoadingTree {
108
90
  root;
109
91
  db;
@@ -233,7 +215,7 @@ const _EagerLoadingTree = class _EagerLoadingTree {
233
215
  attributes: [primaryKeyField],
234
216
  group: `${node.model.name}.${primaryKeyField}`,
235
217
  transaction,
236
- include: processIncludes(includeForFilter, node.model)
218
+ include: (0, import_utils.processIncludes)(includeForFilter, node.model)
237
219
  })).map((row) => {
238
220
  return { row, pk: row[primaryKeyField] };
239
221
  });
package/lib/index.d.ts CHANGED
@@ -42,3 +42,4 @@ export { default as fieldTypeMap } from './view/field-type-map';
42
42
  export * from './view/view-inference';
43
43
  export * from './update-guard';
44
44
  export { default as operators } from './operators';
45
+ export { filterIncludes, mergeIncludes } from './utils/filter-include';
package/lib/index.js CHANGED
@@ -54,8 +54,10 @@ __export(src_exports, {
54
54
  ValidationErrorItem: () => import_sequelize.ValidationErrorItem,
55
55
  default: () => import_database.Database,
56
56
  fieldTypeMap: () => import_field_type_map.default,
57
+ filterIncludes: () => import_filter_include.filterIncludes,
57
58
  fn: () => import_sequelize.fn,
58
59
  literal: () => import_sequelize.literal,
60
+ mergeIncludes: () => import_filter_include.mergeIncludes,
59
61
  operators: () => import_operators.default,
60
62
  snakeCase: () => import_utils.snakeCase,
61
63
  sqlParser: () => import_sql_parser.default,
@@ -98,6 +100,7 @@ var import_field_type_map = __toESM(require("./view/field-type-map"));
98
100
  __reExport(src_exports, require("./view/view-inference"), module.exports);
99
101
  __reExport(src_exports, require("./update-guard"), module.exports);
100
102
  var import_operators = __toESM(require("./operators"));
103
+ var import_filter_include = require("./utils/filter-include");
101
104
  // Annotate the CommonJS export names for ESM import in node:
102
105
  0 && (module.exports = {
103
106
  BaseError,
@@ -116,8 +119,10 @@ var import_operators = __toESM(require("./operators"));
116
119
  ValidationError,
117
120
  ValidationErrorItem,
118
121
  fieldTypeMap,
122
+ filterIncludes,
119
123
  fn,
120
124
  literal,
125
+ mergeIncludes,
121
126
  operators,
122
127
  snakeCase,
123
128
  sqlParser,
@@ -12,4 +12,5 @@ export declare class NumberInterface extends BaseInterface {
12
12
  toValue(value: any): Promise<any>;
13
13
  parseValue(value: any): any;
14
14
  validate(value: any): boolean;
15
+ toString(value: number, ctx?: any): string | number;
15
16
  }
@@ -7,9 +7,11 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
+ var __create = Object.create;
10
11
  var __defProp = Object.defineProperty;
11
12
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
13
  var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
13
15
  var __hasOwnProp = Object.prototype.hasOwnProperty;
14
16
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
15
17
  var __export = (target, all) => {
@@ -24,12 +26,21 @@ var __copyProps = (to, from, except, desc) => {
24
26
  }
25
27
  return to;
26
28
  };
29
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
30
+ // If the importer is in node compatibility mode or this is not an ESM
31
+ // file that has been converted to a CommonJS file using a Babel-
32
+ // compatible transform (i.e. "__esModule" has not been set), then set
33
+ // "default" to the CommonJS "module.exports" for node compatibility.
34
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
35
+ mod
36
+ ));
27
37
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
38
  var number_interface_exports = {};
29
39
  __export(number_interface_exports, {
30
40
  NumberInterface: () => NumberInterface
31
41
  });
32
42
  module.exports = __toCommonJS(number_interface_exports);
43
+ var import_lodash = __toESM(require("lodash"));
33
44
  var import_base_interface = require("./base-interface");
34
45
  const _NumberInterface = class _NumberInterface extends import_base_interface.BaseInterface {
35
46
  sanitizeValue(value) {
@@ -63,6 +74,23 @@ const _NumberInterface = class _NumberInterface extends import_base_interface.Ba
63
74
  validate(value) {
64
75
  return !isNaN(value);
65
76
  }
77
+ toString(value, ctx) {
78
+ var _a, _b, _c, _d;
79
+ value = super.toString(value, ctx);
80
+ const step = (_c = (_b = (_a = this.options) == null ? void 0 : _a.uiSchema) == null ? void 0 : _b["x-component-props"]) == null ? void 0 : _c.step;
81
+ if (value != null && !import_lodash.default.isUndefined(step)) {
82
+ const s = step.toString();
83
+ const precision = ((_d = s.split(".")[1]) == null ? void 0 : _d.length) || 0;
84
+ const num = Number(value);
85
+ if (precision > 0) {
86
+ const factor = Math.pow(10, precision);
87
+ const rounded = Math.round(num * factor) / factor;
88
+ return rounded.toFixed(precision);
89
+ }
90
+ return num.toFixed(0);
91
+ }
92
+ return value;
93
+ }
66
94
  };
67
95
  __name(_NumberInterface, "NumberInterface");
68
96
  let NumberInterface = _NumberInterface;
@@ -27,7 +27,9 @@ export default class PostgresQueryInterface extends QueryInterface {
27
27
  currentVal: number;
28
28
  }>;
29
29
  collectionTableExists(collection: Collection, options?: any): Promise<any>;
30
- listViews(): Promise<[unknown[], unknown]>;
30
+ listViews(options?: {
31
+ schema?: string;
32
+ }): Promise<[unknown[], unknown]>;
31
33
  viewDef(viewName: string): Promise<string>;
32
34
  parseSQL(sql: string): any;
33
35
  viewColumnUsage(options: any): Promise<{
@@ -110,8 +110,15 @@ const _PostgresQueryInterface = class _PostgresQueryInterface extends import_que
110
110
  const results = await this.db.sequelize.query(sql, { type: "SELECT", transaction });
111
111
  return results[0]["exists"];
112
112
  }
113
- async listViews() {
114
- const sql = `
113
+ async listViews(options) {
114
+ var _a;
115
+ const targetSchema = (options == null ? void 0 : options.schema) || ((_a = this.db.options) == null ? void 0 : _a.schema) || "public";
116
+ const sql = targetSchema ? `
117
+ SELECT viewname as name, definition, schemaname as schema
118
+ FROM pg_views
119
+ WHERE schemaname = '${targetSchema}'
120
+ ORDER BY viewname;
121
+ ` : `
115
122
  SELECT viewname as name, definition, schemaname as schema
116
123
  FROM pg_views
117
124
  WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
@@ -18,7 +18,9 @@ export default abstract class QueryInterface {
18
18
  sequelizeQueryInterface: SequelizeQueryInterface;
19
19
  protected constructor(db: Database);
20
20
  abstract collectionTableExists(collection: Collection, options?: Transactionable): Promise<boolean>;
21
- abstract listViews(): any;
21
+ abstract listViews(options?: {
22
+ schema?: string;
23
+ }): any;
22
24
  abstract viewDef(viewName: string): Promise<string>;
23
25
  abstract viewColumnUsage(options: {
24
26
  viewName: string;
package/lib/repository.js CHANGED
@@ -72,6 +72,7 @@ var import_hasone_repository = require("./relation-repository/hasone-repository"
72
72
  var import_update_associations = require("./update-associations");
73
73
  var import_update_guard = require("./update-guard");
74
74
  var import_filter_utils = require("./utils/filter-utils");
75
+ var import_utils2 = require("./utils");
75
76
  var import_sequelize2 = require("sequelize");
76
77
  const debug = require("debug")("noco-database");
77
78
  const transaction = (0, import_transaction_decorator.transactionWrapperBuilder)(function() {
@@ -134,7 +135,6 @@ const _Repository = class _Repository {
134
135
  * return count by filter
135
136
  */
136
137
  async count(countOptions) {
137
- var _a;
138
138
  let options = countOptions ? import_lodash.default.clone(countOptions) : {};
139
139
  const transaction2 = await this.getTransaction(options);
140
140
  if (countOptions == null ? void 0 : countOptions.filter) {
@@ -155,7 +155,9 @@ const _Repository = class _Repository {
155
155
  ...options,
156
156
  distinct: Boolean(this.collection.model.primaryKeyAttribute) && !this.collection.isMultiFilterTargetKey()
157
157
  };
158
- if (((_a = queryOptions.include) == null ? void 0 : _a.length) === 0) {
158
+ if (Array.isArray(queryOptions.include) && queryOptions.include.length > 0) {
159
+ queryOptions.include = (0, import_utils2.processIncludes)(queryOptions.include, this.collection.model);
160
+ } else {
159
161
  delete queryOptions.include;
160
162
  }
161
163
  return await this.collection.model.count({
@@ -174,7 +176,6 @@ const _Repository = class _Repository {
174
176
  const tableName = this.collection.tableName();
175
177
  try {
176
178
  if (this.database.isMySQLCompatibleDialect()) {
177
- await this.database.sequelize.query(`ANALYZE TABLE ${this.collection.getTableNameWithSchema()}`);
178
179
  const results = await this.database.sequelize.query(
179
180
  `
180
181
  SELECT table_rows FROM information_schema.tables
@@ -183,17 +184,16 @@ const _Repository = class _Repository {
183
184
  `,
184
185
  { replacements: [tableName], type: import_sequelize.QueryTypes.SELECT }
185
186
  );
186
- return Number(((_a = results == null ? void 0 : results[0]) == null ? void 0 : _a.table_rows) ?? 0);
187
+ return Number(((_a = results == null ? void 0 : results[0]) == null ? void 0 : _a[this.database.inDialect("mysql") ? "TABLE_ROWS" : "table_rows"]) ?? 0);
187
188
  }
188
189
  if (this.database.isPostgresCompatibleDialect()) {
189
- await this.database.sequelize.query(`ANALYZE ${this.collection.getTableNameWithSchema()}`);
190
190
  const results = await this.database.sequelize.query(
191
191
  `
192
192
  SELECT reltuples::BIGINT AS estimate
193
193
  FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid
194
- WHERE c.relname = ? AND n.nspname = current_schema();
194
+ WHERE c.relname = ? AND n.nspname = ?;
195
195
  `,
196
- { replacements: [tableName], type: import_sequelize.QueryTypes.SELECT }
196
+ { replacements: [tableName, this.collection.collectionSchema()], type: import_sequelize.QueryTypes.SELECT, logging: true }
197
197
  );
198
198
  return Number(((_b = results == null ? void 0 : results[0]) == null ? void 0 : _b.estimate) ?? 0);
199
199
  }
@@ -345,6 +345,9 @@ const _Repository = class _Repository {
345
345
  subQuery: false,
346
346
  ...this.buildQueryOptions(options)
347
347
  };
348
+ if (!import_lodash2.default.isUndefined(opts.limit)) {
349
+ opts.limit = Number(opts.limit);
350
+ }
348
351
  let rows;
349
352
  if (opts.include && opts.include.length > 0) {
350
353
  const eagerLoadingTree = import_eager_loading_tree.EagerLoadingTree.buildFromSequelizeOptions({
@@ -0,0 +1,55 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ /**
10
+ * Merge a flat list of include descriptors by association (alias) key.
11
+ * - Nodes with the same association are merged into one.
12
+ * - `required` is OR-ed (true if any source is true).
13
+ * - Child includes are recursively merged with the same rules.
14
+ * - Empty `include` arrays are removed to keep the payload minimal.
15
+ *
16
+ * Notes:
17
+ * - Association keys are normalized via snake_case to ensure consistent merging.
18
+ * - This function is idempotent and order-insensitive for equivalent input sets.
19
+ *
20
+ * Usage example (input and output):
21
+ *
22
+ * const includesA = [
23
+ * { association: 'posts', required: true, include: [{ association: 'comments' }] },
24
+ * { association: 'profile' },
25
+ * ];
26
+ *
27
+ * const includesB = [
28
+ * { association: 'posts', include: [
29
+ * { association: 'comments', required: true },
30
+ * { association: 'tags' },
31
+ * ]
32
+ * },
33
+ * { association: 'roles', required: true },
34
+ * ];
35
+ *
36
+ * const merged = mergeIncludes([...includesA, ...includesB]);
37
+ *
38
+ * Result:
39
+ * [
40
+ * {
41
+ * association: 'posts',
42
+ * required: true,
43
+ * include: [
44
+ * { association: 'comments', required: true },
45
+ * { association: 'tags' },
46
+ * ],
47
+ * },
48
+ * { association: 'profile' },
49
+ * { association: 'roles', required: true },
50
+ * ]
51
+ */
52
+ export declare const mergeIncludes: (includes?: any[]) => any[];
53
+ export declare const filterIncludes: (where: any, includes: any, options: {
54
+ underscored: boolean;
55
+ }) => any[];
@@ -0,0 +1,118 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
18
+ };
19
+ var __copyProps = (to, from, except, desc) => {
20
+ if (from && typeof from === "object" || typeof from === "function") {
21
+ for (let key of __getOwnPropNames(from))
22
+ if (!__hasOwnProp.call(to, key) && key !== except)
23
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
+ }
25
+ return to;
26
+ };
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var filter_include_exports = {};
29
+ __export(filter_include_exports, {
30
+ filterIncludes: () => filterIncludes,
31
+ mergeIncludes: () => mergeIncludes
32
+ });
33
+ module.exports = __toCommonJS(filter_include_exports);
34
+ var import_utils = require("../utils");
35
+ const collectAssociationPathsFromWhere = /* @__PURE__ */ __name((where) => {
36
+ const aliasPaths = /* @__PURE__ */ new Set();
37
+ const traverse = /* @__PURE__ */ __name((value) => {
38
+ if (value == null) return;
39
+ if (Array.isArray(value)) {
40
+ for (const item of value) traverse(item);
41
+ return;
42
+ }
43
+ if (typeof value === "object") {
44
+ for (const [rawKey, child] of Object.entries(value)) {
45
+ if (typeof rawKey === "string" && rawKey.startsWith("$") && rawKey.endsWith("$")) {
46
+ const inner = rawKey.slice(1, -1);
47
+ const segments = inner.split(".");
48
+ if (segments.length > 1) {
49
+ aliasPaths.add(segments.slice(0, -1).join("."));
50
+ }
51
+ }
52
+ traverse(child);
53
+ }
54
+ for (const sym of Object.getOwnPropertySymbols(value)) {
55
+ traverse(value[sym]);
56
+ }
57
+ }
58
+ }, "traverse");
59
+ traverse(where);
60
+ return Array.from(aliasPaths);
61
+ }, "collectAssociationPathsFromWhere");
62
+ const pruneIncludeTreeByPaths = /* @__PURE__ */ __name((includes = [], requiredPathsRaw, options) => {
63
+ const normalizedPaths = options.underscored ? requiredPathsRaw.map(
64
+ (p) => p.split(".").map((s) => (0, import_utils.snakeCase)(s)).join(".")
65
+ ) : requiredPathsRaw;
66
+ if (!(includes == null ? void 0 : includes.length) || !(normalizedPaths == null ? void 0 : normalizedPaths.length)) return [];
67
+ const pruned = [];
68
+ for (const inc of includes) {
69
+ const association = inc == null ? void 0 : inc.association;
70
+ if (!association) continue;
71
+ const assocKey = options.underscored ? (0, import_utils.snakeCase)(String(association)) : String(association);
72
+ const matched = normalizedPaths.filter((p) => p === assocKey || p.startsWith(assocKey + "."));
73
+ if (!matched.length) continue;
74
+ const childRemainders = matched.map((p) => p === assocKey ? null : p.slice(assocKey.length + 1)).filter(Boolean);
75
+ const children = pruneIncludeTreeByPaths(inc.include ?? [], childRemainders, options);
76
+ const copy = { ...inc };
77
+ if (children.length) {
78
+ copy.include = children;
79
+ } else if ("include" in copy) {
80
+ delete copy.include;
81
+ }
82
+ pruned.push(copy);
83
+ }
84
+ return pruned;
85
+ }, "pruneIncludeTreeByPaths");
86
+ const mergeIncludes = /* @__PURE__ */ __name((includes = []) => {
87
+ const byAssociation = /* @__PURE__ */ new Map();
88
+ const mergeAll = /* @__PURE__ */ __name((list = []) => {
89
+ for (const inc of list) {
90
+ const association = inc == null ? void 0 : inc.association;
91
+ if (!association) continue;
92
+ const key = (0, import_utils.snakeCase)(String(association));
93
+ if (!byAssociation.has(key)) {
94
+ byAssociation.set(key, { ...inc, include: void 0 });
95
+ }
96
+ const target = byAssociation.get(key);
97
+ if (inc.required) target.required = true;
98
+ const mergedChildren = mergeIncludes([...target.include ?? [], ...inc.include ?? []]);
99
+ if (mergedChildren.length) {
100
+ target.include = mergedChildren;
101
+ } else if ("include" in target) {
102
+ delete target.include;
103
+ }
104
+ }
105
+ }, "mergeAll");
106
+ mergeAll(includes);
107
+ return Array.from(byAssociation.values());
108
+ }, "mergeIncludes");
109
+ const filterIncludes = /* @__PURE__ */ __name((where, includes, options) => {
110
+ const path = collectAssociationPathsFromWhere(where);
111
+ const result = pruneIncludeTreeByPaths(includes, path, options);
112
+ return result;
113
+ }, "filterIncludes");
114
+ // Annotate the CommonJS export names for ESM import in node:
115
+ 0 && (module.exports = {
116
+ filterIncludes,
117
+ mergeIncludes
118
+ });
package/lib/utils.d.ts CHANGED
@@ -16,3 +16,4 @@ export declare function percent2float(value: string): number;
16
16
  export declare function isUndefinedOrNull(value: any): boolean;
17
17
  export declare function isStringOrNumber(value: any): boolean;
18
18
  export declare function getKeysByPrefix(keys: string[], prefix: string): string[];
19
+ export declare function processIncludes(includes: any[], model: any, parentAs?: string): any[];
package/lib/utils.js CHANGED
@@ -45,6 +45,7 @@ __export(utils_exports, {
45
45
  md5: () => md5,
46
46
  patchSequelizeQueryInterface: () => patchSequelizeQueryInterface,
47
47
  percent2float: () => percent2float,
48
+ processIncludes: () => processIncludes,
48
49
  snakeCase: () => snakeCase
49
50
  });
50
51
  module.exports = __toCommonJS(utils_exports);
@@ -140,6 +141,26 @@ function getKeysByPrefix(keys, prefix) {
140
141
  return keys.filter((key) => key.startsWith(`${prefix}.`)).map((key) => key.substring(prefix.length + 1));
141
142
  }
142
143
  __name(getKeysByPrefix, "getKeysByPrefix");
144
+ function processIncludes(includes, model, parentAs = "") {
145
+ includes.forEach((include, index) => {
146
+ const association = model.associations[include.association];
147
+ if (association == null ? void 0 : association.generateInclude) {
148
+ includes[index] = {
149
+ ...include,
150
+ ...association.generateInclude(parentAs)
151
+ };
152
+ }
153
+ if (include.include && Array.isArray(include.include) && include.include.length > 0) {
154
+ const nextModel = association == null ? void 0 : association.target;
155
+ if (!nextModel) {
156
+ return;
157
+ }
158
+ processIncludes(include.include, nextModel, parentAs ? `${parentAs}->${association.as}` : association.as);
159
+ }
160
+ });
161
+ return includes;
162
+ }
163
+ __name(processIncludes, "processIncludes");
143
164
  // Annotate the CommonJS export names for ESM import in node:
144
165
  0 && (module.exports = {
145
166
  checkIdentifier,
@@ -150,5 +171,6 @@ __name(getKeysByPrefix, "getKeysByPrefix");
150
171
  md5,
151
172
  patchSequelizeQueryInterface,
152
173
  percent2float,
174
+ processIncludes,
153
175
  snakeCase
154
176
  });
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@nocobase/database",
3
- "version": "1.9.0-beta.5",
3
+ "version": "1.9.0-beta.7",
4
4
  "description": "",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
7
7
  "license": "AGPL-3.0",
8
8
  "dependencies": {
9
- "@nocobase/logger": "1.9.0-beta.5",
10
- "@nocobase/utils": "1.9.0-beta.5",
9
+ "@nocobase/logger": "1.9.0-beta.7",
10
+ "@nocobase/utils": "1.9.0-beta.7",
11
11
  "async-mutex": "^0.3.2",
12
12
  "chalk": "^4.1.1",
13
13
  "cron-parser": "4.4.0",
@@ -38,5 +38,5 @@
38
38
  "url": "git+https://github.com/nocobase/nocobase.git",
39
39
  "directory": "packages/database"
40
40
  },
41
- "gitHead": "9a61c60dd3db5af64244e82447309b0cb17aabb6"
41
+ "gitHead": "4a5055c973b51611d5db1604aaaf6c1b73b4733c"
42
42
  }