@tachybase/database 1.6.13 → 1.6.14
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/database.js +15 -6
- package/lib/fields/sort-field.js +97 -76
- package/package.json +4 -4
package/lib/database.js
CHANGED
|
@@ -541,14 +541,23 @@ const _Database = class _Database extends import_node_events.EventEmitter {
|
|
|
541
541
|
if (isMySQL) {
|
|
542
542
|
await this.sequelize.query("SET FOREIGN_KEY_CHECKS = 0", null);
|
|
543
543
|
}
|
|
544
|
-
|
|
545
|
-
|
|
544
|
+
const isSQLite = this.inDialect("sqlite");
|
|
545
|
+
if (isSQLite) {
|
|
546
|
+
await this.sequelize.query("PRAGMA foreign_keys = OFF");
|
|
546
547
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
548
|
+
try {
|
|
549
|
+
if (this.options.schema && this.inDialect("postgres")) {
|
|
550
|
+
await this.sequelize.query(`CREATE SCHEMA IF NOT EXISTS "${this.options.schema}"`, null);
|
|
551
|
+
}
|
|
552
|
+
return await this.sequelize.sync(options);
|
|
553
|
+
} finally {
|
|
554
|
+
if (isMySQL) {
|
|
555
|
+
await this.sequelize.query("SET FOREIGN_KEY_CHECKS = 1", null);
|
|
556
|
+
}
|
|
557
|
+
if (isSQLite) {
|
|
558
|
+
await this.sequelize.query("PRAGMA foreign_keys = ON");
|
|
559
|
+
}
|
|
550
560
|
}
|
|
551
|
-
return result;
|
|
552
561
|
}
|
|
553
562
|
async clean(options) {
|
|
554
563
|
const { drop, ...others } = options || {};
|
package/lib/fields/sort-field.js
CHANGED
|
@@ -55,58 +55,60 @@ const _SortField = class _SortField extends import_field.Field {
|
|
|
55
55
|
}
|
|
56
56
|
}, "onScopeChange");
|
|
57
57
|
this.initRecordsSortValue = /* @__PURE__ */ __name(async ({ transaction }) => {
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (model.rawAttributes["createdAt"]) {
|
|
64
|
-
return model.rawAttributes["createdAt"].field;
|
|
65
|
-
}
|
|
66
|
-
throw new Error(`can not find order key for collection ${this.collection.name}`);
|
|
67
|
-
})();
|
|
68
|
-
const needInit = /* @__PURE__ */ __name(async (scopeKey2 = null, scopeValue = null) => {
|
|
69
|
-
const filter = {};
|
|
70
|
-
if (scopeKey2 && scopeValue) {
|
|
71
|
-
filter[scopeKey2] = scopeValue;
|
|
72
|
-
}
|
|
73
|
-
const totalCount = await this.collection.repository.count({
|
|
74
|
-
filter,
|
|
75
|
-
transaction
|
|
76
|
-
});
|
|
77
|
-
const emptyCount = await this.collection.repository.count({
|
|
78
|
-
filter: {
|
|
79
|
-
[this.name]: null,
|
|
80
|
-
...filter
|
|
81
|
-
},
|
|
82
|
-
transaction
|
|
83
|
-
});
|
|
84
|
-
return emptyCount === totalCount && emptyCount > 0;
|
|
85
|
-
}, "needInit");
|
|
86
|
-
const doInit = /* @__PURE__ */ __name(async (scopeKey2 = null, scopeValue = null) => {
|
|
87
|
-
const queryInterface = this.collection.db.sequelize.getQueryInterface();
|
|
88
|
-
if (scopeKey2) {
|
|
89
|
-
const scopeAttribute = this.collection.model.rawAttributes[scopeKey2];
|
|
90
|
-
if (!scopeAttribute) {
|
|
91
|
-
throw new Error(`can not find scope field ${scopeKey2} for collection ${this.collection.name}`);
|
|
58
|
+
try {
|
|
59
|
+
const orderField = (() => {
|
|
60
|
+
const model = this.collection.model;
|
|
61
|
+
if (model.primaryKeyAttribute) {
|
|
62
|
+
return model.primaryKeyAttribute;
|
|
92
63
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
if (
|
|
101
|
-
|
|
64
|
+
if (model.rawAttributes["createdAt"]) {
|
|
65
|
+
return model.rawAttributes["createdAt"].field;
|
|
66
|
+
}
|
|
67
|
+
throw new Error(`can not find order key for collection ${this.collection.name}`);
|
|
68
|
+
})();
|
|
69
|
+
const needInit = /* @__PURE__ */ __name(async (scopeKey2 = null, scopeValue = null) => {
|
|
70
|
+
const filter = {};
|
|
71
|
+
if (scopeKey2 != null && scopeValue != null) {
|
|
72
|
+
filter[scopeKey2] = scopeValue;
|
|
102
73
|
}
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
74
|
+
const totalCount = await this.collection.repository.count({
|
|
75
|
+
filter,
|
|
76
|
+
transaction
|
|
77
|
+
});
|
|
78
|
+
const emptyCount = await this.collection.repository.count({
|
|
79
|
+
filter: {
|
|
80
|
+
[this.name]: null,
|
|
81
|
+
...filter
|
|
82
|
+
},
|
|
83
|
+
transaction
|
|
84
|
+
});
|
|
85
|
+
return emptyCount === totalCount && emptyCount > 0;
|
|
86
|
+
}, "needInit");
|
|
87
|
+
const doInit = /* @__PURE__ */ __name(async (scopeKey2 = null, scopeValue = null) => {
|
|
88
|
+
const queryInterface = this.collection.db.sequelize.getQueryInterface();
|
|
89
|
+
const escape = this.collection.db.sequelize.escape.bind(this.collection.db.sequelize);
|
|
90
|
+
if (scopeKey2) {
|
|
91
|
+
const scopeAttribute = this.collection.model.rawAttributes[scopeKey2];
|
|
92
|
+
if (!scopeAttribute) {
|
|
93
|
+
throw new Error(`can not find scope field ${scopeKey2} for collection ${this.collection.name}`);
|
|
94
|
+
}
|
|
95
|
+
scopeKey2 = scopeAttribute.field;
|
|
96
|
+
}
|
|
97
|
+
const quotedOrderField = queryInterface.quoteIdentifier(orderField);
|
|
98
|
+
const sortColumnName = queryInterface.quoteIdentifier(this.collection.model.rawAttributes[this.name].field);
|
|
99
|
+
let sql;
|
|
100
|
+
const whereClause = scopeKey2 != null && scopeValue != null ? (() => {
|
|
101
|
+
const filteredScopeValue = scopeValue.filter((v) => v !== null);
|
|
102
|
+
if (filteredScopeValue.length === 0) {
|
|
103
|
+
return "";
|
|
104
|
+
}
|
|
105
|
+
const initialClause = `
|
|
106
|
+
WHERE ${queryInterface.quoteIdentifier(scopeKey2)} IN (${filteredScopeValue.map((v) => escape(v)).join(", ")})`;
|
|
107
|
+
const nullCheck = scopeValue.includes(null) ? ` OR ${queryInterface.quoteIdentifier(scopeKey2)} IS NULL` : "";
|
|
108
|
+
return initialClause + nullCheck;
|
|
109
|
+
})() : "";
|
|
110
|
+
if (this.collection.db.inDialect("postgres")) {
|
|
111
|
+
sql = `
|
|
110
112
|
UPDATE ${this.collection.quotedTableName()}
|
|
111
113
|
SET ${sortColumnName} = ordered_table.new_sequence_number
|
|
112
114
|
FROM (
|
|
@@ -116,8 +118,17 @@ const _SortField = class _SortField extends import_field.Field {
|
|
|
116
118
|
) AS ordered_table
|
|
117
119
|
WHERE ${this.collection.quotedTableName()}.${quotedOrderField} = ordered_table.${quotedOrderField};
|
|
118
120
|
`;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
} else if (this.collection.db.inDialect("sqlite")) {
|
|
122
|
+
const outerWhere = scopeKey2 && scopeValue ? (() => {
|
|
123
|
+
const filtered = scopeValue.filter((v) => v !== null);
|
|
124
|
+
if (filtered.length === 0) return "";
|
|
125
|
+
let clause = `WHERE ${queryInterface.quoteIdentifier(scopeKey2)} IN (${filtered.map((v) => escape(v)).join(", ")})`;
|
|
126
|
+
if (scopeValue.includes(null)) {
|
|
127
|
+
clause += ` OR ${queryInterface.quoteIdentifier(scopeKey2)} IS NULL`;
|
|
128
|
+
}
|
|
129
|
+
return clause;
|
|
130
|
+
})() : "";
|
|
131
|
+
sql = `
|
|
121
132
|
UPDATE ${this.collection.quotedTableName()}
|
|
122
133
|
SET ${sortColumnName} = (
|
|
123
134
|
SELECT new_sequence_number
|
|
@@ -127,10 +138,11 @@ const _SortField = class _SortField extends import_field.Field {
|
|
|
127
138
|
${whereClause}
|
|
128
139
|
) AS ordered_table
|
|
129
140
|
WHERE ${this.collection.quotedTableName()}.${quotedOrderField} = ordered_table.${quotedOrderField}
|
|
130
|
-
)
|
|
141
|
+
)
|
|
142
|
+
${outerWhere};
|
|
131
143
|
`;
|
|
132
|
-
|
|
133
|
-
|
|
144
|
+
} else if (this.collection.db.inDialect("mysql") || this.collection.db.inDialect("mariadb")) {
|
|
145
|
+
sql = `
|
|
134
146
|
UPDATE ${this.collection.quotedTableName()}
|
|
135
147
|
JOIN (
|
|
136
148
|
SELECT *, ROW_NUMBER() OVER (${scopeKey2 ? `PARTITION BY ${queryInterface.quoteIdentifier(scopeKey2)}` : ""} ORDER BY ${quotedOrderField}) AS new_sequence_number
|
|
@@ -139,30 +151,39 @@ const _SortField = class _SortField extends import_field.Field {
|
|
|
139
151
|
) AS ordered_table ON ${this.collection.quotedTableName()}.${quotedOrderField} = ordered_table.${quotedOrderField}
|
|
140
152
|
SET ${this.collection.quotedTableName()}.${sortColumnName} = ordered_table.new_sequence_number;
|
|
141
153
|
`;
|
|
142
|
-
}
|
|
143
|
-
await this.collection.db.sequelize.query(sql, {
|
|
144
|
-
transaction
|
|
145
|
-
});
|
|
146
|
-
}, "doInit");
|
|
147
|
-
const scopeKey = this.options.scopeKey;
|
|
148
|
-
if (scopeKey) {
|
|
149
|
-
const groups = await this.collection.repository.find({
|
|
150
|
-
attributes: [scopeKey],
|
|
151
|
-
group: [scopeKey],
|
|
152
|
-
raw: true,
|
|
153
|
-
transaction
|
|
154
|
-
});
|
|
155
|
-
const needInitGroups = [];
|
|
156
|
-
for (const group of groups) {
|
|
157
|
-
if (await needInit(scopeKey, group[scopeKey])) {
|
|
158
|
-
needInitGroups.push(group[scopeKey]);
|
|
159
154
|
}
|
|
155
|
+
await this.collection.db.sequelize.query(sql, {
|
|
156
|
+
transaction
|
|
157
|
+
});
|
|
158
|
+
}, "doInit");
|
|
159
|
+
const scopeKey = this.options.scopeKey;
|
|
160
|
+
if (scopeKey) {
|
|
161
|
+
const groups = await this.collection.repository.find({
|
|
162
|
+
attributes: [scopeKey],
|
|
163
|
+
group: [scopeKey],
|
|
164
|
+
raw: true,
|
|
165
|
+
transaction
|
|
166
|
+
});
|
|
167
|
+
const needInitGroups = [];
|
|
168
|
+
for (const group of groups) {
|
|
169
|
+
if (await needInit(scopeKey, group[scopeKey])) {
|
|
170
|
+
needInitGroups.push(group[scopeKey]);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (needInitGroups.length > 0) {
|
|
174
|
+
await doInit(scopeKey, needInitGroups);
|
|
175
|
+
}
|
|
176
|
+
} else if (await needInit()) {
|
|
177
|
+
await doInit();
|
|
160
178
|
}
|
|
161
|
-
|
|
162
|
-
|
|
179
|
+
} catch (err) {
|
|
180
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
181
|
+
const isMissingTable = /no such table|relation .* does not exist|Table .* doesn't exist|No description found|SQLITE_ERROR/i.test(
|
|
182
|
+
msg
|
|
183
|
+
);
|
|
184
|
+
if (!isMissingTable) {
|
|
185
|
+
throw err;
|
|
163
186
|
}
|
|
164
|
-
} else if (await needInit()) {
|
|
165
|
-
await doInit();
|
|
166
187
|
}
|
|
167
188
|
}, "initRecordsSortValue");
|
|
168
189
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tachybase/database",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.14",
|
|
4
4
|
"description": "",
|
|
5
5
|
"homepage": "https://github.com/tegojs/tego#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"semver": "7.7.2",
|
|
32
32
|
"sequelize": "^6.37.7",
|
|
33
33
|
"umzug": "^3.8.2",
|
|
34
|
-
"@tachybase/
|
|
35
|
-
"@tachybase/
|
|
36
|
-
"@tachybase/
|
|
34
|
+
"@tachybase/globals": "1.6.14",
|
|
35
|
+
"@tachybase/logger": "1.6.14",
|
|
36
|
+
"@tachybase/utils": "1.6.14"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/flat": "^5.0.5",
|