rado 1.0.15 → 1.2.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 (81) hide show
  1. package/dist/compat.d.ts +3 -3
  2. package/dist/compat.js +2 -0
  3. package/dist/core/Builder.d.ts +14 -9
  4. package/dist/core/Builder.js +24 -32
  5. package/dist/core/Column.d.ts +13 -4
  6. package/dist/core/Column.js +43 -8
  7. package/dist/core/Constraint.d.ts +16 -5
  8. package/dist/core/Constraint.js +17 -6
  9. package/dist/core/Database.d.ts +11 -4
  10. package/dist/core/Database.js +20 -4
  11. package/dist/core/Dialect.js +2 -2
  12. package/dist/core/Driver.d.ts +3 -3
  13. package/dist/core/Emitter.d.ts +7 -29
  14. package/dist/core/Emitter.js +31 -139
  15. package/dist/core/Index.d.ts +1 -1
  16. package/dist/core/Internal.d.ts +5 -4
  17. package/dist/core/Queries.d.ts +46 -0
  18. package/dist/core/{Query.js → Queries.js} +10 -8
  19. package/dist/core/Resolver.d.ts +2 -2
  20. package/dist/core/Selection.d.ts +7 -10
  21. package/dist/core/Selection.js +15 -13
  22. package/dist/core/Sql.d.ts +8 -29
  23. package/dist/core/Sql.js +67 -118
  24. package/dist/core/Table.d.ts +7 -3
  25. package/dist/core/Table.js +24 -8
  26. package/dist/core/Virtual.d.ts +1 -1
  27. package/dist/core/Virtual.js +15 -14
  28. package/dist/core/expr/Conditions.d.ts +4 -4
  29. package/dist/core/expr/Conditions.js +18 -8
  30. package/dist/core/expr/Field.d.ts +8 -6
  31. package/dist/core/expr/Field.js +3 -3
  32. package/dist/core/expr/Include.d.ts +10 -7
  33. package/dist/core/expr/Include.js +29 -12
  34. package/dist/core/expr/Input.d.ts +3 -1
  35. package/dist/core/expr/Input.js +24 -7
  36. package/dist/core/expr/Json.js +2 -2
  37. package/dist/core/query/CTE.d.ts +8 -0
  38. package/dist/core/query/CTE.js +33 -0
  39. package/dist/core/query/Delete.d.ts +14 -13
  40. package/dist/core/query/Delete.js +32 -6
  41. package/dist/core/query/Insert.d.ts +17 -36
  42. package/dist/core/query/Insert.js +121 -72
  43. package/dist/core/query/Query.d.ts +124 -0
  44. package/dist/core/query/Select.d.ts +74 -33
  45. package/dist/core/query/Select.js +255 -57
  46. package/dist/core/query/Shared.d.ts +3 -0
  47. package/dist/core/query/Shared.js +23 -0
  48. package/dist/core/query/Update.d.ts +13 -13
  49. package/dist/core/query/Update.js +51 -22
  50. package/dist/driver/d1.d.ts +2 -2
  51. package/dist/driver/libsql.d.ts +2 -2
  52. package/dist/driver/mysql2.d.ts +2 -2
  53. package/dist/driver/pg.d.ts +2 -2
  54. package/dist/driver/pglite.d.ts +2 -2
  55. package/dist/index.d.ts +7 -7
  56. package/dist/index.js +7 -7
  57. package/dist/mysql/columns.d.ts +37 -37
  58. package/dist/mysql/columns.js +32 -15
  59. package/dist/mysql/dialect.js +6 -7
  60. package/dist/mysql/diff.js +2 -1
  61. package/dist/mysql.d.ts +3 -2
  62. package/dist/mysql.js +11 -2
  63. package/dist/postgres/columns.d.ts +13 -13
  64. package/dist/postgres/columns.js +15 -6
  65. package/dist/postgres/dialect.js +6 -7
  66. package/dist/postgres/diff.js +2 -1
  67. package/dist/postgres.d.ts +3 -2
  68. package/dist/postgres.js +11 -2
  69. package/dist/sqlite/columns.d.ts +16 -1
  70. package/dist/sqlite/columns.js +36 -3
  71. package/dist/sqlite/dialect.js +6 -6
  72. package/dist/sqlite/diff.js +3 -5
  73. package/dist/sqlite.d.ts +3 -2
  74. package/dist/sqlite.js +11 -2
  75. package/dist/universal/functions.js +4 -1
  76. package/package.json +4 -4
  77. package/dist/core/Join.d.ts +0 -1
  78. package/dist/core/Query.d.ts +0 -46
  79. package/dist/core/query/Union.d.ts +0 -35
  80. package/dist/core/query/Union.js +0 -107
  81. /package/dist/core/{Join.js → query/Query.js} +0 -0
package/dist/core/Sql.js CHANGED
@@ -1,122 +1,65 @@
1
1
  // src/core/Sql.ts
2
- import { getSql, hasSql, internalSql } from "./Internal.js";
3
- var Chunk = class {
4
- constructor(type, inner) {
5
- this.type = type;
6
- this.inner = inner;
7
- }
2
+ import {
3
+ getSql,
4
+ getTarget,
5
+ hasSql,
6
+ hasTarget,
7
+ internalSql
8
+ } from "./Internal.js";
9
+ var noop = () => {
8
10
  };
9
11
  var Sql = class _Sql {
12
+ constructor(emit = noop) {
13
+ this.emit = emit;
14
+ }
10
15
  static SELF_TARGET = "$$self";
11
16
  alias;
12
17
  mapFromDriverValue;
13
18
  [internalSql] = this;
14
- #chunks;
15
- constructor(chunks = []) {
16
- this.#chunks = chunks;
17
- }
18
19
  as(name) {
19
20
  this.alias = name;
20
21
  return this;
21
22
  }
22
23
  mapWith(decoder) {
23
24
  const res = this;
24
- res.mapFromDriverValue = typeof decoder === "function" ? decoder : decoder.mapFromDriverValue;
25
+ res.mapFromDriverValue = typeof decoder === "function" ? (input) => input === null ? null : decoder(input) : decoder.mapFromDriverValue;
25
26
  return res;
26
27
  }
27
- chunk(type, inner) {
28
- this.#chunks.push(new Chunk(type, inner));
29
- return this;
30
- }
31
- unsafe(sql2) {
32
- if (sql2.length > 0) this.chunk("emitUnsafe", sql2);
33
- return this;
34
- }
35
- field(field) {
36
- return this.chunk("emitField", field);
37
- }
38
- add(sql2) {
39
- const inner = getSql(sql2);
40
- if (!(inner instanceof _Sql)) throw new Error("Invalid SQL");
41
- this.#chunks.push(...inner.#chunks);
42
- return this;
43
- }
44
- value(value) {
45
- return this.chunk("emitValue", value);
46
- }
47
- getValue() {
48
- if (this.#chunks.length !== 1) return;
49
- const chunk = this.#chunks[0];
50
- if (chunk?.type === "emitValue") return chunk.inner;
28
+ inlineFields(withTableName) {
29
+ return new _Sql((emitter) => emitter.inlineFields(this, withTableName));
51
30
  }
52
- inline(value) {
53
- return this.chunk("emitInline", value);
31
+ inlineValues() {
32
+ return new _Sql((emitter) => emitter.inlineValues(this));
54
33
  }
55
- jsonPath(path) {
56
- const inner = path.target.#chunks[0];
57
- if (inner?.type !== "emitJsonPath") return this.chunk("emitJsonPath", path);
58
- const innerPath = inner.inner;
59
- return this.chunk("emitJsonPath", {
60
- ...innerPath,
61
- segments: [...innerPath.segments, ...path.segments]
62
- });
34
+ nameSelf(name) {
35
+ return new _Sql((emitter) => emitter.emitSelf(this, name));
63
36
  }
64
37
  forSelection() {
65
- if (this.#chunks.length === 1) {
66
- const first = this.#chunks[0];
67
- if (first.type === "emitJsonPath")
68
- return sql.jsonPath({ ...first.inner, asSql: false }).mapWith(this);
69
- }
70
38
  return this;
71
39
  }
72
- placeholder(name) {
73
- return this.chunk("emitPlaceholder", name);
74
- }
75
- identifier(identifier) {
76
- return this.chunk("emitIdentifierOrSelf", identifier);
77
- }
78
- inlineValues() {
79
- return new _Sql(
80
- this.#chunks.map((chunk) => {
81
- if (chunk.type !== "emitValue") return chunk;
82
- return new Chunk("emitInline", chunk.inner);
83
- })
84
- );
85
- }
86
- inlineFields(withTableName) {
87
- return new _Sql(
88
- this.#chunks.flatMap((chunk) => {
89
- if (chunk.type !== "emitField") return [chunk];
90
- const data = chunk.inner;
91
- if (withTableName)
92
- return [
93
- new Chunk("emitIdentifierOrSelf", data.targetName),
94
- new Chunk("emitUnsafe", "."),
95
- new Chunk("emitIdentifier", data.fieldName)
96
- ];
97
- return [new Chunk("emitIdentifier", data.fieldName)];
98
- })
99
- );
100
- }
101
- nameSelf(name) {
102
- return sql.chunk("emitSelf", { name, inner: this });
40
+ };
41
+ var JsonPathSql = class extends Sql {
42
+ constructor(path) {
43
+ super((emitter) => emitter.emitJsonPath(path));
44
+ this.path = path;
103
45
  }
104
- emitTo(emitter) {
105
- for (const chunk of this.#chunks) emitter[chunk.type](chunk.inner);
46
+ forSelection() {
47
+ return sql.jsonPath({ ...this.path, asSql: false }).mapWith(this);
106
48
  }
107
49
  };
108
50
  function sql(strings, ...inner) {
109
- const sql2 = new Sql();
110
- for (let i = 0; i < strings.length; i++) {
111
- sql2.unsafe(strings[i]);
112
- if (i < inner.length) {
113
- const insert = inner[i];
114
- if (insert !== null && typeof insert === "object" && hasSql(insert))
115
- sql2.add(insert);
116
- else sql2.value(insert);
51
+ return new Sql((emitter) => {
52
+ for (let i = 0; i < strings.length; i++) {
53
+ emitter.emitUnsafe(strings[i]);
54
+ if (i < inner.length) {
55
+ const insert = inner[i];
56
+ const isObject = insert !== null && typeof insert === "object";
57
+ if (isObject && hasSql(insert)) getSql(insert).emit(emitter);
58
+ else if (isObject && hasTarget(insert)) getTarget(insert).emit(emitter);
59
+ else emitter.emitValueOrInline(insert);
60
+ }
117
61
  }
118
- }
119
- return sql2;
62
+ });
120
63
  }
121
64
  ((sql2) => {
122
65
  function empty() {
@@ -124,61 +67,67 @@ function sql(strings, ...inner) {
124
67
  }
125
68
  sql2.empty = empty;
126
69
  function unsafe(directSql) {
127
- return empty().unsafe(String(directSql));
70
+ return new Sql((emitter) => emitter.emitUnsafe(String(directSql)));
128
71
  }
129
72
  sql2.unsafe = unsafe;
130
73
  function value(value2) {
131
- return empty().value(value2);
74
+ return new Sql((emitter) => emitter.emitValueOrInline(value2));
132
75
  }
133
76
  sql2.value = value;
134
77
  function inline(value2) {
135
- return empty().inline(value2);
78
+ return new Sql((emitter) => emitter.emitInline(value2));
136
79
  }
137
80
  sql2.inline = inline;
138
81
  function placeholder(name) {
139
- return empty().placeholder(name);
82
+ return new Sql((emitter) => emitter.emitPlaceholder(name));
140
83
  }
141
84
  sql2.placeholder = placeholder;
142
85
  function identifier(identifier2) {
143
- return empty().identifier(identifier2);
86
+ return new Sql((emitter) => emitter.emitIdentifierOrSelf(identifier2));
144
87
  }
145
88
  sql2.identifier = identifier;
146
89
  function field(field2) {
147
- return empty().field(field2);
90
+ return new Sql((emitter) => emitter.emitField(field2));
148
91
  }
149
92
  sql2.field = field;
150
93
  function jsonPath(path) {
151
- return empty().jsonPath(path);
94
+ if (path.target instanceof JsonPathSql) {
95
+ const inner = path.target.path;
96
+ return new JsonPathSql({
97
+ ...inner,
98
+ segments: [...inner.segments, ...path.segments]
99
+ });
100
+ }
101
+ return new JsonPathSql(path);
152
102
  }
153
103
  sql2.jsonPath = jsonPath;
154
- function chunk(type, inner) {
155
- return empty().chunk(type, inner);
156
- }
157
- sql2.chunk = chunk;
158
104
  function universal(runtimes) {
159
- return empty().chunk("emitUniversal", runtimes);
105
+ return new Sql((emitter) => emitter.emitUniversal(runtimes));
160
106
  }
161
107
  sql2.universal = universal;
162
- function query(ast) {
108
+ function query(...chunks) {
163
109
  return join(
164
- Object.entries(ast).map(([key, value2]) => {
165
- const statement = key.replace(/([A-Z])/g, " $1").toLocaleLowerCase();
166
- if (value2 === true) return sql2.unsafe(statement);
167
- if (Array.isArray(value2)) value2 = join(value2);
168
- if (!key) return value2;
169
- return value2 && sql2`${sql2.unsafe(statement)} ${value2}`;
110
+ chunks.filter(Boolean).flatMap((chunk) => {
111
+ if (hasSql(chunk)) return chunk;
112
+ return Object.entries(chunk).map(([key, value2]) => {
113
+ const statement = key.replace(/([A-Z])/g, " $1").toLowerCase();
114
+ if (value2 === true) return sql2.unsafe(statement);
115
+ if (Array.isArray(value2)) value2 = join(value2);
116
+ if (!key) return value2;
117
+ return value2 && sql2`${sql2.unsafe(statement)} ${value2}`;
118
+ });
170
119
  })
171
120
  );
172
121
  }
173
122
  sql2.query = query;
174
123
  function join(items, separator = sql2` `) {
175
124
  const parts = items.filter(Boolean);
176
- const sql3 = new Sql();
177
- for (let i = 0; i < parts.length; i++) {
178
- if (i > 0) sql3.add(separator);
179
- sql3.add(parts[i]);
180
- }
181
- return sql3;
125
+ return new Sql((emitter) => {
126
+ for (let i = 0; i < parts.length; i++) {
127
+ if (i > 0) separator.emit(emitter);
128
+ getSql(parts[i]).emit(emitter);
129
+ }
130
+ });
182
131
  }
183
132
  sql2.join = join;
184
133
  })(sql || (sql = {}));
@@ -1,7 +1,7 @@
1
- import type { Column, JsonColumn, RequiredColumn } from './Column.js';
1
+ import { type Column, type JsonColumn, type RequiredColumn } from './Column.js';
2
2
  import type { ForeignKeyConstraint, PrimaryKeyConstraint, UniqueConstraint } from './Constraint.js';
3
3
  import { Index } from './Index.js';
4
- import { type HasSql, type HasTable, type HasTarget } from './Internal.js';
4
+ import { type HasSelection, type HasSql, type HasTable } from './Internal.js';
5
5
  import { type Sql } from './Sql.js';
6
6
  import { Field } from './expr/Field.js';
7
7
  import type { Input } from './expr/Input.js';
@@ -31,7 +31,7 @@ export declare class TableApi<Definition extends TableDefinition = TableDefiniti
31
31
  drop(): Sql;
32
32
  indexes(): Record<string, Index>;
33
33
  }
34
- export type Table<Definition extends TableDefinition = Record<never, Column>, Name extends string = string> = TableFields<Definition, Name> & HasTable<Definition, Name> & HasTarget;
34
+ export type Table<Definition extends TableDefinition = Record<never, Column>, Name extends string = string> = TableFields<Definition, Name> & HasTable<Definition, Name> & HasSelection;
35
35
  export type TableFields<Definition extends TableDefinition, TableName extends string = string> = {
36
36
  [K in keyof Definition]: Definition[K] extends JsonColumn<infer T> ? JsonExpr<T> : Definition[K] extends Column<infer T> ? Field<T, TableName> : never;
37
37
  };
@@ -54,4 +54,8 @@ export interface TableConfig<Name extends string = string> extends Record<string
54
54
  }
55
55
  export declare function table<Definition extends TableDefinition, Name extends string>(name: Name, columns: Definition, config?: (self: Table<Definition, Name>) => TableConfig<Name>, schemaName?: string): Table<Definition, Name>;
56
56
  export declare function alias<Definition extends TableDefinition, Alias extends string>(table: Table<Definition>, alias: Alias): Table<Definition, Alias>;
57
+ export declare function tableCreator(nameTable: (name: string) => string): typeof table;
58
+ export type InsertRow<T> = T extends Table<infer Definition> ? TableInsert<Definition> : never;
59
+ export type SelectRow<T> = T extends Table<infer Definition> ? TableRow<Definition> : never;
60
+ export type UpdateRow<T> = T extends Table<infer Definition> ? TableUpdate<Definition> : never;
57
61
  export {};
@@ -1,13 +1,18 @@
1
1
  // src/core/Table.ts
2
+ import {
3
+ formatColumn
4
+ } from "./Column.js";
2
5
  import { Index } from "./Index.js";
3
6
  import {
4
7
  getConstraint,
5
8
  getData,
6
9
  getTable,
7
10
  hasConstraint,
11
+ internalSelection,
8
12
  internalTable,
9
13
  internalTarget
10
14
  } from "./Internal.js";
15
+ import { selection } from "./Selection.js";
11
16
  import { sql } from "./Sql.js";
12
17
  import { Field } from "./expr/Field.js";
13
18
  import { jsonExpr } from "./expr/Json.js";
@@ -42,17 +47,18 @@ var TableApi = class extends TableData {
42
47
  const columnData = this.columns[name];
43
48
  const column = getData(columnData);
44
49
  const columnName = sql.identifier(column.name ?? name);
45
- return sql`${columnName} ${sql.chunk("emitColumn", column)}`;
50
+ return sql`${columnName} ${formatColumn(column)}`;
46
51
  }
47
52
  createDefinition() {
48
53
  const createColumns = keys(this.columns).map(
49
54
  (name) => this.columnDefinition(name)
50
55
  );
51
- const createConstraints = entries(this.config ?? {}).filter(([, constraint]) => hasConstraint(constraint)).map(
52
- ([name, constraint]) => sql`constraint ${sql.identifier(name)} ${getConstraint(
56
+ const createConstraints = entries(this.config ?? {}).filter(([, constraint]) => hasConstraint(constraint)).map(([key, constraint]) => {
57
+ const { name } = getData(constraint);
58
+ return sql`constraint ${sql.identifier(name ?? key)} ${getConstraint(
53
59
  constraint
54
- )}`
55
- );
60
+ )}`;
61
+ });
56
62
  return sql.join(createColumns.concat(createConstraints), sql`, `);
57
63
  }
58
64
  listColumns() {
@@ -94,7 +100,7 @@ var TableApi = class extends TableData {
94
100
  return [this.createTable(), ...this.createIndexes()];
95
101
  }
96
102
  drop() {
97
- return sql`drop table ${this.target()}`;
103
+ return sql`drop table if exists ${this.target()}`;
98
104
  }
99
105
  indexes() {
100
106
  return fromEntries(
@@ -108,10 +114,12 @@ function table(name, columns, config, schemaName) {
108
114
  schemaName,
109
115
  columns
110
116
  });
117
+ const fields = api.fields();
111
118
  const table2 = {
112
119
  [internalTable]: api,
113
120
  [internalTarget]: api.target(),
114
- ...api.fields()
121
+ [internalSelection]: selection(fields),
122
+ ...fields
115
123
  };
116
124
  if (config) api.config = config(table2);
117
125
  return table2;
@@ -121,14 +129,22 @@ function alias(table2, alias2) {
121
129
  ...getTable(table2),
122
130
  alias: alias2
123
131
  });
132
+ const fields = api.fields();
124
133
  return {
125
134
  [internalTable]: api,
126
135
  [internalTarget]: api.target(),
136
+ [internalSelection]: selection(fields),
127
137
  ...api.fields()
128
138
  };
129
139
  }
140
+ function tableCreator(nameTable) {
141
+ return (name, columns, config, schemaName) => {
142
+ return table(nameTable(name), columns, config, schemaName);
143
+ };
144
+ }
130
145
  export {
131
146
  TableApi,
132
147
  alias,
133
- table
148
+ table,
149
+ tableCreator
134
150
  };
@@ -1,2 +1,2 @@
1
1
  import { type HasTarget } from './Internal.js';
2
- export declare function virtual<Input>(alias: string, source?: Input): Input & HasTarget;
2
+ export declare function virtual<Input>(alias: string, source: Input): Input & HasTarget;
@@ -3,25 +3,26 @@ import { getSql, hasSql, internalTarget } from "./Internal.js";
3
3
  import { sql } from "./Sql.js";
4
4
  import { Field } from "./expr/Field.js";
5
5
  function virtual(alias, source) {
6
- const target = { [internalTarget]: sql.identifier(alias) };
7
- if (source && hasSql(source)) {
6
+ const target = {
7
+ [internalTarget]: sql.identifier(alias)
8
+ };
9
+ if (!source || typeof source !== "object")
10
+ throw new Error("Cannot alias a non-object");
11
+ if (hasSql(source)) {
8
12
  const expr = getSql(source);
9
13
  const name = expr.alias;
10
14
  if (!name) throw new Error("Cannot alias a virtual field without a name");
11
15
  return Object.assign(new Field(alias, name, expr), target);
12
16
  }
13
- return new Proxy(target, {
14
- get(target2, field) {
15
- if (field in target2) return target2[field];
16
- const from = source?.[field];
17
- if (typeof field !== "string") return from;
18
- return target2[field] = new Field(
19
- alias,
20
- field,
21
- from ? getSql(from) : void 0
22
- );
23
- }
24
- });
17
+ const aliased = Object.fromEntries(
18
+ Object.entries(source).map(([key, value]) => {
19
+ return [key, new Field(alias, key, getSql(value))];
20
+ })
21
+ );
22
+ return {
23
+ [internalTarget]: sql.identifier(alias),
24
+ ...aliased
25
+ };
25
26
  }
26
27
  export {
27
28
  virtual
@@ -1,6 +1,6 @@
1
1
  import { type HasSql } from '../Internal.js';
2
2
  import type { Either } from '../MetaData.js';
3
- import type { Query } from '../Query.js';
3
+ import type { SingleQuery } from '../Queries.js';
4
4
  import { type Sql } from '../Sql.js';
5
5
  import { type Input } from './Input.js';
6
6
  export declare const eq: <T>(left: Input<T>, right: Input<T>) => Sql<boolean>;
@@ -19,8 +19,8 @@ export declare const arrayOverlaps: <T>(left: Input<Array<T>>, right: Input<Arra
19
19
  export declare function and(...conditions: Array<undefined | Input<boolean>>): Sql<boolean>;
20
20
  export declare function or(...conditions: Array<undefined | Input<boolean>>): Sql<boolean>;
21
21
  export declare function not(condition: Input<boolean>): Sql<boolean>;
22
- export declare function inArray<T>(left: Input<T>, right: Query<T, any> | Input<Array<T>>): Sql<boolean>;
23
- export declare function notInArray<T>(left: Input<T>, right: Query<T, any> | Input<Array<T>>): Sql<boolean>;
22
+ export declare function inArray<T>(left: Input<T>, right: SingleQuery<Array<T>, any> | Input<Array<T>>): Sql<boolean>;
23
+ export declare function notInArray<T>(left: Input<T>, right: SingleQuery<T, any> | Input<Array<T>>): Sql<boolean>;
24
24
  export declare function isNull(value: Input): Sql<boolean>;
25
25
  export declare function isNotNull(value: Input): Sql<boolean>;
26
26
  export declare function between<T>(value: Input<T>, left: Input<T>, right: Input<T>): Sql<boolean>;
@@ -30,4 +30,4 @@ export declare function desc<T>(input: HasSql<T>): Sql;
30
30
  export declare function distinct<T>(input: HasSql<T>): Sql;
31
31
  export declare function when<In, Out>(compare: Input<In>, ...cases: Array<[condition: Input<In>, result: Input<Out>] | Input<Out>>): Sql<Out>;
32
32
  export declare function when<Out>(...cases: Array<[condition: Input<boolean>, result: Input<Out>] | Input<Out>>): Sql<Out>;
33
- export declare function exists(query: Query<any, Either>): Sql<boolean>;
33
+ export declare function exists(query: SingleQuery<any, Either>): Sql<boolean>;
@@ -1,12 +1,14 @@
1
1
  // src/core/expr/Conditions.ts
2
- import { getQuery, getSql, hasSql } from "../Internal.js";
2
+ import { getQuery, hasSql } from "../Internal.js";
3
3
  import { sql } from "../Sql.js";
4
4
  import { input } from "./Input.js";
5
5
  function bool(impl) {
6
6
  return impl.mapWith(Boolean);
7
7
  }
8
8
  function binop(operator) {
9
- return (left, right) => bool(sql`${input(left)} ${sql.unsafe(operator)} ${input(right)}`);
9
+ return (left, right) => bool(
10
+ sql`${input(left, right)} ${sql.unsafe(operator)} ${input(right, left)}`
11
+ );
10
12
  }
11
13
  var eq = binop("=");
12
14
  var ne = binop("<>");
@@ -22,13 +24,13 @@ var arrayContains = binop("@>");
22
24
  var arrayContained = binop("<@");
23
25
  var arrayOverlaps = binop("&&");
24
26
  function and(...conditions) {
25
- const inputs = conditions.filter((v) => v !== void 0).map(input);
27
+ const inputs = conditions.filter((v) => v !== void 0).map((i) => input(i));
26
28
  if (inputs.length === 0) return bool(sql`true`);
27
29
  if (inputs.length === 1) return bool(inputs[0]);
28
30
  return bool(sql`(${sql.join(inputs, sql` and `)})`);
29
31
  }
30
32
  function or(...conditions) {
31
- const inputs = conditions.filter((v) => v !== void 0).map(input);
33
+ const inputs = conditions.filter((v) => v !== void 0).map((i) => input(i));
32
34
  if (inputs.length === 0) return bool(sql`true`);
33
35
  if (inputs.length === 1) return bool(inputs[0]);
34
36
  return bool(sql`(${sql.join(inputs, sql` or `)})`);
@@ -37,19 +39,27 @@ function not(condition) {
37
39
  return bool(sql`not ${input(condition)}`);
38
40
  }
39
41
  function inArray(left, right) {
40
- const value = (hasSql(right) ? getSql(right).getValue() : void 0) ?? right;
42
+ const value = hasSql(right) ? void 0 : right;
41
43
  if (Array.isArray(value)) {
42
44
  if (value.length === 0) return sql`false`;
43
- return bool(sql`${input(left)} in (${sql.join(value.map(input), sql`, `)})`);
45
+ return bool(
46
+ sql`${input(left)} in (${sql.join(
47
+ value.map((i) => input(i)),
48
+ sql`, `
49
+ )})`
50
+ );
44
51
  }
45
52
  return bool(sql`${input(left)} in ${input(right)}`);
46
53
  }
47
54
  function notInArray(left, right) {
48
- const value = (hasSql(right) ? getSql(right).getValue() : void 0) ?? right;
55
+ const value = hasSql(right) ? void 0 : right;
49
56
  if (Array.isArray(value)) {
50
57
  if (value.length === 0) return sql`true`;
51
58
  return bool(
52
- sql`${input(left)} not in (${sql.join(value.map(input), sql`, `)})`
59
+ sql`${input(left)} not in (${sql.join(
60
+ value.map((i) => input(i)),
61
+ sql`, `
62
+ )})`
53
63
  );
54
64
  }
55
65
  return bool(sql`${input(left)} not in ${input(right)}`);
@@ -1,15 +1,17 @@
1
- import type { DriverSpecs } from '../Driver.js';
2
- import { internalField, internalSql, type HasSql } from '../Internal.js';
3
- import { type Sql } from '../Sql.js';
1
+ import { type HasSql, internalField, internalSql } from '../Internal.js';
2
+ import type { SelectionRecord } from '../Selection.js';
3
+ import { type Decoder, type Sql } from '../Sql.js';
4
4
  export interface FieldData {
5
5
  targetName: string;
6
6
  fieldName: string;
7
+ source: Decoder;
7
8
  }
8
9
  export declare class Field<Value = unknown, Table extends string = string> implements HasSql<Value> {
9
10
  private brand;
10
11
  readonly [internalField]: FieldData;
11
12
  readonly [internalSql]: Sql<Value>;
12
- constructor(targetName: string, fieldName: string, options?: {
13
- mapFromDriverValue?(value: unknown, specs: DriverSpecs): Value;
14
- });
13
+ constructor(targetName: string, fieldName: string, source?: Decoder<Value>);
15
14
  }
15
+ export type StripFieldMeta<Input> = Input extends HasSql<infer Value> ? HasSql<Value> : Input extends SelectionRecord ? {
16
+ [Key in keyof Input]: StripFieldMeta<Input[Key]>;
17
+ } : Input;
@@ -4,10 +4,10 @@ import { sql } from "../Sql.js";
4
4
  var Field = class {
5
5
  [internalField];
6
6
  [internalSql];
7
- constructor(targetName, fieldName, options = {}) {
8
- const field = { targetName, fieldName };
7
+ constructor(targetName, fieldName, source = {}) {
8
+ const field = { targetName, fieldName, source };
9
9
  this[internalField] = field;
10
- const expr = sql.field(field).as(fieldName).mapWith(options);
10
+ const expr = sql.field(field).as(fieldName).mapWith(source);
11
11
  this[internalSql] = expr;
12
12
  }
13
13
  };
@@ -1,19 +1,22 @@
1
- import { type HasData, type HasSql, internalData, internalSql } from '../Internal.js';
1
+ import { type HasSql, internalData, internalSql } from '../Internal.js';
2
2
  import type { QueryMeta } from '../MetaData.js';
3
+ import type { QueryData } from '../Queries.js';
3
4
  import type { RowOfRecord } from '../Selection.js';
4
5
  import { type Sql } from '../Sql.js';
5
- import type { Select, SelectBase, SelectData } from '../query/Select.js';
6
- export interface IncludeData<Meta extends QueryMeta = QueryMeta> extends SelectData<Meta> {
6
+ import type { SelectQuery } from '../query/Query.js';
7
+ import { type Select, type SelectBase } from '../query/Select.js';
8
+ export type IncludeQuery = SelectQuery & {
7
9
  first: boolean;
8
- }
9
- export declare class Include<Result, Meta extends QueryMeta = QueryMeta> implements HasData<IncludeData<Meta>>, HasSql<Result> {
10
+ };
11
+ export declare class Include<Result, Meta extends QueryMeta = QueryMeta> implements HasSql<Result> {
10
12
  #private;
11
13
  private brand;
12
- readonly [internalData]: IncludeData<Meta>;
13
- constructor(data: IncludeData<Meta>);
14
+ readonly [internalData]: QueryData<Meta> & IncludeQuery;
15
+ constructor(data: QueryData<Meta> & IncludeQuery);
14
16
  get [internalSql](): Sql<Result>;
15
17
  }
16
18
  export declare function include<Input, Meta extends QueryMeta>(select: Select<Input, Meta>): Include<Array<RowOfRecord<Input>>, Meta>;
17
19
  export declare namespace include {
18
20
  function one<Input, Meta extends QueryMeta>(select: SelectBase<Input, Meta>): Include<RowOfRecord<Input> | null, Meta>;
19
21
  }
22
+ export declare function includeQuery(query: IncludeQuery): Sql;
@@ -1,20 +1,22 @@
1
1
  // src/core/expr/Include.ts
2
- import {
3
- getData,
4
- internalData,
5
- internalSql
6
- } from "../Internal.js";
2
+ import { getData, internalData, internalSql } from "../Internal.js";
7
3
  import { sql } from "../Sql.js";
4
+ import {
5
+ querySelection,
6
+ selectQuery
7
+ } from "../query/Select.js";
8
+ import { jsonAggregateArray, jsonArray } from "./Json.js";
8
9
  var Include = class {
9
10
  [internalData];
10
11
  constructor(data) {
11
12
  this[internalData] = data;
12
13
  }
13
14
  #mapFromDriverValue = (value, specs) => {
14
- const { select, first } = getData(this);
15
+ const query = getData(this);
15
16
  const parsed = specs.parsesJson ? value : JSON.parse(value);
16
- if (first) {
17
- const result = parsed ? select.mapRow({ values: parsed, index: 0, specs }) : null;
17
+ const selected = querySelection(query);
18
+ if (query.first) {
19
+ const result = parsed ? selected.mapRow({ values: parsed, index: 0, specs }) : null;
18
20
  return result;
19
21
  }
20
22
  if (!parsed) return [];
@@ -27,12 +29,12 @@ var Include = class {
27
29
  for (let i = 0; i < rows.length; i++) {
28
30
  ctx.values = rows[i];
29
31
  ctx.index = 0;
30
- rows[i] = select.mapRow(ctx);
32
+ rows[i] = selected.mapRow(ctx);
31
33
  }
32
34
  return rows ?? [];
33
35
  };
34
36
  get [internalSql]() {
35
- return sql.chunk("emitInclude", getData(this)).mapWith({
37
+ return includeQuery(getData(this)).mapWith({
36
38
  mapFromDriverValue: this.#mapFromDriverValue
37
39
  });
38
40
  }
@@ -42,11 +44,26 @@ function include(select) {
42
44
  }
43
45
  ((include2) => {
44
46
  function one(select) {
45
- return new Include({ ...getData(select), first: true });
47
+ return new Include({
48
+ ...getData(select),
49
+ first: true
50
+ });
46
51
  }
47
52
  include2.one = one;
48
53
  })(include || (include = {}));
54
+ function includeQuery(query) {
55
+ const { first, limit, offset, orderBy } = query;
56
+ const wrapQuery = Boolean(limit || offset || orderBy);
57
+ const innerQuery = selectQuery(query);
58
+ const inner = wrapQuery ? sql`select * from (${innerQuery})` : innerQuery;
59
+ const fields = querySelection(query).fieldNames();
60
+ const subject = jsonArray(
61
+ ...fields.map((name) => sql`_.${sql.identifier(name)}`)
62
+ );
63
+ return sql`(select ${first ? subject : jsonAggregateArray(subject)} from (${inner}) as _)`;
64
+ }
49
65
  export {
50
66
  Include,
51
- include
67
+ include,
68
+ includeQuery
52
69
  };
@@ -1,4 +1,6 @@
1
+ import type { ColumnData } from '../Column.js';
1
2
  import { type HasSql } from '../Internal.js';
2
3
  import { type Sql } from '../Sql.js';
3
4
  export type Input<T = unknown> = HasSql<T> | T;
4
- export declare function input<T>(value: Input<T>): Sql<T>;
5
+ export declare function input<T>(value: Input<T>, maybeField?: Input<T>): Sql<T>;
6
+ export declare function mapToColumn<T>({ mapToDriverValue }: ColumnData, expr: Input<T>): Sql<T>;