@bungres/kit 0.3.0 → 0.5.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 +22 -13
- package/dist/cli.js +1513 -638
- package/dist/commands/drop.d.ts.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/studio.d.ts.map +1 -1
- package/dist/config.d.ts +32 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/index.js +609 -191
- package/package.json +20 -4
- package/src/cli.ts +0 -162
- package/src/commands/drop.ts +0 -92
- package/src/commands/fresh.ts +0 -17
- package/src/commands/generate.ts +0 -151
- package/src/commands/migrate.ts +0 -84
- package/src/commands/pull.ts +0 -339
- package/src/commands/push.ts +0 -105
- package/src/commands/refresh.ts +0 -37
- package/src/commands/seed.ts +0 -41
- package/src/commands/status.ts +0 -64
- package/src/commands/studio.ts +0 -471
- package/src/commands/tusky.ts +0 -83
- package/src/config.ts +0 -102
- package/src/differ.ts +0 -236
- package/src/ensure-db.ts +0 -32
- package/src/index.ts +0 -21
- package/src/schema-loader.ts +0 -50
- package/src/utils/colors.ts +0 -4
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/config.ts
|
|
3
|
-
import {
|
|
3
|
+
import { join, resolve } from "path";
|
|
4
4
|
var CONFIG_FILES = [
|
|
5
5
|
"bungres.config.ts",
|
|
6
6
|
"bungres.config.js",
|
|
@@ -17,7 +17,7 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
17
17
|
break;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
const dbUrl = userConfig.dbCredentials?.url ??
|
|
20
|
+
const dbUrl = userConfig.dbCredentials?.url ?? Bun.env.DATABASE_URL ?? Bun.env.POSTGRES_URL ?? "";
|
|
21
21
|
if (!dbUrl) {
|
|
22
22
|
console.error(`bungres: No database URL found.
|
|
23
23
|
Add dbCredentials.url to bungres.config.ts or set DATABASE_URL.`);
|
|
@@ -30,7 +30,10 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
30
30
|
out,
|
|
31
31
|
dbUrl,
|
|
32
32
|
dbSchema: userConfig.dbSchema ?? "public",
|
|
33
|
-
|
|
33
|
+
migrationsTable: userConfig.migrations?.table ?? "__bungres_migrations",
|
|
34
|
+
migrationsSchema: userConfig.migrations?.schema ?? "bungres",
|
|
35
|
+
breakpoints: userConfig.breakpoints ?? true,
|
|
36
|
+
strict: userConfig.strict ?? false,
|
|
34
37
|
outDir: "./src/db/generated",
|
|
35
38
|
verbose: userConfig.verbose ?? false
|
|
36
39
|
};
|
|
@@ -38,7 +41,7 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
38
41
|
// src/schema-loader.ts
|
|
39
42
|
import { resolve as resolve2, join as join2 } from "path";
|
|
40
43
|
|
|
41
|
-
//
|
|
44
|
+
// ../bungres-orm/src/schema/table.ts
|
|
42
45
|
var TableConfigSymbol = Symbol.for("BungresTableConfig");
|
|
43
46
|
function getTableConfig(table) {
|
|
44
47
|
return table[TableConfigSymbol];
|
|
@@ -48,8 +51,13 @@ function camelToSnakeCase(str) {
|
|
|
48
51
|
}
|
|
49
52
|
function createTableFactory(casing) {
|
|
50
53
|
return function(name, columns, extra) {
|
|
54
|
+
let schema;
|
|
55
|
+
if (extra && typeof extra !== "function") {
|
|
56
|
+
schema = extra.schema;
|
|
57
|
+
}
|
|
58
|
+
const qualifiedName = schema ? `"${schema}"."${name}"` : `"${name}"`;
|
|
51
59
|
const columnConfigs = Object.fromEntries(Object.entries(columns).map(([key, config]) => {
|
|
52
|
-
const c = { ...config };
|
|
60
|
+
const c = { ...config, tableName: qualifiedName };
|
|
53
61
|
if (!c.name) {
|
|
54
62
|
if (casing === "snake") {
|
|
55
63
|
c.name = camelToSnakeCase(key);
|
|
@@ -59,26 +67,50 @@ function createTableFactory(casing) {
|
|
|
59
67
|
}
|
|
60
68
|
return [key, c];
|
|
61
69
|
}));
|
|
62
|
-
const
|
|
63
|
-
const
|
|
70
|
+
const indexes = [];
|
|
71
|
+
const checks = [];
|
|
72
|
+
const primaryKeys = [];
|
|
73
|
+
const foreignKeys = [];
|
|
74
|
+
if (extra) {
|
|
75
|
+
if (typeof extra === "function") {
|
|
76
|
+
const builders = extra(columnConfigs);
|
|
77
|
+
for (const builder of builders) {
|
|
78
|
+
const config = builder.build();
|
|
79
|
+
if (config.type === "index")
|
|
80
|
+
indexes.push(config);
|
|
81
|
+
else if (config.type === "check")
|
|
82
|
+
checks.push(config.condition);
|
|
83
|
+
else if (config.type === "primaryKey")
|
|
84
|
+
primaryKeys.push(...config.columns);
|
|
85
|
+
else if (config.type === "foreignKey")
|
|
86
|
+
foreignKeys.push(config);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
if (extra.indexes)
|
|
90
|
+
indexes.push(...extra.indexes);
|
|
91
|
+
if (extra.checks)
|
|
92
|
+
checks.push(...extra.checks);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
64
95
|
const tableObj = {
|
|
65
96
|
[TableConfigSymbol]: {
|
|
66
97
|
name,
|
|
67
98
|
schema,
|
|
68
99
|
columns: columnConfigs,
|
|
69
|
-
indexes
|
|
70
|
-
checks
|
|
71
|
-
primaryKeys
|
|
100
|
+
indexes,
|
|
101
|
+
checks,
|
|
102
|
+
primaryKeys,
|
|
103
|
+
foreignKeys,
|
|
72
104
|
qualifiedName
|
|
73
105
|
}
|
|
74
106
|
};
|
|
75
107
|
return Object.assign(tableObj, columnConfigs);
|
|
76
108
|
};
|
|
77
109
|
}
|
|
78
|
-
var table = createTableFactory("
|
|
110
|
+
var table = createTableFactory("snake");
|
|
79
111
|
var snakeCase = { table: createTableFactory("snake") };
|
|
80
112
|
var camelCase = { table: createTableFactory("camel") };
|
|
81
|
-
//
|
|
113
|
+
// ../bungres-orm/src/schema/columns.ts
|
|
82
114
|
function buildColumn(dataType, nameOrOpts, opts) {
|
|
83
115
|
let name = "";
|
|
84
116
|
let options = opts;
|
|
@@ -132,7 +164,33 @@ var interval = col("interval");
|
|
|
132
164
|
var inet = col("inet");
|
|
133
165
|
var cidr = col("cidr");
|
|
134
166
|
var macaddr = col("macaddr");
|
|
135
|
-
|
|
167
|
+
var textArray = col("text[]");
|
|
168
|
+
var integerArray = col("integer[]");
|
|
169
|
+
var varcharArray = col("varchar[]");
|
|
170
|
+
var uuidArray = col("uuid[]");
|
|
171
|
+
// ../bungres-orm/src/core/sql.ts
|
|
172
|
+
function sql(strings, ...values) {
|
|
173
|
+
let query = "";
|
|
174
|
+
const params = [];
|
|
175
|
+
for (let i = 0;i < strings.length; i++) {
|
|
176
|
+
query += strings[i];
|
|
177
|
+
if (i < values.length) {
|
|
178
|
+
const val = values[i];
|
|
179
|
+
if (isSQLChunk(val)) {
|
|
180
|
+
const offset = params.length;
|
|
181
|
+
query += val.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
182
|
+
params.push(...val.params);
|
|
183
|
+
} else {
|
|
184
|
+
params.push(val);
|
|
185
|
+
query += `$${params.length}`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return { sql: query, params };
|
|
190
|
+
}
|
|
191
|
+
function isSQLChunk(value) {
|
|
192
|
+
return typeof value === "object" && value !== null && "sql" in value && "params" in value && typeof value.sql === "string" && Array.isArray(value.params);
|
|
193
|
+
}
|
|
136
194
|
function sqlJoin(chunks, separator = ", ") {
|
|
137
195
|
const params = [];
|
|
138
196
|
const parts = [];
|
|
@@ -143,12 +201,326 @@ function sqlJoin(chunks, separator = ", ") {
|
|
|
143
201
|
}
|
|
144
202
|
return { sql: parts.join(separator), params };
|
|
145
203
|
}
|
|
146
|
-
|
|
204
|
+
function rawSql(query) {
|
|
205
|
+
return { sql: query, params: [] };
|
|
206
|
+
}
|
|
207
|
+
// ../bungres-orm/src/core/conditions.ts
|
|
208
|
+
var colName = (c) => {
|
|
209
|
+
if (typeof c === "string")
|
|
210
|
+
return `"${c}"`;
|
|
211
|
+
if (isSQLChunk(c))
|
|
212
|
+
return c.sql;
|
|
213
|
+
return c.tableName ? `${c.tableName}."${c.name}"` : `"${c.name}"`;
|
|
214
|
+
};
|
|
215
|
+
function isColumnConfig(val) {
|
|
216
|
+
return val !== null && typeof val === "object" && "name" in val && "dataType" in val;
|
|
217
|
+
}
|
|
218
|
+
var eq = (column, value) => {
|
|
219
|
+
if (isColumnConfig(value))
|
|
220
|
+
return sql`${rawSql(colName(column))} = ${rawSql(colName(value))}`;
|
|
221
|
+
if (isSQLChunk(value))
|
|
222
|
+
return sql`${rawSql(colName(column))} = ${value}`;
|
|
223
|
+
return sql`${rawSql(colName(column))} = ${value}`;
|
|
224
|
+
};
|
|
225
|
+
var ne = (column, value) => {
|
|
226
|
+
if (isColumnConfig(value))
|
|
227
|
+
return sql`${rawSql(colName(column))} != ${rawSql(colName(value))}`;
|
|
228
|
+
if (isSQLChunk(value))
|
|
229
|
+
return sql`${rawSql(colName(column))} != ${value}`;
|
|
230
|
+
return sql`${rawSql(colName(column))} != ${value}`;
|
|
231
|
+
};
|
|
232
|
+
var gt = (column, value) => {
|
|
233
|
+
if (isColumnConfig(value))
|
|
234
|
+
return sql`${rawSql(colName(column))} > ${rawSql(colName(value))}`;
|
|
235
|
+
if (isSQLChunk(value))
|
|
236
|
+
return sql`${rawSql(colName(column))} > ${value}`;
|
|
237
|
+
return sql`${rawSql(colName(column))} > ${value}`;
|
|
238
|
+
};
|
|
239
|
+
var gte = (column, value) => {
|
|
240
|
+
if (isColumnConfig(value))
|
|
241
|
+
return sql`${rawSql(colName(column))} >= ${rawSql(colName(value))}`;
|
|
242
|
+
if (isSQLChunk(value))
|
|
243
|
+
return sql`${rawSql(colName(column))} >= ${value}`;
|
|
244
|
+
return sql`${rawSql(colName(column))} >= ${value}`;
|
|
245
|
+
};
|
|
246
|
+
var lt = (column, value) => {
|
|
247
|
+
if (isColumnConfig(value))
|
|
248
|
+
return sql`${rawSql(colName(column))} < ${rawSql(colName(value))}`;
|
|
249
|
+
if (isSQLChunk(value))
|
|
250
|
+
return sql`${rawSql(colName(column))} < ${value}`;
|
|
251
|
+
return sql`${rawSql(colName(column))} < ${value}`;
|
|
252
|
+
};
|
|
253
|
+
var lte = (column, value) => {
|
|
254
|
+
if (isColumnConfig(value))
|
|
255
|
+
return sql`${rawSql(colName(column))} <= ${rawSql(colName(value))}`;
|
|
256
|
+
if (isSQLChunk(value))
|
|
257
|
+
return sql`${rawSql(colName(column))} <= ${value}`;
|
|
258
|
+
return sql`${rawSql(colName(column))} <= ${value}`;
|
|
259
|
+
};
|
|
260
|
+
var like = (column, pattern) => sql`${rawSql(colName(column))} LIKE ${pattern}`;
|
|
261
|
+
var ilike = (column, pattern) => sql`${rawSql(colName(column))} ILIKE ${pattern}`;
|
|
262
|
+
var isNull = (column) => rawSql(`${colName(column)} IS NULL`);
|
|
263
|
+
var isNotNull = (column) => rawSql(`${colName(column)} IS NOT NULL`);
|
|
264
|
+
var inArray = (column, values) => {
|
|
265
|
+
if (values.length === 0)
|
|
266
|
+
return rawSql("FALSE");
|
|
267
|
+
const params = values;
|
|
268
|
+
const placeholders = params.map((_, i) => `$${i + 1}`).join(", ");
|
|
269
|
+
return { sql: `${colName(column)} = ANY(ARRAY[${placeholders}])`, params };
|
|
270
|
+
};
|
|
271
|
+
var and = (...conditions) => sqlJoin(conditions, " AND ");
|
|
272
|
+
var or = (...conditions) => {
|
|
273
|
+
const joined = sqlJoin(conditions, " OR ");
|
|
274
|
+
return { sql: `(${joined.sql})`, params: joined.params };
|
|
275
|
+
};
|
|
276
|
+
var not = (condition) => ({
|
|
277
|
+
sql: `NOT (${condition.sql})`,
|
|
278
|
+
params: condition.params
|
|
279
|
+
});
|
|
280
|
+
var asc = (column) => sql`${rawSql(colName(column))} ASC`;
|
|
281
|
+
var desc = (column) => sql`${rawSql(colName(column))} DESC`;
|
|
282
|
+
function parseWhereObject(tableConfig, whereObj) {
|
|
283
|
+
const conditions = [];
|
|
284
|
+
for (const [key, val] of Object.entries(whereObj)) {
|
|
285
|
+
if (val === undefined)
|
|
286
|
+
continue;
|
|
287
|
+
if (key === "OR") {
|
|
288
|
+
const orConditions = val.map((o) => parseWhereObject(tableConfig, o));
|
|
289
|
+
if (orConditions.length > 0)
|
|
290
|
+
conditions.push(or(...orConditions));
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (key === "AND") {
|
|
294
|
+
const andConditions = val.map((o) => parseWhereObject(tableConfig, o));
|
|
295
|
+
if (andConditions.length > 0)
|
|
296
|
+
conditions.push(and(...andConditions));
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (key === "NOT") {
|
|
300
|
+
conditions.push(not(parseWhereObject(tableConfig, val)));
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
const colConfig = tableConfig.columns[key];
|
|
304
|
+
const columnArg = colConfig ?? key;
|
|
305
|
+
if (val !== null && typeof val === "object" && !Array.isArray(val) && !(val instanceof Date) && !(val instanceof Uint8Array)) {
|
|
306
|
+
const opVal = val;
|
|
307
|
+
if (opVal.eq !== undefined)
|
|
308
|
+
conditions.push(eq(columnArg, opVal.eq));
|
|
309
|
+
if (opVal.ne !== undefined)
|
|
310
|
+
conditions.push(ne(columnArg, opVal.ne));
|
|
311
|
+
if (opVal.gt !== undefined)
|
|
312
|
+
conditions.push(gt(columnArg, opVal.gt));
|
|
313
|
+
if (opVal.gte !== undefined)
|
|
314
|
+
conditions.push(gte(columnArg, opVal.gte));
|
|
315
|
+
if (opVal.lt !== undefined)
|
|
316
|
+
conditions.push(lt(columnArg, opVal.lt));
|
|
317
|
+
if (opVal.lte !== undefined)
|
|
318
|
+
conditions.push(lte(columnArg, opVal.lte));
|
|
319
|
+
if (opVal.in !== undefined)
|
|
320
|
+
conditions.push(inArray(columnArg, opVal.in));
|
|
321
|
+
if (opVal.like !== undefined)
|
|
322
|
+
conditions.push(like(columnArg, opVal.like));
|
|
323
|
+
if (opVal.ilike !== undefined)
|
|
324
|
+
conditions.push(ilike(columnArg, opVal.ilike));
|
|
325
|
+
if (opVal.isNull)
|
|
326
|
+
conditions.push(isNull(columnArg));
|
|
327
|
+
if (opVal.isNotNull)
|
|
328
|
+
conditions.push(isNotNull(columnArg));
|
|
329
|
+
} else {
|
|
330
|
+
if (val === null) {
|
|
331
|
+
conditions.push(isNull(columnArg));
|
|
332
|
+
} else {
|
|
333
|
+
conditions.push(eq(columnArg, val));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (conditions.length === 0) {
|
|
338
|
+
return rawSql("TRUE");
|
|
339
|
+
}
|
|
340
|
+
return and(...conditions);
|
|
341
|
+
}
|
|
342
|
+
function parseOrderByObject(tableConfig, orderByObj) {
|
|
343
|
+
const parts = [];
|
|
344
|
+
for (const [key, dir] of Object.entries(orderByObj)) {
|
|
345
|
+
if (dir === undefined)
|
|
346
|
+
continue;
|
|
347
|
+
const colConfig = tableConfig.columns[key];
|
|
348
|
+
const columnArg = colConfig ?? key;
|
|
349
|
+
if (dir === "asc")
|
|
350
|
+
parts.push(asc(columnArg));
|
|
351
|
+
else if (dir === "desc")
|
|
352
|
+
parts.push(desc(columnArg));
|
|
353
|
+
}
|
|
354
|
+
return parts;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ../bungres-orm/src/builders/delete.ts
|
|
358
|
+
class DeleteBuilder {
|
|
359
|
+
_table;
|
|
360
|
+
_executor;
|
|
361
|
+
_where = [];
|
|
362
|
+
_returning;
|
|
363
|
+
_comment;
|
|
364
|
+
constructor(table2, executor) {
|
|
365
|
+
this._table = table2;
|
|
366
|
+
this._executor = executor;
|
|
367
|
+
}
|
|
368
|
+
then(onfulfilled, onrejected) {
|
|
369
|
+
return this._executor.execute(this).then(onfulfilled, onrejected);
|
|
370
|
+
}
|
|
371
|
+
async single() {
|
|
372
|
+
return this._executor.executeSingle(this);
|
|
373
|
+
}
|
|
374
|
+
where(condition) {
|
|
375
|
+
if (condition && typeof condition === "object" && !("sql" in condition)) {
|
|
376
|
+
this._where.push(parseWhereObject(getTableConfig(this._table), condition));
|
|
377
|
+
} else {
|
|
378
|
+
this._where.push(condition);
|
|
379
|
+
}
|
|
380
|
+
return this;
|
|
381
|
+
}
|
|
382
|
+
returning(...columns) {
|
|
383
|
+
this._returning = columns.length > 0 ? columns : ["*"];
|
|
384
|
+
return this;
|
|
385
|
+
}
|
|
386
|
+
comment(tag) {
|
|
387
|
+
this._comment = tag;
|
|
388
|
+
return this;
|
|
389
|
+
}
|
|
390
|
+
toSQL() {
|
|
391
|
+
let query = `DELETE FROM ${getTableConfig(this._table).qualifiedName}`;
|
|
392
|
+
const params = [];
|
|
393
|
+
if (this._where.length > 0) {
|
|
394
|
+
const combined = sqlJoin(this._where, " AND ");
|
|
395
|
+
query += " WHERE " + combined.sql;
|
|
396
|
+
params.push(...combined.params);
|
|
397
|
+
}
|
|
398
|
+
if (this._returning) {
|
|
399
|
+
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(getTableConfig(this._table).columns).map((c) => `"${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${getTableConfig(this._table).columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
400
|
+
}
|
|
401
|
+
return { sql: query, params };
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
// ../bungres-orm/src/builders/insert.ts
|
|
405
|
+
class InsertBuilder {
|
|
406
|
+
_table;
|
|
407
|
+
_executor;
|
|
408
|
+
_values = [];
|
|
409
|
+
_onConflict;
|
|
410
|
+
_returning;
|
|
411
|
+
_comment;
|
|
412
|
+
constructor(table2, executor) {
|
|
413
|
+
this._table = table2;
|
|
414
|
+
this._executor = executor;
|
|
415
|
+
}
|
|
416
|
+
then(onfulfilled, onrejected) {
|
|
417
|
+
return this._executor.execute(this).then(onfulfilled, onrejected);
|
|
418
|
+
}
|
|
419
|
+
async single() {
|
|
420
|
+
return this._executor.executeSingle(this);
|
|
421
|
+
}
|
|
422
|
+
values(data) {
|
|
423
|
+
if (Array.isArray(data)) {
|
|
424
|
+
this._values.push(...data);
|
|
425
|
+
} else {
|
|
426
|
+
this._values.push(data);
|
|
427
|
+
}
|
|
428
|
+
return this;
|
|
429
|
+
}
|
|
430
|
+
onConflictDoNothing() {
|
|
431
|
+
this._onConflict = "do nothing";
|
|
432
|
+
return this;
|
|
433
|
+
}
|
|
434
|
+
onConflict(clause) {
|
|
435
|
+
this._onConflict = clause;
|
|
436
|
+
return this;
|
|
437
|
+
}
|
|
438
|
+
returning(...columns) {
|
|
439
|
+
this._returning = columns.length > 0 ? columns : ["*"];
|
|
440
|
+
return this;
|
|
441
|
+
}
|
|
442
|
+
comment(tag) {
|
|
443
|
+
this._comment = tag;
|
|
444
|
+
return this;
|
|
445
|
+
}
|
|
446
|
+
toSQL() {
|
|
447
|
+
if (this._values.length === 0) {
|
|
448
|
+
throw new Error("InsertBuilder: no values provided");
|
|
449
|
+
}
|
|
450
|
+
const tConfig = getTableConfig(this._table);
|
|
451
|
+
const keySet = new Set;
|
|
452
|
+
for (const v of this._values) {
|
|
453
|
+
for (const k of Object.keys(v)) {
|
|
454
|
+
keySet.add(k);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
const keys = Array.from(keySet);
|
|
458
|
+
if (keys.length === 0) {
|
|
459
|
+
return { sql: `INSERT INTO ${tConfig.qualifiedName} DEFAULT VALUES`, params: [] };
|
|
460
|
+
}
|
|
461
|
+
const columnsStr = keys.map((k) => `"${tConfig.columns[k]?.name ?? k}"`).join(", ");
|
|
462
|
+
const params = [];
|
|
463
|
+
const valuesStrs = this._values.map((v) => {
|
|
464
|
+
const vals = keys.map((k) => {
|
|
465
|
+
const val = v[k];
|
|
466
|
+
if (val && typeof val === "object" && "sql" in val && "params" in val) {
|
|
467
|
+
const chunk = val;
|
|
468
|
+
const offset = params.length;
|
|
469
|
+
params.push(...chunk.params);
|
|
470
|
+
return chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
471
|
+
}
|
|
472
|
+
if (val && typeof val === "object" && !(val instanceof Date)) {
|
|
473
|
+
const colType = tConfig.columns[k]?.dataType;
|
|
474
|
+
if (colType === "json" || colType === "jsonb") {
|
|
475
|
+
params.push(val);
|
|
476
|
+
} else if (Array.isArray(val)) {
|
|
477
|
+
const pgArray = "{" + val.map((item) => {
|
|
478
|
+
if (item === null || item === undefined)
|
|
479
|
+
return "NULL";
|
|
480
|
+
if (typeof item === "string")
|
|
481
|
+
return '"' + item.replace(/"/g, "\\\"") + '"';
|
|
482
|
+
return typeof item === "object" ? '"' + JSON.stringify(item).replace(/"/g, "\\\"") + '"' : String(item);
|
|
483
|
+
}).join(",") + "}";
|
|
484
|
+
params.push(pgArray);
|
|
485
|
+
} else {
|
|
486
|
+
params.push(JSON.stringify(val));
|
|
487
|
+
}
|
|
488
|
+
return `$${params.length}`;
|
|
489
|
+
}
|
|
490
|
+
if (val === undefined)
|
|
491
|
+
return "DEFAULT";
|
|
492
|
+
params.push(val);
|
|
493
|
+
return `$${params.length}`;
|
|
494
|
+
});
|
|
495
|
+
return `(${vals.join(", ")})`;
|
|
496
|
+
});
|
|
497
|
+
let query = `INSERT INTO ${tConfig.qualifiedName} (${columnsStr}) VALUES ${valuesStrs.join(", ")}`;
|
|
498
|
+
if (this._onConflict) {
|
|
499
|
+
if (this._onConflict === "do nothing") {
|
|
500
|
+
query += " ON CONFLICT DO NOTHING";
|
|
501
|
+
} else {
|
|
502
|
+
const offset = params.length;
|
|
503
|
+
query += " " + this._onConflict.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
504
|
+
params.push(...this._onConflict.params);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (this._returning) {
|
|
508
|
+
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(tConfig.columns).map((c) => `"${tConfig.columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${tConfig.columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
509
|
+
}
|
|
510
|
+
if (this._comment) {
|
|
511
|
+
query += ` /* ${this._comment} */`;
|
|
512
|
+
}
|
|
513
|
+
return { sql: query, params };
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
// ../bungres-orm/src/builders/select.ts
|
|
147
517
|
class SelectBuilder {
|
|
148
518
|
_table;
|
|
149
519
|
_executor;
|
|
150
520
|
_where = [];
|
|
151
521
|
_orderBy = [];
|
|
522
|
+
_groupBy = [];
|
|
523
|
+
_having = [];
|
|
152
524
|
_limit;
|
|
153
525
|
_offset;
|
|
154
526
|
_select;
|
|
@@ -175,11 +547,27 @@ class SelectBuilder {
|
|
|
175
547
|
return this;
|
|
176
548
|
}
|
|
177
549
|
where(condition) {
|
|
178
|
-
|
|
550
|
+
if (condition && typeof condition === "object" && !("sql" in condition)) {
|
|
551
|
+
this._where.push(parseWhereObject(getTableConfig(this._table), condition));
|
|
552
|
+
} else {
|
|
553
|
+
this._where.push(condition);
|
|
554
|
+
}
|
|
179
555
|
return this;
|
|
180
556
|
}
|
|
181
557
|
orderBy(column, dir = "asc") {
|
|
182
|
-
this._orderBy.push({ column
|
|
558
|
+
this._orderBy.push({ column, dir });
|
|
559
|
+
return this;
|
|
560
|
+
}
|
|
561
|
+
groupBy(...columns) {
|
|
562
|
+
this._groupBy.push(...columns);
|
|
563
|
+
return this;
|
|
564
|
+
}
|
|
565
|
+
having(condition) {
|
|
566
|
+
if (condition && typeof condition === "object" && !("sql" in condition)) {
|
|
567
|
+
this._having.push(parseWhereObject(getTableConfig(this._table), condition));
|
|
568
|
+
} else {
|
|
569
|
+
this._having.push(condition);
|
|
570
|
+
}
|
|
183
571
|
return this;
|
|
184
572
|
}
|
|
185
573
|
limit(n) {
|
|
@@ -194,35 +582,118 @@ class SelectBuilder {
|
|
|
194
582
|
this._joins.push(rawClause);
|
|
195
583
|
return this;
|
|
196
584
|
}
|
|
585
|
+
innerJoin(table2, condition) {
|
|
586
|
+
this._joins.push(sql`INNER JOIN ${rawSql(getTableConfig(table2).qualifiedName)} ON ${condition}`);
|
|
587
|
+
return this;
|
|
588
|
+
}
|
|
589
|
+
leftJoin(table2, condition) {
|
|
590
|
+
this._joins.push(sql`LEFT JOIN ${rawSql(getTableConfig(table2).qualifiedName)} ON ${condition}`);
|
|
591
|
+
return this;
|
|
592
|
+
}
|
|
593
|
+
rightJoin(table2, condition) {
|
|
594
|
+
this._joins.push(sql`RIGHT JOIN ${rawSql(getTableConfig(table2).qualifiedName)} ON ${condition}`);
|
|
595
|
+
return this;
|
|
596
|
+
}
|
|
597
|
+
fullJoin(table2, condition) {
|
|
598
|
+
this._joins.push(sql`FULL JOIN ${rawSql(getTableConfig(table2).qualifiedName)} ON ${condition}`);
|
|
599
|
+
return this;
|
|
600
|
+
}
|
|
601
|
+
_buildSelection(selection, params) {
|
|
602
|
+
const parts = [];
|
|
603
|
+
for (const [alias, col2] of Object.entries(selection)) {
|
|
604
|
+
if (typeof col2 === "object" && col2 !== null) {
|
|
605
|
+
if ("sql" in col2 && "params" in col2) {
|
|
606
|
+
const chunk = col2;
|
|
607
|
+
const offset = params.length;
|
|
608
|
+
params.push(...chunk.params);
|
|
609
|
+
parts.push(`'${alias}', ${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)}`);
|
|
610
|
+
} else if ("name" in col2 && "dataType" in col2) {
|
|
611
|
+
const c = col2;
|
|
612
|
+
parts.push(`'${alias}', ${c.tableName ? c.tableName + "." : ""}"${c.name}"`);
|
|
613
|
+
} else {
|
|
614
|
+
parts.push(`'${alias}', json_build_object(${this._buildSelection(col2, params)})`);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return parts.join(", ");
|
|
619
|
+
}
|
|
197
620
|
toSQL() {
|
|
198
621
|
let cols = "";
|
|
622
|
+
const params = [];
|
|
199
623
|
if (this._selection) {
|
|
200
|
-
cols = Object.entries(this._selection).map(([alias, col2]) =>
|
|
624
|
+
cols = Object.entries(this._selection).map(([alias, col2]) => {
|
|
625
|
+
if (typeof col2 === "object" && col2 !== null && "sql" in col2 && "params" in col2) {
|
|
626
|
+
const chunk = col2;
|
|
627
|
+
const offset = params.length;
|
|
628
|
+
params.push(...chunk.params);
|
|
629
|
+
return `${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)} AS "${alias}"`;
|
|
630
|
+
} else if (typeof col2 === "object" && col2 !== null && "name" in col2 && "dataType" in col2) {
|
|
631
|
+
const c = col2;
|
|
632
|
+
return `${c.tableName ? c.tableName + "." : ""}"${c.name}" AS "${alias}"`;
|
|
633
|
+
} else {
|
|
634
|
+
return `json_build_object(${this._buildSelection(col2, params)}) AS "${alias}"`;
|
|
635
|
+
}
|
|
636
|
+
}).join(", ");
|
|
201
637
|
} else if (this._select && this._select.length > 0) {
|
|
638
|
+
const qName = getTableConfig(this._table).qualifiedName;
|
|
202
639
|
cols = this._select.map((c) => {
|
|
203
640
|
if (typeof c === "string") {
|
|
204
|
-
return
|
|
641
|
+
return `${qName}."${getTableConfig(this._table).columns[c]?.name ?? c}" AS "${c}"`;
|
|
205
642
|
}
|
|
206
|
-
return
|
|
643
|
+
return `${c.tableName ? c.tableName + "." : ""}"${c.name}" AS "${c.alias || c.name}"`;
|
|
207
644
|
}).join(", ");
|
|
208
645
|
} else {
|
|
209
|
-
|
|
646
|
+
const qName = getTableConfig(this._table).qualifiedName;
|
|
647
|
+
cols = Object.keys(getTableConfig(this._table).columns).map((c) => `${qName}."${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ");
|
|
210
648
|
}
|
|
211
649
|
let query = `SELECT ${cols} FROM ${getTableConfig(this._table).qualifiedName}`;
|
|
212
650
|
if (this._joins.length > 0) {
|
|
213
|
-
|
|
651
|
+
const joinChunks = this._joins.map((j) => typeof j === "string" ? rawSql(j) : j);
|
|
652
|
+
const combinedJoins = sqlJoin(joinChunks, " ");
|
|
653
|
+
const offset = params.length;
|
|
654
|
+
query += " " + combinedJoins.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
655
|
+
params.push(...combinedJoins.params);
|
|
214
656
|
}
|
|
215
|
-
const params = [];
|
|
216
657
|
if (this._where.length > 0) {
|
|
217
658
|
const combined = sqlJoin(this._where, " AND ");
|
|
218
|
-
const offset =
|
|
659
|
+
const offset = params.length;
|
|
219
660
|
query += " WHERE " + combined.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
220
661
|
params.push(...combined.params);
|
|
221
662
|
}
|
|
663
|
+
if (this._groupBy.length > 0) {
|
|
664
|
+
const qName = getTableConfig(this._table).qualifiedName;
|
|
665
|
+
query += " GROUP BY " + this._groupBy.map((c) => {
|
|
666
|
+
if (typeof c === "string") {
|
|
667
|
+
const dbCol = getTableConfig(this._table).columns[c]?.name ?? c;
|
|
668
|
+
return `${qName}."${dbCol}"`;
|
|
669
|
+
} else if ("sql" in c && "params" in c) {
|
|
670
|
+
const offset = params.length;
|
|
671
|
+
params.push(...c.params);
|
|
672
|
+
return c.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
673
|
+
} else {
|
|
674
|
+
return `${c.tableName ? c.tableName + "." : ""}"${c.name}"`;
|
|
675
|
+
}
|
|
676
|
+
}).join(", ");
|
|
677
|
+
}
|
|
678
|
+
if (this._having.length > 0) {
|
|
679
|
+
const combined = sqlJoin(this._having, " AND ");
|
|
680
|
+
const offset = params.length;
|
|
681
|
+
query += " HAVING " + combined.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
682
|
+
params.push(...combined.params);
|
|
683
|
+
}
|
|
222
684
|
if (this._orderBy.length > 0) {
|
|
685
|
+
const qName = getTableConfig(this._table).qualifiedName;
|
|
223
686
|
query += " ORDER BY " + this._orderBy.map((o) => {
|
|
224
|
-
|
|
225
|
-
|
|
687
|
+
if (typeof o.column === "string") {
|
|
688
|
+
const dbCol = getTableConfig(this._table).columns[o.column]?.name ?? o.column;
|
|
689
|
+
return `${qName}."${dbCol}" ${o.dir.toUpperCase()}`;
|
|
690
|
+
} else if ("sql" in o.column && "params" in o.column) {
|
|
691
|
+
const offset = params.length;
|
|
692
|
+
params.push(...o.column.params);
|
|
693
|
+
return `${o.column.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)} ${o.dir.toUpperCase()}`;
|
|
694
|
+
} else {
|
|
695
|
+
return `${o.column.tableName ? o.column.tableName + "." : ""}"${o.column.name}" ${o.dir.toUpperCase()}`;
|
|
696
|
+
}
|
|
226
697
|
}).join(", ");
|
|
227
698
|
}
|
|
228
699
|
if (this._limit !== undefined) {
|
|
@@ -251,76 +722,7 @@ class SelectBuilderIntermediate {
|
|
|
251
722
|
return new SelectBuilder(table2, this._executor, this._selection);
|
|
252
723
|
}
|
|
253
724
|
}
|
|
254
|
-
|
|
255
|
-
class InsertBuilder {
|
|
256
|
-
_table;
|
|
257
|
-
_executor;
|
|
258
|
-
_values = [];
|
|
259
|
-
_onConflict;
|
|
260
|
-
_returning;
|
|
261
|
-
_comment;
|
|
262
|
-
constructor(table2, executor) {
|
|
263
|
-
this._table = table2;
|
|
264
|
-
this._executor = executor;
|
|
265
|
-
}
|
|
266
|
-
then(onfulfilled, onrejected) {
|
|
267
|
-
return this._executor.execute(this).then(onfulfilled, onrejected);
|
|
268
|
-
}
|
|
269
|
-
async single() {
|
|
270
|
-
return this._executor.executeSingle(this);
|
|
271
|
-
}
|
|
272
|
-
values(data) {
|
|
273
|
-
const rows = Array.isArray(data) ? data : [data];
|
|
274
|
-
this._values.push(...rows);
|
|
275
|
-
return this;
|
|
276
|
-
}
|
|
277
|
-
onConflictDoNothing() {
|
|
278
|
-
this._onConflict = "do nothing";
|
|
279
|
-
return this;
|
|
280
|
-
}
|
|
281
|
-
onConflictDoUpdate(clause) {
|
|
282
|
-
this._onConflict = clause;
|
|
283
|
-
return this;
|
|
284
|
-
}
|
|
285
|
-
returning(...columns) {
|
|
286
|
-
this._returning = columns.length > 0 ? columns : ["*"];
|
|
287
|
-
return this;
|
|
288
|
-
}
|
|
289
|
-
comment(tag) {
|
|
290
|
-
this._comment = tag;
|
|
291
|
-
return this;
|
|
292
|
-
}
|
|
293
|
-
toSQL() {
|
|
294
|
-
if (this._values.length === 0) {
|
|
295
|
-
throw new Error("InsertBuilder: no values provided");
|
|
296
|
-
}
|
|
297
|
-
const keys = Array.from(new Set(this._values.flatMap((v) => Object.keys(v))));
|
|
298
|
-
const params = [];
|
|
299
|
-
const rowPlaceholders = [];
|
|
300
|
-
for (const row of this._values) {
|
|
301
|
-
const placeholders = [];
|
|
302
|
-
for (const key of keys) {
|
|
303
|
-
params.push(row[key] ?? null);
|
|
304
|
-
placeholders.push(`$${params.length}`);
|
|
305
|
-
}
|
|
306
|
-
rowPlaceholders.push(`(${placeholders.join(", ")})`);
|
|
307
|
-
}
|
|
308
|
-
const colList = keys.map((k) => `"${getTableConfig(this._table).columns[k]?.name ?? k}"`).join(", ");
|
|
309
|
-
let query = `INSERT INTO ${getTableConfig(this._table).qualifiedName} (${colList}) VALUES ${rowPlaceholders.join(", ")}`;
|
|
310
|
-
if (this._onConflict === "do nothing") {
|
|
311
|
-
query += " ON CONFLICT DO NOTHING";
|
|
312
|
-
} else if (this._onConflict && typeof this._onConflict === "object") {
|
|
313
|
-
const offset = params.length;
|
|
314
|
-
query += " ON CONFLICT " + this._onConflict.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
315
|
-
params.push(...this._onConflict.params);
|
|
316
|
-
}
|
|
317
|
-
if (this._returning) {
|
|
318
|
-
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(getTableConfig(this._table).columns).map((c) => `"${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${getTableConfig(this._table).columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
319
|
-
}
|
|
320
|
-
return { sql: query, params };
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
725
|
+
// ../bungres-orm/src/builders/update.ts
|
|
324
726
|
class UpdateBuilder {
|
|
325
727
|
_table;
|
|
326
728
|
_executor;
|
|
@@ -343,7 +745,11 @@ class UpdateBuilder {
|
|
|
343
745
|
return this;
|
|
344
746
|
}
|
|
345
747
|
where(condition) {
|
|
346
|
-
|
|
748
|
+
if (condition && typeof condition === "object" && !("sql" in condition)) {
|
|
749
|
+
this._where.push(parseWhereObject(getTableConfig(this._table), condition));
|
|
750
|
+
} else {
|
|
751
|
+
this._where.push(condition);
|
|
752
|
+
}
|
|
347
753
|
return this;
|
|
348
754
|
}
|
|
349
755
|
returning(...columns) {
|
|
@@ -361,8 +767,32 @@ class UpdateBuilder {
|
|
|
361
767
|
}
|
|
362
768
|
const params = [];
|
|
363
769
|
const setClauses = entries.map(([key, value]) => {
|
|
364
|
-
params.push(value);
|
|
365
770
|
const dbCol = getTableConfig(this._table).columns[key]?.name ?? key;
|
|
771
|
+
if (value && typeof value === "object" && "sql" in value && "params" in value) {
|
|
772
|
+
const chunk = value;
|
|
773
|
+
const offset = params.length;
|
|
774
|
+
params.push(...chunk.params);
|
|
775
|
+
return `"${dbCol}" = ${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)}`;
|
|
776
|
+
}
|
|
777
|
+
if (value && typeof value === "object" && !(value instanceof Date)) {
|
|
778
|
+
const colType = getTableConfig(this._table).columns[key]?.dataType;
|
|
779
|
+
if (colType === "json" || colType === "jsonb") {
|
|
780
|
+
params.push(value);
|
|
781
|
+
} else if (Array.isArray(value)) {
|
|
782
|
+
const pgArray = "{" + value.map((item) => {
|
|
783
|
+
if (item === null || item === undefined)
|
|
784
|
+
return "NULL";
|
|
785
|
+
if (typeof item === "string")
|
|
786
|
+
return '"' + item.replace(/"/g, "\\\"") + '"';
|
|
787
|
+
return typeof item === "object" ? '"' + JSON.stringify(item).replace(/"/g, "\\\"") + '"' : String(item);
|
|
788
|
+
}).join(",") + "}";
|
|
789
|
+
params.push(pgArray);
|
|
790
|
+
} else {
|
|
791
|
+
params.push(JSON.stringify(value));
|
|
792
|
+
}
|
|
793
|
+
return `"${dbCol}" = $${params.length}`;
|
|
794
|
+
}
|
|
795
|
+
params.push(value);
|
|
366
796
|
return `"${dbCol}" = $${params.length}`;
|
|
367
797
|
});
|
|
368
798
|
let query = `UPDATE ${getTableConfig(this._table).qualifiedName} SET ${setClauses.join(", ")}`;
|
|
@@ -378,50 +808,7 @@ class UpdateBuilder {
|
|
|
378
808
|
return { sql: query, params };
|
|
379
809
|
}
|
|
380
810
|
}
|
|
381
|
-
|
|
382
|
-
class DeleteBuilder {
|
|
383
|
-
_table;
|
|
384
|
-
_executor;
|
|
385
|
-
_where = [];
|
|
386
|
-
_returning;
|
|
387
|
-
_comment;
|
|
388
|
-
constructor(table2, executor) {
|
|
389
|
-
this._table = table2;
|
|
390
|
-
this._executor = executor;
|
|
391
|
-
}
|
|
392
|
-
then(onfulfilled, onrejected) {
|
|
393
|
-
return this._executor.execute(this).then(onfulfilled, onrejected);
|
|
394
|
-
}
|
|
395
|
-
async single() {
|
|
396
|
-
return this._executor.executeSingle(this);
|
|
397
|
-
}
|
|
398
|
-
where(condition) {
|
|
399
|
-
this._where.push(condition);
|
|
400
|
-
return this;
|
|
401
|
-
}
|
|
402
|
-
returning(...columns) {
|
|
403
|
-
this._returning = columns.length > 0 ? columns : ["*"];
|
|
404
|
-
return this;
|
|
405
|
-
}
|
|
406
|
-
comment(tag) {
|
|
407
|
-
this._comment = tag;
|
|
408
|
-
return this;
|
|
409
|
-
}
|
|
410
|
-
toSQL() {
|
|
411
|
-
let query = `DELETE FROM ${getTableConfig(this._table).qualifiedName}`;
|
|
412
|
-
const params = [];
|
|
413
|
-
if (this._where.length > 0) {
|
|
414
|
-
const combined = sqlJoin(this._where, " AND ");
|
|
415
|
-
query += " WHERE " + combined.sql;
|
|
416
|
-
params.push(...combined.params);
|
|
417
|
-
}
|
|
418
|
-
if (this._returning) {
|
|
419
|
-
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(getTableConfig(this._table).columns).map((c) => `"${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${getTableConfig(this._table).columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
420
|
-
}
|
|
421
|
-
return { sql: query, params };
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
// ../../node_modules/.bun/@bungres+orm@0.2.0/node_modules/@bungres/orm/src/relational.ts
|
|
811
|
+
// ../bungres-orm/src/builders/relational.ts
|
|
425
812
|
var _relationsCache = new WeakMap;
|
|
426
813
|
|
|
427
814
|
class RelationalQueryBuilder {
|
|
@@ -505,7 +892,7 @@ class RelationalQueryBuilder {
|
|
|
505
892
|
const ones = {};
|
|
506
893
|
const manys = {};
|
|
507
894
|
const manyToManys = {};
|
|
508
|
-
for (const [
|
|
895
|
+
for (const [colName2, col2] of Object.entries(tConfig.columns)) {
|
|
509
896
|
if (col2.references) {
|
|
510
897
|
const ref = col2.references;
|
|
511
898
|
const relName = ref.relationName || ref.table;
|
|
@@ -514,7 +901,7 @@ class RelationalQueryBuilder {
|
|
|
514
901
|
}
|
|
515
902
|
for (const [otherName, otherTable] of Object.entries(this._schema)) {
|
|
516
903
|
const otherConfig = otherTable[TableConfigSymbol];
|
|
517
|
-
for (const [
|
|
904
|
+
for (const [colName2, col2] of Object.entries(otherConfig.columns)) {
|
|
518
905
|
if (col2.references && col2.references.table === tableName) {
|
|
519
906
|
const ref = col2.references;
|
|
520
907
|
const backRelName = ref.backRelationName || otherName;
|
|
@@ -553,10 +940,15 @@ class RelationalQueryBuilder {
|
|
|
553
940
|
const jsonFields = [];
|
|
554
941
|
const lateralJoins = [];
|
|
555
942
|
const columnsConfig = args.columns;
|
|
943
|
+
const hasTrue = columnsConfig ? Object.values(columnsConfig).some((v) => v === true) : false;
|
|
556
944
|
for (const [colKey, colConfig] of Object.entries(tableConfig.columns)) {
|
|
557
945
|
if (columnsConfig) {
|
|
558
|
-
if (
|
|
559
|
-
|
|
946
|
+
if (hasTrue) {
|
|
947
|
+
if (columnsConfig[colKey] !== true)
|
|
948
|
+
continue;
|
|
949
|
+
} else {
|
|
950
|
+
if (columnsConfig[colKey] === false)
|
|
951
|
+
continue;
|
|
560
952
|
}
|
|
561
953
|
}
|
|
562
954
|
jsonFields.push(`'${colKey}', "${alias}"."${colConfig.name}"`);
|
|
@@ -615,10 +1007,16 @@ class RelationalQueryBuilder {
|
|
|
615
1007
|
if (joinCondition) {
|
|
616
1008
|
fromSql += ` WHERE ${joinCondition}`;
|
|
617
1009
|
}
|
|
618
|
-
if (args.where
|
|
1010
|
+
if (args.where) {
|
|
619
1011
|
const offset = params.length;
|
|
620
|
-
|
|
621
|
-
|
|
1012
|
+
let whereChunk = args.where;
|
|
1013
|
+
if (args.where && !args.where.sql) {
|
|
1014
|
+
whereChunk = parseWhereObject(tableConfig, args.where);
|
|
1015
|
+
}
|
|
1016
|
+
if (whereChunk && whereChunk.sql) {
|
|
1017
|
+
fromSql += (joinCondition ? " AND " : " WHERE ") + whereChunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
1018
|
+
params.push(...whereChunk.params);
|
|
1019
|
+
}
|
|
622
1020
|
}
|
|
623
1021
|
if (args.orderBy) {
|
|
624
1022
|
if (typeof args.orderBy === "string") {
|
|
@@ -627,6 +1025,15 @@ class RelationalQueryBuilder {
|
|
|
627
1025
|
const offset = params.length;
|
|
628
1026
|
fromSql += ` ORDER BY ` + args.orderBy.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
629
1027
|
params.push(...args.orderBy.params);
|
|
1028
|
+
} else {
|
|
1029
|
+
const chunks = parseOrderByObject(tableConfig, args.orderBy);
|
|
1030
|
+
if (chunks.length > 0) {
|
|
1031
|
+
fromSql += ` ORDER BY ` + chunks.map((c) => {
|
|
1032
|
+
const offset = params.length;
|
|
1033
|
+
params.push(...c.params);
|
|
1034
|
+
return c.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
1035
|
+
}).join(", ");
|
|
1036
|
+
}
|
|
630
1037
|
}
|
|
631
1038
|
}
|
|
632
1039
|
if (args.limit !== undefined) {
|
|
@@ -648,7 +1055,7 @@ class RelationalQueryBuilder {
|
|
|
648
1055
|
}
|
|
649
1056
|
}
|
|
650
1057
|
|
|
651
|
-
//
|
|
1058
|
+
// ../bungres-orm/src/core/db.ts
|
|
652
1059
|
function parseDBName(url) {
|
|
653
1060
|
try {
|
|
654
1061
|
return new URL(url).pathname.slice(1);
|
|
@@ -792,7 +1199,7 @@ class BungresTransaction {
|
|
|
792
1199
|
return Array.from(result);
|
|
793
1200
|
}
|
|
794
1201
|
}
|
|
795
|
-
function
|
|
1202
|
+
function bungres(config) {
|
|
796
1203
|
const db = new BungresDB(config);
|
|
797
1204
|
if (typeof config === "object" && config.schema) {
|
|
798
1205
|
const schema = config.schema;
|
|
@@ -814,7 +1221,7 @@ function createDB(config) {
|
|
|
814
1221
|
}
|
|
815
1222
|
return db;
|
|
816
1223
|
}
|
|
817
|
-
//
|
|
1224
|
+
// ../bungres-orm/src/ddl.ts
|
|
818
1225
|
function generateCreateTable(config, ifNotExists = true) {
|
|
819
1226
|
const tableName = config.schema ? `"${config.schema}"."${config.name}"` : `"${config.name}"`;
|
|
820
1227
|
const exists = ifNotExists ? " IF NOT EXISTS" : "";
|
|
@@ -1047,11 +1454,11 @@ function diffSchemas(prev, next) {
|
|
|
1047
1454
|
const idxName = idx.name ?? `idx_${tableName}_${idx.columns.join("_")}`;
|
|
1048
1455
|
if (!prevIdxNames.has(idxName)) {
|
|
1049
1456
|
const tbl = nextConfig.schema ? `"${nextConfig.schema}"."${tableName}"` : `"${tableName}"`;
|
|
1050
|
-
const
|
|
1457
|
+
const unique2 = idx.unique ? "UNIQUE " : "";
|
|
1051
1458
|
const using = idx.using ? ` USING ${idx.using.toUpperCase()}` : "";
|
|
1052
1459
|
const cols = idx.columns.map((c) => `"${c}"`).join(", ");
|
|
1053
1460
|
const where = idx.where ? ` WHERE ${idx.where}` : "";
|
|
1054
|
-
statements.push(`CREATE ${
|
|
1461
|
+
statements.push(`CREATE ${unique2}INDEX IF NOT EXISTS "${idxName}" ON ${tbl}${using} (${cols})${where};`);
|
|
1055
1462
|
summary.push(`CREATE INDEX ${idxName} ON ${tableName}`);
|
|
1056
1463
|
}
|
|
1057
1464
|
}
|
|
@@ -1215,7 +1622,7 @@ async function runGenerate(config, name) {
|
|
|
1215
1622
|
console.warn(colorize("No table definitions found. Check your schema glob pattern.", "yellow"));
|
|
1216
1623
|
return;
|
|
1217
1624
|
}
|
|
1218
|
-
const migrationsDir = resolve3(config.
|
|
1625
|
+
const migrationsDir = resolve3(config.out);
|
|
1219
1626
|
await Bun.$`mkdir -p ${migrationsDir}`.quiet();
|
|
1220
1627
|
const currentSnapshot = Object.fromEntries(schemas.map((s) => [s.config.name, s.config]));
|
|
1221
1628
|
const snapshotPath = join3(migrationsDir, SNAPSHOT_FILE);
|
|
@@ -1308,19 +1715,22 @@ function topoSort(schemas) {
|
|
|
1308
1715
|
}
|
|
1309
1716
|
// src/commands/migrate.ts
|
|
1310
1717
|
import { join as join4, resolve as resolve4 } from "path";
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1718
|
+
async function runMigrate(config) {
|
|
1719
|
+
const migrationsDir = resolve4(config.out);
|
|
1720
|
+
const sql2 = new Bun.SQL(config.dbUrl);
|
|
1721
|
+
const table2 = config.migrationsTable;
|
|
1722
|
+
const schema = config.migrationsSchema;
|
|
1723
|
+
const qualifiedTable = `"${schema}"."${table2}"`;
|
|
1724
|
+
const createSchema = `CREATE SCHEMA IF NOT EXISTS "${schema}";`;
|
|
1725
|
+
const createMigrationsTable = `
|
|
1726
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
|
|
1314
1727
|
id SERIAL PRIMARY KEY,
|
|
1315
1728
|
name TEXT NOT NULL UNIQUE,
|
|
1316
1729
|
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
1317
|
-
);
|
|
1318
|
-
`.trim();
|
|
1319
|
-
async function runMigrate(config) {
|
|
1320
|
-
const migrationsDir = resolve4(config.migrationsDir);
|
|
1321
|
-
const sql2 = new Bun.SQL(config.dbUrl);
|
|
1730
|
+
);`.trim();
|
|
1322
1731
|
try {
|
|
1323
|
-
await sql2.unsafe(
|
|
1732
|
+
await sql2.unsafe(createSchema);
|
|
1733
|
+
await sql2.unsafe(createMigrationsTable);
|
|
1324
1734
|
const glob = new Bun.Glob("*.sql");
|
|
1325
1735
|
const files = [];
|
|
1326
1736
|
for await (const file of glob.scan({ cwd: migrationsDir, absolute: false })) {
|
|
@@ -1332,7 +1742,7 @@ async function runMigrate(config) {
|
|
|
1332
1742
|
console.log(colorize("Run `bungres generate` first.", "yellow"));
|
|
1333
1743
|
return;
|
|
1334
1744
|
}
|
|
1335
|
-
const applied = await sql2.unsafe(`SELECT name FROM
|
|
1745
|
+
const applied = await sql2.unsafe(`SELECT name FROM ${qualifiedTable}`);
|
|
1336
1746
|
const appliedSet = new Set(applied.map((r) => r.name));
|
|
1337
1747
|
const pending = files.filter((f) => !appliedSet.has(f));
|
|
1338
1748
|
if (pending.length === 0) {
|
|
@@ -1350,11 +1760,11 @@ ${content}
|
|
|
1350
1760
|
`);
|
|
1351
1761
|
}
|
|
1352
1762
|
await sql2.transaction(async (txSql) => {
|
|
1353
|
-
const statements = content.split(";").map((s) => s.trim()).filter(Boolean);
|
|
1763
|
+
const statements = config.breakpoints ? content.split(/-->statement-breakpoint/g).flatMap((chunk) => chunk.split(";").map((s) => s.trim()).filter(Boolean)) : content.split(";").map((s) => s.trim()).filter(Boolean);
|
|
1354
1764
|
for (const stmt of statements) {
|
|
1355
1765
|
await txSql.unsafe(stmt + ";");
|
|
1356
1766
|
}
|
|
1357
|
-
await txSql.unsafe(`INSERT INTO
|
|
1767
|
+
await txSql.unsafe(`INSERT INTO ${qualifiedTable} (name) VALUES ($1)`, [file]);
|
|
1358
1768
|
});
|
|
1359
1769
|
console.log(colorize(` \u2713 ${file}`, "green"));
|
|
1360
1770
|
}
|
|
@@ -1367,7 +1777,7 @@ Done.`, "green"));
|
|
|
1367
1777
|
// src/commands/pull.ts
|
|
1368
1778
|
import { resolve as resolve5, join as join5 } from "path";
|
|
1369
1779
|
async function introspectDb(sql2, dbSchema) {
|
|
1370
|
-
const
|
|
1780
|
+
const columns2 = await sql2.unsafe(`SELECT
|
|
1371
1781
|
c.table_name,
|
|
1372
1782
|
c.column_name,
|
|
1373
1783
|
c.data_type,
|
|
@@ -1401,7 +1811,7 @@ async function introspectDb(sql2, dbSchema) {
|
|
|
1401
1811
|
const indexes = await sql2.unsafe(`SELECT tablename, indexname, indexdef
|
|
1402
1812
|
FROM pg_indexes
|
|
1403
1813
|
WHERE schemaname = $1`, [dbSchema]);
|
|
1404
|
-
return groupByTable(
|
|
1814
|
+
return groupByTable(columns2, constraints, indexes);
|
|
1405
1815
|
}
|
|
1406
1816
|
async function runPull(config) {
|
|
1407
1817
|
console.log("@bungres/kit pull: introspecting database...");
|
|
@@ -1424,9 +1834,9 @@ async function runPull(config) {
|
|
|
1424
1834
|
await sql2.end();
|
|
1425
1835
|
}
|
|
1426
1836
|
}
|
|
1427
|
-
function groupByTable(
|
|
1837
|
+
function groupByTable(columns2, constraints, indexes) {
|
|
1428
1838
|
const map = new Map;
|
|
1429
|
-
for (const col2 of
|
|
1839
|
+
for (const col2 of columns2) {
|
|
1430
1840
|
if (!map.has(col2.table_name)) {
|
|
1431
1841
|
map.set(col2.table_name, {
|
|
1432
1842
|
tableName: col2.table_name,
|
|
@@ -1462,7 +1872,7 @@ function generateSchemaTS(tableMap, dbSchema) {
|
|
|
1462
1872
|
`// Generated at: ${new Date().toISOString()}`,
|
|
1463
1873
|
``,
|
|
1464
1874
|
`import {`,
|
|
1465
|
-
`
|
|
1875
|
+
` table,`,
|
|
1466
1876
|
` text, varchar, char, integer, bigint, smallint,`,
|
|
1467
1877
|
` serial, bigserial, boolean, real, doublePrecision,`,
|
|
1468
1878
|
` numeric, decimal, json, jsonb,`,
|
|
@@ -1474,7 +1884,7 @@ function generateSchemaTS(tableMap, dbSchema) {
|
|
|
1474
1884
|
];
|
|
1475
1885
|
for (const [, table2] of tableMap) {
|
|
1476
1886
|
const varName = toCamelCase(table2.tableName);
|
|
1477
|
-
lines.push(`export const ${varName} =
|
|
1887
|
+
lines.push(`export const ${varName} = table("${table2.tableName}", {`);
|
|
1478
1888
|
for (const col2 of table2.columns) {
|
|
1479
1889
|
const colExpr = buildColumnExpression(col2);
|
|
1480
1890
|
lines.push(` ${toCamelCase(col2.name)}: ${colExpr},`);
|
|
@@ -1621,15 +2031,17 @@ function toCamelCase(str) {
|
|
|
1621
2031
|
}
|
|
1622
2032
|
// src/commands/status.ts
|
|
1623
2033
|
import { resolve as resolve6 } from "path";
|
|
1624
|
-
var MIGRATIONS_TABLE2 = "__bungres_migrations";
|
|
1625
2034
|
async function runStatus(config) {
|
|
1626
|
-
const migrationsDir = resolve6(config.
|
|
2035
|
+
const migrationsDir = resolve6(config.out);
|
|
1627
2036
|
const sql2 = new Bun.SQL(config.dbUrl);
|
|
2037
|
+
const table2 = config.migrationsTable;
|
|
2038
|
+
const schema = config.migrationsSchema;
|
|
2039
|
+
const qualifiedTable = `"${schema}"."${table2}"`;
|
|
1628
2040
|
try {
|
|
1629
2041
|
const tableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
1630
2042
|
SELECT 1 FROM information_schema.tables
|
|
1631
|
-
WHERE table_name = $
|
|
1632
|
-
) AS exists`, [
|
|
2043
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
2044
|
+
) AS exists`, [schema, table2]);
|
|
1633
2045
|
const trackingExists = tableCheck[0]?.exists ?? false;
|
|
1634
2046
|
const glob = new Bun.Glob("*.sql");
|
|
1635
2047
|
const files = [];
|
|
@@ -1643,7 +2055,7 @@ async function runStatus(config) {
|
|
|
1643
2055
|
}
|
|
1644
2056
|
let appliedSet = new Set;
|
|
1645
2057
|
if (trackingExists) {
|
|
1646
|
-
const applied = await sql2.unsafe(`SELECT name FROM
|
|
2058
|
+
const applied = await sql2.unsafe(`SELECT name FROM ${qualifiedTable} ORDER BY applied_at`);
|
|
1647
2059
|
appliedSet = new Set(applied.map((r) => r.name));
|
|
1648
2060
|
}
|
|
1649
2061
|
console.log(colorize(`
|
|
@@ -1673,14 +2085,19 @@ async function runDrop(config, opts = {}) {
|
|
|
1673
2085
|
}
|
|
1674
2086
|
const sql2 = new Bun.SQL(config.dbUrl);
|
|
1675
2087
|
try {
|
|
1676
|
-
const
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
const
|
|
2088
|
+
const userSchema = config.dbSchema;
|
|
2089
|
+
const existingUserTablesResult = await sql2.unsafe(`SELECT table_name FROM information_schema.tables WHERE table_schema = $1`, [userSchema]);
|
|
2090
|
+
const existingTableNames = new Set(existingUserTablesResult.map((r) => r.table_name));
|
|
2091
|
+
const migTableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
2092
|
+
SELECT 1 FROM information_schema.tables
|
|
2093
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
2094
|
+
) AS exists`, [config.migrationsSchema, config.migrationsTable]);
|
|
2095
|
+
const migrationTableExists = migTableCheck[0]?.exists ?? false;
|
|
2096
|
+
const pushTableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
2097
|
+
SELECT 1 FROM information_schema.tables
|
|
2098
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
2099
|
+
) AS exists`, [config.migrationsSchema, "__bungres_push"]);
|
|
2100
|
+
const pushTableExists = pushTableCheck[0]?.exists ?? false;
|
|
1684
2101
|
const tablesToDrop = schemas.filter((s) => existingTableNames.has(s.config.name));
|
|
1685
2102
|
if (tablesToDrop.length === 0 && !migrationTableExists && !pushTableExists) {
|
|
1686
2103
|
console.log("No tables to drop (they either don't exist or were already dropped).");
|
|
@@ -1688,10 +2105,10 @@ async function runDrop(config, opts = {}) {
|
|
|
1688
2105
|
}
|
|
1689
2106
|
const tableNamesToPrint = tablesToDrop.map((s) => (s.config.schema ? s.config.schema + "." : "") + s.config.name);
|
|
1690
2107
|
if (migrationTableExists) {
|
|
1691
|
-
tableNamesToPrint.push(
|
|
2108
|
+
tableNamesToPrint.push(`${config.migrationsSchema}.${config.migrationsTable}`);
|
|
1692
2109
|
}
|
|
1693
2110
|
if (pushTableExists) {
|
|
1694
|
-
tableNamesToPrint.push(
|
|
2111
|
+
tableNamesToPrint.push(`${config.migrationsSchema}.__bungres_push`);
|
|
1695
2112
|
}
|
|
1696
2113
|
if (!opts.force) {
|
|
1697
2114
|
console.warn(colorize(`
|
|
@@ -1715,12 +2132,13 @@ Are you sure? Type YES to continue: `, "cyan"));
|
|
|
1715
2132
|
console.log(colorize(` \u2713 dropped ${entry.config.name}`, "green"));
|
|
1716
2133
|
}
|
|
1717
2134
|
if (migrationTableExists) {
|
|
1718
|
-
|
|
1719
|
-
|
|
2135
|
+
const qualifiedMigTable = `"${config.migrationsSchema}"."${config.migrationsTable}"`;
|
|
2136
|
+
await sql2.unsafe(`DROP TABLE IF EXISTS ${qualifiedMigTable} CASCADE`);
|
|
2137
|
+
console.log(colorize(` \u2713 dropped ${config.migrationsSchema}.${config.migrationsTable}`, "green"));
|
|
1720
2138
|
}
|
|
1721
2139
|
if (pushTableExists) {
|
|
1722
|
-
await sql2.unsafe(
|
|
1723
|
-
console.log(colorize(` \u2713 dropped __bungres_push`, "green"));
|
|
2140
|
+
await sql2.unsafe(`DROP TABLE IF EXISTS "${config.migrationsSchema}"."__bungres_push" CASCADE`);
|
|
2141
|
+
console.log(colorize(` \u2713 dropped ${config.migrationsSchema}.__bungres_push`, "green"));
|
|
1724
2142
|
}
|
|
1725
2143
|
console.log(colorize(`
|
|
1726
2144
|
Drop complete.`, "green"));
|