rado 1.0.1 → 1.0.3

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.
@@ -5,7 +5,8 @@ import { type SelectionInput } from './Selection.js';
5
5
  import type { Table, TableDefinition } from './Table.js';
6
6
  import { DeleteFrom } from './query/Delete.js';
7
7
  import { InsertInto } from './query/Insert.js';
8
- import type { SelectBase, WithSelection, WithoutSelection } from './query/Select.js';
8
+ import type { WithSelection, WithoutSelection } from './query/Select.js';
9
+ import type { UnionBase } from './query/Union.js';
9
10
  import { UpdateTable } from './query/Update.js';
10
11
  declare class BuilderBase<Meta extends QueryMeta> {
11
12
  readonly [internalData]: QueryData<Meta>;
@@ -23,8 +24,9 @@ declare class BuilderBase<Meta extends QueryMeta> {
23
24
  export type CTE<Input = unknown> = Input & HasTarget & HasQuery;
24
25
  export declare class Builder<Meta extends QueryMeta> extends BuilderBase<Meta> {
25
26
  $with(cteName: string): {
26
- as<Input extends SelectionInput>(query: SelectBase<Input, Meta>): CTE<Input>;
27
+ as<Input extends SelectionInput>(query: UnionBase<Input, Meta>): CTE<Input>;
27
28
  };
28
- with(...cte: Array<CTE>): BuilderBase<Meta>;
29
+ with(...definitions: Array<CTE>): BuilderBase<Meta>;
30
+ withRecursive(...definitions: Array<CTE>): BuilderBase<Meta>;
29
31
  }
30
32
  export {};
@@ -4,11 +4,9 @@ import {
4
4
  getQuery,
5
5
  getSelection,
6
6
  internalData,
7
- internalQuery,
8
- internalTarget
7
+ internalQuery
9
8
  } from "./Internal.js";
10
9
  import { selection } from "./Selection.js";
11
- import { sql } from "./Sql.js";
12
10
  import { DeleteFrom } from "./query/Delete.js";
13
11
  import { InsertInto } from "./query/Insert.js";
14
12
  import { Select } from "./query/Select.js";
@@ -21,32 +19,20 @@ var BuilderBase = class {
21
19
  select(input) {
22
20
  return new Select({
23
21
  ...getData(this),
24
- select: {
25
- type: input ? "selection" : "allFrom",
26
- selection: input && selection(input),
27
- tables: []
28
- }
22
+ select: input && selection(input)
29
23
  });
30
24
  }
31
25
  selectDistinct(input) {
32
26
  return new Select({
33
27
  ...getData(this),
34
- select: {
35
- type: input ? "selection" : "allFrom",
36
- selection: input && selection(input),
37
- tables: []
38
- },
28
+ select: input && selection(input),
39
29
  distinct: true
40
30
  });
41
31
  }
42
32
  selectDistinctOn(columns, input) {
43
33
  return new Select({
44
34
  ...getData(this),
45
- select: {
46
- type: input ? "selection" : "allFrom",
47
- selection: input && selection(input),
48
- tables: []
49
- },
35
+ select: input && selection(input),
50
36
  distinctOn: columns
51
37
  });
52
38
  }
@@ -66,16 +52,21 @@ var Builder = class extends BuilderBase {
66
52
  as(query) {
67
53
  const fields = getSelection(query).makeVirtual(cteName);
68
54
  return Object.assign(fields, {
69
- [internalTarget]: sql.identifier(cteName),
70
- [internalQuery]: getQuery(query)
55
+ [internalQuery]: getQuery(query).nameSelf(cteName)
71
56
  });
72
57
  }
73
58
  };
74
59
  }
75
- with(...cte) {
60
+ with(...definitions) {
61
+ return new BuilderBase({
62
+ ...getData(this),
63
+ cte: { recursive: false, definitions }
64
+ });
65
+ }
66
+ withRecursive(...definitions) {
76
67
  return new BuilderBase({
77
68
  ...getData(this),
78
- cte
69
+ cte: { recursive: true, definitions }
79
70
  });
80
71
  }
81
72
  };
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getQuery,
4
4
  getSql,
5
- hasSql
5
+ hasQuery
6
6
  } from "./Internal.js";
7
7
  var Dialect = class {
8
8
  #createEmitter;
@@ -10,13 +10,13 @@ var Dialect = class {
10
10
  this.#createEmitter = createEmitter;
11
11
  }
12
12
  emit = (input) => {
13
- const sql = hasSql(input) ? getSql(input) : getQuery(input);
13
+ const sql = hasQuery(input) ? getQuery(input) : getSql(input);
14
14
  const emitter = new this.#createEmitter();
15
15
  sql.emitTo(emitter);
16
16
  return emitter;
17
17
  };
18
18
  inline = (input) => {
19
- const sql = hasSql(input) ? getSql(input) : getQuery(input);
19
+ const sql = hasQuery(input) ? getQuery(input) : getSql(input);
20
20
  const emitter = new this.#createEmitter();
21
21
  sql.inlineValues().emitTo(emitter);
22
22
  return emitter.sql;
@@ -2,14 +2,14 @@ import type { ColumnData } from './Column.js';
2
2
  import { type HasQuery, type HasTarget } from './Internal.js';
3
3
  import type { Runtime } from './MetaData.js';
4
4
  import { type Param } from './Param.js';
5
- import { type Sql } from './Sql.js';
5
+ 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
9
  import type { Delete } from './query/Delete.js';
10
10
  import type { Insert } from './query/Insert.js';
11
11
  import type { SelectData } from './query/Select.js';
12
- import type { Union } from './query/Union.js';
12
+ import type { UnionData } from './query/Union.js';
13
13
  import type { Update } from './query/Update.js';
14
14
  export declare abstract class Emitter {
15
15
  sql: string;
@@ -23,17 +23,26 @@ export declare abstract class Emitter {
23
23
  abstract emitInline(value: unknown): void;
24
24
  abstract emitJsonPath(value: Array<number | string>): void;
25
25
  abstract emitPlaceholder(value: string): void;
26
+ emitIdentifierOrSelf(value: string): void;
27
+ selfName?: string;
28
+ emitSelf({ name, inner }: {
29
+ name: string;
30
+ inner: Sql;
31
+ }): void;
26
32
  emitUnsafe(value: string): void;
27
- emitField(field: FieldData): void;
33
+ emitField({ targetName, fieldName }: FieldData): void;
28
34
  emitCreateTable(tableApi: TableApi): void;
29
35
  emitColumn(column: ColumnData): void;
30
36
  emitReferences(fields: Array<FieldData>): void;
31
37
  emitDelete(deleteOp: Delete<unknown>): void;
32
38
  emitInsert(insert: Insert<unknown>): void;
33
39
  emitSelect({ select, cte, from, distinct, distinctOn, where, groupBy, orderBy, having, limit, offset }: SelectData): void;
34
- emitUnion(union: Union<unknown>): void;
40
+ emitUnion({ left, operator, right }: UnionData): void;
35
41
  emitUpdate(update: Update<unknown>): void;
36
- emitWith(cte: Array<HasQuery & HasTarget>): void;
42
+ emitWith(cte: {
43
+ recursive: boolean;
44
+ definitions: Array<HasQuery & HasTarget>;
45
+ }): void;
37
46
  emitInclude(data: IncludeData): void;
38
47
  emitUniversal(runtimes: Partial<Record<Runtime | 'default', Sql>>): void;
39
48
  }
@@ -6,7 +6,7 @@ import {
6
6
  getTarget
7
7
  } from "./Internal.js";
8
8
  import { ValueParam } from "./Param.js";
9
- import { sql } from "./Sql.js";
9
+ import { Sql, sql } from "./Sql.js";
10
10
  import { callFunction } from "./expr/Functions.js";
11
11
  import { jsonAggregateArray, jsonArray } from "./expr/Json.js";
12
12
  var Emitter = class {
@@ -27,13 +27,28 @@ var Emitter = class {
27
27
  processValue(value) {
28
28
  return value;
29
29
  }
30
+ emitIdentifierOrSelf(value) {
31
+ if (value === Sql.SELF_TARGET) {
32
+ if (!this.selfName)
33
+ throw new Error("Self target not defined");
34
+ this.emitIdentifier(this.selfName);
35
+ } else {
36
+ this.emitIdentifier(value);
37
+ }
38
+ }
39
+ selfName;
40
+ emitSelf({ name, inner }) {
41
+ this.selfName = name;
42
+ inner.emitTo(this);
43
+ this.selfName = void 0;
44
+ }
30
45
  emitUnsafe(value) {
31
46
  this.sql += value;
32
47
  }
33
- emitField(field) {
34
- this.emitIdentifier(field.targetName);
48
+ emitField({ targetName, fieldName }) {
49
+ this.emitIdentifierOrSelf(targetName);
35
50
  this.emitUnsafe(".");
36
- this.emitIdentifier(field.fieldName);
51
+ this.emitIdentifier(fieldName);
37
52
  }
38
53
  emitCreateTable(tableApi) {
39
54
  sql.join([
@@ -102,7 +117,7 @@ var Emitter = class {
102
117
  this.emitWith(cte);
103
118
  const prefix = distinctOn ? sql`distinct on (${sql.join(distinctOn, sql`, `)})` : distinct && sql`distinct`;
104
119
  sql.query({
105
- select: sql.join([prefix, select.selection]),
120
+ select: sql.join([prefix, select]),
106
121
  from,
107
122
  where,
108
123
  groupBy,
@@ -112,8 +127,7 @@ var Emitter = class {
112
127
  offset
113
128
  }).emitTo(this);
114
129
  }
115
- emitUnion(union) {
116
- const { left, operator, right } = getData(union);
130
+ emitUnion({ left, operator, right }) {
117
131
  sql.join([getQuery(left), operator, getQuery(right)]).emitTo(this);
118
132
  }
119
133
  emitUpdate(update) {
@@ -130,8 +144,8 @@ var Emitter = class {
130
144
  }
131
145
  emitWith(cte) {
132
146
  sql.query({
133
- with: sql.join(
134
- cte.map((cte2) => {
147
+ [cte.recursive ? "withRecursive" : "with"]: sql.join(
148
+ cte.definitions.map((cte2) => {
135
149
  const query = getQuery(cte2);
136
150
  const target = getTarget(cte2);
137
151
  return sql`${target} as (${query})`;
@@ -144,9 +158,9 @@ var Emitter = class {
144
158
  const wrapQuery = Boolean(data.limit || data.offset || data.orderBy);
145
159
  const innerQuery = sql.chunk("emitSelect", data);
146
160
  const inner = wrapQuery ? sql`select * from (${innerQuery})` : innerQuery;
147
- if (!data.select.selection)
161
+ if (!data.select)
148
162
  throw new Error("No selection defined");
149
- const fields = data.select.selection.fieldNames();
163
+ const fields = data.select.fieldNames();
150
164
  const subject = jsonArray(
151
165
  ...fields.map((name) => sql`_.${sql.identifier(name)}`)
152
166
  );
@@ -0,0 +1 @@
1
+ export type JoinOperator = 'left' | 'right' | 'inner' | 'full';
File without changes
@@ -1,10 +1,13 @@
1
- import { internalData, internalQuery, type HasQuery, type HasResolver, type HasSql, type HasTarget } from './Internal.js';
1
+ import { type HasQuery, type HasResolver, type HasSql, type HasTarget, internalData, internalQuery } from './Internal.js';
2
2
  import type { Deliver, QueryMeta } from './MetaData.js';
3
3
  import type { PreparedStatement, Resolver } from './Resolver.js';
4
4
  import type { Sql } from './Sql.js';
5
5
  export declare class QueryData<Meta extends QueryMeta> {
6
6
  resolver?: Resolver<Meta>;
7
- cte?: Array<HasQuery & HasTarget>;
7
+ cte?: {
8
+ recursive: boolean;
9
+ definitions: Array<HasQuery & HasTarget>;
10
+ };
8
11
  }
9
12
  type Exec = () => any;
10
13
  declare class Executable<Result, Meta extends QueryMeta> implements PromiseLike<Array<Result>> {
@@ -1,5 +1,6 @@
1
1
  import type { DriverSpecs } from './Driver.js';
2
- import { internalSql, type HasSql, type HasTable } from './Internal.js';
2
+ import { type HasSql, type HasTable, type HasTarget, internalSql } from './Internal.js';
3
+ import type { JoinOperator } from './Join.js';
3
4
  import { type Sql } from './Sql.js';
4
5
  import type { Table, TableRow } from './Table.js';
5
6
  import type { Expand } from './Types.js';
@@ -29,9 +30,23 @@ export declare class Selection implements HasSql {
29
30
  nullable: Set<string>;
30
31
  mapRow: (ctx: MapRowContext) => unknown;
31
32
  constructor(input: SelectionInput, nullable: Set<string>);
32
- makeVirtual(name: string): SelectionInput;
33
- get [internalSql](): Sql;
33
+ makeVirtual<Input>(name: string): Input & HasTarget;
34
34
  fieldNames(): Array<string>;
35
+ get [internalSql](): Sql;
36
+ join(right: HasTable, operator: JoinOperator): Selection;
37
+ }
38
+ export declare class TableSelection extends Selection {
39
+ table: HasTable;
40
+ constructor(table: HasTable);
41
+ join(right: HasTable, operator: JoinOperator): Selection;
42
+ }
43
+ export declare class JoinSelection extends Selection {
44
+ tables: Array<HasTable>;
45
+ constructor(tables: Array<HasTable>, nullable: Set<string>);
46
+ join(right: HasTable, operator: JoinOperator): Selection;
35
47
  }
36
48
  export declare function selection(input: SelectionInput, nullable?: Array<string>): Selection;
49
+ export declare namespace selection {
50
+ function table(table: HasTable): TableSelection;
51
+ }
37
52
  export {};
@@ -2,6 +2,7 @@
2
2
  import {
3
3
  getField,
4
4
  getSql,
5
+ getTable,
5
6
  hasField,
6
7
  internalSql
7
8
  } from "./Internal.js";
@@ -69,9 +70,6 @@ var Selection = class {
69
70
  ])
70
71
  );
71
72
  }
72
- get [internalSql]() {
73
- return this.#selectionToSql(this.input, /* @__PURE__ */ new Set());
74
- }
75
73
  fieldNames() {
76
74
  return this.#fieldNames(this.input, /* @__PURE__ */ new Set());
77
75
  }
@@ -111,11 +109,59 @@ var Selection = class {
111
109
  sql`, `
112
110
  );
113
111
  }
112
+ get [internalSql]() {
113
+ return this.#selectionToSql(this.input, /* @__PURE__ */ new Set());
114
+ }
115
+ join(right, operator) {
116
+ return this;
117
+ }
118
+ };
119
+ var TableSelection = class extends Selection {
120
+ constructor(table) {
121
+ super(table, /* @__PURE__ */ new Set());
122
+ this.table = table;
123
+ }
124
+ join(right, operator) {
125
+ const leftTable = getTable(this.table);
126
+ const rightTable = getTable(right);
127
+ const nullable = new Set(this.nullable);
128
+ if (operator === "right" || operator === "full")
129
+ nullable.add(leftTable.aliased);
130
+ if (operator === "left" || operator === "full")
131
+ nullable.add(rightTable.aliased);
132
+ return new JoinSelection([this.table, right], nullable);
133
+ }
134
+ };
135
+ var JoinSelection = class _JoinSelection extends Selection {
136
+ constructor(tables, nullable) {
137
+ super(
138
+ Object.fromEntries(tables.map((table) => [getTable(table).aliased, table])),
139
+ nullable
140
+ );
141
+ this.tables = tables;
142
+ }
143
+ join(right, operator) {
144
+ const rightTable = getTable(right);
145
+ const nullable = new Set(this.nullable);
146
+ if (operator === "right" || operator === "full")
147
+ this.tables.map((table) => getTable(table).aliased).forEach(nullable.add, nullable);
148
+ if (operator === "left" || operator === "full")
149
+ nullable.add(rightTable.aliased);
150
+ return new _JoinSelection([...this.tables, right], nullable);
151
+ }
114
152
  };
115
153
  function selection(input, nullable = []) {
116
154
  return new Selection(input, new Set(nullable));
117
155
  }
156
+ ((selection2) => {
157
+ function table(table2) {
158
+ return new TableSelection(table2);
159
+ }
160
+ selection2.table = table;
161
+ })(selection || (selection = {}));
118
162
  export {
163
+ JoinSelection,
119
164
  Selection,
165
+ TableSelection,
120
166
  selection
121
167
  };
@@ -16,6 +16,7 @@ export type Decoder<T> = ((value: unknown) => T) | {
16
16
  };
17
17
  export declare class Sql<Value = unknown> implements HasSql<Value> {
18
18
  #private;
19
+ static SELF_TARGET: string;
19
20
  private brand;
20
21
  alias?: string;
21
22
  mapFromDriverValue?: (input: unknown, specs: DriverSpecs) => Value;
@@ -34,6 +35,7 @@ export declare class Sql<Value = unknown> implements HasSql<Value> {
34
35
  identifier(identifier: string): Sql<Value>;
35
36
  inlineValues(): Sql<Value>;
36
37
  inlineFields(withTableName: boolean): Sql<Value>;
38
+ nameSelf(name: string): Sql;
37
39
  emitTo(emitter: Emitter): void;
38
40
  }
39
41
  export declare function sql<T>(strings: TemplateStringsArray, ...inner: Array<HasSql>): Sql<T>;
package/dist/core/Sql.js CHANGED
@@ -7,6 +7,7 @@ var Chunk = class {
7
7
  }
8
8
  };
9
9
  var Sql = class _Sql {
10
+ static SELF_TARGET = "$$self";
10
11
  alias;
11
12
  mapFromDriverValue;
12
13
  [internalSql] = this;
@@ -60,7 +61,7 @@ var Sql = class _Sql {
60
61
  return this.chunk("emitPlaceholder", name);
61
62
  }
62
63
  identifier(identifier) {
63
- return this.chunk("emitIdentifier", identifier);
64
+ return this.chunk("emitIdentifierOrSelf", identifier);
64
65
  }
65
66
  inlineValues() {
66
67
  return new _Sql(
@@ -79,7 +80,7 @@ var Sql = class _Sql {
79
80
  const data = chunk.inner;
80
81
  if (withTableName)
81
82
  return [
82
- new Chunk("emitIdentifier", data.targetName),
83
+ new Chunk("emitIdentifierOrSelf", data.targetName),
83
84
  new Chunk("emitUnsafe", "."),
84
85
  new Chunk("emitIdentifier", data.fieldName)
85
86
  ];
@@ -87,6 +88,9 @@ var Sql = class _Sql {
87
88
  })
88
89
  );
89
90
  }
91
+ nameSelf(name) {
92
+ return sql.chunk("emitSelf", { name, inner: this });
93
+ }
90
94
  emitTo(emitter) {
91
95
  for (const chunk of this.#chunks)
92
96
  emitter[chunk.type](chunk.inner);
@@ -1,2 +1,2 @@
1
- import type { SelectionInput } from './Selection.js';
2
- export declare function virtual<Input extends SelectionInput>(alias: string, source?: Input): Input;
1
+ import { type HasTarget } from './Internal.js';
2
+ export declare function virtual<Input>(alias: string, source?: Input): Input & HasTarget;
@@ -1,22 +1,24 @@
1
1
  // src/core/Virtual.ts
2
- import { getSql, hasSql } from "./Internal.js";
2
+ import { getSql, hasSql, internalTarget } from "./Internal.js";
3
+ import { sql } from "./Sql.js";
3
4
  import { Field } from "./expr/Field.js";
4
5
  function virtual(alias, source) {
6
+ const target = { [internalTarget]: sql.identifier(alias) };
5
7
  if (source && hasSql(source)) {
6
8
  const expr = getSql(source);
7
9
  const name = expr.alias;
8
10
  if (!name)
9
11
  throw new Error("Cannot alias a virtual field without a name");
10
- return new Field(alias, name, expr);
12
+ return Object.assign(new Field(alias, name, expr), target);
11
13
  }
12
- return new Proxy(/* @__PURE__ */ Object.create(null), {
13
- get(target, field) {
14
- if (field in target)
15
- return target[field];
14
+ return new Proxy(target, {
15
+ get(target2, field) {
16
+ if (field in target2)
17
+ return target2[field];
16
18
  const from = source?.[field];
17
19
  if (typeof field !== "string")
18
20
  return from;
19
- return target[field] = new Field(
21
+ return target2[field] = new Field(
20
22
  alias,
21
23
  field,
22
24
  from ? getSql(from) : void 0
@@ -1,4 +1,4 @@
1
- import { internalData, internalSql, type HasData, type HasSql } from '../Internal.js';
1
+ import { type HasData, type HasSql, internalData, internalSql } from '../Internal.js';
2
2
  import type { QueryMeta } from '../MetaData.js';
3
3
  import type { RowOfRecord } from '../Selection.js';
4
4
  import { type Sql } from '../Sql.js';
@@ -12,10 +12,9 @@ var Include = class {
12
12
  }
13
13
  #mapFromDriverValue = (value, specs) => {
14
14
  const { select, first } = getData(this);
15
- const selection = select.selection;
16
15
  const parsed = specs.parsesJson ? value : JSON.parse(value);
17
16
  if (first)
18
- return parsed ? selection.mapRow({ values: parsed, index: 0, specs }) : null;
17
+ return parsed ? select.mapRow({ values: parsed, index: 0, specs }) : null;
19
18
  if (!parsed)
20
19
  return [];
21
20
  const rows = parsed;
@@ -27,7 +26,7 @@ var Include = class {
27
26
  for (let i = 0; i < rows.length; i++) {
28
27
  ctx.values = rows[i];
29
28
  ctx.index = 0;
30
- rows[i] = selection.mapRow(ctx);
29
+ rows[i] = select.mapRow(ctx);
31
30
  }
32
31
  return rows ?? [];
33
32
  };
@@ -31,7 +31,7 @@ var DeleteFrom = class _DeleteFrom extends Delete {
31
31
  const data = getData(this);
32
32
  return new Delete({
33
33
  ...data,
34
- returning: selection(returning ?? data.from)
34
+ returning: returning ? selection(returning) : selection.table(data.from)
35
35
  });
36
36
  }
37
37
  };
@@ -30,7 +30,7 @@ var InsertCanReturn = class extends Insert {
30
30
  const data = getData(this);
31
31
  return new Insert({
32
32
  ...data,
33
- returning: selection(returning ?? data.into)
33
+ returning: returning ? selection(returning) : selection.table(data.into)
34
34
  });
35
35
  }
36
36
  };
@@ -1,6 +1,5 @@
1
- import { type HasSelection, type HasSql, type HasTable, type HasTarget, internalData, internalQuery, internalSelection } from '../Internal.js';
1
+ import { type HasSelection, type HasSql, type HasTable, type HasTarget, internalData, internalQuery, internalSelection, internalSql } from '../Internal.js';
2
2
  import type { QueryMeta } from '../MetaData.js';
3
- import type { Query } from '../Query.js';
4
3
  import { type IsNullable, type MakeNullable, type Selection, type SelectionRecord, type SelectionRow } from '../Selection.js';
5
4
  import { type Sql } from '../Sql.js';
6
5
  import type { Table, TableDefinition, TableFields } from '../Table.js';
@@ -10,11 +9,6 @@ import { type Input as UserInput } from '../expr/Input.js';
10
9
  import { UnionBase, type UnionBaseData } from './Union.js';
11
10
  export type SelectionType = 'selection' | 'allFrom' | 'joinTables';
12
11
  export interface SelectData<Meta extends QueryMeta = QueryMeta> extends UnionBaseData<Meta> {
13
- select: {
14
- type: SelectionType;
15
- tables: Array<string>;
16
- selection?: Selection;
17
- };
18
12
  distinct?: boolean;
19
13
  distinctOn?: Array<HasSql>;
20
14
  from?: HasSql;
@@ -37,16 +31,17 @@ export declare class Select<Input, Meta extends QueryMeta = QueryMeta> extends U
37
31
  fullJoin(right: HasTable, on: HasSql<boolean>): Select<Input, Meta>;
38
32
  where(...where: Array<HasSql<boolean> | undefined>): Select<Input, Meta>;
39
33
  groupBy(...exprs: Array<HasSql>): Select<Input, Meta>;
40
- having(having: HasSql<boolean>): Select<Input, Meta>;
34
+ having(having: HasSql<boolean> | ((self: Input) => HasSql<boolean>)): Select<Input, Meta>;
41
35
  orderBy(...exprs: Array<HasSql>): Select<Input, Meta>;
42
36
  limit(limit: UserInput<number>): Select<Input, Meta>;
43
37
  offset(offset: UserInput<number>): Select<Input, Meta>;
44
38
  get [internalSelection](): Selection;
45
39
  get [internalQuery](): Sql;
40
+ get [internalSql](): Sql<SelectionRow<Input>>;
46
41
  }
47
42
  export type SubQuery<Input> = Input & HasTarget;
48
- export interface SelectBase<Input, Meta extends QueryMeta = QueryMeta> extends UnionBase<Input, Meta>, HasSelection {
49
- where(where: HasSql<boolean>): Select<Input, Meta>;
43
+ export interface SelectBase<Input, Meta extends QueryMeta = QueryMeta> extends UnionBase<Input, Meta>, HasSelection, HasSql<SelectionRow<Input>> {
44
+ where(...where: Array<HasSql<boolean> | undefined>): Select<Input, Meta>;
50
45
  groupBy(...exprs: Array<HasSql>): Select<Input, Meta>;
51
46
  having(having: HasSql<boolean>): Select<Input, Meta>;
52
47
  orderBy(...exprs: Array<HasSql>): Select<Input, Meta>;
@@ -58,7 +53,7 @@ export interface WithoutSelection<Meta extends QueryMeta> {
58
53
  from<Definition extends TableDefinition, Name extends string>(from: Table<Definition, Name>): AllFrom<TableFields<Definition>, Meta, Record<Name, TableFields<Definition>>>;
59
54
  from<Input>(from: SubQuery<Input>): SelectionFrom<Input, Meta>;
60
55
  }
61
- export interface WithSelection<Input, Meta extends QueryMeta> extends Query<SelectionRow<Input>, Meta> {
56
+ export interface WithSelection<Input, Meta extends QueryMeta> extends SelectBase<Input, Meta>, HasSql<SelectionRow<Input>> {
62
57
  from<Definition extends TableDefinition, Name extends string>(from: Table<Definition, Name>): SelectionFrom<Input, Meta>;
63
58
  from(from: SubQuery<unknown>): SelectionFrom<Input, Meta>;
64
59
  from(target: HasSql): Select<Input, Meta>;
@@ -11,6 +11,7 @@ import {
11
11
  internalData,
12
12
  internalQuery,
13
13
  internalSelection,
14
+ internalSql,
14
15
  internalTarget
15
16
  } from "../Internal.js";
16
17
  import {
@@ -36,50 +37,24 @@ var Select = class _Select extends UnionBase {
36
37
  }
37
38
  from(target) {
38
39
  const { select: current } = getData(this);
39
- const selected = current.selection;
40
40
  const from = hasTarget(target) ? getTarget(target) : getSql(target);
41
41
  const isTable = hasTable(target);
42
- const selectionInput = selected ?? selection(isTable ? target : sql`*`);
42
+ const selected = current ?? (isTable ? selection.table(target) : selection(sql`*`));
43
43
  return new _Select({
44
44
  ...getData(this),
45
- select: {
46
- ...current,
47
- selection: selectionInput,
48
- tables: isTable ? [getTable(target).aliased] : []
49
- },
45
+ select: selected,
50
46
  from
51
47
  });
52
48
  }
53
49
  #join(operator, right, on) {
54
50
  const { from, select: current } = getData(this);
55
- const selected = current.selection;
56
- const rightTable = getTable(right);
57
- const addNullable = [];
58
- if (operator === "right" || operator === "full")
59
- addNullable.push(...current.tables);
60
- if (operator === "left" || operator === "full")
61
- addNullable.push(rightTable.aliased);
62
- if (selected)
63
- addNullable.push(...selected.nullable);
64
- const select = current.type === "selection" ? current : {
65
- type: "joinTables",
66
- selection: selection(current.type === "allFrom" ? {
67
- // Todo: handle this properly
68
- [getTable(selected.input).aliased]: selected.input,
69
- [rightTable.aliased]: right
70
- } : {
71
- ...selected?.input,
72
- [rightTable.aliased]: right
73
- }, addNullable),
74
- tables: [...current.tables, rightTable.aliased]
75
- };
76
51
  return new _Select({
77
52
  ...getData(this),
78
- select,
53
+ select: current?.join(right, operator),
79
54
  from: sql.join([
80
55
  from,
81
56
  sql.unsafe(`${operator} join`),
82
- rightTable.target(),
57
+ getTable(right).target(),
83
58
  sql`on ${on}`
84
59
  ])
85
60
  });
@@ -106,7 +81,10 @@ var Select = class _Select extends UnionBase {
106
81
  });
107
82
  }
108
83
  having(having) {
109
- return new _Select({ ...getData(this), having });
84
+ return new _Select({
85
+ ...getData(this),
86
+ having: typeof having === "function" ? having(getSelection(this).input) : having
87
+ });
110
88
  }
111
89
  orderBy(...exprs) {
112
90
  return new _Select({
@@ -125,13 +103,16 @@ var Select = class _Select extends UnionBase {
125
103
  }
126
104
  get [internalSelection]() {
127
105
  const { select } = getData(this);
128
- if (!select.selection)
106
+ if (!select)
129
107
  throw new Error("No selection defined");
130
- return select.selection;
108
+ return select;
131
109
  }
132
110
  get [internalQuery]() {
133
111
  return sql.chunk("emitSelect", getData(this));
134
112
  }
113
+ get [internalSql]() {
114
+ return sql`(${getQuery(this)})`;
115
+ }
135
116
  };
136
117
  export {
137
118
  Select
@@ -1,21 +1,22 @@
1
- import { internalData, internalQuery, internalSelection, type HasQuery, type HasSelection, type HasSql } from '../Internal.js';
1
+ import { type HasQuery, type HasSelection, type HasSql, type HasTarget, internalData, internalQuery, internalSelection } from '../Internal.js';
2
2
  import type { IsMysql, IsPostgres, QueryMeta } from '../MetaData.js';
3
3
  import { Query, type QueryData } from '../Query.js';
4
4
  import type { Selection, SelectionRow } from '../Selection.js';
5
- import { type Sql } from '../Sql.js';
5
+ import { Sql } from '../Sql.js';
6
6
  export interface UnionBaseData<Meta extends QueryMeta> extends QueryData<Meta> {
7
- selection?: Selection;
7
+ select?: Selection;
8
8
  }
9
9
  export declare abstract class UnionBase<Input, Meta extends QueryMeta = QueryMeta> extends Query<SelectionRow<Input>, Meta> {
10
+ #private;
10
11
  readonly [internalData]: UnionBaseData<Meta>;
11
- union(right: UnionBase<Input, Meta>): Union<Input, Meta>;
12
- unionAll(right: UnionBase<Input, Meta>): Union<Input, Meta>;
13
- intersect(right: UnionBase<Input, Meta>): Union<Input, Meta>;
14
- intersectAll(this: UnionBase<Input, IsPostgres | IsMysql>, right: UnionBase<Input, Meta>): Union<Input, Meta>;
15
- except(right: UnionBase<Input, Meta>): Union<Input, Meta>;
16
- exceptAll(this: UnionBase<Input, IsPostgres | IsMysql>, right: UnionBase<Input, Meta>): Union<Input, Meta>;
12
+ union(right: UnionBase<Input, Meta> | ((self: Input & HasTarget) => UnionBase<Input, Meta>)): Union<Input, Meta>;
13
+ unionAll(right: UnionBase<Input, Meta> | ((self: Input & HasTarget) => UnionBase<Input, Meta>)): Union<Input, Meta>;
14
+ intersect(right: UnionBase<Input, Meta> | ((self: Input & HasTarget) => UnionBase<Input, Meta>)): Union<Input, Meta>;
15
+ intersectAll(this: UnionBase<Input, IsPostgres | IsMysql>, right: UnionBase<Input, Meta> | ((self: Input & HasTarget) => UnionBase<Input, Meta>)): Union<Input, Meta>;
16
+ except(right: UnionBase<Input, Meta> | ((self: Input & HasTarget) => UnionBase<Input, Meta>)): Union<Input, Meta>;
17
+ exceptAll(this: UnionBase<Input, IsPostgres | IsMysql>, right: UnionBase<Input, Meta> | ((self: Input & HasTarget) => UnionBase<Input, Meta>)): Union<Input, Meta>;
17
18
  }
18
- export interface UnionData<Meta extends QueryMeta> extends UnionBaseData<Meta> {
19
+ export interface UnionData<Meta extends QueryMeta = QueryMeta> extends UnionBaseData<Meta> {
19
20
  left: HasQuery;
20
21
  operator: HasSql;
21
22
  right: HasQuery;
@@ -6,15 +6,19 @@ import {
6
6
  internalSelection
7
7
  } from "../Internal.js";
8
8
  import { Query } from "../Query.js";
9
- import { sql } from "../Sql.js";
9
+ import { Sql, sql } from "../Sql.js";
10
10
  var UnionBase = class extends Query {
11
11
  [internalData];
12
+ #makeSelf() {
13
+ const { select } = getData(this);
14
+ return select.makeVirtual(Sql.SELF_TARGET);
15
+ }
12
16
  union(right) {
13
17
  return new Union({
14
18
  ...getData(this),
15
19
  left: this,
16
20
  operator: sql`union`,
17
- right
21
+ right: typeof right === "function" ? right(this.#makeSelf()) : right
18
22
  });
19
23
  }
20
24
  unionAll(right) {
@@ -22,7 +26,7 @@ var UnionBase = class extends Query {
22
26
  ...getData(this),
23
27
  left: this,
24
28
  operator: sql`union all`,
25
- right
29
+ right: typeof right === "function" ? right(this.#makeSelf()) : right
26
30
  });
27
31
  }
28
32
  intersect(right) {
@@ -30,7 +34,7 @@ var UnionBase = class extends Query {
30
34
  ...getData(this),
31
35
  left: this,
32
36
  operator: sql`intersect`,
33
- right
37
+ right: typeof right === "function" ? right(this.#makeSelf()) : right
34
38
  });
35
39
  }
36
40
  intersectAll(right) {
@@ -38,7 +42,7 @@ var UnionBase = class extends Query {
38
42
  ...getData(this),
39
43
  left: this,
40
44
  operator: sql`intersect all`,
41
- right
45
+ right: typeof right === "function" ? right(this.#makeSelf()) : right
42
46
  });
43
47
  }
44
48
  except(right) {
@@ -46,7 +50,7 @@ var UnionBase = class extends Query {
46
50
  ...getData(this),
47
51
  left: this,
48
52
  operator: sql`except`,
49
- right
53
+ right: typeof right === "function" ? right(this.#makeSelf()) : right
50
54
  });
51
55
  }
52
56
  exceptAll(right) {
@@ -54,7 +58,7 @@ var UnionBase = class extends Query {
54
58
  ...getData(this),
55
59
  left: this,
56
60
  operator: sql`except all`,
57
- right
61
+ right: typeof right === "function" ? right(this.#makeSelf()) : right
58
62
  });
59
63
  }
60
64
  };
@@ -64,10 +68,10 @@ var Union = class extends UnionBase {
64
68
  constructor(data) {
65
69
  super(data);
66
70
  this[internalData] = data;
67
- this[internalSelection] = data.selection;
71
+ this[internalSelection] = data.select;
68
72
  }
69
73
  get [internalQuery]() {
70
- return sql.chunk("emitUnion", this);
74
+ return sql.chunk("emitUnion", getData(this));
71
75
  }
72
76
  };
73
77
  function union(left, right, ...rest) {
@@ -50,7 +50,7 @@ var UpdateTable = class _UpdateTable extends Update {
50
50
  const data = getData(this);
51
51
  return new Update({
52
52
  ...data,
53
- returning: selection(returning ?? data.table)
53
+ returning: returning ? selection(returning) : selection.table(data.table)
54
54
  });
55
55
  }
56
56
  };
package/dist/index.d.ts CHANGED
@@ -1,18 +1,20 @@
1
1
  export * from './compat.js';
2
+ export * from './core/Builder.js';
2
3
  export * from './core/Column.js';
3
4
  export * from './core/Constraint.js';
4
5
  export * from './core/Database.js';
5
6
  export * from './core/Driver.js';
7
+ export * from './core/Index.js';
8
+ export * from './core/Internal.js';
9
+ export * from './core/Query.js';
10
+ export * from './core/Selection.js';
11
+ export * from './core/Sql.js';
12
+ export * from './core/Table.js';
6
13
  export * from './core/expr/Aggregate.js';
7
14
  export * from './core/expr/Conditions.js';
8
15
  export * from './core/expr/Include.js';
9
- export * from './core/Index.js';
10
- export * from './core/Query.js';
11
16
  export * from './core/query/Delete.js';
12
17
  export * from './core/query/Insert.js';
13
18
  export * from './core/query/Select.js';
14
19
  export * from './core/query/Union.js';
15
20
  export * from './core/query/Update.js';
16
- export * from './core/Selection.js';
17
- export * from './core/Sql.js';
18
- export * from './core/Table.js';
package/dist/index.js CHANGED
@@ -1,19 +1,21 @@
1
1
  // src/index.ts
2
2
  export * from "./compat.js";
3
+ export * from "./core/Builder.js";
3
4
  export * from "./core/Column.js";
4
5
  export * from "./core/Constraint.js";
5
6
  export * from "./core/Database.js";
6
7
  export * from "./core/Driver.js";
8
+ export * from "./core/Index.js";
9
+ export * from "./core/Internal.js";
10
+ export * from "./core/Query.js";
11
+ export * from "./core/Selection.js";
12
+ export * from "./core/Sql.js";
13
+ export * from "./core/Table.js";
7
14
  export * from "./core/expr/Aggregate.js";
8
15
  export * from "./core/expr/Conditions.js";
9
16
  export * from "./core/expr/Include.js";
10
- export * from "./core/Index.js";
11
- export * from "./core/Query.js";
12
17
  export * from "./core/query/Delete.js";
13
18
  export * from "./core/query/Insert.js";
14
19
  export * from "./core/query/Select.js";
15
20
  export * from "./core/query/Union.js";
16
21
  export * from "./core/query/Update.js";
17
- export * from "./core/Selection.js";
18
- export * from "./core/Sql.js";
19
- export * from "./core/Table.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rado",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {