kysely 0.12.1 → 0.12.2

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 (49) hide show
  1. package/dist/cjs/index.d.ts +1 -0
  2. package/dist/cjs/index.js +1 -0
  3. package/dist/cjs/kysely.d.ts +151 -0
  4. package/dist/cjs/kysely.js +37 -0
  5. package/dist/cjs/operation-node/common-table-expression-name-node.d.ts +15 -0
  6. package/dist/cjs/operation-node/common-table-expression-name-node.js +23 -0
  7. package/dist/cjs/operation-node/common-table-expression-node.d.ts +3 -3
  8. package/dist/cjs/operation-node/operation-node-transformer.d.ts +2 -0
  9. package/dist/cjs/operation-node/operation-node-transformer.js +9 -0
  10. package/dist/cjs/operation-node/operation-node-visitor.d.ts +2 -0
  11. package/dist/cjs/operation-node/operation-node-visitor.js +1 -0
  12. package/dist/cjs/operation-node/operation-node.d.ts +1 -1
  13. package/dist/cjs/operation-node/with-node.d.ts +3 -1
  14. package/dist/cjs/operation-node/with-node.js +2 -1
  15. package/dist/cjs/parser/with-parser.d.ts +32 -5
  16. package/dist/cjs/parser/with-parser.js +13 -2
  17. package/dist/cjs/plugin/with-schema/with-schema-transformer.js +8 -0
  18. package/dist/cjs/query-compiler/default-query-compiler.d.ts +2 -0
  19. package/dist/cjs/query-compiler/default-query-compiler.js +11 -0
  20. package/dist/cjs/query-creator.d.ts +27 -3
  21. package/dist/cjs/query-creator.js +33 -1
  22. package/dist/cjs/query-executor/default-query-executor.d.ts +19 -0
  23. package/dist/cjs/query-executor/noop-query-executor.d.ts +19 -0
  24. package/dist/cjs/raw-builder/raw-builder.js +1 -1
  25. package/dist/esm/index.d.ts +1 -0
  26. package/dist/esm/index.js +1 -0
  27. package/dist/esm/kysely.d.ts +151 -0
  28. package/dist/esm/kysely.js +37 -0
  29. package/dist/esm/operation-node/common-table-expression-name-node.d.ts +15 -0
  30. package/dist/esm/operation-node/common-table-expression-name-node.js +20 -0
  31. package/dist/esm/operation-node/common-table-expression-node.d.ts +3 -3
  32. package/dist/esm/operation-node/operation-node-transformer.d.ts +2 -0
  33. package/dist/esm/operation-node/operation-node-transformer.js +9 -0
  34. package/dist/esm/operation-node/operation-node-visitor.d.ts +2 -0
  35. package/dist/esm/operation-node/operation-node-visitor.js +1 -0
  36. package/dist/esm/operation-node/operation-node.d.ts +1 -1
  37. package/dist/esm/operation-node/with-node.d.ts +3 -1
  38. package/dist/esm/operation-node/with-node.js +2 -1
  39. package/dist/esm/parser/with-parser.d.ts +32 -5
  40. package/dist/esm/parser/with-parser.js +13 -2
  41. package/dist/esm/plugin/with-schema/with-schema-transformer.js +8 -0
  42. package/dist/esm/query-compiler/default-query-compiler.d.ts +2 -0
  43. package/dist/esm/query-compiler/default-query-compiler.js +11 -0
  44. package/dist/esm/query-creator.d.ts +27 -3
  45. package/dist/esm/query-creator.js +33 -1
  46. package/dist/esm/query-executor/default-query-executor.d.ts +19 -0
  47. package/dist/esm/query-executor/noop-query-executor.d.ts +19 -0
  48. package/dist/esm/raw-builder/raw-builder.js +1 -1
  49. package/package.json +2 -2
@@ -136,7 +136,7 @@ class QueryCreator {
136
136
  });
137
137
  }
138
138
  /**
139
- * Creates a `with` query (common table expressions).
139
+ * Creates a `with` query (Common Table Expression).
140
140
  *
141
141
  * ### Examples
142
142
  *
@@ -157,6 +157,24 @@ class QueryCreator {
157
157
  * .selectAll()
158
158
  * .execute()
159
159
  * ```
160
+ *
161
+ * The CTE name can optionally specify column names in addition to
162
+ * a name. In that case Kysely requires the expression to retun
163
+ * rows with the same columns.
164
+ *
165
+ * ```ts
166
+ * await db
167
+ * .with('jennifers(id, age)', (db) => db
168
+ * .selectFrom('person')
169
+ * .where('first_name', '=', 'Jennifer')
170
+ * // This is ok since we return columns with the same
171
+ * // names as specified by `jennifers(id, age)`.
172
+ * .select(['id', 'age'])
173
+ * )
174
+ * .selectFrom('jennifers')
175
+ * .selectAll()
176
+ * .execute()
177
+ * ```
160
178
  */
161
179
  with(name, expression) {
162
180
  const cte = (0, with_parser_js_1.parseCommonTableExpression)(this.#props.parseContext, name, expression);
@@ -167,6 +185,20 @@ class QueryCreator {
167
185
  : with_node_js_1.WithNode.create(cte),
168
186
  });
169
187
  }
188
+ /**
189
+ * Creates a recursive `with` query (Common Table Expression).
190
+ *
191
+ * See the {@link with} method for examples and more documentation.
192
+ */
193
+ withRecursive(name, expression) {
194
+ const cte = (0, with_parser_js_1.parseCommonTableExpression)(this.#props.parseContext, name, expression);
195
+ return new QueryCreator({
196
+ ...this.#props,
197
+ withNode: this.#props.withNode
198
+ ? with_node_js_1.WithNode.cloneWithExpression(this.#props.withNode, cte)
199
+ : with_node_js_1.WithNode.create(cte, { recursive: true }),
200
+ });
201
+ }
170
202
  /**
171
203
  * Sets the schema to be used for all table references that don't explicitly
172
204
  * specify a schema.
@@ -7,10 +7,29 @@ import { QueryExecutor } from './query-executor.js';
7
7
  export declare class DefaultQueryExecutor extends QueryExecutor {
8
8
  #private;
9
9
  constructor(compiler: QueryCompiler, connectionProvider: ConnectionProvider, plugins?: KyselyPlugin[]);
10
+ /**
11
+ * Compiles the transformed query into SQL. You usually want to pass
12
+ * the output of {@link transformQuery} into this method but you can
13
+ * compile any query using this method.
14
+ */
10
15
  compileQuery(node: RootOperationNode): CompiledQuery;
11
16
  protected executeQueryImpl<R>(compiledQuery: CompiledQuery): Promise<QueryResult<R>>;
17
+ /**
18
+ * Returns a copy of this executor with a plugin added as the
19
+ * last plugin.
20
+ */
12
21
  withPlugin(plugin: KyselyPlugin): DefaultQueryExecutor;
22
+ /**
23
+ * Returns a copy of this executor with a plugin added as the
24
+ * first plugin.
25
+ */
13
26
  withPluginAtFront(plugin: KyselyPlugin): DefaultQueryExecutor;
27
+ /**
28
+ * Returns a copy of this executor with a new connection provider.
29
+ */
14
30
  withConnectionProvider(connectionProvider: ConnectionProvider): QueryExecutor;
31
+ /**
32
+ * Returns a copy of this executor without any plugins.
33
+ */
15
34
  withoutPlugins(): QueryExecutor;
16
35
  }
@@ -8,10 +8,29 @@ import { KyselyPlugin } from '../plugin/kysely-plugin.js';
8
8
  * other needed things to actually execute queries.
9
9
  */
10
10
  export declare class NoopQueryExecutor extends QueryExecutor {
11
+ /**
12
+ * Compiles the transformed query into SQL. You usually want to pass
13
+ * the output of {@link transformQuery} into this method but you can
14
+ * compile any query using this method.
15
+ */
11
16
  compileQuery(): CompiledQuery;
12
17
  protected executeQueryImpl<R>(): Promise<QueryResult<R>>;
18
+ /**
19
+ * Returns a copy of this executor with a new connection provider.
20
+ */
13
21
  withConnectionProvider(): QueryExecutor;
22
+ /**
23
+ * Returns a copy of this executor with a plugin added as the
24
+ * last plugin.
25
+ */
14
26
  withPlugin(plugin: KyselyPlugin): NoopQueryExecutor;
27
+ /**
28
+ * Returns a copy of this executor with a plugin added as the
29
+ * first plugin.
30
+ */
15
31
  withPluginAtFront(plugin: KyselyPlugin): NoopQueryExecutor;
32
+ /**
33
+ * Returns a copy of this executor without any plugins.
34
+ */
16
35
  withoutPlugins(): QueryExecutor;
17
36
  }
@@ -50,7 +50,7 @@ class RawBuilder {
50
50
  if (match.index > 0 && sql[match.index - 1] === '\\') {
51
51
  continue;
52
52
  }
53
- sqlFragments.push(sql.slice(sqlIdx, match.index).replaceAll('\\?', '?'));
53
+ sqlFragments.push(sql.slice(sqlIdx, match.index).replace(/\\\?/g, '?'));
54
54
  argNodes.push(parseRawArg(str, parameters[paramIdx]));
55
55
  sqlIdx = match.index + str.length;
56
56
  ++paramIdx;
@@ -73,6 +73,7 @@ export * from './operation-node/column-definition-node.js';
73
73
  export * from './operation-node/column-node.js';
74
74
  export * from './operation-node/column-update-node.js';
75
75
  export * from './operation-node/common-table-expression-node.js';
76
+ export * from './operation-node/common-table-expression-name-node.js';
76
77
  export * from './operation-node/constraint-node.js';
77
78
  export * from './operation-node/create-index-node.js';
78
79
  export * from './operation-node/create-schema-node.js';
package/dist/esm/index.js CHANGED
@@ -73,6 +73,7 @@ export * from './operation-node/column-definition-node.js';
73
73
  export * from './operation-node/column-node.js';
74
74
  export * from './operation-node/column-update-node.js';
75
75
  export * from './operation-node/common-table-expression-node.js';
76
+ export * from './operation-node/common-table-expression-name-node.js';
76
77
  export * from './operation-node/constraint-node.js';
77
78
  export * from './operation-node/create-index-node.js';
78
79
  export * from './operation-node/create-schema-node.js';
@@ -207,6 +207,38 @@ export declare class Kysely<DB> extends QueryCreator<DB> {
207
207
  * Returns a copy of this Kysely instance without any plugins.
208
208
  */
209
209
  withoutPlugins(): Kysely<DB>;
210
+ /**
211
+ * Returns a copy of this Kysely instance with tables added to its
212
+ * database type.
213
+ *
214
+ * This method only modifies the types and doesn't affect any of the
215
+ * executed queries in any way.
216
+ *
217
+ * ### Examples
218
+ *
219
+ * The following example adds and uses a temporary table:
220
+ *
221
+ * @example
222
+ * ```ts
223
+ * await db.schema
224
+ * .createTable('temp_table')
225
+ * .temporary()
226
+ * .addColumn('some_column', 'integer')
227
+ * .execute()
228
+ *
229
+ * const tempDb = db.withTables<{
230
+ * temp_table: {
231
+ * some_column: number
232
+ * }
233
+ * }>()
234
+ *
235
+ * await tempDb
236
+ * .insertInto('temp_table')
237
+ * .values({ some_column: 100 })
238
+ * .execute()
239
+ * ```
240
+ */
241
+ withTables<T extends Record<string, Record<string, any>>>(): Kysely<DB & T>;
210
242
  /**
211
243
  * Releases all resources and disconnects from the database.
212
244
  *
@@ -223,13 +255,132 @@ export declare class Kysely<DB> extends QueryCreator<DB> {
223
255
  export declare class Transaction<DB> extends Kysely<DB> {
224
256
  #private;
225
257
  constructor(props: KyselyProps);
258
+ /**
259
+ * Returns true if this `Kysely` instance is a transaction.
260
+ *
261
+ * You can also use `db instanceof Transaction`.
262
+ */
226
263
  get isTransaction(): true;
264
+ /**
265
+ * Returns the {@link MigrationModule} module for managing and running migrations.
266
+ */
227
267
  get migration(): MigrationModule;
268
+ /**
269
+ * Creates a {@link TransactionBuilder} that can be used to run queries inside a transaction.
270
+ *
271
+ * The returned {@link TransactionBuilder} can be used to configure the transaction. The
272
+ * {@link TransactionBuilder.execute} method can then be called to run the transaction.
273
+ * {@link TransactionBuilder.execute} takes a function that is run inside the
274
+ * transaction. If the function throws, the transaction is rolled back. Otherwise
275
+ * the transaction is committed.
276
+ *
277
+ * The callback function passed to the {@link TransactionBuilder.execute | execute}
278
+ * method gets the transaction object as its only argument. The transaction is
279
+ * of type {@link Transaction} which inherits {@link Kysely}. Any query
280
+ * started through the transaction object is executed inside the transaction.
281
+ *
282
+ * ### Examples
283
+ *
284
+ * ```ts
285
+ * const catto = await db.transaction().execute(async (trx) => {
286
+ * const jennifer = await trx.insertInto('person')
287
+ * .values({
288
+ * id: db.generated,
289
+ * first_name: 'Jennifer',
290
+ * last_name: 'Aniston',
291
+ * })
292
+ * .returning('id')
293
+ * .executeTakeFirstOrThrow()
294
+ *
295
+ * await someFunction(trx, jennifer)
296
+ *
297
+ * return await trx.insertInto('pet')
298
+ * .values({
299
+ * id: db.generated,
300
+ * user_id: jennifer.id,
301
+ * name: 'Catto',
302
+ * species: 'cat'
303
+ * })
304
+ * .returning('*')
305
+ * .executeTakeFirst()
306
+ * })
307
+ * ```
308
+ *
309
+ * Setting the isolation level:
310
+ *
311
+ * ```ts
312
+ * await db
313
+ * .transaction()
314
+ * .setIsolationLevel('serializable')
315
+ * .execute(async (trx) => {
316
+ * await doStuff(trx)
317
+ * })
318
+ * ```
319
+ */
228
320
  transaction(): TransactionBuilder<DB>;
321
+ /**
322
+ * Provides a kysely instance bound to a single database connection.
323
+ *
324
+ * ### Examples
325
+ *
326
+ * ```ts
327
+ * await db
328
+ * .connection()
329
+ * .execute(async (db) => {
330
+ * // `db` is an instance of `Kysely` that's bound to a single
331
+ * // database connection. All queries executed through `db` use
332
+ * // the same connection.
333
+ * await doStuff(db)
334
+ * })
335
+ * ```
336
+ */
229
337
  connection(): ConnectionBuilder<DB>;
338
+ /**
339
+ * Releases all resources and disconnects from the database.
340
+ *
341
+ * You need to call this when you are done using the `Kysely` instance.
342
+ */
230
343
  destroy(): Promise<void>;
344
+ /**
345
+ * Returns a copy of this Kysely instance with the given plugin installed.
346
+ */
231
347
  withPlugin(plugin: KyselyPlugin): Transaction<DB>;
348
+ /**
349
+ * Returns a copy of this Kysely instance without any plugins.
350
+ */
232
351
  withoutPlugins(): Transaction<DB>;
352
+ /**
353
+ * Returns a copy of this Kysely instance with tables added to its
354
+ * database type.
355
+ *
356
+ * This method only modifies the types and doesn't affect any of the
357
+ * executed queries in any way.
358
+ *
359
+ * ### Examples
360
+ *
361
+ * The following example adds and uses a temporary table:
362
+ *
363
+ * @example
364
+ * ```ts
365
+ * await db.schema
366
+ * .createTable('temp_table')
367
+ * .temporary()
368
+ * .addColumn('some_column', 'integer')
369
+ * .execute()
370
+ *
371
+ * const tempDb = db.withTables<{
372
+ * temp_table: {
373
+ * some_column: number
374
+ * }
375
+ * }>()
376
+ *
377
+ * await tempDb
378
+ * .insertInto('temp_table')
379
+ * .values({ some_column: 100 })
380
+ * .execute()
381
+ * ```
382
+ */
383
+ withTables<T extends Record<string, Record<string, any>>>(): Transaction<DB & T>;
233
384
  }
234
385
  export interface KyselyProps {
235
386
  readonly config: KyselyConfig;
@@ -258,6 +258,40 @@ export class Kysely extends QueryCreator {
258
258
  executor: this.#props.executor.withoutPlugins(),
259
259
  });
260
260
  }
261
+ /**
262
+ * Returns a copy of this Kysely instance with tables added to its
263
+ * database type.
264
+ *
265
+ * This method only modifies the types and doesn't affect any of the
266
+ * executed queries in any way.
267
+ *
268
+ * ### Examples
269
+ *
270
+ * The following example adds and uses a temporary table:
271
+ *
272
+ * @example
273
+ * ```ts
274
+ * await db.schema
275
+ * .createTable('temp_table')
276
+ * .temporary()
277
+ * .addColumn('some_column', 'integer')
278
+ * .execute()
279
+ *
280
+ * const tempDb = db.withTables<{
281
+ * temp_table: {
282
+ * some_column: number
283
+ * }
284
+ * }>()
285
+ *
286
+ * await tempDb
287
+ * .insertInto('temp_table')
288
+ * .values({ some_column: 100 })
289
+ * .execute()
290
+ * ```
291
+ */
292
+ withTables() {
293
+ return new Kysely({ ...this.#props });
294
+ }
261
295
  /**
262
296
  * Releases all resources and disconnects from the database.
263
297
  *
@@ -311,6 +345,9 @@ export class Transaction extends Kysely {
311
345
  executor: this.#props.executor.withoutPlugins(),
312
346
  });
313
347
  }
348
+ withTables() {
349
+ return new Transaction({ ...this.#props });
350
+ }
314
351
  }
315
352
  export function isKyselyProps(obj) {
316
353
  return (isObject(obj) &&
@@ -0,0 +1,15 @@
1
+ import { ColumnNode } from './column-node.js';
2
+ import { OperationNode } from './operation-node.js';
3
+ import { TableNode } from './table-node.js';
4
+ export interface CommonTableExpressionNameNode extends OperationNode {
5
+ readonly kind: 'CommonTableExpressionNameNode';
6
+ readonly table: TableNode;
7
+ readonly columns?: ReadonlyArray<ColumnNode>;
8
+ }
9
+ /**
10
+ * @internal
11
+ */
12
+ export declare const CommonTableExpressionNameNode: Readonly<{
13
+ is(node: OperationNode): node is CommonTableExpressionNameNode;
14
+ create(tableName: string, columnNames?: readonly string[] | undefined): CommonTableExpressionNameNode;
15
+ }>;
@@ -0,0 +1,20 @@
1
+ import { freeze } from '../util/object-utils.js';
2
+ import { ColumnNode } from './column-node.js';
3
+ import { TableNode } from './table-node.js';
4
+ /**
5
+ * @internal
6
+ */
7
+ export const CommonTableExpressionNameNode = freeze({
8
+ is(node) {
9
+ return node.kind === 'CommonTableExpressionNameNode';
10
+ },
11
+ create(tableName, columnNames) {
12
+ return freeze({
13
+ kind: 'CommonTableExpressionNameNode',
14
+ table: TableNode.create(tableName),
15
+ columns: columnNames
16
+ ? freeze(columnNames.map(ColumnNode.create))
17
+ : undefined,
18
+ });
19
+ },
20
+ });
@@ -1,10 +1,10 @@
1
- import { IdentifierNode } from './identifier-node.js';
1
+ import { CommonTableExpressionNameNode } from './common-table-expression-name-node.js';
2
2
  import { OperationNode } from './operation-node.js';
3
3
  import { QueryNode } from './query-node.js';
4
4
  import { RawNode } from './raw-node.js';
5
5
  export interface CommonTableExpressionNode extends OperationNode {
6
6
  readonly kind: 'CommonTableExpressionNode';
7
- readonly name: IdentifierNode;
7
+ readonly name: CommonTableExpressionNameNode;
8
8
  readonly expression: QueryNode | RawNode;
9
9
  }
10
10
  /**
@@ -12,5 +12,5 @@ export interface CommonTableExpressionNode extends OperationNode {
12
12
  */
13
13
  export declare const CommonTableExpressionNode: Readonly<{
14
14
  is(node: OperationNode): node is CommonTableExpressionNode;
15
- create(name: IdentifierNode, expression: QueryNode | RawNode): CommonTableExpressionNode;
15
+ create(name: CommonTableExpressionNameNode, expression: QueryNode | RawNode): CommonTableExpressionNode;
16
16
  }>;
@@ -44,6 +44,7 @@ import { ReferencesNode } from './references-node.js';
44
44
  import { CheckConstraintNode } from './check-constraint-node.js';
45
45
  import { WithNode } from './with-node.js';
46
46
  import { CommonTableExpressionNode } from './common-table-expression-node.js';
47
+ import { CommonTableExpressionNameNode } from './common-table-expression-name-node.js';
47
48
  import { HavingNode } from './having-node.js';
48
49
  import { CreateSchemaNode } from './create-schema-node.js';
49
50
  import { DropSchemaNode } from './drop-schema-node.js';
@@ -142,6 +143,7 @@ export declare class OperationNodeTransformer {
142
143
  protected transformCheckConstraint(node: CheckConstraintNode): CheckConstraintNode;
143
144
  protected transformWith(node: WithNode): WithNode;
144
145
  protected transformCommonTableExpression(node: CommonTableExpressionNode): CommonTableExpressionNode;
146
+ protected transformCommonTableExpressionName(node: CommonTableExpressionNameNode): CommonTableExpressionNameNode;
145
147
  protected transformHaving(node: HavingNode): HavingNode;
146
148
  protected transformCreateSchema(node: CreateSchemaNode): CreateSchemaNode;
147
149
  protected transformDropSchema(node: DropSchemaNode): DropSchemaNode;
@@ -78,6 +78,7 @@ export class OperationNodeTransformer {
78
78
  CheckConstraintNode: this.transformCheckConstraint.bind(this),
79
79
  WithNode: this.transformWith.bind(this),
80
80
  CommonTableExpressionNode: this.transformCommonTableExpression.bind(this),
81
+ CommonTableExpressionNameNode: this.transformCommonTableExpressionName.bind(this),
81
82
  HavingNode: this.transformHaving.bind(this),
82
83
  CreateSchemaNode: this.transformCreateSchema.bind(this),
83
84
  DropSchemaNode: this.transformDropSchema.bind(this),
@@ -444,6 +445,7 @@ export class OperationNodeTransformer {
444
445
  return {
445
446
  kind: 'WithNode',
446
447
  expressions: this.transformNodeList(node.expressions),
448
+ recursive: node.recursive,
447
449
  };
448
450
  }
449
451
  transformCommonTableExpression(node) {
@@ -453,6 +455,13 @@ export class OperationNodeTransformer {
453
455
  expression: this.transformNode(node.expression),
454
456
  };
455
457
  }
458
+ transformCommonTableExpressionName(node) {
459
+ return {
460
+ kind: 'CommonTableExpressionNameNode',
461
+ table: this.transformNode(node.table),
462
+ columns: this.transformNodeList(node.columns),
463
+ };
464
+ }
456
465
  transformHaving(node) {
457
466
  return {
458
467
  kind: 'HavingNode',
@@ -44,6 +44,7 @@ import { ReferencesNode } from './references-node.js';
44
44
  import { CheckConstraintNode } from './check-constraint-node.js';
45
45
  import { WithNode } from './with-node.js';
46
46
  import { CommonTableExpressionNode } from './common-table-expression-node.js';
47
+ import { CommonTableExpressionNameNode } from './common-table-expression-name-node.js';
47
48
  import { HavingNode } from './having-node.js';
48
49
  import { CreateSchemaNode } from './create-schema-node.js';
49
50
  import { DropSchemaNode } from './drop-schema-node.js';
@@ -110,6 +111,7 @@ export declare abstract class OperationNodeVisitor {
110
111
  protected abstract visitCheckConstraint(node: CheckConstraintNode): void;
111
112
  protected abstract visitWith(node: WithNode): void;
112
113
  protected abstract visitCommonTableExpression(node: CommonTableExpressionNode): void;
114
+ protected abstract visitCommonTableExpressionName(node: CommonTableExpressionNameNode): void;
113
115
  protected abstract visitHaving(node: HavingNode): void;
114
116
  protected abstract visitCreateSchema(node: CreateSchemaNode): void;
115
117
  protected abstract visitDropSchema(node: DropSchemaNode): void;
@@ -52,6 +52,7 @@ export class OperationNodeVisitor {
52
52
  CheckConstraintNode: this.visitCheckConstraint.bind(this),
53
53
  WithNode: this.visitWith.bind(this),
54
54
  CommonTableExpressionNode: this.visitCommonTableExpression.bind(this),
55
+ CommonTableExpressionNameNode: this.visitCommonTableExpressionName.bind(this),
55
56
  HavingNode: this.visitHaving.bind(this),
56
57
  CreateSchemaNode: this.visitCreateSchema.bind(this),
57
58
  DropSchemaNode: this.visitDropSchema.bind(this),
@@ -1,4 +1,4 @@
1
- export declare type OperationNodeKind = 'IdentifierNode' | 'RawNode' | 'SelectQueryNode' | 'SelectionNode' | 'ReferenceNode' | 'ColumnNode' | 'TableNode' | 'AliasNode' | 'FromNode' | 'SelectAllNode' | 'FilterNode' | 'AndNode' | 'OrNode' | 'ParensNode' | 'ValueNode' | 'ValueListNode' | 'PrimitiveValueListNode' | 'JoinNode' | 'OperatorNode' | 'WhereNode' | 'InsertQueryNode' | 'DeleteQueryNode' | 'ReturningNode' | 'CreateTableNode' | 'ColumnDefinitionNode' | 'AddColumnNode' | 'DropTableNode' | 'DataTypeNode' | 'OrderByNode' | 'OrderByItemNode' | 'GroupByNode' | 'GroupByItemNode' | 'UpdateQueryNode' | 'ColumnUpdateNode' | 'LimitNode' | 'OffsetNode' | 'OnConflictNode' | 'OnDuplicateKeyNode' | 'CreateIndexNode' | 'DropIndexNode' | 'ListNode' | 'ReferencesNode' | 'PrimaryKeyConstraintNode' | 'UniqueConstraintNode' | 'CheckConstraintNode' | 'ForeignKeyConstraintNode' | 'WithNode' | 'CommonTableExpressionNode' | 'HavingNode' | 'CreateSchemaNode' | 'DropSchemaNode' | 'AlterTableNode' | 'ModifyColumnNode' | 'DropColumnNode' | 'RenameColumnNode' | 'AlterColumnNode' | 'AddConstraintNode' | 'DropConstraintNode' | 'UnionNode' | 'CreateViewNode' | 'DropViewNode' | 'GeneratedAlwaysAsNode' | 'DefaultValueNode' | 'OnNode' | 'ValuesNode';
1
+ export declare type OperationNodeKind = 'IdentifierNode' | 'RawNode' | 'SelectQueryNode' | 'SelectionNode' | 'ReferenceNode' | 'ColumnNode' | 'TableNode' | 'AliasNode' | 'FromNode' | 'SelectAllNode' | 'FilterNode' | 'AndNode' | 'OrNode' | 'ParensNode' | 'ValueNode' | 'ValueListNode' | 'PrimitiveValueListNode' | 'JoinNode' | 'OperatorNode' | 'WhereNode' | 'InsertQueryNode' | 'DeleteQueryNode' | 'ReturningNode' | 'CreateTableNode' | 'ColumnDefinitionNode' | 'AddColumnNode' | 'DropTableNode' | 'DataTypeNode' | 'OrderByNode' | 'OrderByItemNode' | 'GroupByNode' | 'GroupByItemNode' | 'UpdateQueryNode' | 'ColumnUpdateNode' | 'LimitNode' | 'OffsetNode' | 'OnConflictNode' | 'OnDuplicateKeyNode' | 'CreateIndexNode' | 'DropIndexNode' | 'ListNode' | 'ReferencesNode' | 'PrimaryKeyConstraintNode' | 'UniqueConstraintNode' | 'CheckConstraintNode' | 'ForeignKeyConstraintNode' | 'WithNode' | 'CommonTableExpressionNode' | 'HavingNode' | 'CreateSchemaNode' | 'DropSchemaNode' | 'AlterTableNode' | 'ModifyColumnNode' | 'DropColumnNode' | 'RenameColumnNode' | 'AlterColumnNode' | 'AddConstraintNode' | 'DropConstraintNode' | 'UnionNode' | 'CreateViewNode' | 'DropViewNode' | 'GeneratedAlwaysAsNode' | 'DefaultValueNode' | 'OnNode' | 'ValuesNode' | 'CommonTableExpressionNameNode';
2
2
  export interface OperationNode {
3
3
  readonly kind: OperationNodeKind;
4
4
  }
@@ -1,14 +1,16 @@
1
1
  import { OperationNode } from './operation-node.js';
2
2
  import { CommonTableExpressionNode } from './common-table-expression-node.js';
3
+ export declare type WithNodeParams = Omit<WithNode, 'kind' | 'expressions'>;
3
4
  export interface WithNode extends OperationNode {
4
5
  readonly kind: 'WithNode';
5
6
  readonly expressions: ReadonlyArray<CommonTableExpressionNode>;
7
+ readonly recursive?: boolean;
6
8
  }
7
9
  /**
8
10
  * @internal
9
11
  */
10
12
  export declare const WithNode: Readonly<{
11
13
  is(node: OperationNode): node is WithNode;
12
- create(expression: CommonTableExpressionNode): WithNode;
14
+ create(expression: CommonTableExpressionNode, params?: WithNodeParams | undefined): WithNode;
13
15
  cloneWithExpression(withNode: WithNode, expression: CommonTableExpressionNode): WithNode;
14
16
  }>;
@@ -6,10 +6,11 @@ export const WithNode = freeze({
6
6
  is(node) {
7
7
  return node.kind === 'WithNode';
8
8
  },
9
- create(expression) {
9
+ create(expression, params) {
10
10
  return freeze({
11
11
  kind: 'WithNode',
12
12
  expressions: freeze([expression]),
13
+ ...params,
13
14
  });
14
15
  },
15
16
  cloneWithExpression(withNode, expression) {
@@ -5,10 +5,37 @@ import { InsertQueryBuilder } from '../query-builder/insert-query-builder.js';
5
5
  import { CommonTableExpressionNode } from '../operation-node/common-table-expression-node.js';
6
6
  import { QueryCreator } from '../query-creator.js';
7
7
  import { RawBuilder } from '../raw-builder/raw-builder.js';
8
- import { AnyRawBuilder } from '../util/type-utils.js';
9
8
  import { ParseContext } from './parse-context.js';
10
- export declare type CommonTableExpression<DB> = (creator: QueryCreator<DB>) => SelectQueryBuilder<DB, any, any> | InsertQueryBuilder<DB, any, any> | UpdateQueryBuilder<DB, any, any> | DeleteQueryBuilder<DB, any, any> | AnyRawBuilder;
11
- export declare type QueryCreatorWithCommonTableExpression<DB, N extends string, E extends CommonTableExpression<DB>> = QueryCreator<DB & Record<N, ExtractRowTypeFromCommonTableExpression<E>>>;
12
- declare type ExtractRowTypeFromCommonTableExpression<E> = E extends (creator: QueryCreator<any>) => infer Q ? Q extends SelectQueryBuilder<any, any, infer QO> ? QO : Q extends InsertQueryBuilder<any, any, infer QO> ? QO : Q extends UpdateQueryBuilder<any, any, infer QO> ? QO : Q extends DeleteQueryBuilder<any, any, infer QO> ? QO : Q extends RawBuilder<infer RO> ? RO : never : never;
13
- export declare function parseCommonTableExpression(ctx: ParseContext, name: string, expression: CommonTableExpression<any>): CommonTableExpressionNode;
9
+ export declare type CommonTableExpression<DB, CN extends string> = (creator: QueryCreator<DB>) => CommonTableExpressionOutput<DB, CN>;
10
+ export declare type RecursiveCommonTableExpression<DB, CN extends string> = (creator: QueryCreator<DB & Record<ExtractTableFromCommonTableExpressionName<CN>, ExtractRowFromCommonTableExpressionName<CN>>>) => CommonTableExpressionOutput<DB, CN>;
11
+ export declare type QueryCreatorWithCommonTableExpression<DB, CN extends string, CTE> = QueryCreator<DB & Record<ExtractTableFromCommonTableExpressionName<CN>, ExtractRowFromCommonTableExpression<CTE>>>;
12
+ declare type CommonTableExpressionOutput<DB, CN extends string> = SelectQueryBuilder<DB, any, ExtractRowFromCommonTableExpressionName<CN>> | InsertQueryBuilder<DB, any, ExtractRowFromCommonTableExpressionName<CN>> | UpdateQueryBuilder<DB, any, ExtractRowFromCommonTableExpressionName<CN>> | DeleteQueryBuilder<DB, any, ExtractRowFromCommonTableExpressionName<CN>> | RawBuilder<ExtractRowFromCommonTableExpressionName<CN>>;
13
+ /**
14
+ * Given a common CommonTableExpression CTE extracts the row type from it.
15
+ *
16
+ * For example a CTE `(db) => db.selectFrom('person').select(['id', 'first_name'])`
17
+ * would result in `Pick<Person, 'id' | 'first_name'>`.
18
+ */
19
+ declare type ExtractRowFromCommonTableExpression<CTE> = CTE extends (creator: QueryCreator<any>) => infer Q ? Q extends SelectQueryBuilder<any, any, infer QO> ? QO : Q extends InsertQueryBuilder<any, any, infer QO> ? QO : Q extends UpdateQueryBuilder<any, any, infer QO> ? QO : Q extends DeleteQueryBuilder<any, any, infer QO> ? QO : Q extends RawBuilder<infer RO> ? RO : never : never;
20
+ /**
21
+ * Extracts 'person' from a string like 'person(id, first_name)'.
22
+ */
23
+ declare type ExtractTableFromCommonTableExpressionName<CN extends string> = CN extends `${infer TB}(${string})` ? TB : CN;
24
+ /**
25
+ * Parses a string like 'person(id, first_name)' into a type:
26
+ *
27
+ * {
28
+ * id: any,
29
+ * first_name: any
30
+ * }
31
+ *
32
+ */
33
+ declare type ExtractRowFromCommonTableExpressionName<CN extends string> = CN extends `${string}(${infer CL})` ? {
34
+ [C in ExtractColumnNamesFromColumnList<CL>]: any;
35
+ } : Record<string, any>;
36
+ /**
37
+ * Parses a string like 'id, first_name' into a type 'id' | 'first_name'
38
+ */
39
+ declare type ExtractColumnNamesFromColumnList<R extends string> = R extends `${infer C}, ${infer RS}` ? C | ExtractColumnNamesFromColumnList<RS> : R;
40
+ export declare function parseCommonTableExpression(ctx: ParseContext, name: string, expression: CommonTableExpression<any, any>): CommonTableExpressionNode;
14
41
  export {};
@@ -1,6 +1,17 @@
1
- import { IdentifierNode } from '../operation-node/identifier-node.js';
2
1
  import { CommonTableExpressionNode } from '../operation-node/common-table-expression-node.js';
2
+ import { CommonTableExpressionNameNode } from '../operation-node/common-table-expression-name-node.js';
3
3
  export function parseCommonTableExpression(ctx, name, expression) {
4
4
  const builder = expression(ctx.createQueryCreator());
5
- return CommonTableExpressionNode.create(IdentifierNode.create(name), builder.toOperationNode());
5
+ return CommonTableExpressionNode.create(parseCommonTableExpressionName(name), builder.toOperationNode());
6
+ }
7
+ function parseCommonTableExpressionName(name) {
8
+ if (name.includes('(')) {
9
+ const parts = name.split(/[\(\)]/);
10
+ const table = parts[0];
11
+ const columns = parts[1].split(',').map((it) => it.trim());
12
+ return CommonTableExpressionNameNode.create(table, columns);
13
+ }
14
+ else {
15
+ return CommonTableExpressionNameNode.create(name);
16
+ }
6
17
  }
@@ -79,6 +79,9 @@ export class WithSchemaTransformer extends OperationNodeTransformer {
79
79
  if ('joins' in node && node.joins) {
80
80
  this.#collectTablesFromJoins(node.joins, tables);
81
81
  }
82
+ if ('with' in node && node.with) {
83
+ this.#removeCommonTableExpressionTables(node.with, tables);
84
+ }
82
85
  return tables;
83
86
  }
84
87
  #collectTablesFromTableExpressionNodes(nodes, tables) {
@@ -101,4 +104,9 @@ export class WithSchemaTransformer extends OperationNodeTransformer {
101
104
  tables.add(table.table.identifier);
102
105
  }
103
106
  }
107
+ #removeCommonTableExpressionTables(node, tables) {
108
+ for (const expr of node.expressions) {
109
+ tables.delete(expr.name.table.table.identifier);
110
+ }
111
+ }
104
112
  }
@@ -68,6 +68,7 @@ import { GeneratedAlwaysAsNode } from '../operation-node/generated-always-as-nod
68
68
  import { DefaultValueNode } from '../operation-node/default-value-node.js';
69
69
  import { OnNode } from '../operation-node/on-node.js';
70
70
  import { ValuesNode } from '../operation-node/values-node.js';
71
+ import { CommonTableExpressionNameNode } from '../operation-node/common-table-expression-name-node.js';
71
72
  export declare class DefaultQueryCompiler extends OperationNodeVisitor implements QueryCompiler {
72
73
  #private;
73
74
  protected get numParameters(): number;
@@ -129,6 +130,7 @@ export declare class DefaultQueryCompiler extends OperationNodeVisitor implement
129
130
  protected visitList(node: ListNode): void;
130
131
  protected visitWith(node: WithNode): void;
131
132
  protected visitCommonTableExpression(node: CommonTableExpressionNode): void;
133
+ protected visitCommonTableExpressionName(node: CommonTableExpressionNameNode): void;
132
134
  protected visitAlterTable(node: AlterTableNode): void;
133
135
  protected visitAddColumn(node: AddColumnNode): void;
134
136
  protected visitRenameColumn(node: RenameColumnNode): void;