@onreza/sqlx-js 0.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +496 -0
  3. package/ROADMAP.md +28 -0
  4. package/dist/bin/sqlx-js.d.ts +2 -0
  5. package/dist/bin/sqlx-js.js +180 -0
  6. package/dist/src/bun-runtime.d.ts +7 -0
  7. package/dist/src/bun-runtime.js +45 -0
  8. package/dist/src/bun.d.ts +22 -0
  9. package/dist/src/bun.js +9 -0
  10. package/dist/src/cache.d.ts +36 -0
  11. package/dist/src/cache.js +104 -0
  12. package/dist/src/codegen.d.ts +2 -0
  13. package/dist/src/codegen.js +74 -0
  14. package/dist/src/commands/migrate.d.ts +63 -0
  15. package/dist/src/commands/migrate.js +283 -0
  16. package/dist/src/commands/prepare.d.ts +23 -0
  17. package/dist/src/commands/prepare.js +314 -0
  18. package/dist/src/commands/schema.d.ts +14 -0
  19. package/dist/src/commands/schema.js +72 -0
  20. package/dist/src/commands/watch.d.ts +21 -0
  21. package/dist/src/commands/watch.js +94 -0
  22. package/dist/src/config.d.ts +6 -0
  23. package/dist/src/config.js +23 -0
  24. package/dist/src/index.d.ts +23 -0
  25. package/dist/src/index.js +10 -0
  26. package/dist/src/pg/analyze.d.ts +13 -0
  27. package/dist/src/pg/analyze.js +479 -0
  28. package/dist/src/pg/extensions.d.ts +2 -0
  29. package/dist/src/pg/extensions.js +15 -0
  30. package/dist/src/pg/narrow.d.ts +3 -0
  31. package/dist/src/pg/narrow.js +146 -0
  32. package/dist/src/pg/oids.d.ts +10 -0
  33. package/dist/src/pg/oids.js +137 -0
  34. package/dist/src/pg/param-map.d.ts +12 -0
  35. package/dist/src/pg/param-map.js +180 -0
  36. package/dist/src/pg/schema.d.ts +61 -0
  37. package/dist/src/pg/schema.js +225 -0
  38. package/dist/src/pg/wire.d.ts +134 -0
  39. package/dist/src/pg/wire.js +705 -0
  40. package/dist/src/postgres-runtime.d.ts +11 -0
  41. package/dist/src/postgres-runtime.js +150 -0
  42. package/dist/src/runtime.d.ts +69 -0
  43. package/dist/src/runtime.js +446 -0
  44. package/dist/src/scan/scanner.d.ts +12 -0
  45. package/dist/src/scan/scanner.js +283 -0
  46. package/dist/src/schema-snapshot.d.ts +104 -0
  47. package/dist/src/schema-snapshot.js +473 -0
  48. package/dist/src/typed.d.ts +25 -0
  49. package/dist/src/typed.js +1 -0
  50. package/package.json +78 -0
@@ -0,0 +1,473 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { decodeText, parseDatabaseUrl, PgClient } from "./pg/wire.js";
4
+ function rows(result) {
5
+ return result.rows.map((r) => {
6
+ const out = {};
7
+ for (let i = 0; i < result.fields.length; i++) {
8
+ out[result.fields[i].name] = decodeText(r[i] ?? null);
9
+ }
10
+ return out;
11
+ });
12
+ }
13
+ function parseJsonArray(value) {
14
+ if (!value)
15
+ return [];
16
+ const parsed = JSON.parse(value);
17
+ return Array.isArray(parsed) ? parsed.filter((v) => typeof v === "string") : [];
18
+ }
19
+ function bool(value) {
20
+ return value === "t";
21
+ }
22
+ function num(value) {
23
+ return Number(value ?? 0);
24
+ }
25
+ function relationKind(raw) {
26
+ switch (raw) {
27
+ case "r": return "table";
28
+ case "p": return "partitioned_table";
29
+ case "v": return "view";
30
+ case "m": return "materialized_view";
31
+ case "f": return "foreign_table";
32
+ default: return "table";
33
+ }
34
+ }
35
+ function constraintKind(raw) {
36
+ switch (raw) {
37
+ case "p": return "primary_key";
38
+ case "f": return "foreign_key";
39
+ case "u": return "unique";
40
+ case "x": return "exclude";
41
+ default: return "check";
42
+ }
43
+ }
44
+ function functionKind(raw) {
45
+ switch (raw) {
46
+ case "p": return "procedure";
47
+ case "a": return "aggregate";
48
+ case "w": return "window";
49
+ default: return "function";
50
+ }
51
+ }
52
+ function volatility(raw) {
53
+ switch (raw) {
54
+ case "i": return "immutable";
55
+ case "s": return "stable";
56
+ default: return "volatile";
57
+ }
58
+ }
59
+ function action(raw) {
60
+ switch (raw) {
61
+ case "r": return "restrict";
62
+ case "c": return "cascade";
63
+ case "n": return "set null";
64
+ case "d": return "set default";
65
+ default: return "no action";
66
+ }
67
+ }
68
+ function byRelationKey(items) {
69
+ const out = new Map();
70
+ for (const item of items) {
71
+ const key = `${item.schema}.${item.table}`;
72
+ const arr = out.get(key) ?? [];
73
+ arr.push(item);
74
+ out.set(key, arr);
75
+ }
76
+ return out;
77
+ }
78
+ function relationKey(schema, name) {
79
+ return `${schema}.${name}`;
80
+ }
81
+ function systemSchemaFilter(alias = "n") {
82
+ return `${alias}.nspname <> 'information_schema' AND ${alias}.nspname NOT LIKE 'pg\\_%' ESCAPE '\\'`;
83
+ }
84
+ export async function introspectDatabase(databaseUrl) {
85
+ const client = new PgClient(parseDatabaseUrl(databaseUrl));
86
+ await client.connect();
87
+ try {
88
+ return await introspectConnected(client);
89
+ }
90
+ finally {
91
+ await client.end();
92
+ }
93
+ }
94
+ export async function introspectConnected(client) {
95
+ const relRows = rows(await client.simpleQuery(`
96
+ SELECT
97
+ n.nspname AS schema,
98
+ c.relname AS name,
99
+ c.relkind::text AS kind,
100
+ CASE WHEN c.relkind IN ('v', 'm') THEN pg_get_viewdef(c.oid, true) ELSE NULL END AS definition
101
+ FROM pg_class c
102
+ JOIN pg_namespace n ON n.oid = c.relnamespace
103
+ WHERE c.relkind IN ('r', 'p', 'v', 'm', 'f')
104
+ AND ${systemSchemaFilter("n")}
105
+ ORDER BY n.nspname, c.relname
106
+ `));
107
+ const colRows = rows(await client.simpleQuery(`
108
+ SELECT
109
+ n.nspname AS schema,
110
+ c.relname AS table,
111
+ a.attnum::int4 AS ordinal,
112
+ a.attname AS name,
113
+ format_type(a.atttypid, a.atttypmod) AS type,
114
+ a.atttypid::int8 AS type_oid,
115
+ a.attnotnull AS not_null,
116
+ CASE WHEN a.attgenerated = '' THEN pg_get_expr(ad.adbin, ad.adrelid) ELSE NULL END AS default_expr,
117
+ a.attidentity AS identity,
118
+ a.attgenerated AS generated,
119
+ CASE WHEN a.attgenerated <> '' THEN pg_get_expr(ad.adbin, ad.adrelid) ELSE NULL END AS generated_expr
120
+ FROM pg_class c
121
+ JOIN pg_namespace n ON n.oid = c.relnamespace
122
+ JOIN pg_attribute a ON a.attrelid = c.oid
123
+ LEFT JOIN pg_attrdef ad ON ad.adrelid = c.oid AND ad.adnum = a.attnum
124
+ WHERE c.relkind IN ('r', 'p', 'v', 'm', 'f')
125
+ AND ${systemSchemaFilter("n")}
126
+ AND a.attnum > 0
127
+ AND NOT a.attisdropped
128
+ ORDER BY n.nspname, c.relname, a.attnum
129
+ `));
130
+ const constraintRows = rows(await client.simpleQuery(`
131
+ SELECT
132
+ n.nspname AS schema,
133
+ c.relname AS table,
134
+ con.conname AS name,
135
+ con.contype::text AS kind,
136
+ COALESCE((
137
+ SELECT json_agg(a.attname ORDER BY u.ord)::text
138
+ FROM unnest(con.conkey) WITH ORDINALITY AS u(attnum, ord)
139
+ JOIN pg_attribute a ON a.attrelid = con.conrelid AND a.attnum = u.attnum
140
+ ), '[]') AS columns,
141
+ pg_get_constraintdef(con.oid, true) AS definition,
142
+ CASE WHEN con.contype = 'c' THEN pg_get_expr(con.conbin, con.conrelid) ELSE NULL END AS expression,
143
+ rn.nspname AS ref_schema,
144
+ rc.relname AS ref_table,
145
+ COALESCE((
146
+ SELECT json_agg(a.attname ORDER BY u.ord)::text
147
+ FROM unnest(con.confkey) WITH ORDINALITY AS u(attnum, ord)
148
+ JOIN pg_attribute a ON a.attrelid = con.confrelid AND a.attnum = u.attnum
149
+ ), '[]') AS ref_columns,
150
+ con.confupdtype::text AS on_update,
151
+ con.confdeltype::text AS on_delete,
152
+ con.condeferrable AS deferrable,
153
+ con.condeferred AS initially_deferred
154
+ FROM pg_constraint con
155
+ JOIN pg_class c ON c.oid = con.conrelid
156
+ JOIN pg_namespace n ON n.oid = c.relnamespace
157
+ LEFT JOIN pg_class rc ON rc.oid = con.confrelid
158
+ LEFT JOIN pg_namespace rn ON rn.oid = rc.relnamespace
159
+ WHERE c.relkind IN ('r', 'p', 'v', 'm', 'f')
160
+ AND ${systemSchemaFilter("n")}
161
+ ORDER BY n.nspname, c.relname, con.conname
162
+ `));
163
+ const indexRows = rows(await client.simpleQuery(`
164
+ SELECT
165
+ n.nspname AS schema,
166
+ tbl.relname AS table,
167
+ idx.relname AS name,
168
+ i.indisunique AS unique,
169
+ i.indisprimary AS primary,
170
+ am.amname AS method,
171
+ COALESCE((
172
+ SELECT json_agg(a.attname ORDER BY u.ord)::text
173
+ FROM unnest(string_to_array(i.indkey::text, ' ')) WITH ORDINALITY AS u(attnum, ord)
174
+ JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = u.attnum::int2
175
+ WHERE u.attnum <> '0'
176
+ ), '[]') AS columns,
177
+ pg_get_indexdef(idx.oid) AS definition,
178
+ pg_get_expr(i.indpred, i.indrelid) AS predicate
179
+ FROM pg_index i
180
+ JOIN pg_class idx ON idx.oid = i.indexrelid
181
+ JOIN pg_class tbl ON tbl.oid = i.indrelid
182
+ JOIN pg_namespace n ON n.oid = tbl.relnamespace
183
+ JOIN pg_am am ON am.oid = idx.relam
184
+ WHERE tbl.relkind IN ('r', 'p', 'm')
185
+ AND ${systemSchemaFilter("n")}
186
+ ORDER BY n.nspname, tbl.relname, idx.relname
187
+ `));
188
+ const enumRows = rows(await client.simpleQuery(`
189
+ SELECT n.nspname AS schema, t.typname AS name, e.enumlabel AS value
190
+ FROM pg_type t
191
+ JOIN pg_namespace n ON n.oid = t.typnamespace
192
+ JOIN pg_enum e ON e.enumtypid = t.oid
193
+ WHERE ${systemSchemaFilter("n")}
194
+ ORDER BY n.nspname, t.typname, e.enumsortorder
195
+ `));
196
+ const domainRows = rows(await client.simpleQuery(`
197
+ SELECT
198
+ n.nspname AS schema,
199
+ t.typname AS name,
200
+ format_type(t.typbasetype, t.typtypmod) AS base_type,
201
+ t.typnotnull AS not_null,
202
+ pg_get_expr(t.typdefaultbin, 0) AS default_expr,
203
+ COALESCE((
204
+ SELECT json_agg(pg_get_constraintdef(c.oid, true) ORDER BY c.conname)::text
205
+ FROM pg_constraint c
206
+ WHERE c.contypid = t.oid
207
+ ), '[]') AS checks
208
+ FROM pg_type t
209
+ JOIN pg_namespace n ON n.oid = t.typnamespace
210
+ WHERE t.typtype = 'd'
211
+ AND ${systemSchemaFilter("n")}
212
+ ORDER BY n.nspname, t.typname
213
+ `));
214
+ const compositeRows = rows(await client.simpleQuery(`
215
+ SELECT
216
+ n.nspname AS schema,
217
+ t.typname AS name,
218
+ COALESCE((
219
+ SELECT json_agg(json_build_object('name', a.attname, 'type', format_type(a.atttypid, a.atttypmod)) ORDER BY a.attnum)::text
220
+ FROM pg_attribute a
221
+ WHERE a.attrelid = c.oid
222
+ AND a.attnum > 0
223
+ AND NOT a.attisdropped
224
+ ), '[]') AS fields
225
+ FROM pg_type t
226
+ JOIN pg_namespace n ON n.oid = t.typnamespace
227
+ JOIN pg_class c ON c.oid = t.typrelid AND c.relkind = 'c'
228
+ WHERE t.typtype = 'c'
229
+ AND ${systemSchemaFilter("n")}
230
+ ORDER BY n.nspname, t.typname
231
+ `));
232
+ const functionRows = rows(await client.simpleQuery(`
233
+ SELECT
234
+ n.nspname AS schema,
235
+ p.proname AS name,
236
+ p.prokind::text AS kind,
237
+ pg_get_function_identity_arguments(p.oid) AS identity_arguments,
238
+ pg_get_function_arguments(p.oid) AS arguments,
239
+ pg_get_function_result(p.oid) AS return_type,
240
+ p.proretset AS returns_set,
241
+ p.provolatile::text AS volatility,
242
+ p.proisstrict AS strict,
243
+ p.prosecdef AS security_definer,
244
+ l.lanname AS language
245
+ FROM pg_proc p
246
+ JOIN pg_namespace n ON n.oid = p.pronamespace
247
+ JOIN pg_language l ON l.oid = p.prolang
248
+ WHERE ${systemSchemaFilter("n")}
249
+ ORDER BY n.nspname, p.proname, pg_get_function_identity_arguments(p.oid)
250
+ `));
251
+ const columnsByRel = byRelationKey(colRows.map((r) => ({
252
+ schema: r.schema,
253
+ table: r.table,
254
+ column: {
255
+ name: r.name,
256
+ ordinal: num(r.ordinal),
257
+ type: r.type,
258
+ typeOid: num(r.type_oid),
259
+ nullable: !bool(r.not_null),
260
+ writable: r.generated !== "s" && r.identity !== "a",
261
+ ...(r.default_expr ? { default: r.default_expr } : {}),
262
+ ...(r.identity === "a" ? { identity: "always" } : {}),
263
+ ...(r.identity === "d" ? { identity: "by_default" } : {}),
264
+ ...(r.generated === "s" ? { generated: "stored" } : {}),
265
+ ...(r.generated_expr ? { generatedExpression: r.generated_expr } : {}),
266
+ },
267
+ })));
268
+ const constraintsByRel = byRelationKey(constraintRows.map((r) => {
269
+ const item = {
270
+ schema: r.schema,
271
+ table: r.table,
272
+ constraint: {
273
+ name: r.name,
274
+ kind: constraintKind(r.kind),
275
+ columns: parseJsonArray(r.columns),
276
+ definition: r.definition,
277
+ ...(r.expression ? { expression: r.expression } : {}),
278
+ ...(bool(r.deferrable) ? { deferrable: true } : {}),
279
+ ...(bool(r.initially_deferred) ? { initiallyDeferred: true } : {}),
280
+ },
281
+ };
282
+ if (r.ref_schema && r.ref_table) {
283
+ item.constraint.references = {
284
+ schema: r.ref_schema,
285
+ table: r.ref_table,
286
+ columns: parseJsonArray(r.ref_columns),
287
+ onUpdate: action(r.on_update),
288
+ onDelete: action(r.on_delete),
289
+ };
290
+ }
291
+ return item;
292
+ }));
293
+ const indexesByRel = byRelationKey(indexRows.map((r) => ({
294
+ schema: r.schema,
295
+ table: r.table,
296
+ index: {
297
+ name: r.name,
298
+ unique: bool(r.unique),
299
+ primary: bool(r.primary),
300
+ method: r.method,
301
+ columns: parseJsonArray(r.columns),
302
+ definition: r.definition,
303
+ ...(r.predicate ? { predicate: r.predicate } : {}),
304
+ },
305
+ })));
306
+ const relations = relRows.map((r) => {
307
+ const key = relationKey(r.schema, r.name);
308
+ return {
309
+ schema: r.schema,
310
+ name: r.name,
311
+ kind: relationKind(r.kind),
312
+ columns: (columnsByRel.get(key) ?? []).map((c) => c.column),
313
+ constraints: (constraintsByRel.get(key) ?? []).map((c) => c.constraint),
314
+ indexes: (indexesByRel.get(key) ?? []).map((i) => i.index),
315
+ ...(r.definition ? { definition: r.definition } : {}),
316
+ };
317
+ });
318
+ const enumMap = new Map();
319
+ for (const r of enumRows) {
320
+ const key = relationKey(r.schema, r.name);
321
+ const existing = enumMap.get(key);
322
+ if (existing)
323
+ existing.values.push(r.value);
324
+ else
325
+ enumMap.set(key, { kind: "enum", schema: r.schema, name: r.name, values: [r.value] });
326
+ }
327
+ const domains = domainRows.map((r) => ({
328
+ kind: "domain",
329
+ schema: r.schema,
330
+ name: r.name,
331
+ baseType: r.base_type,
332
+ notNull: bool(r.not_null),
333
+ ...(r.default_expr ? { default: r.default_expr } : {}),
334
+ checks: parseJsonArray(r.checks),
335
+ }));
336
+ const composites = compositeRows.map((r) => ({
337
+ kind: "composite",
338
+ schema: r.schema,
339
+ name: r.name,
340
+ fields: JSON.parse(r.fields ?? "[]").flatMap((f) => {
341
+ if (!f || typeof f !== "object")
342
+ return [];
343
+ const obj = f;
344
+ return typeof obj.name === "string" && typeof obj.type === "string"
345
+ ? [{ name: obj.name, type: obj.type }]
346
+ : [];
347
+ }),
348
+ }));
349
+ const functions = functionRows.map((r) => ({
350
+ schema: r.schema,
351
+ name: r.name,
352
+ kind: functionKind(r.kind),
353
+ identityArguments: r.identity_arguments ?? "",
354
+ arguments: r.arguments ?? "",
355
+ returnType: r.return_type ?? "void",
356
+ returnsSet: bool(r.returns_set),
357
+ volatility: volatility(r.volatility),
358
+ strict: bool(r.strict),
359
+ securityDefiner: bool(r.security_definer),
360
+ language: r.language,
361
+ }));
362
+ const schemas = [...new Set([
363
+ ...relations.map((r) => r.schema),
364
+ ...Array.from(enumMap.values()).map((t) => t.schema),
365
+ ...domains.map((t) => t.schema),
366
+ ...composites.map((t) => t.schema),
367
+ ...functions.map((f) => f.schema),
368
+ ])].sort();
369
+ return {
370
+ version: 1,
371
+ schemas,
372
+ relations,
373
+ types: [...Array.from(enumMap.values()), ...domains, ...composites],
374
+ functions,
375
+ };
376
+ }
377
+ export function stableSchemaJson(snapshot) {
378
+ return JSON.stringify(snapshot, null, 2) + "\n";
379
+ }
380
+ export function writeSchemaSnapshot(path, snapshot) {
381
+ mkdirSync(dirname(path), { recursive: true });
382
+ writeFileSync(path, stableSchemaJson(snapshot));
383
+ }
384
+ export function readSchemaSnapshot(path) {
385
+ return JSON.parse(readFileSync(path, "utf8"));
386
+ }
387
+ export function schemaSnapshotEqual(a, b) {
388
+ return stableSchemaJson(a) === stableSchemaJson(b);
389
+ }
390
+ export function renderSchemaManifest(snapshot) {
391
+ const lines = [];
392
+ lines.push("# sqlx-js schema manifest");
393
+ lines.push("");
394
+ lines.push("Generated from PostgreSQL introspection. Do not edit by hand.");
395
+ lines.push("");
396
+ lines.push(`Schemas: ${snapshot.schemas.length === 0 ? "(none)" : snapshot.schemas.join(", ")}`);
397
+ lines.push("");
398
+ lines.push("## Relations");
399
+ if (snapshot.relations.length === 0)
400
+ lines.push("");
401
+ if (snapshot.relations.length === 0)
402
+ lines.push("(none)");
403
+ for (const rel of snapshot.relations) {
404
+ lines.push("");
405
+ lines.push(`### ${rel.schema}.${rel.name} (${rel.kind})`);
406
+ if (rel.definition)
407
+ lines.push(`Definition: ${rel.definition.replace(/\s+/g, " ").trim()}`);
408
+ lines.push("");
409
+ lines.push("| Column | Type | Nullable | Writable | Default / Generated |");
410
+ lines.push("|--------|------|----------|----------|---------------------|");
411
+ for (const col of rel.columns) {
412
+ const defaultInfo = col.generatedExpression ?? col.default ?? col.identity ?? "";
413
+ lines.push(`| ${col.name} | ${col.type} | ${col.nullable ? "yes" : "no"} | ${col.writable ? "yes" : "no"} | ${defaultInfo} |`);
414
+ }
415
+ if (rel.constraints.length > 0) {
416
+ lines.push("");
417
+ lines.push("Constraints:");
418
+ for (const c of rel.constraints) {
419
+ const cols = c.columns.length > 0 ? ` [${c.columns.join(", ")}]` : "";
420
+ const ref = c.references ? ` -> ${c.references.schema}.${c.references.table}(${c.references.columns.join(", ")})` : "";
421
+ lines.push(`- ${c.name}: ${c.kind}${cols}${ref}; ${c.definition}`);
422
+ }
423
+ }
424
+ if (rel.indexes.length > 0) {
425
+ lines.push("");
426
+ lines.push("Indexes:");
427
+ for (const idx of rel.indexes) {
428
+ const flags = [idx.primary ? "primary" : "", idx.unique ? "unique" : ""].filter(Boolean).join(", ");
429
+ const cols = idx.columns.length > 0 ? ` [${idx.columns.join(", ")}]` : "";
430
+ lines.push(`- ${idx.name}: ${idx.method}${cols}${flags ? ` (${flags})` : ""}`);
431
+ }
432
+ }
433
+ }
434
+ lines.push("");
435
+ lines.push("## Types");
436
+ if (snapshot.types.length === 0)
437
+ lines.push("(none)");
438
+ for (const t of snapshot.types) {
439
+ if (t.kind === "enum") {
440
+ lines.push(`- enum ${t.schema}.${t.name}: ${t.values.map((v) => JSON.stringify(v)).join(" | ")}`);
441
+ }
442
+ else if (t.kind === "domain") {
443
+ const checks = t.checks.length > 0 ? `; checks: ${t.checks.join("; ")}` : "";
444
+ lines.push(`- domain ${t.schema}.${t.name}: ${t.baseType}${t.notNull ? " not null" : ""}${checks}`);
445
+ }
446
+ else {
447
+ lines.push(`- composite ${t.schema}.${t.name}: ${t.fields.map((f) => `${f.name} ${f.type}`).join(", ")}`);
448
+ }
449
+ }
450
+ lines.push("");
451
+ lines.push("## Functions");
452
+ if (snapshot.functions.length === 0)
453
+ lines.push("(none)");
454
+ for (const fn of snapshot.functions) {
455
+ const attrs = [
456
+ fn.kind,
457
+ fn.volatility,
458
+ fn.strict ? "strict" : "",
459
+ fn.securityDefiner ? "security definer" : "",
460
+ fn.returnsSet ? "returns set" : "",
461
+ ].filter(Boolean).join(", ");
462
+ lines.push(`- ${fn.schema}.${fn.name}(${fn.identityArguments}) -> ${fn.returnType} [${attrs}]`);
463
+ }
464
+ lines.push("");
465
+ return lines.join("\n");
466
+ }
467
+ export function writeSchemaManifest(path, snapshot) {
468
+ mkdirSync(dirname(path), { recursive: true });
469
+ writeFileSync(path, renderSchemaManifest(snapshot));
470
+ }
471
+ export function schemaSnapshotExists(path) {
472
+ return existsSync(path);
473
+ }
@@ -0,0 +1,25 @@
1
+ type ParamsOf<T> = T extends {
2
+ params: infer P extends readonly unknown[];
3
+ } ? P : never[];
4
+ type RowOf<T> = T extends {
5
+ row: infer R;
6
+ } ? R : never;
7
+ export type TypedFile<TFileQueries> = {
8
+ <P extends keyof TFileQueries>(path: P, ...params: ParamsOf<TFileQueries[P]>): Promise<RowOf<TFileQueries[P]>[]>;
9
+ one: <P extends keyof TFileQueries>(path: P, ...params: ParamsOf<TFileQueries[P]>) => Promise<RowOf<TFileQueries[P]>>;
10
+ optional: <P extends keyof TFileQueries>(path: P, ...params: ParamsOf<TFileQueries[P]>) => Promise<RowOf<TFileQueries[P]> | null>;
11
+ };
12
+ export type TypedSql<TQueries, TFileQueries> = {
13
+ <Q extends keyof TQueries>(query: Q, ...params: ParamsOf<TQueries[Q]>): Promise<RowOf<TQueries[Q]>[]>;
14
+ one: <Q extends keyof TQueries>(query: Q, ...params: ParamsOf<TQueries[Q]>) => Promise<RowOf<TQueries[Q]>>;
15
+ optional: <Q extends keyof TQueries>(query: Q, ...params: ParamsOf<TQueries[Q]>) => Promise<RowOf<TQueries[Q]> | null>;
16
+ file: TypedFile<TFileQueries>;
17
+ id: (...parts: string[]) => string;
18
+ };
19
+ export type Typed<TQueries, TFileQueries, TTransactionOptions> = TypedSql<TQueries, TFileQueries> & {
20
+ transaction: {
21
+ <R>(fn: (tx: TypedSql<TQueries, TFileQueries>) => Promise<R>): Promise<R>;
22
+ <R>(opts: TTransactionOptions, fn: (tx: TypedSql<TQueries, TFileQueries>) => Promise<R>): Promise<R>;
23
+ };
24
+ };
25
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@onreza/sqlx-js",
3
+ "version": "0.0.0",
4
+ "description": "Compile-time-checked raw SQL for TypeScript + PostgreSQL. Inspired by sqlx.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "main": "./dist/src/index.js",
9
+ "types": "./dist/src/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/src/index.d.ts",
13
+ "import": "./dist/src/index.js",
14
+ "default": "./dist/src/index.js"
15
+ },
16
+ "./bun": {
17
+ "types": "./dist/src/bun.d.ts",
18
+ "bun": "./dist/src/bun.js",
19
+ "import": "./dist/src/bun.js",
20
+ "default": "./dist/src/bun.js"
21
+ }
22
+ },
23
+ "bin": {
24
+ "sqlx-js": "./dist/bin/sqlx-js.js"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "ROADMAP.md",
30
+ "LICENSE"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/ONREZA/sqlx-js.git"
38
+ },
39
+ "homepage": "https://github.com/ONREZA/sqlx-js#readme",
40
+ "bugs": {
41
+ "url": "https://github.com/ONREZA/sqlx-js/issues"
42
+ },
43
+ "keywords": [
44
+ "bun",
45
+ "node",
46
+ "postgres",
47
+ "postgresql",
48
+ "sql",
49
+ "sqlx",
50
+ "typescript",
51
+ "type-safe",
52
+ "migrations"
53
+ ],
54
+ "scripts": {
55
+ "prepare": "[ -d .git ] && lefthook install >/dev/null 2>&1 || true",
56
+ "test": "bun test tests",
57
+ "test:typecheck": "tsc --noEmit",
58
+ "test:example": "bunx tsc -p example --noEmit",
59
+ "sqlx:prepare": "bun bin/sqlx-js.ts prepare",
60
+ "sqlx:migrate": "bun bin/sqlx-js.ts migrate",
61
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && bun scripts/fix-dist-imports.ts",
62
+ "prepack": "bun run build"
63
+ },
64
+ "peerDependencies": {
65
+ "typescript": ">=5.4"
66
+ },
67
+ "dependencies": {
68
+ "libpg-query": "^17.7.3",
69
+ "postgres": "^3.4.9"
70
+ },
71
+ "devDependencies": {
72
+ "@testcontainers/postgresql": "^11.14.0",
73
+ "@types/bun": "latest",
74
+ "lefthook": "^2.1.6",
75
+ "testcontainers": "^11.14.0",
76
+ "typescript": "^5.6.0"
77
+ }
78
+ }