rado 0.2.25 → 0.2.26

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.
@@ -1,4 +1,5 @@
1
1
  // src/define/Expr.ts
2
+ import { randomAlias } from "../util/Alias.js";
2
3
  import { OrderDirection } from "./OrderBy.js";
3
4
  import { ParamData, ParamType } from "./Param.js";
4
5
  import { Target } from "./Target.js";
@@ -336,7 +337,7 @@ var Expr = class {
336
337
  return Expr.create(value).isIn(this);
337
338
  }
338
339
  filter(fn) {
339
- const alias = `__${Math.random().toString(36).slice(2, 9)}`;
340
+ const alias = randomAlias();
340
341
  const target = new Target.Expr(this[DATA], alias);
341
342
  return new Expr(
342
343
  new ExprData.Filter(
@@ -346,7 +347,7 @@ var Expr = class {
346
347
  );
347
348
  }
348
349
  map(fn) {
349
- const alias = `__${Math.random().toString(36).slice(2, 9)}`;
350
+ const alias = randomAlias();
350
351
  const target = new Target.Expr(this[DATA], alias);
351
352
  return new Expr(
352
353
  new ExprData.Map(
@@ -4,7 +4,9 @@ import { Batch } from './query/Batch';
4
4
  import { Delete } from './query/Delete';
5
5
  import { Insert } from './query/Insert';
6
6
  import { SelectMultiple } from './query/Select';
7
+ import { RecursiveUnion } from './query/Union';
7
8
  import { Update } from './query/Update';
9
+ export declare function withRecursive<Row>(initialSelect: SelectMultiple<Row>): RecursiveUnion<Row>;
8
10
  export declare function select<X extends Selection>(selection: X): SelectMultiple<Selection.Infer<X>>;
9
11
  export declare function from<Row>(source: Table<Row> | SelectMultiple<Row>): SelectMultiple<Row>;
10
12
  export declare function update<Row>(table: Table<Row>): Update<Row>;
@@ -8,7 +8,11 @@ import { Batch } from "./query/Batch.js";
8
8
  import { Delete } from "./query/Delete.js";
9
9
  import { Insert } from "./query/Insert.js";
10
10
  import { SelectMultiple } from "./query/Select.js";
11
+ import { RecursiveUnion } from "./query/Union.js";
11
12
  import { Update } from "./query/Update.js";
13
+ function withRecursive(initialSelect) {
14
+ return new RecursiveUnion(initialSelect[Query.Data]);
15
+ }
12
16
  function select(selection) {
13
17
  return new SelectMultiple(
14
18
  new QueryData.Select({
@@ -45,5 +49,6 @@ export {
45
49
  from,
46
50
  insertInto,
47
51
  select,
48
- update
52
+ update,
53
+ withRecursive
49
54
  };
@@ -49,7 +49,7 @@ export declare namespace QueryData {
49
49
  type: QueryType.Union;
50
50
  a: Select | Union;
51
51
  operator: UnionOperation;
52
- b: Select | Union;
52
+ b: Select | Union | (() => Select | Union);
53
53
  }
54
54
  export class Select extends Data<Select> {
55
55
  type: QueryType.Select;
@@ -1,3 +1,4 @@
1
+ import { ClearFunctionProto } from '../util/Callable';
1
2
  import { Column, ColumnData, OptionalColumn, PrimaryColumn } from './Column';
2
3
  import { EV, Expr } from './Expr';
3
4
  import type { Fields } from './Fields';
@@ -18,7 +19,7 @@ export declare class TableData {
18
19
  };
19
20
  constructor(data: TableData);
20
21
  }
21
- export interface TableInstance<Definition> {
22
+ export interface TableInstance<Definition> extends ClearFunctionProto {
22
23
  (conditions: {
23
24
  [K in keyof Definition]?: Definition[K] extends Expr<infer V> ? EV<V> : never;
24
25
  }): TableSelect<Definition>;
@@ -27,19 +28,13 @@ export interface TableInstance<Definition> {
27
28
  export declare class TableInstance<Definition> {
28
29
  [Selection.TableType](): Table.Select<Definition>;
29
30
  get [DATA](): TableData;
30
- get name(): unknown;
31
- get length(): unknown;
32
- get call(): unknown;
33
- get apply(): unknown;
34
- get bind(): unknown;
35
- get prototype(): unknown;
36
31
  }
37
32
  export type Table<Definition> = Definition & TableInstance<Definition>;
38
33
  export declare namespace Table {
39
34
  export const Data: typeof DATA;
40
35
  export const Meta: typeof META;
41
36
  export type Of<Row> = Table<{
42
- [K in keyof Row as K extends string ? K : never]: Fields<Row[K]>;
37
+ [K in keyof Row as K extends string ? K : never]: Column<Row[K]> & Fields<Row[K]>;
43
38
  }>;
44
39
  export type Select<Definition> = {
45
40
  [K in keyof Definition as Definition[K] extends Column<any> ? K : never]: Definition[K] extends Column<infer T> ? T : never;
@@ -62,7 +57,6 @@ interface Define<T> {
62
57
  new (): T;
63
58
  }
64
59
  export type table<T> = T extends Table<infer D> ? Table.Select<D> : never;
65
- export declare function virtualTable<Definition>(name: string): Table<Definition>;
66
60
  export declare function createTable<Definition>(data: TableData): Table<Definition>;
67
61
  export declare function table<T extends {}>(define: Record<string, T | Define<T>>): Table<T>;
68
62
  export declare namespace table {
@@ -8,7 +8,6 @@ import { Target } from "./Target.js";
8
8
  import { TableSelect } from "./query/TableSelect.js";
9
9
  var {
10
10
  assign,
11
- create,
12
11
  keys,
13
12
  entries,
14
13
  fromEntries,
@@ -29,42 +28,6 @@ var Table;
29
28
  Table2.Data = DATA;
30
29
  Table2.Meta = META;
31
30
  })(Table || (Table = {}));
32
- function virtualTable(name) {
33
- const data = new TableData({
34
- name,
35
- columns: {},
36
- definition: create(null),
37
- meta: () => ({ indexes: {} })
38
- });
39
- const target = new Target.Table(data);
40
- const cache = create(null);
41
- function call(...args) {
42
- const isConditionalRecord = args.length === 1 && !Expr.isExpr(args[0]);
43
- const conditions = isConditionalRecord ? entries(args[0]).map(([key, value]) => {
44
- return new Expr(
45
- new ExprData.BinOp(
46
- BinOpType.Equals,
47
- new ExprData.Field(new ExprData.Row(target), key),
48
- ExprData.create(value)
49
- )
50
- );
51
- }) : args;
52
- return new TableSelect(data, conditions);
53
- }
54
- return new Proxy(call, {
55
- get(_, column) {
56
- if (column === DATA)
57
- return data;
58
- if (column === Expr.ToExpr)
59
- return new Expr(new ExprData.Row(target));
60
- if (column in cache)
61
- return cache[column];
62
- return (cache[column] = new Expr(
63
- new ExprData.Field(new ExprData.Row(target), column)
64
- )).dynamic();
65
- }
66
- });
67
- }
68
31
  function createTable(data) {
69
32
  const target = new Target.Table(data);
70
33
  const call = {
@@ -160,6 +123,5 @@ export {
160
123
  Table,
161
124
  TableData,
162
125
  createTable,
163
- table,
164
- virtualTable
126
+ table
165
127
  };
@@ -0,0 +1,33 @@
1
+ import { ClearFunctionProto } from '../util/Callable';
2
+ import { Column } from './Column';
3
+ import { EV, Expr } from './Expr';
4
+ import { Fields } from './Fields';
5
+ import { Selection } from './Selection';
6
+ import { Table } from './Table';
7
+ import { Target } from './Target';
8
+ import { SelectMultiple } from './query/Select';
9
+ declare const DATA: unique symbol;
10
+ export interface VirtualTableInstance<Definition> extends ClearFunctionProto {
11
+ (conditions: {
12
+ [K in keyof Definition]?: Definition[K] extends Expr<infer V> ? EV<V> : never;
13
+ }): SelectMultiple<Table.Select<Definition>>;
14
+ (...conditions: Array<EV<boolean>>): SelectMultiple<Table.Select<Definition>>;
15
+ }
16
+ export declare class VirtualTableInstance<Definition> {
17
+ [Selection.TableType](): Table.Select<Definition>;
18
+ get [DATA](): VirtualTableData;
19
+ }
20
+ export interface VirtualTableData {
21
+ name: string;
22
+ target: Target;
23
+ select: (conditions: Array<EV<boolean>>) => SelectMultiple<any>;
24
+ }
25
+ export type VirtualTable<Definition> = Definition & VirtualTableInstance<Definition>;
26
+ export declare namespace VirtualTable {
27
+ const Data: typeof DATA;
28
+ type Of<Row> = VirtualTable<{
29
+ [K in keyof Row as K extends string ? K : never]: Column<Row[K]> & Fields<Row[K]>;
30
+ }>;
31
+ }
32
+ export declare function createVirtualTable<Definition>(data: VirtualTableData): VirtualTable<Definition>;
33
+ export {};
@@ -0,0 +1,41 @@
1
+ // src/define/VirtualTable.ts
2
+ import { BinOpType, Expr, ExprData } from "./Expr.js";
3
+ var { create, entries } = Object;
4
+ var DATA = Symbol("VirtualTable.Data");
5
+ var VirtualTable;
6
+ ((VirtualTable2) => {
7
+ VirtualTable2.Data = DATA;
8
+ })(VirtualTable || (VirtualTable = {}));
9
+ function createVirtualTable(data) {
10
+ const cache = create(null);
11
+ function call(...args) {
12
+ const isConditionalRecord = args.length === 1 && !Expr.isExpr(args[0]);
13
+ const conditions = isConditionalRecord ? entries(args[0]).map(([key, value]) => {
14
+ return new Expr(
15
+ new ExprData.BinOp(
16
+ BinOpType.Equals,
17
+ new ExprData.Field(new ExprData.Row(data.target), key),
18
+ ExprData.create(value)
19
+ )
20
+ );
21
+ }) : args;
22
+ return data.select(conditions);
23
+ }
24
+ return new Proxy(call, {
25
+ get(_, column) {
26
+ if (column === DATA)
27
+ return data;
28
+ if (column === Expr.ToExpr)
29
+ return new Expr(new ExprData.Row(data.target));
30
+ if (column in cache)
31
+ return cache[column];
32
+ return (cache[column] = new Expr(
33
+ new ExprData.Field(new ExprData.Row(data.target), column)
34
+ )).dynamic();
35
+ }
36
+ });
37
+ }
38
+ export {
39
+ VirtualTable,
40
+ createVirtualTable
41
+ };
@@ -3,12 +3,13 @@ import { OrderBy } from '../OrderBy';
3
3
  import { Query, QueryData } from '../Query';
4
4
  import { Selection } from '../Selection';
5
5
  import { Table } from '../Table';
6
+ import { VirtualTable } from '../VirtualTable';
6
7
  import { TableSelect } from './TableSelect';
7
8
  import { Union } from './Union';
8
9
  export declare class SelectMultiple<Row> extends Union<Row> {
9
10
  [Query.Data]: QueryData.Select;
10
11
  constructor(query: QueryData.Select);
11
- from(table: Table<any>): SelectMultiple<Row>;
12
+ from(table: Table<any> | VirtualTable<any>): SelectMultiple<Row>;
12
13
  leftJoin<C>(that: Table<C> | TableSelect<C>, ...on: Array<EV<boolean>>): SelectMultiple<Row>;
13
14
  innerJoin<C>(that: Table<C> | TableSelect<C>, ...on: Array<EV<boolean>>): SelectMultiple<Row>;
14
15
  select<X extends Selection>(selection: X): SelectMultiple<Selection.Infer<X>>;
@@ -20,8 +21,6 @@ export declare class SelectMultiple<Row> extends Union<Row> {
20
21
  where(...where: Array<EV<boolean>>): SelectMultiple<Row>;
21
22
  take(limit: number | undefined): SelectMultiple<Row>;
22
23
  skip(offset: number | undefined): SelectMultiple<Row>;
23
- recursiveUnion<T extends {}>(this: SelectMultiple<T>, create: (fields: Record<string, Table.Of<T>>) => SelectMultiple<T> | Union<T>): SelectMultiple<T>;
24
- recursiveUnionAll<T extends {}>(this: SelectMultiple<T>, create: (fields: Record<string, Table.Of<T>>) => SelectMultiple<T> | Union<T>): SelectMultiple<T>;
25
24
  [Expr.ToExpr](): Expr<Row>;
26
25
  }
27
26
  export declare class SelectSingle<Row> extends Query<Row> {
@@ -1,10 +1,10 @@
1
1
  // src/define/query/Select.ts
2
- import { makeRecursiveUnion } from "../CTE.js";
3
2
  import { Expr, ExprData } from "../Expr.js";
4
3
  import { Functions } from "../Functions.js";
5
- import { Query, QueryData } from "../Query.js";
4
+ import { Query } from "../Query.js";
6
5
  import { Table } from "../Table.js";
7
6
  import { Target } from "../Target.js";
7
+ import { VirtualTable } from "../VirtualTable.js";
8
8
  import { Union } from "./Union.js";
9
9
  function joinTarget(joinType, query, to, on) {
10
10
  const toQuery = Query.isQuery(to) ? to[Query.Data] : void 0;
@@ -29,8 +29,9 @@ var SelectMultiple = class extends Union {
29
29
  super(query);
30
30
  }
31
31
  from(table) {
32
+ const virtual = table[VirtualTable.Data];
32
33
  return new SelectMultiple(
33
- this[Query.Data].with({ from: new Target.Table(table) })
34
+ this[Query.Data].with({ from: virtual?.target || new Target.Table(table) })
34
35
  );
35
36
  }
36
37
  leftJoin(that, ...on) {
@@ -100,24 +101,6 @@ var SelectMultiple = class extends Union {
100
101
  skip(offset) {
101
102
  return new SelectMultiple(this[Query.Data].with({ offset }));
102
103
  }
103
- recursiveUnion(create) {
104
- return new SelectMultiple(
105
- makeRecursiveUnion(
106
- this[Query.Data],
107
- create,
108
- QueryData.UnionOperation.Union
109
- )
110
- );
111
- }
112
- recursiveUnionAll(create) {
113
- return new SelectMultiple(
114
- makeRecursiveUnion(
115
- this[Query.Data],
116
- create,
117
- QueryData.UnionOperation.UnionAll
118
- )
119
- );
120
- }
121
104
  [Expr.ToExpr]() {
122
105
  return new Expr(new ExprData.Query(this[Query.Data]));
123
106
  }
@@ -1,5 +1,12 @@
1
1
  import { Query, QueryData } from '../Query';
2
+ import { VirtualTable } from '../VirtualTable';
2
3
  import { SelectMultiple } from './Select';
4
+ export declare class RecursiveUnion<Row> {
5
+ initialSelect: QueryData.Select;
6
+ constructor(initialSelect: QueryData.Select);
7
+ union(create: () => SelectMultiple<Row> | Union<Row>): VirtualTable.Of<Row>;
8
+ unionAll(create: () => SelectMultiple<Row> | Union<Row>): VirtualTable.Of<Row>;
9
+ }
3
10
  export declare class Union<Row> extends Query<Array<Row>> {
4
11
  [Query.Data]: QueryData.Union | QueryData.Select;
5
12
  constructor(query: QueryData.Union | QueryData.Select);
@@ -1,5 +1,75 @@
1
1
  // src/define/query/Union.ts
2
+ import { randomAlias } from "../../util/Alias.js";
3
+ import { Expr, ExprData, ExprType } from "../Expr.js";
2
4
  import { Query, QueryData } from "../Query.js";
5
+ import { Target, TargetType } from "../Target.js";
6
+ import { createVirtualTable } from "../VirtualTable.js";
7
+ import { SelectMultiple } from "./Select.js";
8
+ var { keys, create, fromEntries } = Object;
9
+ function columnsOf(expr) {
10
+ switch (expr.type) {
11
+ case ExprType.Record:
12
+ return keys(expr.fields);
13
+ case ExprType.Row:
14
+ switch (expr.target.type) {
15
+ case TargetType.Table:
16
+ return keys(expr.target.table.columns);
17
+ default:
18
+ throw new Error("Could not retrieve CTE columns");
19
+ }
20
+ default:
21
+ throw new Error("Could not retrieve CTE columns");
22
+ }
23
+ }
24
+ function makeRecursiveUnion(initial, createUnion, operator) {
25
+ const name = randomAlias();
26
+ const cols = columnsOf(initial.selection);
27
+ const union = new QueryData.Union({
28
+ a: initial,
29
+ operator,
30
+ b: () => createUnion()[Query.Data]
31
+ });
32
+ const target = new Target.CTE(name, union);
33
+ const row = new ExprData.Row(target);
34
+ const selection = new ExprData.Record(
35
+ fromEntries(cols.map((col) => [col, new ExprData.Field(row, col)]))
36
+ );
37
+ const select = (conditions) => {
38
+ const where = Expr.and(...conditions)[Expr.Data];
39
+ return new SelectMultiple(
40
+ new QueryData.Select({
41
+ selection,
42
+ from: target,
43
+ where
44
+ })
45
+ );
46
+ };
47
+ const cte = createVirtualTable({
48
+ name,
49
+ target,
50
+ select
51
+ });
52
+ return cte;
53
+ }
54
+ var RecursiveUnion = class {
55
+ constructor(initialSelect) {
56
+ this.initialSelect = initialSelect;
57
+ }
58
+ union(create2) {
59
+ return makeRecursiveUnion(
60
+ this.initialSelect,
61
+ create2,
62
+ QueryData.UnionOperation.Union
63
+ );
64
+ }
65
+ unionAll(create2) {
66
+ return makeRecursiveUnion(
67
+ this.initialSelect,
68
+ create2,
69
+ QueryData.UnionOperation.UnionAll
70
+ );
71
+ }
72
+ };
3
73
  var Union = class extends Query {
4
74
  constructor(query) {
5
75
  super(query);
@@ -42,5 +112,6 @@ var Union = class extends Query {
42
112
  }
43
113
  };
44
114
  export {
115
+ RecursiveUnion,
45
116
  Union
46
117
  };
@@ -23,6 +23,7 @@ export interface FormatContext {
23
23
  formatAsIn?: boolean;
24
24
  topLevel?: boolean;
25
25
  selectAsColumns?: boolean;
26
+ formattingCte?: string;
26
27
  }
27
28
  type FormatSubject = (stmt: Statement, mkSubject: () => void) => void;
28
29
  export interface CompileOptions extends Partial<FormatContext>, StatementOptions {
@@ -45,6 +46,7 @@ export declare abstract class Formatter implements Sanitizer {
45
46
  formatAsIn?: boolean | undefined;
46
47
  topLevel?: boolean | undefined;
47
48
  selectAsColumns?: boolean | undefined;
49
+ formattingCte?: string | undefined;
48
50
  skipNewlines?: boolean | undefined;
49
51
  };
50
52
  format(ctx: FormatContext, query: QueryData): Statement;
@@ -62,7 +64,7 @@ export declare abstract class Formatter implements Sanitizer {
62
64
  formatBatch(ctx: FormatContext, { queries }: QueryData.Batch): Statement;
63
65
  formatRaw(ctx: FormatContext, { strings, params }: QueryData.Raw): Statement;
64
66
  formatColumn(ctx: FormatContext, column: ColumnData): Statement;
65
- formatContraintReference(ctx: FormatContext, reference: ExprData): Statement;
67
+ formatConstraintReference(ctx: FormatContext, reference: ExprData): Statement;
66
68
  formatType(ctx: FormatContext, type: ColumnType): Statement;
67
69
  formatInsertRow(ctx: FormatContext, columns: Record<string, ColumnData>, row: Record<string, any>): Statement;
68
70
  formatColumnValue(ctx: FormatContext, column: ColumnData, columnValue: any): Statement;
@@ -89,12 +89,19 @@ var Formatter = class {
89
89
  const { stmt } = ctx;
90
90
  switch (query.from?.type) {
91
91
  case TargetType.CTE:
92
- stmt.add("WITH RECURSIVE").addIdentifier(query.from.name).add("AS").space().openParenthesis();
93
- this.formatUnion(
94
- { ...ctx, topLevel: false, selectAsColumns: true },
95
- query.from.union
96
- );
97
- stmt.closeParenthesis().space();
92
+ if (ctx.formattingCte !== query.from.name) {
93
+ stmt.add("WITH RECURSIVE").addIdentifier(query.from.name).add("AS").space().openParenthesis();
94
+ this.formatUnion(
95
+ {
96
+ ...ctx,
97
+ topLevel: false,
98
+ selectAsColumns: true,
99
+ formattingCte: query.from.name
100
+ },
101
+ query.from.union
102
+ );
103
+ stmt.closeParenthesis().space();
104
+ }
98
105
  default:
99
106
  stmt.raw("SELECT").space();
100
107
  this.formatSelection(
@@ -118,7 +125,7 @@ var Formatter = class {
118
125
  const { stmt } = ctx;
119
126
  this.format(ctx, a);
120
127
  stmt.add(unions[operator]).space();
121
- this.format(ctx, b);
128
+ this.format(ctx, typeof b === "function" ? b() : b);
122
129
  return stmt;
123
130
  }
124
131
  formatInsert(ctx, query) {
@@ -306,10 +313,10 @@ var Formatter = class {
306
313
  }
307
314
  }
308
315
  if (column.references)
309
- this.formatContraintReference(ctx, column.references());
316
+ this.formatConstraintReference(ctx, column.references());
310
317
  return stmt;
311
318
  }
312
- formatContraintReference(ctx, reference) {
319
+ formatConstraintReference(ctx, reference) {
313
320
  const { stmt } = ctx;
314
321
  if (reference.type !== ExprType.Field || reference.expr.type !== ExprType.Row)
315
322
  throw new Error("not supported");
@@ -602,6 +609,8 @@ var Formatter = class {
602
609
  switch (from.type) {
603
610
  case ExprType.Row:
604
611
  switch (from.target.type) {
612
+ case TargetType.CTE:
613
+ return stmt.identifier(from.target.name).raw(".").identifier(field);
605
614
  case TargetType.Table:
606
615
  const column = from.target.table.columns[field];
607
616
  const asBoolean = column?.type === ColumnType.Boolean && ctx.formatAsJson;
@@ -685,6 +694,16 @@ var Formatter = class {
685
694
  throw new Error(`Cannot select empty target`);
686
695
  if (ctx.tableAsExpr)
687
696
  return stmt.identifier(table.alias || table.name);
697
+ if (ctx.selectAsColumns) {
698
+ const inner = { ...ctx, selectAsColumns: false };
699
+ for (const [key, column] of stmt.separate(
700
+ Object.entries(table.columns)
701
+ )) {
702
+ this.formatFieldOf(inner, expr, column.name);
703
+ stmt.add("AS").addIdentifier(key);
704
+ }
705
+ return stmt;
706
+ }
688
707
  stmt.identifier("json_object");
689
708
  for (const [key, column] of stmt.call(Object.entries(table.columns))) {
690
709
  this.formatString(ctx, key).raw(", ");
@@ -0,0 +1 @@
1
+ export declare function randomAlias(): string;
@@ -0,0 +1,7 @@
1
+ // src/util/Alias.ts
2
+ function randomAlias() {
3
+ return `__${Math.random().toString(36).slice(2, 9)}`;
4
+ }
5
+ export {
6
+ randomAlias
7
+ };
@@ -1,3 +1,11 @@
1
1
  export declare class Callable {
2
2
  constructor(fn: Function);
3
3
  }
4
+ export declare class ClearFunctionProto {
5
+ get name(): unknown;
6
+ get length(): unknown;
7
+ get call(): unknown;
8
+ get apply(): unknown;
9
+ get bind(): unknown;
10
+ get prototype(): unknown;
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rado",
3
- "version": "0.2.25",
3
+ "version": "0.2.26",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,2 +0,0 @@
1
- import { Query, QueryData } from './Query';
2
- export declare function makeRecursiveUnion<T extends Query<any>>(initial: QueryData.Select, createUnion: (target: any) => T, operator: QueryData.UnionOperation): QueryData.Select;
@@ -1,51 +0,0 @@
1
- // src/define/CTE.ts
2
- import { Expr, ExprData, ExprType } from "./Expr.js";
3
- import { Query, QueryData } from "./Query.js";
4
- import { virtualTable } from "./Table.js";
5
- import { Target, TargetType } from "./Target.js";
6
- var { keys, create, fromEntries } = Object;
7
- function columnsOf(expr) {
8
- switch (expr.type) {
9
- case ExprType.Record:
10
- return keys(expr.fields);
11
- case ExprType.Row:
12
- switch (expr.target.type) {
13
- case TargetType.Table:
14
- return keys(expr.target.table.columns);
15
- default:
16
- throw new Error("Could not retrieve CTE columns");
17
- }
18
- default:
19
- throw new Error("Could not retrieve CTE columns");
20
- }
21
- }
22
- function makeRecursiveUnion(initial, createUnion, operator) {
23
- let name;
24
- const alias = new Proxy(create(null), {
25
- get(_, key) {
26
- name = key;
27
- return virtualTable(name);
28
- }
29
- });
30
- const right = createUnion(alias)[Query.Data];
31
- if (!name)
32
- throw new TypeError("No CTE name provided");
33
- const cte = alias[name];
34
- const cols = columnsOf(initial.selection);
35
- const selection = new ExprData.Record(
36
- fromEntries(cols.map((col) => [col, cte[col][Expr.Data]]))
37
- );
38
- const union = new QueryData.Union({
39
- a: initial,
40
- operator,
41
- b: right
42
- });
43
- const from = new Target.CTE(name, union);
44
- return new QueryData.Select({
45
- selection,
46
- from
47
- });
48
- }
49
- export {
50
- makeRecursiveUnion
51
- };