rado 1.0.7 → 1.0.8

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.
@@ -8,7 +8,6 @@ import { QueryBatch } from './Query.js';
8
8
  import { Resolver } from './Resolver.js';
9
9
  import type { Table } from './Table.js';
10
10
  export declare class Database<Meta extends QueryMeta = Either> extends Builder<Meta> implements HasResolver<Meta> {
11
- #private;
12
11
  driver: Driver;
13
12
  dialect: Dialect;
14
13
  diff: Diff;
@@ -64,7 +64,6 @@ var Database = class extends Builder {
64
64
  throw new Error("Query has parameters");
65
65
  return this.driver.exec(emitter.sql);
66
66
  }
67
- #transactionLock;
68
67
  transaction(run, options = {}) {
69
68
  return this.driver.transaction(
70
69
  (inner) => {
@@ -6,6 +6,7 @@ import { Sql } from './Sql.js';
6
6
  import type { TableApi } from './Table.js';
7
7
  import type { FieldData } from './expr/Field.js';
8
8
  import type { IncludeData } from './expr/Include.js';
9
+ import { type JsonPath } from './expr/Json.js';
9
10
  import type { Delete } from './query/Delete.js';
10
11
  import type { Insert } from './query/Insert.js';
11
12
  import type { SelectData } from './query/Select.js';
@@ -21,7 +22,7 @@ export declare abstract class Emitter {
21
22
  abstract emitIdentifier(value: string): void;
22
23
  abstract emitValue(value: unknown): void;
23
24
  abstract emitInline(value: unknown): void;
24
- abstract emitJsonPath(value: Array<number | string>): void;
25
+ abstract emitJsonPath(path: JsonPath): void;
25
26
  abstract emitPlaceholder(value: string): void;
26
27
  emitIdentifierOrSelf(value: string): void;
27
28
  selfName?: string;
@@ -76,9 +76,11 @@ var Selection = class {
76
76
  #fieldNames(input, names, name) {
77
77
  const expr = getSql(input);
78
78
  if (expr) {
79
- const exprName = name ?? expr.alias;
79
+ let exprName = name ?? expr.alias;
80
80
  if (!exprName)
81
81
  throw new Error("Missing field name");
82
+ while (names.has(exprName))
83
+ exprName = `${exprName}_`;
82
84
  return [exprName];
83
85
  }
84
86
  return Object.entries(input).flatMap(
@@ -98,7 +100,7 @@ var Selection = class {
98
100
  if (field.fieldName === exprName)
99
101
  return expr;
100
102
  }
101
- return sql`${expr} as ${sql.identifier(exprName)}`;
103
+ return sql`${expr.forSelection()} as ${sql.identifier(exprName)}`;
102
104
  }
103
105
  return expr;
104
106
  }
@@ -3,6 +3,7 @@ import type { Emitter } from './Emitter.js';
3
3
  import { type HasSql, internalSql } from './Internal.js';
4
4
  import type { Runtime } from './MetaData.js';
5
5
  import type { FieldData } from './expr/Field.js';
6
+ import type { JsonPath } from './expr/Json.js';
6
7
  type EmitMethods = {
7
8
  [K in keyof Emitter as K extends `emit${string}` ? K : never]: Emitter[K];
8
9
  };
@@ -31,7 +32,8 @@ export declare class Sql<Value = unknown> implements HasSql<Value> {
31
32
  value(value: unknown): Sql<Value>;
32
33
  getValue(): Value | undefined;
33
34
  inline(value: unknown): Sql<Value>;
34
- jsonPath(path: Array<string | number>): Sql<Value>;
35
+ jsonPath(path: JsonPath): Sql<Value>;
36
+ forSelection(): Sql<Value>;
35
37
  placeholder(name: string): Sql<Value>;
36
38
  identifier(identifier: string): Sql<Value>;
37
39
  inlineValues(): Sql<Value>;
@@ -48,6 +50,7 @@ export declare namespace sql {
48
50
  export function placeholder<T>(name: string): Sql<T>;
49
51
  export function identifier<T>(identifier: string): Sql<T>;
50
52
  export function field<T>(field: FieldData): Sql<T>;
53
+ export function jsonPath<T>(path: JsonPath): Sql<T>;
51
54
  export function chunk<Type extends keyof EmitMethods>(type: Type, inner: Parameters<EmitMethods[Type]>[0]): Sql;
52
55
  export function universal<T>(runtimes: Partial<Record<Runtime | 'default', Sql<T>>>): Sql<T>;
53
56
  type QueryChunk = HasSql | undefined;
package/dist/core/Sql.js CHANGED
@@ -57,11 +57,21 @@ var Sql = class _Sql {
57
57
  return this.chunk("emitInline", value);
58
58
  }
59
59
  jsonPath(path) {
60
- const last = this.#chunks.at(-1);
61
- if (last?.type === "emitJsonPath")
62
- last.inner.push(...path);
63
- else
64
- this.chunk("emitJsonPath", path);
60
+ const inner = path.target.#chunks[0];
61
+ if (inner?.type !== "emitJsonPath")
62
+ return this.chunk("emitJsonPath", path);
63
+ const innerPath = inner.inner;
64
+ return this.chunk("emitJsonPath", {
65
+ ...innerPath,
66
+ segments: [...innerPath.segments, ...path.segments]
67
+ });
68
+ }
69
+ forSelection() {
70
+ if (this.#chunks.length === 1) {
71
+ const first = this.#chunks[0];
72
+ if (first.type === "emitJsonPath")
73
+ return sql.jsonPath({ ...first.inner, asSql: false }).mapWith(this);
74
+ }
65
75
  return this;
66
76
  }
67
77
  placeholder(name) {
@@ -143,6 +153,10 @@ function sql(strings, ...inner) {
143
153
  return empty().field(field2);
144
154
  }
145
155
  sql2.field = field;
156
+ function jsonPath(path) {
157
+ return empty().jsonPath(path);
158
+ }
159
+ sql2.jsonPath = jsonPath;
146
160
  function chunk(type, inner) {
147
161
  return empty().chunk(type, inner);
148
162
  }
@@ -1,4 +1,5 @@
1
- import type { HasSql } from '../Internal.js';
1
+ import { type HasSql } from '../Internal.js';
2
+ import { type Sql } from '../Sql.js';
2
3
  import type { Input } from './Input.js';
3
4
  export interface JsonArrayHasSql<Value> extends HasSql<Array<Value>> {
4
5
  [index: number]: JsonExpr<Value>;
@@ -10,7 +11,12 @@ type NullableEach<T> = {
10
11
  [P in keyof T]: T[P] | null;
11
12
  };
12
13
  export type JsonExpr<Value> = [NonNullable<Value>] extends [Array<infer V>] ? JsonArrayHasSql<null extends Value ? V | null : V> : [NonNullable<Value>] extends [object] ? JsonRecordHasSql<null extends Value ? NullableEach<Value> : Value> : HasSql<Value>;
14
+ export interface JsonPath {
15
+ target: Sql;
16
+ segments: Array<number | string>;
17
+ asSql: boolean;
18
+ }
13
19
  export declare function jsonExpr<Value>(e: HasSql<Value>): JsonExpr<Value>;
14
- export declare function jsonAggregateArray(...args: Array<Input<unknown>>): import("../Sql.ts").Sql<unknown>;
15
- export declare function jsonArray(...args: Array<Input<unknown>>): import("../Sql.ts").Sql<unknown>;
20
+ export declare function jsonAggregateArray(...args: Array<Input<unknown>>): Sql<unknown>;
21
+ export declare function jsonArray(...args: Array<Input<unknown>>): Sql<unknown>;
16
22
  export {};
@@ -1,4 +1,5 @@
1
1
  // src/core/expr/Json.ts
2
+ import { getSql } from "../Internal.js";
2
3
  import { sql } from "../Sql.js";
3
4
  import { callFunction } from "./Functions.js";
4
5
  var INDEX_PROPERTY = /^\d+$/;
@@ -8,7 +9,17 @@ function jsonExpr(e) {
8
9
  if (typeof prop !== "string")
9
10
  return Reflect.get(target, prop);
10
11
  const isNumber = INDEX_PROPERTY.test(prop);
11
- return jsonExpr(sql`${target}`.jsonPath([isNumber ? Number(prop) : prop]));
12
+ return jsonExpr(
13
+ sql.jsonPath({
14
+ target: getSql(target),
15
+ asSql: true,
16
+ segments: [isNumber ? Number(prop) : prop]
17
+ }).mapWith({
18
+ mapFromDriverValue(value, specs) {
19
+ return specs.parsesJson ? value : JSON.parse(value);
20
+ }
21
+ })
22
+ );
12
23
  }
13
24
  });
14
25
  }
@@ -16,10 +16,12 @@ var mysqlDialect = new Dialect(
16
16
  this.sql += "?";
17
17
  this.params.push(new ValueParam(value));
18
18
  }
19
- emitJsonPath(path) {
20
- this.sql += `->>${this.quoteString(
21
- `$${path.map((p) => typeof p === "number" ? `[${p}]` : `.${p}`).join("")}`
22
- )}`;
19
+ emitJsonPath({ target, asSql, segments }) {
20
+ target.emitTo(this);
21
+ this.sql += asSql ? "->>" : "->";
22
+ this.sql += this.quoteString(
23
+ `$${segments.map((p) => typeof p === "number" ? `[${p}]` : `.${p}`).join("")}`
24
+ );
23
25
  }
24
26
  emitInline(value) {
25
27
  if (value === null || value === void 0)
@@ -16,13 +16,14 @@ var postgresDialect = new Dialect(
16
16
  this.sql += `$${++this.paramIndex}`;
17
17
  this.params.push(new ValueParam(value));
18
18
  }
19
- emitJsonPath(path) {
20
- for (let i = 0; i < path.length; i++) {
21
- const access = path[i];
22
- if (i <= path.length - 2)
19
+ emitJsonPath({ target, asSql, segments }) {
20
+ target.emitTo(this);
21
+ for (let i = 0; i < segments.length; i++) {
22
+ const access = segments[i];
23
+ if (i <= segments.length - 2)
23
24
  this.sql += "->";
24
- else if (i === path.length - 1)
25
- this.sql += "->>";
25
+ else if (i === segments.length - 1)
26
+ this.sql += asSql ? "->>" : "->";
26
27
  if (typeof access === "number")
27
28
  this.sql += access;
28
29
  else
@@ -18,10 +18,12 @@ var sqliteDialect = new Dialect(
18
18
  this.sql += "?";
19
19
  this.params.push(new ValueParam(value));
20
20
  }
21
- emitJsonPath(path) {
22
- this.sql += `->>${this.quoteString(
23
- `$${path.map((p) => typeof p === "number" ? `[${p}]` : `.${p}`).join("")}`
24
- )}`;
21
+ emitJsonPath({ target, asSql, segments }) {
22
+ target.emitTo(this);
23
+ this.sql += asSql ? "->>" : "->";
24
+ this.sql += this.quoteString(
25
+ `$${segments.map((p) => typeof p === "number" ? `[${p}]` : `.${p}`).join("")}`
26
+ );
25
27
  }
26
28
  emitInline(value) {
27
29
  if (value === null || value === void 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rado",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -27,7 +27,7 @@
27
27
  "files": ["dist"],
28
28
  "devDependencies": {
29
29
  "@benmerckx/suite": "^0.3.0",
30
- "@biomejs/biome": "^1.6.1",
30
+ "@biomejs/biome": "^1.8.3",
31
31
  "@cloudflare/workers-types": "^4.20230628.0",
32
32
  "@electric-sql/pglite": "^0.1.5",
33
33
  "@sqlite.org/sqlite-wasm": "^3.42.0-build4",