@nocobase/database 1.7.0-beta.9 → 1.8.0-beta.1
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/belongs-to-array/belongs-to-array-repository.d.ts +2 -2
- package/lib/belongs-to-array/belongs-to-array-repository.js +6 -7
- package/lib/cursor-builder.d.ts +38 -0
- package/lib/cursor-builder.js +307 -0
- package/lib/dialects/mariadb-dialect.d.ts +2 -0
- package/lib/dialects/mariadb-dialect.js +4 -0
- package/lib/eager-loading/eager-loading-tree.js +20 -10
- package/lib/fields/array-field.d.ts +1 -1
- package/lib/fields/array-field.js +12 -7
- package/lib/fields/date-field.js +14 -9
- package/lib/fields/datetime-no-tz-field.d.ts +1 -1
- package/lib/fields/datetime-no-tz-field.js +24 -18
- package/lib/fields/encryption-field/encryption-field.js +2 -0
- package/lib/fields/nanoid-field.js +12 -5
- package/lib/fields/set-field.d.ts +1 -1
- package/lib/fields/set-field.js +9 -4
- package/lib/fields/string-field.d.ts +4 -0
- package/lib/fields/string-field.js +18 -0
- package/lib/fields/text-field.d.ts +4 -0
- package/lib/fields/text-field.js +18 -0
- package/lib/fields/uuid-field.js +11 -4
- package/lib/index.d.ts +1 -0
- package/lib/index.js +3 -1
- package/lib/interfaces/index.d.ts +1 -0
- package/lib/interfaces/index.js +3 -1
- package/lib/interfaces/input-interface.d.ts +13 -0
- package/lib/interfaces/input-interface.js +64 -0
- package/lib/interfaces/time-interface.d.ts +13 -0
- package/lib/interfaces/time-interface.js +65 -0
- package/lib/interfaces/utils.js +4 -1
- package/lib/options-parser.d.ts +3 -1
- package/lib/options-parser.js +3 -2
- package/lib/query-interface/mysql-query-interface.d.ts +1 -0
- package/lib/query-interface/mysql-query-interface.js +3 -0
- package/lib/query-interface/postgres-query-interface.d.ts +1 -0
- package/lib/query-interface/postgres-query-interface.js +3 -0
- package/lib/query-interface/query-interface.d.ts +1 -0
- package/lib/query-interface/query-interface.js +4 -0
- package/lib/query-interface/sqlite-query-interface.d.ts +1 -0
- package/lib/query-interface/sqlite-query-interface.js +3 -0
- package/lib/relation-repository/hasmany-repository.js +7 -1
- package/lib/relation-repository/multiple-relation-repository.d.ts +4 -1
- package/lib/relation-repository/multiple-relation-repository.js +2 -2
- package/lib/repository.d.ts +21 -0
- package/lib/repository.js +30 -4
- package/lib/view-collection.js +1 -1
- package/package.json +6 -6
|
@@ -31,8 +31,8 @@ export declare class BelongsToArrayAssociation {
|
|
|
31
31
|
targetKey: string;
|
|
32
32
|
});
|
|
33
33
|
get target(): import("sequelize/types").ModelStatic<Model<any, any>>;
|
|
34
|
-
generateInclude(): {
|
|
35
|
-
on:
|
|
34
|
+
generateInclude(parentAs?: string): {
|
|
35
|
+
on: void;
|
|
36
36
|
};
|
|
37
37
|
update(instance: Model, value: any, options?: UpdateAssociationOptions): Promise<void>;
|
|
38
38
|
}
|
|
@@ -78,19 +78,18 @@ const _BelongsToArrayAssociation = class _BelongsToArrayAssociation {
|
|
|
78
78
|
get target() {
|
|
79
79
|
return this.db.getModel(this.targetName);
|
|
80
80
|
}
|
|
81
|
-
generateInclude() {
|
|
82
|
-
if (this.db.sequelize.getDialect() !== "postgres") {
|
|
83
|
-
throw new Error("Filtering by many to many (array) associations is only supported on postgres");
|
|
84
|
-
}
|
|
81
|
+
generateInclude(parentAs) {
|
|
85
82
|
const targetCollection = this.db.getCollection(this.targetName);
|
|
86
83
|
const targetField = targetCollection.getField(this.targetKey);
|
|
87
84
|
const sourceCollection = this.db.getCollection(this.source.name);
|
|
88
85
|
const foreignField = sourceCollection.getField(this.foreignKey);
|
|
89
86
|
const queryInterface = this.db.sequelize.getQueryInterface();
|
|
90
|
-
const
|
|
91
|
-
const
|
|
87
|
+
const asLeft = parentAs ? `${parentAs}->${this.as}` : this.as;
|
|
88
|
+
const asRight = parentAs || this.source.collection.name;
|
|
89
|
+
const left = queryInterface.quoteIdentifiers(`${asLeft}.${targetField.columnName()}`);
|
|
90
|
+
const right = queryInterface.quoteIdentifiers(`${asRight}.${foreignField.columnName()}`);
|
|
92
91
|
return {
|
|
93
|
-
on: this.db.
|
|
92
|
+
on: this.db.queryInterface.generateJoinOnForJSONArray(left, right)
|
|
94
93
|
};
|
|
95
94
|
}
|
|
96
95
|
async update(instance, value, options = {}) {
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
import { Sequelize } from 'sequelize';
|
|
10
|
+
import { FindOptions } from './repository';
|
|
11
|
+
import { Model } from './model';
|
|
12
|
+
import { Collection } from './collection';
|
|
13
|
+
export declare class SmartCursorBuilder {
|
|
14
|
+
private sequelize;
|
|
15
|
+
private tableName;
|
|
16
|
+
private collection;
|
|
17
|
+
constructor(sequelize: Sequelize, tableName: string, collection: Collection);
|
|
18
|
+
/**
|
|
19
|
+
* 根据表结构自动选择最优游标策略
|
|
20
|
+
*/
|
|
21
|
+
private getBestCursorStrategy;
|
|
22
|
+
/**
|
|
23
|
+
* Cursor-based pagination query function.
|
|
24
|
+
* Ideal for large datasets (e.g., millions of rows)
|
|
25
|
+
* Note:
|
|
26
|
+
* 1. does not support jumping to arbitrary pages (e.g., "Page 5")
|
|
27
|
+
* 2. Requires a stable, indexed sort field (e.g. ID, createdAt)
|
|
28
|
+
* 3. If custom orderBy is used, it must match the cursor field(s) and direction, otherwise results may be incorrect or unstable.
|
|
29
|
+
* @param options
|
|
30
|
+
*/
|
|
31
|
+
chunk(options: FindOptions & {
|
|
32
|
+
chunkSize: number;
|
|
33
|
+
callback: (rows: Model[], options: FindOptions) => Promise<void>;
|
|
34
|
+
find: (options: FindOptions) => Promise<any[]>;
|
|
35
|
+
beforeFind?: (options: FindOptions) => Promise<void>;
|
|
36
|
+
afterFind?: (rows: Model[], options: FindOptions) => Promise<void>;
|
|
37
|
+
}): Promise<void>;
|
|
38
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
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 __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
20
|
+
};
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(from))
|
|
24
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
25
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
26
|
+
}
|
|
27
|
+
return to;
|
|
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
|
+
));
|
|
37
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
|
+
var cursor_builder_exports = {};
|
|
39
|
+
__export(cursor_builder_exports, {
|
|
40
|
+
SmartCursorBuilder: () => SmartCursorBuilder
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(cursor_builder_exports);
|
|
43
|
+
var import_sequelize = require("sequelize");
|
|
44
|
+
var import_lodash = __toESM(require("lodash"));
|
|
45
|
+
const _SmartCursorBuilder = class _SmartCursorBuilder {
|
|
46
|
+
sequelize;
|
|
47
|
+
tableName;
|
|
48
|
+
collection;
|
|
49
|
+
constructor(sequelize, tableName, collection) {
|
|
50
|
+
this.sequelize = sequelize;
|
|
51
|
+
this.tableName = tableName;
|
|
52
|
+
this.collection = collection;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 根据表结构自动选择最优游标策略
|
|
56
|
+
*/
|
|
57
|
+
async getBestCursorStrategy() {
|
|
58
|
+
let indexInfoSql = "";
|
|
59
|
+
const dialect = this.sequelize.getDialect();
|
|
60
|
+
if (dialect === "postgres") {
|
|
61
|
+
indexInfoSql = `
|
|
62
|
+
SELECT
|
|
63
|
+
t.relname AS table_name,
|
|
64
|
+
i.relname AS index_name,
|
|
65
|
+
a.attname AS column_name,
|
|
66
|
+
array_position(ix.indkey, a.attnum) + 1 AS seq_in_index,
|
|
67
|
+
CASE
|
|
68
|
+
WHEN ix.indisprimary THEN 1
|
|
69
|
+
WHEN ix.indisunique THEN 2
|
|
70
|
+
ELSE 3
|
|
71
|
+
END AS index_type,
|
|
72
|
+
-- \u5224\u65AD\u7D22\u5F15\u6392\u5E8F\u65B9\u5411 (0=ASC, 1=DESC)
|
|
73
|
+
CASE WHEN (ix.indoption[array_position(ix.indkey, a.attnum) - 1] & 1) = 1
|
|
74
|
+
THEN 'DESC' ELSE 'ASC'
|
|
75
|
+
END AS direction
|
|
76
|
+
FROM
|
|
77
|
+
pg_class t,
|
|
78
|
+
pg_class i,
|
|
79
|
+
pg_index ix,
|
|
80
|
+
pg_attribute a,
|
|
81
|
+
pg_namespace n
|
|
82
|
+
WHERE
|
|
83
|
+
t.oid = ix.indrelid
|
|
84
|
+
AND i.oid = ix.indexrelid
|
|
85
|
+
AND a.attrelid = t.oid
|
|
86
|
+
AND t.relnamespace = n.oid
|
|
87
|
+
AND a.attnum = ANY(ix.indkey)
|
|
88
|
+
AND t.relkind = 'r'
|
|
89
|
+
AND n.nspname = current_schema()
|
|
90
|
+
AND t.relname = $1
|
|
91
|
+
ORDER BY
|
|
92
|
+
i.relname,
|
|
93
|
+
array_position(ix.indkey, a.attnum)
|
|
94
|
+
`;
|
|
95
|
+
} else if (dialect === "mariadb" || dialect === "mysql") {
|
|
96
|
+
indexInfoSql = `
|
|
97
|
+
SELECT
|
|
98
|
+
i.TABLE_NAME,
|
|
99
|
+
i.INDEX_NAME,
|
|
100
|
+
i.COLUMN_NAME,
|
|
101
|
+
i.SEQ_IN_INDEX,
|
|
102
|
+
CASE
|
|
103
|
+
WHEN i.INDEX_NAME = 'PRIMARY' THEN 1
|
|
104
|
+
WHEN i.NON_UNIQUE = 0 THEN 2
|
|
105
|
+
ELSE 3
|
|
106
|
+
END as INDEX_TYPE
|
|
107
|
+
FROM
|
|
108
|
+
information_schema.STATISTICS i
|
|
109
|
+
WHERE
|
|
110
|
+
i.TABLE_SCHEMA = DATABASE()
|
|
111
|
+
AND i.TABLE_NAME = ?
|
|
112
|
+
ORDER BY
|
|
113
|
+
i.INDEX_NAME,
|
|
114
|
+
i.SEQ_IN_INDEX;
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
117
|
+
const indexRows = await this.sequelize.query(indexInfoSql, {
|
|
118
|
+
type: import_sequelize.QueryTypes.SELECT,
|
|
119
|
+
replacements: [this.tableName],
|
|
120
|
+
raw: true
|
|
121
|
+
});
|
|
122
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
123
|
+
const indexDirections = /* @__PURE__ */ new Map();
|
|
124
|
+
if (!indexRows || indexRows.length === 0) {
|
|
125
|
+
if (Array.isArray(this.collection.filterTargetKey)) {
|
|
126
|
+
return new CompositeKeyCursorStrategy(this.collection.filterTargetKey);
|
|
127
|
+
}
|
|
128
|
+
return new SingleColumnCursorStrategy(this.collection.filterTargetKey);
|
|
129
|
+
}
|
|
130
|
+
for (const row of indexRows) {
|
|
131
|
+
const indexName = dialect === "postgres" ? row.index_name : row.INDEX_NAME;
|
|
132
|
+
const columnName = dialect === "postgres" ? row.column_name : row.COLUMN_NAME;
|
|
133
|
+
const indexType = dialect === "postgres" ? row.index_type : row.INDEX_TYPE;
|
|
134
|
+
if (dialect === "postgres" && row.direction) {
|
|
135
|
+
if (!indexDirections.has(indexName)) {
|
|
136
|
+
indexDirections.set(indexName, /* @__PURE__ */ new Map());
|
|
137
|
+
}
|
|
138
|
+
indexDirections.get(indexName).set(columnName, row.direction);
|
|
139
|
+
}
|
|
140
|
+
if (!indexes.has(indexName)) {
|
|
141
|
+
indexes.set(indexName, {
|
|
142
|
+
name: indexName,
|
|
143
|
+
columns: [],
|
|
144
|
+
isPrimary: dialect === "postgres" ? indexType === 1 : indexName === "PRIMARY",
|
|
145
|
+
isUnique: indexType < 3
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const index = indexes.get(row.INDEX_NAME);
|
|
149
|
+
index.columns[row.SEQ_IN_INDEX - 1] = row.COLUMN_NAME;
|
|
150
|
+
}
|
|
151
|
+
for (const index of indexes.values()) {
|
|
152
|
+
if (index.isPrimary) {
|
|
153
|
+
if (index.columns.length === 1) {
|
|
154
|
+
return new SingleColumnCursorStrategy(index.columns[0]);
|
|
155
|
+
} else {
|
|
156
|
+
if (dialect === "postgres" && indexDirections.has(index.name)) {
|
|
157
|
+
const directions = index.columns.map((col) => indexDirections.get(index.name).get(col) || "ASC");
|
|
158
|
+
return new CompositeKeyCursorStrategy(index.columns, directions);
|
|
159
|
+
} else {
|
|
160
|
+
return new CompositeKeyCursorStrategy(index.columns);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
let singleColumnUniqueIndex = null;
|
|
166
|
+
let multiColumnUniqueIndex = null;
|
|
167
|
+
for (const index of indexes.values()) {
|
|
168
|
+
if (index.isUnique && !index.isPrimary) {
|
|
169
|
+
if (index.columns.length === 1 && !singleColumnUniqueIndex) {
|
|
170
|
+
singleColumnUniqueIndex = index;
|
|
171
|
+
} else if (index.columns.length > 1 && !multiColumnUniqueIndex) {
|
|
172
|
+
multiColumnUniqueIndex = index;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (singleColumnUniqueIndex) {
|
|
177
|
+
return new SingleColumnCursorStrategy(singleColumnUniqueIndex.columns[0]);
|
|
178
|
+
}
|
|
179
|
+
if (multiColumnUniqueIndex) {
|
|
180
|
+
return new CompositeKeyCursorStrategy(multiColumnUniqueIndex.columns);
|
|
181
|
+
}
|
|
182
|
+
let anyIndex = null;
|
|
183
|
+
for (const index of indexes.values()) {
|
|
184
|
+
if (index.columns.length > 0 && !index.isPrimary && !index.isUnique) {
|
|
185
|
+
anyIndex = index;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (anyIndex) {
|
|
190
|
+
if (anyIndex.columns.length === 1) {
|
|
191
|
+
return new SingleColumnCursorStrategy(anyIndex.columns[0]);
|
|
192
|
+
} else {
|
|
193
|
+
return new CompositeKeyCursorStrategy(anyIndex.columns);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Cursor-based pagination query function.
|
|
199
|
+
* Ideal for large datasets (e.g., millions of rows)
|
|
200
|
+
* Note:
|
|
201
|
+
* 1. does not support jumping to arbitrary pages (e.g., "Page 5")
|
|
202
|
+
* 2. Requires a stable, indexed sort field (e.g. ID, createdAt)
|
|
203
|
+
* 3. If custom orderBy is used, it must match the cursor field(s) and direction, otherwise results may be incorrect or unstable.
|
|
204
|
+
* @param options
|
|
205
|
+
*/
|
|
206
|
+
async chunk(options) {
|
|
207
|
+
const cursorStrategy = await this.getBestCursorStrategy();
|
|
208
|
+
let cursorRecord = null;
|
|
209
|
+
let hasMoreData = true;
|
|
210
|
+
let isFirst = true;
|
|
211
|
+
options.order = cursorStrategy.buildSort();
|
|
212
|
+
options["parseSort"] = false;
|
|
213
|
+
while (hasMoreData) {
|
|
214
|
+
if (!isFirst) {
|
|
215
|
+
options.where = cursorStrategy.buildWhere(options.where, cursorRecord);
|
|
216
|
+
}
|
|
217
|
+
if (isFirst) {
|
|
218
|
+
isFirst = false;
|
|
219
|
+
}
|
|
220
|
+
options.limit = options.chunkSize || 1e3;
|
|
221
|
+
if (options.beforeFind) {
|
|
222
|
+
await options.beforeFind(options);
|
|
223
|
+
}
|
|
224
|
+
const records = await options.find(import_lodash.default.omit(options, "callback", "beforeFind", "afterFind", "chunkSize", "find"));
|
|
225
|
+
if (options.afterFind) {
|
|
226
|
+
await options.afterFind(records, options);
|
|
227
|
+
}
|
|
228
|
+
if (records.length === 0) {
|
|
229
|
+
hasMoreData = false;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
await options.callback(records, options);
|
|
233
|
+
cursorRecord = records[records.length - 1];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
__name(_SmartCursorBuilder, "SmartCursorBuilder");
|
|
238
|
+
let SmartCursorBuilder = _SmartCursorBuilder;
|
|
239
|
+
const _SingleColumnCursorStrategy = class _SingleColumnCursorStrategy {
|
|
240
|
+
columnName;
|
|
241
|
+
constructor(columnName) {
|
|
242
|
+
this.columnName = columnName;
|
|
243
|
+
}
|
|
244
|
+
buildSort() {
|
|
245
|
+
return [[this.columnName, "ASC"]];
|
|
246
|
+
}
|
|
247
|
+
buildWhere(baseWhere, record) {
|
|
248
|
+
if (!record) {
|
|
249
|
+
return baseWhere;
|
|
250
|
+
}
|
|
251
|
+
return { ...baseWhere, [this.columnName]: { [import_sequelize.Op.gt]: record[this.columnName] } };
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
__name(_SingleColumnCursorStrategy, "SingleColumnCursorStrategy");
|
|
255
|
+
let SingleColumnCursorStrategy = _SingleColumnCursorStrategy;
|
|
256
|
+
const _CompositeKeyCursorStrategy = class _CompositeKeyCursorStrategy {
|
|
257
|
+
columns;
|
|
258
|
+
directions;
|
|
259
|
+
constructor(columns, directions) {
|
|
260
|
+
this.columns = columns;
|
|
261
|
+
this.directions = directions || Array(columns.length).fill("ASC");
|
|
262
|
+
}
|
|
263
|
+
buildSort() {
|
|
264
|
+
const orderBy = [];
|
|
265
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
266
|
+
orderBy.push([this.columns[i], this.directions[i]]);
|
|
267
|
+
}
|
|
268
|
+
return orderBy;
|
|
269
|
+
}
|
|
270
|
+
buildWhere(baseWhere, record) {
|
|
271
|
+
if (!record) {
|
|
272
|
+
return baseWhere;
|
|
273
|
+
}
|
|
274
|
+
const whereConditions = [];
|
|
275
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
276
|
+
const column = this.columns[i];
|
|
277
|
+
if (i > 0) {
|
|
278
|
+
const equalConditions = {};
|
|
279
|
+
for (let j = 0; j < i; j++) {
|
|
280
|
+
equalConditions[this.columns[j]] = record[this.columns[j]];
|
|
281
|
+
}
|
|
282
|
+
whereConditions.push({
|
|
283
|
+
...equalConditions,
|
|
284
|
+
[column]: {
|
|
285
|
+
[import_sequelize.Op.gt]: record[column]
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
} else {
|
|
289
|
+
whereConditions.push({
|
|
290
|
+
[column]: {
|
|
291
|
+
[import_sequelize.Op.gt]: record[column]
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
const cursorCondition = {
|
|
297
|
+
[import_sequelize.Op.or]: whereConditions
|
|
298
|
+
};
|
|
299
|
+
return baseWhere ? { [import_sequelize.Op.and]: [baseWhere, cursorCondition] } : cursorCondition;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
__name(_CompositeKeyCursorStrategy, "CompositeKeyCursorStrategy");
|
|
303
|
+
let CompositeKeyCursorStrategy = _CompositeKeyCursorStrategy;
|
|
304
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
305
|
+
0 && (module.exports = {
|
|
306
|
+
SmartCursorBuilder
|
|
307
|
+
});
|
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
+
import { DatabaseOptions } from '../database';
|
|
9
10
|
import { BaseDialect } from './base-dialect';
|
|
10
11
|
export declare class MariadbDialect extends BaseDialect {
|
|
11
12
|
static dialectName: string;
|
|
13
|
+
getSequelizeOptions(options: DatabaseOptions): import("../database").IDatabaseOptions;
|
|
12
14
|
getVersionGuard(): {
|
|
13
15
|
sql: string;
|
|
14
16
|
get: (v: string) => string;
|
|
@@ -34,6 +34,10 @@ __export(mariadb_dialect_exports, {
|
|
|
34
34
|
module.exports = __toCommonJS(mariadb_dialect_exports);
|
|
35
35
|
var import_base_dialect = require("./base-dialect");
|
|
36
36
|
const _MariadbDialect = class _MariadbDialect extends import_base_dialect.BaseDialect {
|
|
37
|
+
getSequelizeOptions(options) {
|
|
38
|
+
options.dialectOptions = { ...options.dialectOptions || {}, supportBigNumbers: true, bigNumberStrings: true };
|
|
39
|
+
return options;
|
|
40
|
+
}
|
|
37
41
|
getVersionGuard() {
|
|
38
42
|
return {
|
|
39
43
|
sql: "select version() as version",
|
|
@@ -85,6 +85,25 @@ const queryParentSQL = /* @__PURE__ */ __name((options) => {
|
|
|
85
85
|
)
|
|
86
86
|
SELECT ${q(targetKeyField)} AS ${q(targetKey)}, ${q(foreignKeyField)} AS ${q(foreignKey)} FROM cte`;
|
|
87
87
|
}, "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");
|
|
88
107
|
const _EagerLoadingTree = class _EagerLoadingTree {
|
|
89
108
|
root;
|
|
90
109
|
db;
|
|
@@ -208,22 +227,13 @@ const _EagerLoadingTree = class _EagerLoadingTree {
|
|
|
208
227
|
if (!primaryKeyField) {
|
|
209
228
|
throw new Error(`Model ${node.model.name} does not have primary key`);
|
|
210
229
|
}
|
|
211
|
-
includeForFilter.forEach((include, index) => {
|
|
212
|
-
const association = node.model.associations[include.association];
|
|
213
|
-
if ((association == null ? void 0 : association.associationType) == "BelongsToArray") {
|
|
214
|
-
includeForFilter[index] = {
|
|
215
|
-
...include,
|
|
216
|
-
...association.generateInclude()
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
230
|
const ids2 = (await node.model.findAll({
|
|
221
231
|
...this.rootQueryOptions,
|
|
222
232
|
includeIgnoreAttributes: false,
|
|
223
233
|
attributes: [primaryKeyField],
|
|
224
234
|
group: `${node.model.name}.${primaryKeyField}`,
|
|
225
235
|
transaction,
|
|
226
|
-
include: includeForFilter
|
|
236
|
+
include: processIncludes(includeForFilter, node.model)
|
|
227
237
|
})).map((row) => {
|
|
228
238
|
return { row, pk: row[primaryKeyField] };
|
|
229
239
|
});
|
|
@@ -10,7 +10,7 @@ import { DataTypes } from 'sequelize';
|
|
|
10
10
|
import { BaseColumnFieldOptions, Field } from './field';
|
|
11
11
|
export declare class ArrayField extends Field {
|
|
12
12
|
get dataType(): DataTypes.AbstractDataTypeConstructor | DataTypes.ArrayDataType<any>;
|
|
13
|
-
sortValue: (
|
|
13
|
+
sortValue: (instances: any) => void;
|
|
14
14
|
bind(): void;
|
|
15
15
|
unbind(): void;
|
|
16
16
|
}
|
|
@@ -43,23 +43,28 @@ const _ArrayField = class _ArrayField extends import_field.Field {
|
|
|
43
43
|
}
|
|
44
44
|
return import_sequelize.DataTypes.JSON;
|
|
45
45
|
}
|
|
46
|
-
sortValue = /* @__PURE__ */ __name((
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
sortValue = /* @__PURE__ */ __name((instances) => {
|
|
47
|
+
instances = Array.isArray(instances) ? instances : [instances];
|
|
48
|
+
for (const instance of instances) {
|
|
49
|
+
let oldValue = instance.get(this.options.name);
|
|
50
|
+
if (oldValue) {
|
|
51
|
+
if (typeof oldValue === "string") {
|
|
52
|
+
oldValue = JSON.parse(oldValue);
|
|
53
|
+
}
|
|
54
|
+
const newValue = oldValue.sort();
|
|
55
|
+
instance.set(this.options.name, newValue);
|
|
51
56
|
}
|
|
52
|
-
const newValue = oldValue.sort();
|
|
53
|
-
model.set(this.options.name, newValue);
|
|
54
57
|
}
|
|
55
58
|
}, "sortValue");
|
|
56
59
|
bind() {
|
|
57
60
|
super.bind();
|
|
58
61
|
this.on("beforeSave", this.sortValue);
|
|
62
|
+
this.on("beforeBulkCreate", this.sortValue);
|
|
59
63
|
}
|
|
60
64
|
unbind() {
|
|
61
65
|
super.unbind();
|
|
62
66
|
this.off("beforeSave", this.sortValue);
|
|
67
|
+
this.off("beforeBulkCreate", this.sortValue);
|
|
63
68
|
}
|
|
64
69
|
};
|
|
65
70
|
__name(_ArrayField, "ArrayField");
|
package/lib/fields/date-field.js
CHANGED
|
@@ -82,15 +82,18 @@ const _DateField = class _DateField extends import_field.Field {
|
|
|
82
82
|
}
|
|
83
83
|
return serverTimeZone;
|
|
84
84
|
};
|
|
85
|
-
this.beforeSave = async (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
instance.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
this.beforeSave = async (instances, options) => {
|
|
86
|
+
instances = Array.isArray(instances) ? instances : [instances];
|
|
87
|
+
for (const instance of instances) {
|
|
88
|
+
const value = instance.get(name);
|
|
89
|
+
if (!value && instance.isNewRecord && defaultToCurrentTime) {
|
|
90
|
+
instance.set(name, /* @__PURE__ */ new Date());
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (onUpdateToCurrentTime) {
|
|
94
|
+
instance.set(name, /* @__PURE__ */ new Date());
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
94
97
|
}
|
|
95
98
|
};
|
|
96
99
|
if (this.options.defaultValue && this.database.isMySQLCompatibleDialect()) {
|
|
@@ -143,10 +146,12 @@ const _DateField = class _DateField extends import_field.Field {
|
|
|
143
146
|
model.refreshAttributes();
|
|
144
147
|
}
|
|
145
148
|
this.on("beforeSave", this.beforeSave);
|
|
149
|
+
this.on("beforeBulkCreate", this.beforeSave);
|
|
146
150
|
}
|
|
147
151
|
unbind() {
|
|
148
152
|
super.unbind();
|
|
149
153
|
this.off("beforeSave", this.beforeSave);
|
|
154
|
+
this.off("beforeBulkCreate", this.beforeSave);
|
|
150
155
|
}
|
|
151
156
|
};
|
|
152
157
|
__name(_DateField, "DateField");
|
|
@@ -13,7 +13,7 @@ declare class DatetimeNoTzTypeMySQL extends DataTypes.ABSTRACT {
|
|
|
13
13
|
}
|
|
14
14
|
export declare class DatetimeNoTzField extends Field {
|
|
15
15
|
get dataType(): typeof DatetimeNoTzTypeMySQL;
|
|
16
|
-
|
|
16
|
+
beforeSave: (instances: any, options: any) => Promise<void>;
|
|
17
17
|
additionalSequelizeOptions(): {};
|
|
18
18
|
bind(): void;
|
|
19
19
|
unbind(): void;
|
|
@@ -61,58 +61,64 @@ const _DatetimeNoTzField = class _DatetimeNoTzField extends import_field.Field {
|
|
|
61
61
|
if (this.database.isMySQLCompatibleDialect()) {
|
|
62
62
|
return DatetimeNoTzTypeMySQL;
|
|
63
63
|
}
|
|
64
|
-
return import_sequelize.DataTypes.
|
|
64
|
+
return import_sequelize.DataTypes.DATE;
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
beforeSave = /* @__PURE__ */ __name(async (instances, options) => {
|
|
67
|
+
instances = Array.isArray(instances) ? instances : [instances];
|
|
67
68
|
const { name, defaultToCurrentTime, onUpdateToCurrentTime } = this.options;
|
|
68
|
-
|
|
69
|
+
for (const instance of instances) {
|
|
69
70
|
const value = instance.get(name);
|
|
70
71
|
if (!value && instance.isNewRecord && defaultToCurrentTime) {
|
|
71
72
|
instance.set(name, /* @__PURE__ */ new Date());
|
|
72
|
-
|
|
73
|
+
continue;
|
|
73
74
|
}
|
|
74
75
|
if (onUpdateToCurrentTime) {
|
|
75
76
|
instance.set(name, /* @__PURE__ */ new Date());
|
|
76
|
-
|
|
77
|
+
continue;
|
|
77
78
|
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
79
|
+
}
|
|
80
|
+
}, "beforeSave");
|
|
80
81
|
additionalSequelizeOptions() {
|
|
81
82
|
const { name } = this.options;
|
|
82
83
|
const timezone = this.database.options.rawTimezone || "+00:00";
|
|
83
84
|
const isPg = this.database.inDialect("postgres");
|
|
85
|
+
const isMySQLCompatibleDialect = this.database.isMySQLCompatibleDialect();
|
|
84
86
|
return {
|
|
85
87
|
get() {
|
|
86
88
|
const val = this.getDataValue(name);
|
|
87
89
|
if (val instanceof Date) {
|
|
88
|
-
|
|
89
|
-
return (0, import_moment.default)(val).format("YYYY-MM-DD HH:mm:ss");
|
|
90
|
-
}
|
|
91
|
-
const momentVal = (0, import_moment.default)(val).utcOffset(timezone);
|
|
90
|
+
const momentVal = (0, import_moment.default)(val);
|
|
92
91
|
return momentVal.format("YYYY-MM-DD HH:mm:ss");
|
|
93
92
|
}
|
|
94
93
|
return val;
|
|
95
94
|
},
|
|
96
95
|
set(val) {
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
if (val == null) {
|
|
97
|
+
return this.setDataValue(name, null);
|
|
98
|
+
}
|
|
99
|
+
const dateOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset();
|
|
100
|
+
const momentVal = (0, import_moment.default)(val);
|
|
101
|
+
if (typeof val === "string" && isIso8601(val) || val instanceof Date) {
|
|
102
|
+
momentVal.utcOffset(timezone);
|
|
103
|
+
momentVal.utcOffset(-dateOffset, true);
|
|
100
104
|
}
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
val = momentVal.format("YYYY-MM-DD HH:mm:ss");
|
|
105
|
+
if (isMySQLCompatibleDialect) {
|
|
106
|
+
momentVal.millisecond(0);
|
|
104
107
|
}
|
|
105
|
-
|
|
108
|
+
const date = momentVal.toDate();
|
|
109
|
+
return this.setDataValue(name, date);
|
|
106
110
|
}
|
|
107
111
|
};
|
|
108
112
|
}
|
|
109
113
|
bind() {
|
|
110
114
|
super.bind();
|
|
111
115
|
this.on("beforeSave", this.beforeSave);
|
|
116
|
+
this.on("beforeBulkCreate", this.beforeSave);
|
|
112
117
|
}
|
|
113
118
|
unbind() {
|
|
114
119
|
super.unbind();
|
|
115
120
|
this.off("beforeSave", this.beforeSave);
|
|
121
|
+
this.off("beforeBulkCreate", this.beforeSave);
|
|
116
122
|
}
|
|
117
123
|
};
|
|
118
124
|
__name(_DatetimeNoTzField, "DatetimeNoTzField");
|
|
@@ -93,11 +93,13 @@ const _EncryptionField = class _EncryptionField extends import_field.Field {
|
|
|
93
93
|
super.bind();
|
|
94
94
|
this.on("afterFind", this.findListener);
|
|
95
95
|
this.on("beforeSave", this.writeListener);
|
|
96
|
+
this.on("beforeBulkCreate", this.writeListener);
|
|
96
97
|
}
|
|
97
98
|
unbind() {
|
|
98
99
|
super.unbind();
|
|
99
100
|
this.off("afterFind", this.findListener);
|
|
100
101
|
this.off("beforeSave", this.writeListener);
|
|
102
|
+
this.off("beforeBulkCreate", this.writeListener);
|
|
101
103
|
}
|
|
102
104
|
};
|
|
103
105
|
__name(_EncryptionField, "EncryptionField");
|