@pdg/drizzle-mysql 0.0.0-stage → 1.0.0
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/README.md +371 -2
- package/dist/@types/MySqlConditions.d.cts +20 -0
- package/dist/@types/MySqlConditions.d.ts +20 -0
- package/dist/@types/MySqlInsertValues.d.cts +7 -0
- package/dist/@types/MySqlInsertValues.d.ts +7 -0
- package/dist/@types/MySqlUpdateValues.d.cts +7 -0
- package/dist/@types/MySqlUpdateValues.d.ts +7 -0
- package/dist/@types/common.d.cts +16 -0
- package/dist/@types/common.d.ts +16 -0
- package/dist/@types/index.d.cts +4 -0
- package/dist/@types/index.d.ts +4 -0
- package/dist/MySqlQuery.d.cts +264 -0
- package/dist/MySqlQuery.d.ts +264 -0
- package/dist/alias.d.cts +6 -0
- package/dist/alias.d.ts +6 -0
- package/dist/columns.d.cts +89 -0
- package/dist/columns.d.ts +89 -0
- package/dist/conditions.d.cts +106 -0
- package/dist/conditions.d.ts +106 -0
- package/dist/drizzleMySql.d.cts +166 -0
- package/dist/drizzleMySql.d.ts +166 -0
- package/dist/index.cjs +666 -0
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.esm.js +666 -0
- package/package.json +88 -4
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
import mysql from'mysql2/promise';import {drizzle}from'drizzle-orm/mysql2';import*as native from'drizzle-orm';import {isTable,getTableColumns,sql,is,SQL,eq,and,count,defineRelations}from'drizzle-orm';export{asc,avg,avgDistinct,count,countDistinct,desc,exists,max,min,not,notExists,sum,sumDistinct}from'drizzle-orm';import {AsyncLocalStorage}from'node:async_hooks';import {alias}from'drizzle-orm/mysql-core/alias';import {MySqlTable,getTableConfig,MySqlColumn}from'drizzle-orm/mysql-core';export{bigint,binary,blob,boolean,char,check,customType,date,datetime,decimal,double,float,foreignKey,index,int,json,longblob,longtext,mediumblob,mediumint,mediumtext,mysqlDatabase,mysqlEnum,mysqlSchema,mysqlTable,mysqlTableCreator,mysqlView,primaryKey,real,serial,smallint,text,time,timestamp,tinyblob,tinyint,tinytext,unique,uniqueIndex,varbinary,varchar,year}from'drizzle-orm/mysql-core';function createAlias(schema) {
|
|
2
|
+
/********************************************************************************************************************
|
|
3
|
+
* getDefaultAlias
|
|
4
|
+
* ******************************************************************************************************************/
|
|
5
|
+
const getDefaultAlias = (tableName) => `${tableName[0]}${(tableName.slice(1).match(/[A-Z]/g) ?? []).join('')}`.toLowerCase();
|
|
6
|
+
/********************************************************************************************************************
|
|
7
|
+
* createAlias
|
|
8
|
+
* ******************************************************************************************************************/
|
|
9
|
+
const createAlias = (tableName) => (alias$1 = getDefaultAlias(tableName)) => alias(schema[tableName], alias$1);
|
|
10
|
+
/********************************************************************************************************************
|
|
11
|
+
* alias
|
|
12
|
+
* ******************************************************************************************************************/
|
|
13
|
+
const alias$1 = Object.fromEntries(Object.keys(schema).map((tableName) => [tableName, createAlias(tableName)]));
|
|
14
|
+
return alias$1;
|
|
15
|
+
}function createConditions(schema) {
|
|
16
|
+
const resolveTable = (table) => {
|
|
17
|
+
if (typeof table !== 'string')
|
|
18
|
+
return table;
|
|
19
|
+
if (!Object.hasOwn(schema, table)) {
|
|
20
|
+
throw new Error(`Condition: unknown table "${table}".`);
|
|
21
|
+
}
|
|
22
|
+
return schema[table];
|
|
23
|
+
};
|
|
24
|
+
const getColumn = (table, name) => {
|
|
25
|
+
const columns = native.getTableColumns(table);
|
|
26
|
+
if (!Object.hasOwn(columns, name)) {
|
|
27
|
+
throw new Error(`Condition: unknown column "${name}".`);
|
|
28
|
+
}
|
|
29
|
+
return columns[name];
|
|
30
|
+
};
|
|
31
|
+
const recordEntries = (values) => {
|
|
32
|
+
if (typeof values !== 'object' || values === null || Array.isArray(values)) {
|
|
33
|
+
throw new Error('Condition: expected a column/value object.');
|
|
34
|
+
}
|
|
35
|
+
return Object.entries(values);
|
|
36
|
+
};
|
|
37
|
+
const compareValue = (column, value, operator) => {
|
|
38
|
+
if (value === null) {
|
|
39
|
+
if (operator === 'eq')
|
|
40
|
+
return native.isNull(column);
|
|
41
|
+
if (operator === 'ne')
|
|
42
|
+
return native.isNotNull(column);
|
|
43
|
+
throw new Error(`${operator}: column "${column.name}" must not be null.`);
|
|
44
|
+
}
|
|
45
|
+
switch (operator) {
|
|
46
|
+
case 'eq':
|
|
47
|
+
return native.eq(column, value);
|
|
48
|
+
case 'ne':
|
|
49
|
+
return native.ne(column, value);
|
|
50
|
+
case 'gt':
|
|
51
|
+
return native.gt(column, value);
|
|
52
|
+
case 'gte':
|
|
53
|
+
return native.gte(column, value);
|
|
54
|
+
case 'lt':
|
|
55
|
+
return native.lt(column, value);
|
|
56
|
+
case 'lte':
|
|
57
|
+
return native.lte(column, value);
|
|
58
|
+
case 'inArray':
|
|
59
|
+
case 'notInArray':
|
|
60
|
+
if (!Array.isArray(value))
|
|
61
|
+
throw new Error(`${operator}: expected an array.`);
|
|
62
|
+
return operator === 'inArray' ? native.inArray(column, value) : native.notInArray(column, value);
|
|
63
|
+
case 'between':
|
|
64
|
+
case 'notBetween':
|
|
65
|
+
if (!Array.isArray(value) || value.length !== 2 || value.some((item) => item == null)) {
|
|
66
|
+
throw new Error(`${operator}: expected two non-null bounds.`);
|
|
67
|
+
}
|
|
68
|
+
return operator === 'between'
|
|
69
|
+
? native.between(column, value[0], value[1])
|
|
70
|
+
: native.notBetween(column, value[0], value[1]);
|
|
71
|
+
default:
|
|
72
|
+
if (typeof value !== 'string')
|
|
73
|
+
throw new Error(`${operator}: expected a string pattern.`);
|
|
74
|
+
return native[operator](column, value);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const valueConditions = (table, values, operator) => {
|
|
78
|
+
const conditions = [];
|
|
79
|
+
for (const [name, value] of recordEntries(values)) {
|
|
80
|
+
const column = getColumn(table, name);
|
|
81
|
+
if (value !== undefined)
|
|
82
|
+
conditions.push(compareValue(column, value, operator));
|
|
83
|
+
}
|
|
84
|
+
return conditions;
|
|
85
|
+
};
|
|
86
|
+
function extendOperator(original, objectOperator) {
|
|
87
|
+
return (...args) => {
|
|
88
|
+
if (typeof args[0] === 'string' || native.is(args[0], MySqlTable)) {
|
|
89
|
+
const table = typeof args[0] === 'string' ? resolveTable(args[0]) : args[0];
|
|
90
|
+
return objectOperator(table, args[1]);
|
|
91
|
+
}
|
|
92
|
+
return Reflect.apply(original, undefined, args);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const objectOperator = (operator) => (table, values) => native.and(...valueConditions(resolveTable(table), values, operator));
|
|
96
|
+
// Tables use object dispatch at runtime, not the native SQLWrapper/unknown overload.
|
|
97
|
+
const binaryOperator = (operator) => extendOperator(native[operator], objectOperator(operator));
|
|
98
|
+
const nullOperator = (operator) => ((table, input) => {
|
|
99
|
+
const names = typeof input === 'string' ? [input] : input === undefined ? [] : input;
|
|
100
|
+
if (!Array.isArray(names))
|
|
101
|
+
throw new Error(`${operator}: expected column names.`);
|
|
102
|
+
const conditions = [];
|
|
103
|
+
for (const name of names) {
|
|
104
|
+
if (name === undefined)
|
|
105
|
+
continue;
|
|
106
|
+
if (typeof name !== 'string')
|
|
107
|
+
throw new Error(`${operator}: expected a column name.`);
|
|
108
|
+
conditions.push(native[operator](getColumn(resolveTable(table), name)));
|
|
109
|
+
}
|
|
110
|
+
return native.and(...conditions);
|
|
111
|
+
});
|
|
112
|
+
const groupOperator = (operator) => (input, options) => {
|
|
113
|
+
const table = resolveTable(input);
|
|
114
|
+
const sqlConditions = [];
|
|
115
|
+
for (const [name, values] of recordEntries(options)) {
|
|
116
|
+
if (!Object.hasOwn(conditions, name) || name === 'and' || name === 'or') {
|
|
117
|
+
throw new Error(`Condition: unknown operator "${name}".`);
|
|
118
|
+
}
|
|
119
|
+
if (values === undefined)
|
|
120
|
+
continue;
|
|
121
|
+
if (name === 'isNull' || name === 'isNotNull') {
|
|
122
|
+
const condition = nullOperator(name)(table, values);
|
|
123
|
+
if (condition !== undefined)
|
|
124
|
+
sqlConditions.push(condition);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
const group = native.and(...valueConditions(table, values, name));
|
|
128
|
+
if (group !== undefined)
|
|
129
|
+
sqlConditions.push(group);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return native[operator](...sqlConditions);
|
|
133
|
+
};
|
|
134
|
+
const logicalOperator = (operator) => extendOperator((...conditions) => native[operator](...conditions.filter((condition) => condition !== false && condition !== undefined)), groupOperator(operator));
|
|
135
|
+
const conditions = {
|
|
136
|
+
eq: binaryOperator('eq'),
|
|
137
|
+
ne: binaryOperator('ne'),
|
|
138
|
+
gt: binaryOperator('gt'),
|
|
139
|
+
gte: binaryOperator('gte'),
|
|
140
|
+
lt: binaryOperator('lt'),
|
|
141
|
+
lte: binaryOperator('lte'),
|
|
142
|
+
inArray: extendOperator(native.inArray, objectOperator('inArray')),
|
|
143
|
+
notInArray: extendOperator(native.notInArray, objectOperator('notInArray')),
|
|
144
|
+
between: extendOperator(native.between, objectOperator('between')),
|
|
145
|
+
notBetween: extendOperator(native.notBetween, objectOperator('notBetween')),
|
|
146
|
+
like: extendOperator(native.like, objectOperator('like')),
|
|
147
|
+
notLike: extendOperator(native.notLike, objectOperator('notLike')),
|
|
148
|
+
ilike: extendOperator(native.ilike, objectOperator('ilike')),
|
|
149
|
+
notIlike: extendOperator(native.notIlike, objectOperator('notIlike')),
|
|
150
|
+
isNull: extendOperator(native.isNull, nullOperator('isNull')),
|
|
151
|
+
isNotNull: extendOperator(native.isNotNull, nullOperator('isNotNull')),
|
|
152
|
+
and: logicalOperator('and'),
|
|
153
|
+
or: logicalOperator('or'),
|
|
154
|
+
};
|
|
155
|
+
return conditions;
|
|
156
|
+
}function TableColumns(first, ...rest) {
|
|
157
|
+
if (Array.isArray(first) && isTable(first[0])) {
|
|
158
|
+
const result = {};
|
|
159
|
+
for (const group of [first, ...rest]) {
|
|
160
|
+
if (!Array.isArray(group) || !isTable(group[0])) {
|
|
161
|
+
throw new Error('columns: expected a table/column-name tuple.');
|
|
162
|
+
}
|
|
163
|
+
Object.assign(result, TableColumns(group[0], ...group.slice(1)));
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
if (isTable(first)) {
|
|
168
|
+
const tableColumns = getTableColumns(first);
|
|
169
|
+
if (rest.length === 0)
|
|
170
|
+
return Object.fromEntries(Object.values(tableColumns).map((column) => [column.name, column]));
|
|
171
|
+
const selected = {};
|
|
172
|
+
for (const selection of rest) {
|
|
173
|
+
if (typeof selection !== 'string') {
|
|
174
|
+
throw new Error('columns: expected a column name.');
|
|
175
|
+
}
|
|
176
|
+
const match = /^(.+?)\s+as\s+(.+)$/i.exec(selection.trim());
|
|
177
|
+
const name = (match?.[1] ?? selection).trim();
|
|
178
|
+
const alias = match?.[2]?.trim();
|
|
179
|
+
if (!Object.hasOwn(tableColumns, name)) {
|
|
180
|
+
throw new Error(`columns: unknown column "${name}".`);
|
|
181
|
+
}
|
|
182
|
+
if (alias)
|
|
183
|
+
selected[alias] = sql `${tableColumns[name]}`.as(alias);
|
|
184
|
+
else
|
|
185
|
+
selected[tableColumns[name].name] = tableColumns[name];
|
|
186
|
+
}
|
|
187
|
+
return selected;
|
|
188
|
+
}
|
|
189
|
+
const columns = (Array.isArray(first) ? first : [first, ...rest]);
|
|
190
|
+
return Object.fromEntries(columns.map((column) => {
|
|
191
|
+
if (typeof column === 'string' || Array.isArray(column))
|
|
192
|
+
throw new Error('columns: expected a column object.');
|
|
193
|
+
return [column.name, column];
|
|
194
|
+
}));
|
|
195
|
+
}/********************************************************************************************************************
|
|
196
|
+
* MySqlQuery
|
|
197
|
+
* ******************************************************************************************************************/
|
|
198
|
+
class MySqlQuery {
|
|
199
|
+
current;
|
|
200
|
+
getTimestamp;
|
|
201
|
+
timestampColumns;
|
|
202
|
+
// Table
|
|
203
|
+
t;
|
|
204
|
+
/********************************************************************************************************************
|
|
205
|
+
* constructor
|
|
206
|
+
* ******************************************************************************************************************/
|
|
207
|
+
constructor(table, current, getTimestamp, timestampColumns = {}) {
|
|
208
|
+
this.current = current;
|
|
209
|
+
this.getTimestamp = getTimestamp;
|
|
210
|
+
this.timestampColumns = timestampColumns;
|
|
211
|
+
this.t = table;
|
|
212
|
+
}
|
|
213
|
+
drizzle = { ...createConditions({}), sqlNumber: (value) => sql `${value}`.mapWith(Number) };
|
|
214
|
+
/********************************************************************************************************************
|
|
215
|
+
* (PROTECTED) getTx
|
|
216
|
+
* ******************************************************************************************************************/
|
|
217
|
+
getTx() {
|
|
218
|
+
return this.current();
|
|
219
|
+
}
|
|
220
|
+
columns(...names) {
|
|
221
|
+
const table = this.t;
|
|
222
|
+
return TableColumns(table, ...names);
|
|
223
|
+
}
|
|
224
|
+
resolveFields(fields, table = this.t) {
|
|
225
|
+
if (Array.isArray(fields) && fields.length > 0 && fields.every((field) => typeof field === 'string')) {
|
|
226
|
+
return TableColumns(table, ...fields);
|
|
227
|
+
}
|
|
228
|
+
if (typeof fields !== 'function')
|
|
229
|
+
return normalizeFields(fields);
|
|
230
|
+
const query = {
|
|
231
|
+
t: table,
|
|
232
|
+
columns: (...names) => TableColumns(table, ...names),
|
|
233
|
+
};
|
|
234
|
+
return normalizeFields(fields(query));
|
|
235
|
+
}
|
|
236
|
+
select(fieldsOrAlias, fields) {
|
|
237
|
+
const tx = this.getTx();
|
|
238
|
+
const isAlias = isTable(fieldsOrAlias);
|
|
239
|
+
const table = isAlias ? fieldsOrAlias : this.t;
|
|
240
|
+
const selectedFields = this.resolveFields(isAlias ? fields : fieldsOrAlias, table);
|
|
241
|
+
return tx.select(selectedFields ?? TableColumns(table)).from(table);
|
|
242
|
+
}
|
|
243
|
+
async find(aliasOrFieldsOrWhere, fieldsOrWhere, where) {
|
|
244
|
+
const hasAlias = isTable(aliasOrFieldsOrWhere);
|
|
245
|
+
const fieldsOrCondition = hasAlias ? fieldsOrWhere : aliasOrFieldsOrWhere;
|
|
246
|
+
const hasFields = arguments.length === (hasAlias ? 3 : 2);
|
|
247
|
+
const isCondition = (value) => is(value, SQL) || typeof value === 'function';
|
|
248
|
+
const table = hasAlias ? aliasOrFieldsOrWhere : this.t;
|
|
249
|
+
const selectedFields = this.resolveFields(!hasFields && isCondition(fieldsOrCondition) ? undefined : fieldsOrCondition, table);
|
|
250
|
+
const conditionInput = !hasFields && isCondition(fieldsOrCondition)
|
|
251
|
+
? fieldsOrCondition
|
|
252
|
+
: hasAlias
|
|
253
|
+
? where
|
|
254
|
+
: isCondition(fieldsOrWhere)
|
|
255
|
+
? fieldsOrWhere
|
|
256
|
+
: undefined;
|
|
257
|
+
const condition = typeof conditionInput === 'function' ? conditionInput(this) : conditionInput;
|
|
258
|
+
if (condition !== undefined && !is(condition, SQL)) {
|
|
259
|
+
throw new Error('find: the where callback must return SQL or undefined.');
|
|
260
|
+
}
|
|
261
|
+
const builder = (() => {
|
|
262
|
+
if (hasAlias) {
|
|
263
|
+
const alias = aliasOrFieldsOrWhere;
|
|
264
|
+
if (selectedFields === undefined) {
|
|
265
|
+
return this.select(alias);
|
|
266
|
+
}
|
|
267
|
+
return this.select(alias, selectedFields);
|
|
268
|
+
}
|
|
269
|
+
return selectedFields === undefined
|
|
270
|
+
? this.select()
|
|
271
|
+
: this.select(selectedFields);
|
|
272
|
+
})();
|
|
273
|
+
const [result] = await builder.where(condition).limit(1);
|
|
274
|
+
return result;
|
|
275
|
+
}
|
|
276
|
+
async findByPrimaryKey(fieldsOrKey, key) {
|
|
277
|
+
const hasFields = arguments.length === 2;
|
|
278
|
+
const primaryKeyValue = hasFields ? key : fieldsOrKey;
|
|
279
|
+
const condition = this.primaryKeyCondition(primaryKeyValue, 'findByPrimaryKey');
|
|
280
|
+
if (hasFields) {
|
|
281
|
+
return this.find(this.resolveFields(fieldsOrKey), condition);
|
|
282
|
+
}
|
|
283
|
+
return this.find(condition);
|
|
284
|
+
}
|
|
285
|
+
/********************************************************************************************************************
|
|
286
|
+
* primaryKeyCondition
|
|
287
|
+
* ******************************************************************************************************************/
|
|
288
|
+
primaryKeyCondition(primaryKeyValue, method) {
|
|
289
|
+
// 固定された MySqlTable 型で取得し、ジェネリックによる型の拡大を避ける。
|
|
290
|
+
const table = this.t;
|
|
291
|
+
const config = getTableConfig(table);
|
|
292
|
+
const columns = getTableColumns(table);
|
|
293
|
+
const primaryColumns = new Set(config.columns.filter((column) => column.primary));
|
|
294
|
+
for (const primaryKey of config.primaryKeys) {
|
|
295
|
+
for (const column of primaryKey.columns) {
|
|
296
|
+
primaryColumns.add(column);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const primaryEntries = Object.entries(columns).filter(([, column]) => primaryColumns.has(column));
|
|
300
|
+
if (primaryEntries.length === 0) {
|
|
301
|
+
throw new Error(`${method}: ${config.name} has no primary key.`);
|
|
302
|
+
}
|
|
303
|
+
const isKeyObject = typeof primaryKeyValue === 'object' && primaryKeyValue !== null && !Array.isArray(primaryKeyValue);
|
|
304
|
+
if (primaryEntries.length > 1 && !isKeyObject) {
|
|
305
|
+
throw new Error(`${method}: ${config.name} requires a composite key object.`);
|
|
306
|
+
}
|
|
307
|
+
const keyObject = isKeyObject ? primaryKeyValue : undefined;
|
|
308
|
+
if (keyObject &&
|
|
309
|
+
Object.keys(keyObject).some((name) => !primaryEntries.some(([primaryName]) => primaryName === name))) {
|
|
310
|
+
throw new Error(`${method}: ${config.name} received an unknown primary key field.`);
|
|
311
|
+
}
|
|
312
|
+
const conditions = primaryEntries.map(([name, column]) => {
|
|
313
|
+
if (keyObject && !Object.hasOwn(keyObject, name)) {
|
|
314
|
+
throw new Error(`${method}: missing primary key field "${name}".`);
|
|
315
|
+
}
|
|
316
|
+
const value = keyObject ? keyObject[name] : primaryKeyValue;
|
|
317
|
+
if (value === undefined || value === null) {
|
|
318
|
+
throw new Error(`${method}: primary key field "${name}" must have a value.`);
|
|
319
|
+
}
|
|
320
|
+
return eq(column, value);
|
|
321
|
+
});
|
|
322
|
+
const condition = and(...conditions);
|
|
323
|
+
if (!condition) {
|
|
324
|
+
throw new Error(`${method}: failed to build the primary key condition.`);
|
|
325
|
+
}
|
|
326
|
+
return condition;
|
|
327
|
+
}
|
|
328
|
+
/********************************************************************************************************************
|
|
329
|
+
* exists
|
|
330
|
+
* ******************************************************************************************************************/
|
|
331
|
+
async exists(where) {
|
|
332
|
+
const condition = typeof where === 'function' ? where(this) : where;
|
|
333
|
+
if (condition !== undefined && !is(condition, SQL)) {
|
|
334
|
+
throw new Error('exists: the where callback must return SQL or undefined.');
|
|
335
|
+
}
|
|
336
|
+
const [result] = await this.select({ matched: this.drizzle.sqlNumber(1) })
|
|
337
|
+
.where(condition)
|
|
338
|
+
.limit(1);
|
|
339
|
+
return result !== undefined;
|
|
340
|
+
}
|
|
341
|
+
/********************************************************************************************************************
|
|
342
|
+
* existsByPrimarykey
|
|
343
|
+
* ******************************************************************************************************************/
|
|
344
|
+
async existsByPrimaryKey(key) {
|
|
345
|
+
const result = await this.findByPrimaryKey({ matched: this.drizzle.sqlNumber(1) }, key);
|
|
346
|
+
return result !== undefined;
|
|
347
|
+
}
|
|
348
|
+
/********************************************************************************************************************
|
|
349
|
+
* notExists
|
|
350
|
+
* ******************************************************************************************************************/
|
|
351
|
+
async notExists(where) {
|
|
352
|
+
return !(await this.exists(where));
|
|
353
|
+
}
|
|
354
|
+
/********************************************************************************************************************
|
|
355
|
+
* notExistsByPrimaryKey
|
|
356
|
+
* ******************************************************************************************************************/
|
|
357
|
+
async notExistsByPrimaryKey(key) {
|
|
358
|
+
return !(await this.existsByPrimaryKey(key));
|
|
359
|
+
}
|
|
360
|
+
/********************************************************************************************************************
|
|
361
|
+
* count
|
|
362
|
+
* ******************************************************************************************************************/
|
|
363
|
+
async count(where) {
|
|
364
|
+
const condition = typeof where === 'function' ? where(this) : where;
|
|
365
|
+
if (condition !== undefined && !is(condition, SQL)) {
|
|
366
|
+
throw new Error('count: the where callback must return SQL or undefined.');
|
|
367
|
+
}
|
|
368
|
+
const [{ cnt }] = await this.select({ cnt: count() }).where(condition);
|
|
369
|
+
return cnt;
|
|
370
|
+
}
|
|
371
|
+
/********************************************************************************************************************
|
|
372
|
+
* (PRIVATE) insertValues
|
|
373
|
+
* ******************************************************************************************************************/
|
|
374
|
+
async insertValues(value) {
|
|
375
|
+
const tx = this.getTx();
|
|
376
|
+
const autoIncrementColumn = getTableConfig(this.t).columns.find((column) => 'autoIncrement' in column && column.autoIncrement === true);
|
|
377
|
+
const hasAutoIncrement = !!autoIncrementColumn;
|
|
378
|
+
const autoIncrementKey = autoIncrementColumn &&
|
|
379
|
+
Object.keys(getTableColumns(this.t)).find((key) => getTableColumns(this.t)[key] === autoIncrementColumn);
|
|
380
|
+
if (hasAutoIncrement) {
|
|
381
|
+
if (Array.isArray(value)) {
|
|
382
|
+
const addedItems = await tx.insert(this.t).values(value).$returningId();
|
|
383
|
+
return addedItems.map((item) => item[autoIncrementKey]);
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
const [item] = await tx.insert(this.t).values(value).$returningId();
|
|
387
|
+
return item[autoIncrementKey];
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
if (Array.isArray(value)) {
|
|
392
|
+
await tx.insert(this.t).values(value);
|
|
393
|
+
return Array(value.length).fill(undefined);
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
await tx.insert(this.t).values(value);
|
|
397
|
+
return undefined;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
add(value) {
|
|
402
|
+
return this.insertValues(value);
|
|
403
|
+
}
|
|
404
|
+
addWithCreatedAt(value) {
|
|
405
|
+
const created_at = this.getTimestamp();
|
|
406
|
+
const items = Array.isArray(value) ? value : [value];
|
|
407
|
+
const values = items.map((item) => ({
|
|
408
|
+
...item,
|
|
409
|
+
[this.timestampColumns.createdAt ?? 'created_at']: created_at,
|
|
410
|
+
}));
|
|
411
|
+
return this.insertValues(Array.isArray(value) ? values : values[0]);
|
|
412
|
+
}
|
|
413
|
+
addWithCreatedUpdatedAt(value) {
|
|
414
|
+
const dateTime = this.getTimestamp();
|
|
415
|
+
const items = Array.isArray(value) ? value : [value];
|
|
416
|
+
const values = items.map((item) => ({
|
|
417
|
+
...item,
|
|
418
|
+
[this.timestampColumns.createdAt ?? 'created_at']: dateTime,
|
|
419
|
+
[this.timestampColumns.updatedAt ?? 'updated_at']: dateTime,
|
|
420
|
+
}));
|
|
421
|
+
return this.insertValues(Array.isArray(value) ? values : values[0]);
|
|
422
|
+
}
|
|
423
|
+
/********************************************************************************************************************
|
|
424
|
+
* edit
|
|
425
|
+
* ******************************************************************************************************************/
|
|
426
|
+
edit(set, where) {
|
|
427
|
+
const condition = typeof where === 'function' ? where(this) : where;
|
|
428
|
+
if (!is(condition, SQL)) {
|
|
429
|
+
throw new Error('edit: a SQL where condition is required.');
|
|
430
|
+
}
|
|
431
|
+
const tx = this.getTx();
|
|
432
|
+
return tx.update(this.t).set(set).where(condition);
|
|
433
|
+
}
|
|
434
|
+
/********************************************************************************************************************
|
|
435
|
+
* editByPrimaryKey
|
|
436
|
+
* ******************************************************************************************************************/
|
|
437
|
+
editByPrimaryKey(set, key) {
|
|
438
|
+
return this.edit(set, this.primaryKeyCondition(key, 'editByPrimaryKey'));
|
|
439
|
+
}
|
|
440
|
+
/********************************************************************************************************************
|
|
441
|
+
* editWithUpdatedAt
|
|
442
|
+
* ******************************************************************************************************************/
|
|
443
|
+
editWithUpdatedAt(set, where) {
|
|
444
|
+
const condition = typeof where === 'function' ? where(this) : where;
|
|
445
|
+
if (!is(condition, SQL)) {
|
|
446
|
+
throw new Error('editWithUpdatedAt: a SQL where condition is required.');
|
|
447
|
+
}
|
|
448
|
+
const tx = this.getTx();
|
|
449
|
+
const values = {
|
|
450
|
+
...set,
|
|
451
|
+
[this.timestampColumns.updatedAt ?? 'updated_at']: this.getTimestamp(),
|
|
452
|
+
};
|
|
453
|
+
return tx.update(this.t).set(values).where(condition);
|
|
454
|
+
}
|
|
455
|
+
/********************************************************************************************************************
|
|
456
|
+
* editWithUpdatedAtByPrimaryKey
|
|
457
|
+
* ******************************************************************************************************************/
|
|
458
|
+
editWithUpdatedAtByPrimaryKey(set, key) {
|
|
459
|
+
return this.editWithUpdatedAt(set, this.primaryKeyCondition(key, 'editWithUpdatedAtByPrimaryKey'));
|
|
460
|
+
}
|
|
461
|
+
/********************************************************************************************************************
|
|
462
|
+
* remove
|
|
463
|
+
* ******************************************************************************************************************/
|
|
464
|
+
remove(where) {
|
|
465
|
+
const condition = typeof where === 'function' ? where(this) : where;
|
|
466
|
+
if (!is(condition, SQL)) {
|
|
467
|
+
throw new Error('remove: a SQL where condition is required.');
|
|
468
|
+
}
|
|
469
|
+
const tx = this.getTx();
|
|
470
|
+
return tx.delete(this.t).where(condition);
|
|
471
|
+
}
|
|
472
|
+
/********************************************************************************************************************
|
|
473
|
+
* removeByPrimaryKey
|
|
474
|
+
* ******************************************************************************************************************/
|
|
475
|
+
removeByPrimaryKey(key) {
|
|
476
|
+
return this.remove(this.primaryKeyCondition(key, 'removeByPrimaryKey'));
|
|
477
|
+
}
|
|
478
|
+
/********************************************************************************************************************
|
|
479
|
+
* eq
|
|
480
|
+
* ******************************************************************************************************************/
|
|
481
|
+
eq(values) {
|
|
482
|
+
return this.drizzle.eq(this.t, values);
|
|
483
|
+
}
|
|
484
|
+
/********************************************************************************************************************
|
|
485
|
+
* ne
|
|
486
|
+
* ******************************************************************************************************************/
|
|
487
|
+
ne(values) {
|
|
488
|
+
return this.drizzle.ne(this.t, values);
|
|
489
|
+
}
|
|
490
|
+
/********************************************************************************************************************
|
|
491
|
+
* gt
|
|
492
|
+
* ******************************************************************************************************************/
|
|
493
|
+
gt(values) {
|
|
494
|
+
return this.drizzle.gt(this.t, values);
|
|
495
|
+
}
|
|
496
|
+
/********************************************************************************************************************
|
|
497
|
+
* gte
|
|
498
|
+
* ******************************************************************************************************************/
|
|
499
|
+
gte(values) {
|
|
500
|
+
return this.drizzle.gte(this.t, values);
|
|
501
|
+
}
|
|
502
|
+
/********************************************************************************************************************
|
|
503
|
+
* lt
|
|
504
|
+
* ******************************************************************************************************************/
|
|
505
|
+
lt(values) {
|
|
506
|
+
return this.drizzle.lt(this.t, values);
|
|
507
|
+
}
|
|
508
|
+
/********************************************************************************************************************
|
|
509
|
+
* lte
|
|
510
|
+
* ******************************************************************************************************************/
|
|
511
|
+
lte(values) {
|
|
512
|
+
return this.drizzle.lte(this.t, values);
|
|
513
|
+
}
|
|
514
|
+
/********************************************************************************************************************
|
|
515
|
+
* lte
|
|
516
|
+
* ******************************************************************************************************************/
|
|
517
|
+
inArray(values) {
|
|
518
|
+
return this.drizzle.inArray(this.t, values);
|
|
519
|
+
}
|
|
520
|
+
/********************************************************************************************************************
|
|
521
|
+
* notInArray
|
|
522
|
+
* ******************************************************************************************************************/
|
|
523
|
+
notInArray(values) {
|
|
524
|
+
return this.drizzle.notInArray(this.t, values);
|
|
525
|
+
}
|
|
526
|
+
/********************************************************************************************************************
|
|
527
|
+
* between
|
|
528
|
+
* ******************************************************************************************************************/
|
|
529
|
+
between(values) {
|
|
530
|
+
return this.drizzle.between(this.t, values);
|
|
531
|
+
}
|
|
532
|
+
/********************************************************************************************************************
|
|
533
|
+
* notBetween
|
|
534
|
+
* ******************************************************************************************************************/
|
|
535
|
+
notBetween(values) {
|
|
536
|
+
return this.drizzle.notBetween(this.t, values);
|
|
537
|
+
}
|
|
538
|
+
/********************************************************************************************************************
|
|
539
|
+
* like
|
|
540
|
+
* ******************************************************************************************************************/
|
|
541
|
+
like(values) {
|
|
542
|
+
return this.drizzle.like(this.t, values);
|
|
543
|
+
}
|
|
544
|
+
/********************************************************************************************************************
|
|
545
|
+
* notLike
|
|
546
|
+
* ******************************************************************************************************************/
|
|
547
|
+
notLike(values) {
|
|
548
|
+
return this.drizzle.notLike(this.t, values);
|
|
549
|
+
}
|
|
550
|
+
/********************************************************************************************************************
|
|
551
|
+
* ilike
|
|
552
|
+
* ******************************************************************************************************************/
|
|
553
|
+
ilike(values) {
|
|
554
|
+
return this.drizzle.ilike(this.t, values);
|
|
555
|
+
}
|
|
556
|
+
/********************************************************************************************************************
|
|
557
|
+
* notIlike
|
|
558
|
+
* ******************************************************************************************************************/
|
|
559
|
+
notIlike(values) {
|
|
560
|
+
return this.drizzle.notIlike(this.t, values);
|
|
561
|
+
}
|
|
562
|
+
isNull(names) {
|
|
563
|
+
return this.drizzle.isNull(this.t, names);
|
|
564
|
+
}
|
|
565
|
+
isNotNull(names) {
|
|
566
|
+
return this.drizzle.isNotNull(this.t, names);
|
|
567
|
+
}
|
|
568
|
+
/********************************************************************************************************************
|
|
569
|
+
* and
|
|
570
|
+
* ******************************************************************************************************************/
|
|
571
|
+
and(options) {
|
|
572
|
+
return this.drizzle.and(this.t, options);
|
|
573
|
+
}
|
|
574
|
+
/********************************************************************************************************************
|
|
575
|
+
* or
|
|
576
|
+
* ******************************************************************************************************************/
|
|
577
|
+
or(options) {
|
|
578
|
+
return this.drizzle.or(this.t, options);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
const normalizeFields = (fields) => {
|
|
582
|
+
if (fields === undefined)
|
|
583
|
+
return undefined;
|
|
584
|
+
const groups = Array.isArray(fields) ? fields : [fields];
|
|
585
|
+
const result = {};
|
|
586
|
+
for (const group of groups) {
|
|
587
|
+
if (Array.isArray(fields) && (group === false || group === undefined))
|
|
588
|
+
continue;
|
|
589
|
+
if (typeof group !== 'object' || group === null || Array.isArray(group) || isTable(group) || is(group, SQL)) {
|
|
590
|
+
throw new Error('fields: expected a selection object or an array of selection objects.');
|
|
591
|
+
}
|
|
592
|
+
Object.assign(result, group);
|
|
593
|
+
}
|
|
594
|
+
for (const [name, field] of Object.entries(result)) {
|
|
595
|
+
if (is(field, MySqlColumn) && field.name !== name) {
|
|
596
|
+
result[name] = sql `${field}`.mapWith(field).as(name);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return result;
|
|
600
|
+
};function drizzleMySql(options) {
|
|
601
|
+
const pool = mysql.createPool({ uri: options.url });
|
|
602
|
+
const raw = drizzle({ client: pool, relations: defineRelations(options.schema) });
|
|
603
|
+
const context = new AsyncLocalStorage();
|
|
604
|
+
const current = () => context.getStore() ?? raw;
|
|
605
|
+
const trans = (callback) => {
|
|
606
|
+
const parent = context.getStore();
|
|
607
|
+
const execute = (tx) => context.run(tx, callback);
|
|
608
|
+
return parent ? parent.transaction(execute) : raw.transaction(execute);
|
|
609
|
+
};
|
|
610
|
+
const paginate = async (builder, page, limit) => {
|
|
611
|
+
if (!Number.isInteger(page) || page < 1 || !Number.isInteger(limit) || limit < 1) {
|
|
612
|
+
throw new RangeError('page and limit must be positive integers');
|
|
613
|
+
}
|
|
614
|
+
const offset = (page - 1) * limit;
|
|
615
|
+
const [[{ total }], data] = await Promise.all([
|
|
616
|
+
current().select({ total: count() }).from(builder.as('a')),
|
|
617
|
+
builder.limit(limit).offset(offset),
|
|
618
|
+
]);
|
|
619
|
+
return {
|
|
620
|
+
data,
|
|
621
|
+
paging: {
|
|
622
|
+
current_page: page,
|
|
623
|
+
per_page: limit,
|
|
624
|
+
last_page: Math.ceil(total / limit),
|
|
625
|
+
total,
|
|
626
|
+
from: offset,
|
|
627
|
+
to: offset + data.length,
|
|
628
|
+
},
|
|
629
|
+
};
|
|
630
|
+
};
|
|
631
|
+
return {
|
|
632
|
+
asc: native.asc,
|
|
633
|
+
desc: native.desc,
|
|
634
|
+
count: native.count,
|
|
635
|
+
countDistinct: native.countDistinct,
|
|
636
|
+
avg: native.avg,
|
|
637
|
+
avgDistinct: native.avgDistinct,
|
|
638
|
+
sum: native.sum,
|
|
639
|
+
sumDistinct: native.sumDistinct,
|
|
640
|
+
max: native.max,
|
|
641
|
+
min: native.min,
|
|
642
|
+
not: native.not,
|
|
643
|
+
exists: native.exists,
|
|
644
|
+
notExists: native.notExists,
|
|
645
|
+
arrayContains: native.arrayContains,
|
|
646
|
+
arrayContained: native.arrayContained,
|
|
647
|
+
arrayOverlaps: native.arrayOverlaps,
|
|
648
|
+
s: options.schema,
|
|
649
|
+
a: createAlias(options.schema),
|
|
650
|
+
...createConditions(options.schema),
|
|
651
|
+
columns: TableColumns,
|
|
652
|
+
sql,
|
|
653
|
+
sqlNumber: (value) => (is(value, SQL) ? value : sql `${value}`).mapWith(Number),
|
|
654
|
+
sqlString: (value) => (is(value, SQL) ? value : sql `${value}`).mapWith(String),
|
|
655
|
+
sqlBoolean: (value) => (is(value, SQL) ? value : sql `${value}`).mapWith((v) => v === true || v === 1),
|
|
656
|
+
current,
|
|
657
|
+
query: (table) => new MySqlQuery(table, current, () => {
|
|
658
|
+
if (!options.timestamp)
|
|
659
|
+
throw new Error('timestamp generator is not configured');
|
|
660
|
+
return options.timestamp();
|
|
661
|
+
}, options.timestampColumns),
|
|
662
|
+
trans,
|
|
663
|
+
paginate,
|
|
664
|
+
close: () => pool.end(),
|
|
665
|
+
};
|
|
666
|
+
}export{MySqlQuery,TableColumns,createConditions,drizzleMySql as default,drizzleMySql};
|