@onreza/sqlx-js 0.7.0 → 0.9.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.
@@ -0,0 +1,101 @@
1
+ import { isEscapeStringPrefix, isIdentifierContinuation, readBlockComment, readDollarQuoted, readLineComment, readQuotedIdentifier, readSingleQuoted, } from "./sql-lex.js";
2
+ export function rewriteNamedParameters(query) {
3
+ let out = "";
4
+ let i = 0;
5
+ let positional = false;
6
+ const names = [];
7
+ const indexes = new Map();
8
+ const positionMap = [];
9
+ const append = (text, sourceStart) => {
10
+ out += text;
11
+ for (let offset = 0; offset < text.length; offset++)
12
+ positionMap.push(sourceStart + offset);
13
+ };
14
+ while (i < query.length) {
15
+ const start = i;
16
+ const ch = query[i];
17
+ if (ch === "-" && query[i + 1] === "-") {
18
+ i = readLineComment(query, i);
19
+ append(query.slice(start, i), start);
20
+ continue;
21
+ }
22
+ if (ch === "/" && query[i + 1] === "*") {
23
+ i = readBlockComment(query, i);
24
+ append(query.slice(start, i), start);
25
+ continue;
26
+ }
27
+ if (ch === "'") {
28
+ i = readSingleQuoted(query, i, isEscapeStringPrefix(query, i));
29
+ append(query.slice(start, i), start);
30
+ continue;
31
+ }
32
+ if (ch === '"') {
33
+ i = readQuotedIdentifier(query, i);
34
+ append(query.slice(start, i), start);
35
+ continue;
36
+ }
37
+ if (ch === "$") {
38
+ if (i > 0 && isIdentifierContinuation(query[i - 1])) {
39
+ append(ch, i);
40
+ i++;
41
+ continue;
42
+ }
43
+ const quotedEnd = readDollarQuoted(query, i);
44
+ if (quotedEnd !== null) {
45
+ i = quotedEnd;
46
+ append(query.slice(start, i), start);
47
+ continue;
48
+ }
49
+ const positionalMatch = /^\$[1-9][0-9]*/.exec(query.slice(i));
50
+ if (positionalMatch) {
51
+ positional = true;
52
+ i += positionalMatch[0].length;
53
+ append(positionalMatch[0], start);
54
+ continue;
55
+ }
56
+ const namedMatch = /^\$([A-Za-z_][A-Za-z0-9_]*)/.exec(query.slice(i));
57
+ if (namedMatch) {
58
+ const name = namedMatch[1];
59
+ let index = indexes.get(name);
60
+ if (index === undefined) {
61
+ names.push(name);
62
+ index = names.length;
63
+ indexes.set(name, index);
64
+ }
65
+ const replacement = `$${index}`;
66
+ append(replacement, start);
67
+ i += namedMatch[0].length;
68
+ continue;
69
+ }
70
+ }
71
+ append(ch, i);
72
+ i++;
73
+ }
74
+ if (positional && names.length > 0) {
75
+ throw new Error("sqlx-js: named and positional parameters cannot be mixed in one query");
76
+ }
77
+ positionMap.push(query.length);
78
+ return { query: out, names, positionMap };
79
+ }
80
+ export function bindNamedParameters(rewritten, args) {
81
+ if (rewritten.names.length === 0)
82
+ return { query: rewritten.query, params: [...args] };
83
+ if (args.length !== 1 || args[0] === null || typeof args[0] !== "object" || Array.isArray(args[0])) {
84
+ throw new Error("sqlx-js: a query with named parameters requires exactly one parameter object");
85
+ }
86
+ const values = args[0];
87
+ const missing = rewritten.names.filter((name) => !Object.hasOwn(values, name));
88
+ const expected = new Set(rewritten.names);
89
+ const extra = Object.keys(values).filter((name) => !expected.has(name));
90
+ if (missing.length > 0)
91
+ throw new Error(`sqlx-js: missing named parameter(s): ${missing.join(", ")}`);
92
+ if (extra.length > 0)
93
+ throw new Error(`sqlx-js: unknown named parameter(s): ${extra.join(", ")}`);
94
+ return { query: rewritten.query, params: rewritten.names.map((name) => values[name]) };
95
+ }
96
+ export function originalPosition(rewritten, oneBasedPosition) {
97
+ const position = Number(oneBasedPosition);
98
+ if (!Number.isInteger(position) || position < 1)
99
+ return oneBasedPosition;
100
+ return (rewritten.positionMap[position - 1] ?? position - 1) + 1;
101
+ }
@@ -1,14 +1,15 @@
1
+ import type { QUERY_EXECUTOR, QueryExecutorMethod } from "./query.js";
1
2
  type ParamsOf<T> = T extends {
2
- params: infer P extends readonly unknown[];
3
- } ? P : never[];
3
+ params: infer P;
4
+ } ? P extends readonly unknown[] ? P : [P] : never[];
4
5
  type RowOf<T> = T extends {
5
6
  row: infer R;
6
7
  } ? R : never;
7
8
  type ExecuteResult = import("./runtime.js").ExecuteResult;
8
- type JsonInputValue = import("./runtime.js").JsonInputValue;
9
+ type JsonCompatible<T> = import("./runtime.js").JsonCompatible<T>;
9
10
  type JsonParameter<T> = import("./runtime.js").JsonParameter<T>;
10
11
  type PgArrayParameter<T> = import("./runtime.js").PgArrayParameter<T>;
11
- type JsonFn = <T extends JsonInputValue>(value: T) => JsonParameter<T>;
12
+ type JsonFn = <T>(value: T & JsonCompatible<T>) => JsonParameter<T>;
12
13
  type ArrayFn = <T>(value: readonly (T | null)[]) => PgArrayParameter<T>;
13
14
  export type TypedFile<TFileQueries> = {
14
15
  <P extends keyof TFileQueries>(path: P, ...params: ParamsOf<TFileQueries[P]>): Promise<RowOf<TFileQueries[P]>[]>;
@@ -25,6 +26,7 @@ export type TypedSql<TQueries, TFileQueries> = {
25
26
  id: (...parts: string[]) => string;
26
27
  json: JsonFn;
27
28
  array: ArrayFn;
29
+ readonly [QUERY_EXECUTOR]?: QueryExecutorMethod;
28
30
  };
29
31
  export type Typed<TQueries, TFileQueries, TTransactionOptions> = TypedSql<TQueries, TFileQueries> & {
30
32
  transaction: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onreza/sqlx-js",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Compile-time-checked raw SQL for TypeScript + PostgreSQL. Inspired by sqlx.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -66,6 +66,11 @@
66
66
  "peerDependencies": {
67
67
  "typescript": ">=5.4"
68
68
  },
69
+ "peerDependenciesMeta": {
70
+ "typescript": {
71
+ "optional": true
72
+ }
73
+ },
69
74
  "dependencies": {
70
75
  "libpg-query": "^17.7.3",
71
76
  "postgres": "^3.4.9"