@hypequery/clickhouse 1.3.1-beta.0 → 1.3.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 (82) hide show
  1. package/README.md +18 -1
  2. package/dist/cli/generate-types.js +41 -3
  3. package/dist/core/connection.d.ts.map +1 -1
  4. package/dist/core/connection.js +4 -3
  5. package/dist/core/cross-filter.d.ts +3 -7
  6. package/dist/core/cross-filter.d.ts.map +1 -1
  7. package/dist/core/cross-filter.js +3 -2
  8. package/dist/core/env/auto-client.browser.d.ts +3 -0
  9. package/dist/core/env/auto-client.browser.d.ts.map +1 -0
  10. package/dist/core/env/auto-client.browser.js +3 -0
  11. package/dist/core/env/auto-client.d.ts +9 -0
  12. package/dist/core/env/auto-client.d.ts.map +1 -0
  13. package/dist/core/env/auto-client.js +21 -0
  14. package/dist/core/features/aggregations.d.ts +18 -22
  15. package/dist/core/features/aggregations.d.ts.map +1 -1
  16. package/dist/core/features/aggregations.js +6 -6
  17. package/dist/core/features/analytics.d.ts +15 -19
  18. package/dist/core/features/analytics.d.ts.map +1 -1
  19. package/dist/core/features/analytics.js +2 -2
  20. package/dist/core/features/cross-filtering.d.ts +5 -24
  21. package/dist/core/features/cross-filtering.d.ts.map +1 -1
  22. package/dist/core/features/cross-filtering.js +0 -33
  23. package/dist/core/features/executor.d.ts +5 -9
  24. package/dist/core/features/executor.d.ts.map +1 -1
  25. package/dist/core/features/filtering.d.ts +32 -28
  26. package/dist/core/features/filtering.d.ts.map +1 -1
  27. package/dist/core/features/filtering.js +27 -26
  28. package/dist/core/features/joins.d.ts +7 -10
  29. package/dist/core/features/joins.d.ts.map +1 -1
  30. package/dist/core/features/pagination.d.ts +8 -10
  31. package/dist/core/features/pagination.d.ts.map +1 -1
  32. package/dist/core/features/pagination.js +13 -41
  33. package/dist/core/features/query-modifiers.d.ts +18 -21
  34. package/dist/core/features/query-modifiers.d.ts.map +1 -1
  35. package/dist/core/formatters/sql-formatter.d.ts.map +1 -1
  36. package/dist/core/formatters/sql-formatter.js +6 -0
  37. package/dist/core/join-relationships.d.ts +2 -1
  38. package/dist/core/join-relationships.d.ts.map +1 -1
  39. package/dist/core/query-builder.d.ts +50 -73
  40. package/dist/core/query-builder.d.ts.map +1 -1
  41. package/dist/core/query-builder.js +113 -92
  42. package/dist/core/tests/integration/setup.d.ts +1 -1
  43. package/dist/core/tests/test-utils.d.ts +4 -3
  44. package/dist/core/tests/test-utils.d.ts.map +1 -1
  45. package/dist/core/tests/test-utils.js +18 -8
  46. package/dist/core/types/builder-state.d.ts +25 -0
  47. package/dist/core/types/builder-state.d.ts.map +1 -0
  48. package/dist/core/types/builder-state.js +1 -0
  49. package/dist/core/types/select-types.d.ts +25 -0
  50. package/dist/core/types/select-types.d.ts.map +1 -0
  51. package/dist/core/types/select-types.js +1 -0
  52. package/dist/core/types/type-helpers.d.ts +5 -0
  53. package/dist/core/types/type-helpers.d.ts.map +1 -0
  54. package/dist/core/types/type-helpers.js +1 -0
  55. package/dist/core/utils/predicate-builder.d.ts +29 -0
  56. package/dist/core/utils/predicate-builder.d.ts.map +1 -0
  57. package/dist/core/utils/predicate-builder.js +92 -0
  58. package/dist/core/utils/sql-expressions.d.ts +11 -10
  59. package/dist/core/utils/sql-expressions.d.ts.map +1 -1
  60. package/dist/core/utils/sql-expressions.js +4 -2
  61. package/dist/core/validators/filter-validator.d.ts +2 -1
  62. package/dist/core/validators/filter-validator.d.ts.map +1 -1
  63. package/dist/core/validators/value-validator.d.ts +2 -1
  64. package/dist/core/validators/value-validator.d.ts.map +1 -1
  65. package/dist/index.d.ts +4 -2
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/types/base.d.ts +10 -15
  68. package/dist/types/base.d.ts.map +1 -1
  69. package/dist/types/clickhouse-types.d.ts +2 -2
  70. package/dist/types/clickhouse-types.d.ts.map +1 -1
  71. package/dist/types/filters.d.ts +1 -1
  72. package/dist/types/filters.d.ts.map +1 -1
  73. package/dist/types/index.d.ts +1 -0
  74. package/dist/types/index.d.ts.map +1 -1
  75. package/dist/types/index.js +1 -0
  76. package/dist/types/schema.d.ts +19 -0
  77. package/dist/types/schema.d.ts.map +1 -0
  78. package/dist/types/schema.js +1 -0
  79. package/package.json +7 -3
  80. package/dist/core/tests/integration/test-initializer.d.ts +0 -7
  81. package/dist/core/tests/integration/test-initializer.d.ts.map +0 -1
  82. package/dist/core/tests/integration/test-initializer.js +0 -32
@@ -8,26 +8,23 @@ import { ExecutorFeature } from './features/executor.js';
8
8
  import { QueryModifiersFeature } from './features/query-modifiers.js';
9
9
  import { FilterValidator } from './validators/filter-validator.js';
10
10
  import { PaginationFeature } from './features/pagination.js';
11
+ import { createPredicateBuilder, } from './utils/predicate-builder.js';
11
12
  import { CrossFilteringFeature } from './features/cross-filtering.js';
12
13
  /**
13
14
  * Type guard to check if a config is a client-based configuration.
14
15
  */
15
16
  export function isClientConfig(config) {
16
- return 'client' in config && !('host' in config);
17
+ return 'client' in config && config.client !== undefined;
17
18
  }
18
19
  /**
19
20
  * A type-safe query builder for ClickHouse databases.
20
- * @template Schema - The full database schema
21
- * @template T - The schema type of the current table
22
- * @template HasSelect - Whether a SELECT clause has been applied
23
- * @template Aggregations - The type of any aggregation functions applied
21
+ * The builder carries a single state object that encodes scope, output, and schema metadata.
24
22
  */
25
23
  export class QueryBuilder {
26
24
  static relationships;
27
25
  config = {};
28
26
  tableName;
29
- schema;
30
- originalSchema;
27
+ state;
31
28
  formatter = new SQLFormatter();
32
29
  aggregations;
33
30
  joins;
@@ -37,10 +34,9 @@ export class QueryBuilder {
37
34
  modifiers;
38
35
  pagination;
39
36
  crossFiltering;
40
- constructor(tableName, schema, originalSchema) {
37
+ constructor(tableName, state) {
41
38
  this.tableName = tableName;
42
- this.schema = schema;
43
- this.originalSchema = originalSchema;
39
+ this.state = state;
44
40
  this.aggregations = new AggregationFeature(this);
45
41
  this.joins = new JoinFeature(this);
46
42
  this.filtering = new FilteringFeature(this);
@@ -50,28 +46,18 @@ export class QueryBuilder {
50
46
  this.pagination = new PaginationFeature(this);
51
47
  this.crossFiltering = new CrossFilteringFeature(this);
52
48
  }
49
+ fork(state, config) {
50
+ const builder = new QueryBuilder(this.tableName, state);
51
+ builder.config = { ...config };
52
+ return builder;
53
+ }
53
54
  debug() {
54
55
  console.log('Current Type:', {
55
- schema: this.schema,
56
- originalSchema: this.originalSchema,
56
+ state: this.state,
57
57
  config: this.config
58
58
  });
59
59
  return this;
60
60
  }
61
- clone() {
62
- const newBuilder = new QueryBuilder(this.tableName, this.schema, this.originalSchema);
63
- newBuilder.config = { ...this.config };
64
- // Initialize features with the new builder
65
- newBuilder.aggregations = new AggregationFeature(newBuilder);
66
- newBuilder.joins = new JoinFeature(newBuilder);
67
- newBuilder.filtering = new FilteringFeature(newBuilder);
68
- newBuilder.analytics = new AnalyticsFeature(newBuilder);
69
- newBuilder.executor = new ExecutorFeature(newBuilder);
70
- newBuilder.modifiers = new QueryModifiersFeature(newBuilder);
71
- newBuilder.pagination = new PaginationFeature(newBuilder);
72
- newBuilder.crossFiltering = new CrossFilteringFeature(newBuilder);
73
- return newBuilder;
74
- }
75
61
  // --- Analytics Helper: Add a CTE.
76
62
  withCTE(alias, subquery) {
77
63
  this.config = this.analytics.addCTE(alias, subquery);
@@ -90,7 +76,7 @@ export class QueryBuilder {
90
76
  * @returns The current QueryBuilder instance.
91
77
  */
92
78
  groupByTimeInterval(column, interval, method = 'toStartOfInterval') {
93
- this.config = this.analytics.addTimeInterval(column, interval, method);
79
+ this.config = this.analytics.addTimeInterval(String(column), interval, method);
94
80
  return this;
95
81
  }
96
82
  // --- Analytics Helper: Add a raw SQL fragment.
@@ -116,23 +102,34 @@ export class QueryBuilder {
116
102
  this.config = this.crossFiltering.applyCrossFilters(crossFilter);
117
103
  return this;
118
104
  }
119
- // Implementation
120
- select(columns) {
121
- // Create a new builder with the appropriate type parameters
122
- const newBuilder = new QueryBuilder(this.tableName, {
123
- name: this.schema.name,
124
- columns: this.schema.columns
125
- }, this.originalSchema);
126
- // Handle both string and array cases
127
- const processedColumns = typeof columns === 'string'
128
- ? [columns]
129
- : columns.map((col) => {
130
- if (typeof col === 'object' && col !== null && '__type' in col) {
131
- return col.toSql();
132
- }
133
- return String(col);
134
- });
135
- newBuilder.config = {
105
+ select(columnsOrAsterisk) {
106
+ if (columnsOrAsterisk === '*') {
107
+ const nextState = {
108
+ ...this.state,
109
+ output: {}
110
+ };
111
+ const nextConfig = {
112
+ ...this.config,
113
+ select: ['*'],
114
+ orderBy: this.config.orderBy?.map(({ column, direction }) => ({
115
+ column: String(column),
116
+ direction
117
+ }))
118
+ };
119
+ return this.fork(nextState, nextConfig);
120
+ }
121
+ const columns = columnsOrAsterisk;
122
+ const processedColumns = columns.map(col => {
123
+ if (typeof col === 'object' && col !== null && '__type' in col) {
124
+ return col.toSql();
125
+ }
126
+ return String(col);
127
+ });
128
+ const nextState = {
129
+ ...this.state,
130
+ output: {}
131
+ };
132
+ const nextConfig = {
136
133
  ...this.config,
137
134
  select: processedColumns,
138
135
  orderBy: this.config.orderBy?.map(({ column, direction }) => ({
@@ -140,32 +137,35 @@ export class QueryBuilder {
140
137
  direction
141
138
  }))
142
139
  };
143
- return newBuilder;
140
+ return this.fork(nextState, nextConfig);
141
+ }
142
+ selectConst(...columns) {
143
+ return this.select(columns);
144
144
  }
145
145
  sum(column, alias) {
146
- const newBuilder = this.clone();
147
- newBuilder.config = this.aggregations.sum(column, alias);
148
- return newBuilder;
146
+ return this.applyAggregation(column, alias, 'sum', (col, finalAlias) => this.aggregations.sum(col, finalAlias));
149
147
  }
150
148
  count(column, alias) {
151
- const newBuilder = this.clone();
152
- newBuilder.config = this.aggregations.count(column, alias);
153
- return newBuilder;
149
+ return this.applyAggregation(column, alias, 'count', (col, finalAlias) => this.aggregations.count(col, finalAlias));
154
150
  }
155
151
  avg(column, alias) {
156
- const newBuilder = this.clone();
157
- newBuilder.config = this.aggregations.avg(column, alias);
158
- return newBuilder;
152
+ return this.applyAggregation(column, alias, 'avg', (col, finalAlias) => this.aggregations.avg(col, finalAlias));
159
153
  }
160
154
  min(column, alias) {
161
- const newBuilder = this.clone();
162
- newBuilder.config = this.aggregations.min(column, alias);
163
- return newBuilder;
155
+ return this.applyAggregation(column, alias, 'min', (col, finalAlias) => this.aggregations.min(col, finalAlias));
164
156
  }
165
157
  max(column, alias) {
166
- const newBuilder = this.clone();
167
- newBuilder.config = this.aggregations.max(column, alias);
168
- return newBuilder;
158
+ return this.applyAggregation(column, alias, 'max', (col, finalAlias) => this.aggregations.max(col, finalAlias));
159
+ }
160
+ applyAggregation(column, alias, suffix, updater) {
161
+ const columnName = String(column);
162
+ const finalAlias = (alias || `${columnName}_${suffix}`);
163
+ const nextState = {
164
+ ...this.state,
165
+ output: {}
166
+ };
167
+ const nextConfig = updater(columnName, finalAlias);
168
+ return this.fork(nextState, nextConfig);
169
169
  }
170
170
  // Make needed properties accessible to features
171
171
  getTableName() {
@@ -223,39 +223,52 @@ export class QueryBuilder {
223
223
  if (advancedInOperators.includes(operator)) {
224
224
  return;
225
225
  }
226
- if (FilterValidator.validateJoinedColumn(String(column)))
226
+ const columnName = String(column);
227
+ if (FilterValidator.validateJoinedColumn(columnName))
227
228
  return;
228
- const columnType = this.schema.columns[column];
229
- FilterValidator.validateFilterCondition({ column: String(column), operator, value }, columnType);
229
+ const baseColumns = this.state.base;
230
+ const columnType = baseColumns[columnName];
231
+ FilterValidator.validateFilterCondition({ column: columnName, operator, value }, columnType);
230
232
  }
231
233
  where(columnOrColumns, operator, value) {
234
+ if (typeof columnOrColumns === 'function') {
235
+ const expression = columnOrColumns(createPredicateBuilder());
236
+ this.config = this.filtering.addExpressionCondition('AND', expression);
237
+ return this;
238
+ }
239
+ if (operator === undefined) {
240
+ throw new Error('Operator is required when specifying a column for where()');
241
+ }
232
242
  // Handle tuple operations
233
243
  if (Array.isArray(columnOrColumns) && (operator === 'inTuple' || operator === 'globalInTuple')) {
234
- // For tuple operations, we need to handle the column array specially
235
244
  const columns = columnOrColumns;
236
245
  this.validateFilterValue(columns, operator, value);
237
- this.config = this.filtering.addCondition('AND', columns, operator, value);
246
+ this.config = this.filtering.addCondition('AND', columns.map(String), operator, value);
238
247
  return this;
239
248
  }
240
- // Handle regular operations
241
249
  const column = columnOrColumns;
242
250
  this.validateFilterValue(column, operator, value);
243
- this.config = this.filtering.addCondition('AND', column, operator, value);
251
+ this.config = this.filtering.addCondition('AND', String(column), operator, value);
244
252
  return this;
245
253
  }
246
254
  orWhere(columnOrColumns, operator, value) {
247
- // Handle tuple operations
255
+ if (typeof columnOrColumns === 'function') {
256
+ const expression = columnOrColumns(createPredicateBuilder());
257
+ this.config = this.filtering.addExpressionCondition('OR', expression);
258
+ return this;
259
+ }
260
+ if (operator === undefined) {
261
+ throw new Error('Operator is required when specifying a column for orWhere()');
262
+ }
248
263
  if (Array.isArray(columnOrColumns) && (operator === 'inTuple' || operator === 'globalInTuple')) {
249
- // For tuple operations, we need to handle the column array specially
250
264
  const columns = columnOrColumns;
251
265
  this.validateFilterValue(columns, operator, value);
252
- this.config = this.filtering.addCondition('OR', columns, operator, value);
266
+ this.config = this.filtering.addCondition('OR', columns.map(String), operator, value);
253
267
  return this;
254
268
  }
255
- // Handle regular operations
256
269
  const column = columnOrColumns;
257
270
  this.validateFilterValue(column, operator, value);
258
- this.config = this.filtering.addCondition('OR', column, operator, value);
271
+ this.config = this.filtering.addCondition('OR', String(column), operator, value);
259
272
  return this;
260
273
  }
261
274
  /**
@@ -302,7 +315,8 @@ export class QueryBuilder {
302
315
  * ```
303
316
  */
304
317
  groupBy(columns) {
305
- this.config = this.modifiers.addGroupBy(columns);
318
+ const normalized = Array.isArray(columns) ? columns.map(String) : String(columns);
319
+ this.config = this.modifiers.addGroupBy(normalized);
306
320
  return this;
307
321
  }
308
322
  limit(count) {
@@ -324,7 +338,7 @@ export class QueryBuilder {
324
338
  * ```
325
339
  */
326
340
  orderBy(column, direction = 'ASC') {
327
- this.config = this.modifiers.addOrderBy(column, direction);
341
+ this.config = this.modifiers.addOrderBy(String(column), direction);
328
342
  return this;
329
343
  }
330
344
  /**
@@ -351,24 +365,24 @@ export class QueryBuilder {
351
365
  return this.where(column, 'between', [min, max]);
352
366
  }
353
367
  innerJoin(table, leftColumn, rightColumn, alias) {
354
- const newBuilder = this.clone();
355
- newBuilder.config = this.joins.addJoin('INNER', table, leftColumn, rightColumn, alias);
356
- return newBuilder;
368
+ return this.applyJoin('INNER', table, leftColumn, rightColumn, alias);
357
369
  }
358
370
  leftJoin(table, leftColumn, rightColumn, alias) {
359
- const newBuilder = this.clone();
360
- newBuilder.config = this.joins.addJoin('LEFT', table, leftColumn, rightColumn, alias);
361
- return newBuilder;
371
+ return this.applyJoin('LEFT', table, leftColumn, rightColumn, alias);
362
372
  }
363
373
  rightJoin(table, leftColumn, rightColumn, alias) {
364
- const newBuilder = this.clone();
365
- newBuilder.config = this.joins.addJoin('RIGHT', table, leftColumn, rightColumn, alias);
366
- return newBuilder;
374
+ return this.applyJoin('RIGHT', table, leftColumn, rightColumn, alias);
367
375
  }
368
376
  fullJoin(table, leftColumn, rightColumn, alias) {
369
- const newBuilder = this.clone();
370
- newBuilder.config = this.joins.addJoin('FULL', table, leftColumn, rightColumn, alias);
371
- return newBuilder;
377
+ return this.applyJoin('FULL', table, leftColumn, rightColumn, alias);
378
+ }
379
+ applyJoin(type, table, leftColumn, rightColumn, alias) {
380
+ const nextState = {
381
+ ...this.state,
382
+ aliases: alias ? { ...this.state.aliases, [alias]: table } : this.state.aliases
383
+ };
384
+ const nextConfig = this.joins.addJoin(type, table, String(leftColumn), rightColumn, alias);
385
+ return this.fork(nextState, nextConfig);
372
386
  }
373
387
  // Make config accessible to features
374
388
  getConfig() {
@@ -412,7 +426,8 @@ export class QueryBuilder {
412
426
  const type = options?.type || joinPath.type || 'INNER';
413
427
  const alias = options?.alias || joinPath.alias;
414
428
  const table = String(joinPath.to);
415
- this.config = this.joins.addJoin(type, table, joinPath.leftColumn, `${table}.${joinPath.rightColumn}`, alias);
429
+ const rightColumn = `${table}.${joinPath.rightColumn}`;
430
+ this.config = this.joins.addJoin(type, table, joinPath.leftColumn, rightColumn, alias);
416
431
  });
417
432
  }
418
433
  else {
@@ -420,7 +435,8 @@ export class QueryBuilder {
420
435
  const type = options?.type || path.type || 'INNER';
421
436
  const alias = options?.alias || path.alias;
422
437
  const table = String(path.to);
423
- this.config = this.joins.addJoin(type, table, path.leftColumn, `${table}.${path.rightColumn}`, alias);
438
+ const rightColumn = `${table}.${path.rightColumn}`;
439
+ this.config = this.joins.addJoin(type, table, path.leftColumn, rightColumn, alias);
424
440
  }
425
441
  return this;
426
442
  }
@@ -429,10 +445,15 @@ export function createQueryBuilder(config) {
429
445
  ClickHouseConnection.initialize(config);
430
446
  return {
431
447
  table(tableName) {
432
- return new QueryBuilder(tableName, {
433
- name: tableName,
434
- columns: {}
435
- }, {});
448
+ const state = {
449
+ schema: {},
450
+ tables: tableName,
451
+ output: {},
452
+ baseTable: tableName,
453
+ base: {},
454
+ aliases: {}
455
+ };
456
+ return new QueryBuilder(tableName, state);
436
457
  }
437
458
  };
438
459
  }
@@ -1,5 +1,5 @@
1
1
  export declare const initializeTestConnection: () => Promise<{
2
- table<TableName extends never>(tableName: TableName): import("../../query-builder.js").QueryBuilder<{}, {}[TableName], false, {}, {}[TableName]>;
2
+ table<TableName extends never>(tableName: TableName): import("../../query-builder.js").SelectQB<import("../../types/builder-state.js").SchemaDefinition<unknown>, TableName, import("../../../index.js").TableRecord<import("../../types/builder-state.js").SchemaDefinition<unknown>[TableName]>, TableName>;
3
3
  }>;
4
4
  export declare const ensureConnectionInitialized: () => import("@clickhouse/client").ClickHouseClient | import("@clickhouse/client-web").ClickHouseClient;
5
5
  export declare const isDockerAvailable: () => Promise<boolean>;
@@ -1,4 +1,5 @@
1
- import { QueryBuilder } from '../query-builder.js';
1
+ import { SelectQB } from '../query-builder.js';
2
+ import type { TableRecord } from '../../types/schema.js';
2
3
  export type TestTableSchema = {
3
4
  id: 'Int32';
4
5
  name: 'String';
@@ -38,6 +39,6 @@ export interface TestSchema {
38
39
  users: UsersSchema;
39
40
  }
40
41
  export declare const TEST_SCHEMAS: TestSchema;
41
- export declare function setupUsersBuilder(): QueryBuilder<TestSchema, TestSchema['users'], false, {}, TestSchema['users']>;
42
- export declare function setupTestBuilder(): QueryBuilder<TestSchema, TestSchema['test_table'], false, {}, TestSchema['test_table']>;
42
+ export declare function setupUsersBuilder(): SelectQB<TestSchema, 'users', TableRecord<TestSchema['users']>, 'users'>;
43
+ export declare function setupTestBuilder(): SelectQB<TestSchema, 'test_table', TableRecord<TestSchema['test_table']>, 'test_table'>;
43
44
  //# sourceMappingURL=test-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tests/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IAEnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,qCAAqC,CAAC;IAChD,aAAa,EAAE,kBAAkB,CAAC;IAClC,UAAU,EAAE,+BAA+B,CAAC;IAC5C,aAAa,EAAE,4CAA4C,CAAC;IAC5D,aAAa,EAAE,yBAAyB,CAAC;IACzC,WAAW,EAAE,4BAA4B,CAAC;IAC1C,iBAAiB,EAAE,eAAe,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,QAAQ,CAAC;IACpB,KAAK,EAAE,QAAQ,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,EAAE,qBAAqB,CAAC;IAC/B,WAAW,EAAE,+CAA+C,CAAC;IAC7D,KAAK,EAAE,+BAA+B,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,eAAe,CAAC;IAC5B,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,eAAO,MAAM,YAAY,EAAE,UAmC1B,CAAC;AAGF,wBAAgB,iBAAiB,IAAI,YAAY,CAAC,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CASjH;AAED,wBAAgB,gBAAgB,IAAI,YAAY,CAAC,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,CAS1H"}
1
+ {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tests/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IAEnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,qCAAqC,CAAC;IAChD,aAAa,EAAE,kBAAkB,CAAC;IAClC,UAAU,EAAE,+BAA+B,CAAC;IAC5C,aAAa,EAAE,4CAA4C,CAAC;IAC5D,aAAa,EAAE,yBAAyB,CAAC;IACzC,WAAW,EAAE,4BAA4B,CAAC;IAC1C,iBAAiB,EAAE,eAAe,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,QAAQ,CAAC;IACpB,KAAK,EAAE,QAAQ,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,EAAE,qBAAqB,CAAC;IAC/B,WAAW,EAAE,+CAA+C,CAAC;IAC7D,KAAK,EAAE,+BAA+B,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,eAAe,CAAC;IAC5B,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,eAAO,MAAM,YAAY,EAAE,UAmC1B,CAAC;AAgBF,wBAAgB,iBAAiB,IAAI,QAAQ,CAAC,UAAU,EAAE,OAAO,EAAE,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAU5G;AAED,wBAAgB,gBAAgB,IAAI,QAAQ,CAAC,UAAU,EAAE,YAAY,EAAE,WAAW,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,YAAY,CAAC,CAU1H"}
@@ -36,14 +36,24 @@ export const TEST_SCHEMAS = {
36
36
  }
37
37
  };
38
38
  export function setupUsersBuilder() {
39
- return new QueryBuilder('users', {
40
- name: 'users',
41
- columns: TEST_SCHEMAS.users
42
- }, TEST_SCHEMAS);
39
+ const state = {
40
+ schema: TEST_SCHEMAS,
41
+ tables: 'users',
42
+ output: {},
43
+ baseTable: 'users',
44
+ base: TEST_SCHEMAS.users,
45
+ aliases: {}
46
+ };
47
+ return new QueryBuilder('users', state);
43
48
  }
44
49
  export function setupTestBuilder() {
45
- return new QueryBuilder('test_table', {
46
- name: 'test_table',
47
- columns: TEST_SCHEMAS.test_table
48
- }, TEST_SCHEMAS);
50
+ const state = {
51
+ schema: TEST_SCHEMAS,
52
+ tables: 'test_table',
53
+ output: {},
54
+ baseTable: 'test_table',
55
+ base: TEST_SCHEMAS.test_table,
56
+ aliases: {}
57
+ };
58
+ return new QueryBuilder('test_table', state);
49
59
  }
@@ -0,0 +1,25 @@
1
+ import type { ColumnType, InferColumnType, TableRecord } from '../../types/schema.js';
2
+ import type { Simplify } from './type-helpers.js';
3
+ export type SchemaDefinition<Schema extends Record<string, any> = Record<string, any>> = {
4
+ [K in keyof Schema]: Record<string, ColumnType>;
5
+ };
6
+ export type BuilderState<Schema extends SchemaDefinition<Schema>, VisibleTables extends string, OutputRow, BaseTable extends keyof Schema, Aliases extends Partial<Record<string, keyof Schema>> = {}> = {
7
+ schema: Schema;
8
+ tables: VisibleTables;
9
+ output: OutputRow;
10
+ baseTable: BaseTable;
11
+ base: Schema[BaseTable];
12
+ aliases: Aliases;
13
+ };
14
+ export type AnyBuilderState = BuilderState<any, any, any, any, any>;
15
+ export type BaseRow<State extends AnyBuilderState> = Simplify<{
16
+ [K in keyof State['base']]: State['base'][K] extends ColumnType ? InferColumnType<State['base'][K]> : never;
17
+ }>;
18
+ export type WidenTables<State extends AnyBuilderState, Table extends keyof State['schema']> = BuilderState<State['schema'], State['tables'] | (Table & string), State['output'], State['baseTable'], State['aliases']>;
19
+ export type UpdateOutput<State extends AnyBuilderState, Output> = BuilderState<State['schema'], State['tables'], Output, State['baseTable'], State['aliases']>;
20
+ export type InitialState<Schema extends SchemaDefinition<Schema>, Table extends keyof Schema> = BuilderState<Schema, Table & string, TableRecord<Schema[Table]>, Table, {}>;
21
+ export type ExplicitSelectionState<State extends AnyBuilderState> = BaseRow<State> extends State['output'] ? State['output'] extends BaseRow<State> ? false : true : true;
22
+ export type AppendToOutput<State extends AnyBuilderState, Added> = UpdateOutput<State, ExplicitSelectionState<State> extends true ? Simplify<State['output'] & Added> : Simplify<Added>>;
23
+ export type AddAlias<State extends AnyBuilderState, Alias extends string, Table extends keyof State['schema']> = BuilderState<State['schema'], State['tables'] | Alias, State['output'], State['baseTable'], State['aliases'] & Record<Alias, Table>>;
24
+ export type ResolveTableSchema<State extends AnyBuilderState, Table extends string> = Table extends keyof State['schema'] ? State['schema'][Table] : Table extends keyof State['aliases'] ? State['schema'][State['aliases'][Table]] : never;
25
+ //# sourceMappingURL=builder-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder-state.d.ts","sourceRoot":"","sources":["../../../src/core/types/builder-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,MAAM,gBAAgB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;KACtF,CAAC,IAAI,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,YAAY,CACtB,MAAM,SAAS,gBAAgB,CAAC,MAAM,CAAC,EACvC,aAAa,SAAS,MAAM,EAC5B,SAAS,EACT,SAAS,SAAS,MAAM,MAAM,EAC9B,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,MAAM,CAAC,CAAC,GAAG,EAAE,IACxD;IACF,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAEpE,MAAM,MAAM,OAAO,CAAC,KAAK,SAAS,eAAe,IAAI,QAAQ,CAAC;KAC3D,CAAC,IAAI,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,GAC3D,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GACjC,KAAK;CACV,CAAC,CAAC;AAEH,MAAM,MAAM,WAAW,CACrB,KAAK,SAAS,eAAe,EAC7B,KAAK,SAAS,MAAM,KAAK,CAAC,QAAQ,CAAC,IACjC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;AAE7H,MAAM,MAAM,YAAY,CACtB,KAAK,SAAS,eAAe,EAC7B,MAAM,IACJ,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;AAEjG,MAAM,MAAM,YAAY,CACtB,MAAM,SAAS,gBAAgB,CAAC,MAAM,CAAC,EACvC,KAAK,SAAS,MAAM,MAAM,IACxB,YAAY,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;AAEhF,MAAM,MAAM,sBAAsB,CAAC,KAAK,SAAS,eAAe,IAC9D,OAAO,CAAC,KAAK,CAAC,SAAS,KAAK,CAAC,QAAQ,CAAC,GAClC,KAAK,CAAC,QAAQ,CAAC,SAAS,OAAO,CAAC,KAAK,CAAC,GACpC,KAAK,GACL,IAAI,GACN,IAAI,CAAC;AAEX,MAAM,MAAM,cAAc,CACxB,KAAK,SAAS,eAAe,EAC7B,KAAK,IACH,YAAY,CACd,KAAK,EACL,sBAAsB,CAAC,KAAK,CAAC,SAAS,IAAI,GACtC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,GACjC,QAAQ,CAAC,KAAK,CAAC,CACpB,CAAC;AAEF,MAAM,MAAM,QAAQ,CAClB,KAAK,SAAS,eAAe,EAC7B,KAAK,SAAS,MAAM,EACpB,KAAK,SAAS,MAAM,KAAK,CAAC,QAAQ,CAAC,IACjC,YAAY,CACd,KAAK,CAAC,QAAQ,CAAC,EACf,KAAK,CAAC,QAAQ,CAAC,GAAG,KAAK,EACvB,KAAK,CAAC,QAAQ,CAAC,EACf,KAAK,CAAC,WAAW,CAAC,EAClB,KAAK,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CACxC,CAAC;AAEF,MAAM,MAAM,kBAAkB,CAC5B,KAAK,SAAS,eAAe,EAC7B,KAAK,SAAS,MAAM,IAClB,KAAK,SAAS,MAAM,KAAK,CAAC,QAAQ,CAAC,GACnC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GACtB,KAAK,SAAS,MAAM,KAAK,CAAC,SAAS,CAAC,GAClC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,GACxC,KAAK,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import type { SqlExpression, AliasedExpression } from '../utils/sql-expressions.js';
2
+ import type { ColumnType, InferColumnType } from '../../types/schema.js';
3
+ import type { AnyBuilderState, BaseRow, ResolveTableSchema } from './builder-state.js';
4
+ import { Simplify, UnionToIntersection } from './type-helpers.js';
5
+ type TableIdentifiers<State extends AnyBuilderState> = State['tables'] & string;
6
+ type QualifiedColumnsFor<State extends AnyBuilderState, Table extends string> = ResolveTableSchema<State, Table> extends Record<string, ColumnType> ? `${Table}.${Extract<keyof ResolveTableSchema<State, Table>, string>}` : never;
7
+ export type QualifiedColumnKeys<State extends AnyBuilderState> = {
8
+ [Table in TableIdentifiers<State>]: QualifiedColumnsFor<State, Table>;
9
+ }[TableIdentifiers<State>];
10
+ export type BaseColumnKeys<State extends AnyBuilderState> = keyof BaseRow<State>;
11
+ export type OutputColumnKeys<State extends AnyBuilderState> = keyof State['output'];
12
+ export type SelectableColumn<State extends AnyBuilderState> = OutputColumnKeys<State> | BaseColumnKeys<State> | QualifiedColumnKeys<State>;
13
+ export type SelectableItem<State extends AnyBuilderState> = SelectableColumn<State> | SqlExpression;
14
+ export type ColumnSelectionKey<P> = P extends `${string}.${infer C}` ? C : P;
15
+ type QualifiedColumnValue<State extends AnyBuilderState, P> = P extends `${infer Table}.${infer Column}` ? ResolveTableSchema<State, Table> extends Record<string, ColumnType> ? Column extends keyof ResolveTableSchema<State, Table> ? ResolveTableSchema<State, Table>[Column] extends ColumnType ? InferColumnType<ResolveTableSchema<State, Table>[Column]> : never : never : never : never;
16
+ export type ColumnSelectionValue<State extends AnyBuilderState, P> = P extends OutputColumnKeys<State> ? State['output'][P] : P extends BaseColumnKeys<State> ? BaseRow<State>[P] : QualifiedColumnValue<State, P>;
17
+ export type ColumnSelectionRecord<State extends AnyBuilderState, K> = {
18
+ [P in Extract<K, SelectableColumn<State>> as ColumnSelectionKey<P>]: ColumnSelectionValue<State, P>;
19
+ };
20
+ export type ExpressionSelectionRecord<K> = UnionToIntersection<K extends AliasedExpression<infer R, infer A> ? {
21
+ [P in A]: R;
22
+ } : {}>;
23
+ export type SelectionResult<State extends AnyBuilderState, K> = Simplify<ColumnSelectionRecord<State, K> & ExpressionSelectionRecord<K>>;
24
+ export {};
25
+ //# sourceMappingURL=select-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-types.d.ts","sourceRoot":"","sources":["../../../src/core/types/select-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
2
+ export type Simplify<T> = {
3
+ [K in keyof T]: T[K];
4
+ } & {};
5
+ //# sourceMappingURL=type-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-helpers.d.ts","sourceRoot":"","sources":["../../../src/core/types/type-helpers.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAC/B,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC;AAEpF,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
1
+ import type { AnyBuilderState, BaseRow } from '../types/builder-state.js';
2
+ import type { SelectableColumn } from '../types/select-types.js';
3
+ export type PredicatePrimitive = string | number | boolean | Date | null;
4
+ type PredicateValue = Exclude<PredicatePrimitive, string>;
5
+ export interface PredicateExpression<T = unknown> {
6
+ __type: 'predicate_expression';
7
+ sql: string;
8
+ parameters: any[];
9
+ readonly expressionType?: T | undefined;
10
+ }
11
+ export interface PredicateLiteral<T = PredicatePrimitive> {
12
+ __type: 'predicate_literal';
13
+ value: T;
14
+ }
15
+ export type ColumnReference<State extends AnyBuilderState> = keyof BaseRow<State> | keyof State['output'] | Extract<SelectableColumn<State>, string>;
16
+ export type PredicateArg<State extends AnyBuilderState> = ColumnReference<State> | PredicateExpression | PredicateLiteral | PredicateValue | PredicatePrimitive[];
17
+ export interface PredicateBuilder<State extends AnyBuilderState> {
18
+ fn<T = unknown>(name: string, ...args: Array<PredicateArg<State>>): PredicateExpression<T>;
19
+ col(column: ColumnReference<State>): PredicateExpression;
20
+ value<T extends PredicatePrimitive>(value: T): PredicateLiteral<T>;
21
+ literal<T extends PredicatePrimitive>(value: T): PredicateLiteral<T>;
22
+ array(values: Array<PredicatePrimitive | PredicateLiteral>): PredicateExpression;
23
+ raw(sql: string): PredicateExpression;
24
+ and(expressions: PredicateExpression[]): PredicateExpression<boolean>;
25
+ or(expressions: PredicateExpression[]): PredicateExpression<boolean>;
26
+ }
27
+ export declare function createPredicateBuilder<State extends AnyBuilderState>(): PredicateBuilder<State>;
28
+ export {};
29
+ //# sourceMappingURL=predicate-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predicate-builder.d.ts","sourceRoot":"","sources":["../../../src/core/utils/predicate-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;AACzE,KAAK,cAAc,GAAG,OAAO,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;AAE1D,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,OAAO;IAC9C,MAAM,EAAE,sBAAsB,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,GAAG,EAAE,CAAC;IAClB,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,kBAAkB;IACtD,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC;CACV;AAED,MAAM,MAAM,eAAe,CAAC,KAAK,SAAS,eAAe,IACrD,MAAM,OAAO,CAAC,KAAK,CAAC,GACpB,MAAM,KAAK,CAAC,QAAQ,CAAC,GACrB,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;AAE7C,MAAM,MAAM,YAAY,CAAC,KAAK,SAAS,eAAe,IAClD,eAAe,CAAC,KAAK,CAAC,GACtB,mBAAmB,GACnB,gBAAgB,GAChB,cAAc,GACd,kBAAkB,EAAE,CAAC;AAEzB,MAAM,WAAW,gBAAgB,CAAC,KAAK,SAAS,eAAe;IAC7D,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;IAC3F,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,mBAAmB,CAAC;IACzD,KAAK,CAAC,CAAC,SAAS,kBAAkB,EAAE,KAAK,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,CAAC,CAAC,SAAS,kBAAkB,EAAE,KAAK,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;IACrE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,kBAAkB,GAAG,gBAAgB,CAAC,GAAG,mBAAmB,CAAC;IACjF,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,CAAC;IACtC,GAAG,CAAC,WAAW,EAAE,mBAAmB,EAAE,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACtE,EAAE,CAAC,WAAW,EAAE,mBAAmB,EAAE,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;CACtE;AA4GD,wBAAgB,sBAAsB,CAAC,KAAK,SAAS,eAAe,KAAK,gBAAgB,CAAC,KAAK,CAAC,CAY/F"}
@@ -0,0 +1,92 @@
1
+ function createExpression(sql, parameters = []) {
2
+ return {
3
+ __type: 'predicate_expression',
4
+ sql,
5
+ parameters,
6
+ expressionType: undefined
7
+ };
8
+ }
9
+ function literal(value) {
10
+ return {
11
+ __type: 'predicate_literal',
12
+ value
13
+ };
14
+ }
15
+ function isPredicateExpression(value) {
16
+ return value?.__type === 'predicate_expression';
17
+ }
18
+ function isPredicateLiteral(value) {
19
+ return value?.__type === 'predicate_literal';
20
+ }
21
+ function buildArrayLiteral(values) {
22
+ const parts = [];
23
+ const parameters = [];
24
+ values.forEach(value => {
25
+ const normalized = normalizeLiteralValue(value);
26
+ parts.push(normalized.sql);
27
+ parameters.push(...normalized.parameters);
28
+ });
29
+ return createExpression(`[${parts.join(', ')}]`, parameters);
30
+ }
31
+ function normalizeLiteralValue(value) {
32
+ if (isPredicateLiteral(value)) {
33
+ return createExpression('?', [value.value]);
34
+ }
35
+ if (value === null) {
36
+ return createExpression('NULL');
37
+ }
38
+ if (value instanceof Date || typeof value === 'number' || typeof value === 'boolean' || typeof value === 'string') {
39
+ return createExpression('?', [value]);
40
+ }
41
+ throw new Error('Unsupported literal value in predicate array');
42
+ }
43
+ function normalizeArgument(arg) {
44
+ if (isPredicateExpression(arg)) {
45
+ return arg;
46
+ }
47
+ if (isPredicateLiteral(arg)) {
48
+ return createExpression('?', [arg.value]);
49
+ }
50
+ if (Array.isArray(arg)) {
51
+ return buildArrayLiteral(arg);
52
+ }
53
+ if (arg === null) {
54
+ return createExpression('NULL');
55
+ }
56
+ if (arg instanceof Date || typeof arg === 'number' || typeof arg === 'boolean') {
57
+ return createExpression('?', [arg]);
58
+ }
59
+ if (typeof arg === 'string') {
60
+ return createExpression(arg);
61
+ }
62
+ throw new Error('Unsupported predicate argument type');
63
+ }
64
+ function buildFunctionExpression(name, args) {
65
+ const builtArgs = args.map(arg => normalizeArgument(arg));
66
+ const sql = `${name}(${builtArgs.map(arg => arg.sql).join(', ')})`;
67
+ const parameters = builtArgs.flatMap(arg => arg.parameters);
68
+ return createExpression(sql, parameters);
69
+ }
70
+ function buildLogical(operator, expressions) {
71
+ if (!expressions.length) {
72
+ throw new Error(`${operator} requires at least one expression`);
73
+ }
74
+ if (expressions.length === 1) {
75
+ return expressions[0];
76
+ }
77
+ const sql = expressions.map(expr => `(${expr.sql})`).join(` ${operator} `);
78
+ const parameters = expressions.flatMap(expr => expr.parameters);
79
+ return createExpression(sql, parameters);
80
+ }
81
+ export function createPredicateBuilder() {
82
+ return {
83
+ fn: (name, ...args) => buildFunctionExpression(name, args),
84
+ col: column => createExpression(String(column)),
85
+ value: value => literal(value),
86
+ literal: value => literal(value),
87
+ array: values => buildArrayLiteral(values),
88
+ raw: sql => createExpression(sql),
89
+ and: expressions => buildLogical('AND', expressions),
90
+ or: expressions => buildLogical('OR', expressions)
91
+ };
92
+ }