data-finder-ts 0.1.4 → 0.1.5

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 (58) hide show
  1. package/dist/{chunk-4JVW4TAB.js → chunk-BGEX377Q.js} +58 -8
  2. package/dist/chunk-BGEX377Q.js.map +1 -0
  3. package/dist/chunk-BKPWV3OF.js +962 -0
  4. package/dist/chunk-BKPWV3OF.js.map +1 -0
  5. package/dist/{chunk-PMPLCEWQ.js → chunk-GPHWC533.js} +2 -2
  6. package/dist/{chunk-FJYA2ASS.js → chunk-KAK75RVS.js} +74 -12
  7. package/dist/chunk-KAK75RVS.js.map +1 -0
  8. package/dist/{chunk-4LNZV6EN.js → chunk-MGEL5RWM.js} +206 -78
  9. package/dist/chunk-MGEL5RWM.js.map +1 -0
  10. package/dist/chunk-PF6EJZHB.js +1015 -0
  11. package/dist/chunk-PF6EJZHB.js.map +1 -0
  12. package/dist/datafinder/attribute.cjs +537 -11
  13. package/dist/datafinder/attribute.cjs.map +1 -1
  14. package/dist/datafinder/attribute.d.cts +29 -7
  15. package/dist/datafinder/attribute.d.ts +29 -7
  16. package/dist/datafinder/attribute.js +2 -2
  17. package/dist/datafinder/runner.cjs +1267 -215
  18. package/dist/datafinder/runner.cjs.map +1 -1
  19. package/dist/datafinder/runner.d.cts +28 -5
  20. package/dist/datafinder/runner.d.ts +28 -5
  21. package/dist/datafinder/runner.js +6 -6
  22. package/dist/datafinder/sql-generator.cjs +1203 -206
  23. package/dist/datafinder/sql-generator.cjs.map +1 -1
  24. package/dist/datafinder/sql-generator.d.cts +19 -5
  25. package/dist/datafinder/sql-generator.d.ts +19 -5
  26. package/dist/datafinder/sql-generator.js +9 -5
  27. package/dist/datafinder/typed-attributes.cjs +693 -88
  28. package/dist/datafinder/typed-attributes.cjs.map +1 -1
  29. package/dist/datafinder/typed-attributes.d.cts +3 -242
  30. package/dist/datafinder/typed-attributes.d.ts +3 -242
  31. package/dist/datafinder/typed-attributes.js +3 -3
  32. package/dist/dialect-CogGPm_y.d.cts +38 -0
  33. package/dist/dialect-aaG1bDi5.d.ts +38 -0
  34. package/dist/index.cjs +1677 -408
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +109 -5
  37. package/dist/index.d.ts +109 -5
  38. package/dist/index.js +321 -11
  39. package/dist/index.js.map +1 -1
  40. package/dist/model/milestoning.cjs +529 -0
  41. package/dist/model/milestoning.cjs.map +1 -1
  42. package/dist/model/milestoning.js +2 -2
  43. package/dist/model/relational.cjs +547 -16
  44. package/dist/model/relational.cjs.map +1 -1
  45. package/dist/model/relational.d.cts +421 -57
  46. package/dist/model/relational.d.ts +421 -57
  47. package/dist/model/relational.js +53 -3
  48. package/dist/typed-attributes-CUTf_6Ru.d.ts +328 -0
  49. package/dist/typed-attributes-CdWXq_78.d.cts +328 -0
  50. package/package.json +3 -2
  51. package/dist/chunk-4JVW4TAB.js.map +0 -1
  52. package/dist/chunk-4LNZV6EN.js.map +0 -1
  53. package/dist/chunk-FJYA2ASS.js.map +0 -1
  54. package/dist/chunk-MH4XMYVB.js +0 -696
  55. package/dist/chunk-MH4XMYVB.js.map +0 -1
  56. package/dist/chunk-UYMOE6YU.js +0 -509
  57. package/dist/chunk-UYMOE6YU.js.map +0 -1
  58. /package/dist/{chunk-PMPLCEWQ.js.map → chunk-GPHWC533.js.map} +0 -0
package/dist/index.js CHANGED
@@ -7,15 +7,19 @@ import {
7
7
  convertInputsAndSelectForDateRange,
8
8
  getRunner,
9
9
  registerRunner
10
- } from "./chunk-FJYA2ASS.js";
10
+ } from "./chunk-KAK75RVS.js";
11
11
  import {
12
12
  getRelatedFinderClass,
13
13
  registerRelatedFinderClass
14
14
  } from "./chunk-FLEIUDZZ.js";
15
15
  import {
16
+ DATABRICKS,
17
+ DUCKDB,
18
+ POSTGRES,
19
+ dialectOf,
16
20
  selectSqlToString,
17
21
  toSql
18
- } from "./chunk-MH4XMYVB.js";
22
+ } from "./chunk-BKPWV3OF.js";
19
23
  import {
20
24
  BiTemporalColumns,
21
25
  BusinessDateAndProcessingTemporalColumns,
@@ -23,7 +27,7 @@ import {
23
27
  MilestoningColumns,
24
28
  ProcessingTemporalColumns,
25
29
  SingleBusinessDateColumn
26
- } from "./chunk-PMPLCEWQ.js";
30
+ } from "./chunk-GPHWC533.js";
27
31
  import {
28
32
  BooleanAttribute,
29
33
  DateAttribute,
@@ -33,23 +37,34 @@ import {
33
37
  FloatAttribute,
34
38
  IntegerAttribute,
35
39
  NumericAttribute,
36
- StringAttribute
37
- } from "./chunk-4LNZV6EN.js";
40
+ NumericFunctionOperation,
41
+ StringAttribute,
42
+ StringFunctionOperation
43
+ } from "./chunk-MGEL5RWM.js";
38
44
  import {
39
45
  Attribute
40
- } from "./chunk-4JVW4TAB.js";
46
+ } from "./chunk-BGEX377Q.js";
41
47
  import {
42
48
  AggregateOperation,
43
49
  AggregateOperator,
50
+ Aggregates,
44
51
  Alias,
52
+ Arithmetic,
53
+ ArithmeticOperation,
54
+ ArithmeticOperator,
45
55
  BinaryOperation,
56
+ BooleanAggregates,
46
57
  BooleanConstantOperation,
58
+ CaseOperation,
47
59
  Column,
48
60
  ColumnWithJoin,
61
+ Comparable,
49
62
  ComparisonOperation,
50
63
  ComparisonOperator,
64
+ ConcatOperation,
51
65
  ConstantOperation,
52
66
  CountAllOperation,
67
+ DATE_ONLY_PATTERN,
53
68
  DataCatalog,
54
69
  DataStore,
55
70
  Database,
@@ -57,21 +72,28 @@ import {
57
72
  DateConstantOperation,
58
73
  DateDiffOperation,
59
74
  DateExtractOperation,
75
+ DateOnly,
60
76
  DatePart,
61
77
  DateTimeConstantOperation,
78
+ DateTruncOperation,
62
79
  DecimalConstantOperation,
63
80
  ExistsOperation,
64
81
  FloatConstantOperation,
65
82
  ForeignKey,
83
+ InOperation,
66
84
  IntegerConstantOperation,
67
85
  IsNotNullOperation,
68
86
  IsNullOperation,
69
87
  JoinOperation,
70
88
  JoinTreeNodeOperation,
89
+ LIKE_ESCAPE,
71
90
  LogicalOperation,
72
91
  LogicalOperator,
92
+ NUMERIC_FUNCTIONS,
73
93
  NoOperation,
74
94
  NotExistsOperation,
95
+ NotInOperation,
96
+ NumericConstantOperation,
75
97
  Operation,
76
98
  RelationalOperationElement,
77
99
  ScalarFunction,
@@ -81,16 +103,102 @@ import {
81
103
  SortDirection,
82
104
  SortOperation,
83
105
  StringConstantOperation,
106
+ StringPredicates,
84
107
  Table,
85
108
  UnaryOperation,
86
109
  WindowFunction,
87
110
  WindowFunctionOperation,
88
- WindowSpecification
89
- } from "./chunk-UYMOE6YU.js";
111
+ WindowSpecification,
112
+ applyMixins,
113
+ concat,
114
+ containsAggregate,
115
+ containsAggregateOrWindow,
116
+ escapeLike,
117
+ operandOf,
118
+ sample,
119
+ valueOperand
120
+ } from "./chunk-PF6EJZHB.js";
121
+
122
+ // src/datafinder/expressions.ts
123
+ function constant(value2) {
124
+ if (typeof value2 === "boolean") return new BooleanConstantOperation(value2);
125
+ if (typeof value2 === "number" && Number.isFinite(value2)) {
126
+ return Number.isInteger(value2) ? new IntegerConstantOperation(value2) : new FloatConstantOperation(value2);
127
+ }
128
+ if (typeof value2 === "string") return new StringConstantOperation(value2);
129
+ if (value2 instanceof DateOnly) return new DateConstantOperation(value2);
130
+ if (value2 instanceof Date) return new DateTimeConstantOperation(value2);
131
+ throw new TypeError(`A constant column holds a boolean, a finite number, a string or a date, not ${value2 === null ? "null" : typeof value2}`);
132
+ }
133
+ function countAll() {
134
+ return new CountAllOperation("");
135
+ }
136
+
137
+ // src/datafinder/conditional.ts
138
+ var CONDITIONS = [
139
+ ComparisonOperation,
140
+ LogicalOperation,
141
+ IsNullOperation,
142
+ IsNotNullOperation,
143
+ InOperation,
144
+ NotInOperation,
145
+ ExistsOperation,
146
+ NotExistsOperation
147
+ ];
148
+ function value(branch) {
149
+ if (branch instanceof Attribute) return branch.cwj();
150
+ if (branch instanceof RelationalOperationElement) return branch;
151
+ try {
152
+ return constant(branch);
153
+ } catch {
154
+ throw new TypeError(`A branch is a column, an expression or a value, not ${branch === null ? "null" : typeof branch}`);
155
+ }
156
+ }
157
+ function checked(condition) {
158
+ if (!CONDITIONS.some((c) => condition instanceof c)) {
159
+ throw new TypeError("The condition is a comparison, a null check, a membership test, exists, or and/or of those");
160
+ }
161
+ return condition;
162
+ }
163
+ function chain(cases, fallback) {
164
+ const [[condition, then], ...rest] = cases;
165
+ return new CaseOperation(condition, then, rest.length > 0 ? chain(rest, fallback) : fallback);
166
+ }
167
+ var Then = class extends CaseOperation {
168
+ constructor(cases) {
169
+ const first = chain(cases);
170
+ super(first.condition, first.then, first.fallback);
171
+ this.cases = cases;
172
+ }
173
+ cases;
174
+ /** Another case, tried when the ones before it do not hold. */
175
+ when(condition) {
176
+ return new When(checked(condition), this.cases);
177
+ }
178
+ /** The value when none of the cases hold. */
179
+ otherwise(branch) {
180
+ return chain(this.cases, value(branch));
181
+ }
182
+ };
183
+ var When = class {
184
+ constructor(condition, earlier = []) {
185
+ this.condition = condition;
186
+ this.earlier = earlier;
187
+ }
188
+ condition;
189
+ earlier;
190
+ /** The value where the condition holds. A value is a column, an expression or a plain value. */
191
+ then(branch) {
192
+ return new Then([...this.earlier, [this.condition, value(branch)]]);
193
+ }
194
+ };
195
+ function when(condition) {
196
+ return new When(checked(condition));
197
+ }
90
198
 
91
199
  // src/datafinder/naming.ts
92
- function titleCase(value) {
93
- return value.replace(/[A-Za-z]+/g, (w) => w[0].toUpperCase() + w.slice(1).toLowerCase());
200
+ function titleCase(value2) {
201
+ return value2.replace(/[A-Za-z]+/g, (w) => w[0].toUpperCase() + w.slice(1).toLowerCase());
94
202
  }
95
203
 
96
204
  // src/datafinder/embedded.ts
@@ -116,34 +224,215 @@ var RelatedFinder = class {
116
224
  return new NotExistsOperation(this._node);
117
225
  }
118
226
  };
227
+
228
+ // src/datafinder/databricks-runner.ts
229
+ var DatabricksQueryError = class extends Error {
230
+ constructor(message, code, statementId) {
231
+ super(message);
232
+ this.code = code;
233
+ this.statementId = statementId;
234
+ this.name = "DatabricksQueryError";
235
+ }
236
+ code;
237
+ statementId;
238
+ };
239
+ var API = "/api/2.0/sql/statements";
240
+ var MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
241
+ function convertValue(text, typeName) {
242
+ if (text === null || text === void 0) return null;
243
+ switch ((typeName ?? "").toUpperCase()) {
244
+ case "BYTE":
245
+ case "SHORT":
246
+ case "INT":
247
+ return Number(text);
248
+ case "LONG": {
249
+ const value2 = BigInt(text);
250
+ return value2 >= -MAX_SAFE && value2 <= MAX_SAFE ? Number(value2) : value2;
251
+ }
252
+ case "FLOAT":
253
+ case "DOUBLE":
254
+ case "DECIMAL":
255
+ return Number(text);
256
+ case "BOOLEAN":
257
+ return text.toLowerCase() === "true";
258
+ case "DATE":
259
+ return new DateOnly(text + "T00:00:00Z");
260
+ case "TIMESTAMP":
261
+ case "TIMESTAMP_NTZ": {
262
+ const zoned = /(Z|[+-]\d{2}:?\d{2})$/.test(text);
263
+ return new Date(zoned ? text : text.replace(" ", "T") + "Z");
264
+ }
265
+ default:
266
+ return text;
267
+ }
268
+ }
269
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
270
+ var DatabricksConnect = class {
271
+ constructor(config) {
272
+ this.config = config;
273
+ if (!config.host) throw new Error("DatabricksConnect needs the host of a workspace, or of a server in front of it");
274
+ if (!config.warehouseId) throw new Error("DatabricksConnect needs the id of a SQL warehouse");
275
+ }
276
+ config;
277
+ dialect = "databricks";
278
+ /** Names of the columns of the last query that returned. */
279
+ lastColumns = [];
280
+ async select(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit, timeoutMs = DEFAULT_TIMEOUT_MS, businessDateTo = null, distinct = false, offset, having) {
281
+ const statement = toSql(
282
+ businessDate,
283
+ processingDatetime,
284
+ columns,
285
+ table,
286
+ op,
287
+ orderBy,
288
+ groupBy,
289
+ limit,
290
+ businessDateTo,
291
+ distinct,
292
+ offset,
293
+ having,
294
+ this.dialect
295
+ );
296
+ const deadline = Date.now() + timeoutMs;
297
+ const controller = new AbortController();
298
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
299
+ let statementId;
300
+ try {
301
+ let response = await this.call("POST", `${API}/`, controller.signal, {
302
+ warehouse_id: this.config.warehouseId,
303
+ statement,
304
+ // the API holds the request for up to 50 s and answers at once if the statement is quicker; a shorter
305
+ // wait than 5 s is not allowed except 0, so poll
306
+ wait_timeout: timeoutMs >= 5e3 ? `${Math.min(50, Math.floor(timeoutMs / 1e3))}s` : "0s",
307
+ on_wait_timeout: "CONTINUE",
308
+ disposition: "INLINE",
309
+ format: "JSON_ARRAY",
310
+ ...this.config.catalog ? { catalog: this.config.catalog } : {},
311
+ ...this.config.schema ? { schema: this.config.schema } : {}
312
+ });
313
+ statementId = response.statement_id;
314
+ let delay = this.config.pollIntervalMs ?? 250;
315
+ while (response.status.state === "PENDING" || response.status.state === "RUNNING") {
316
+ if (Date.now() >= deadline) throw new QueryTimeoutError(timeoutMs);
317
+ await sleep(Math.min(delay, Math.max(0, deadline - Date.now())));
318
+ delay = Math.min(delay * 2, 2e3);
319
+ response = await this.call("GET", `${API}/${statementId}`, controller.signal);
320
+ }
321
+ if (response.status.state !== "SUCCEEDED") {
322
+ const error = response.status.error;
323
+ throw new DatabricksQueryError(
324
+ error?.message ?? `The statement ${response.status.state.toLowerCase()}`,
325
+ error?.error_code,
326
+ statementId
327
+ );
328
+ }
329
+ return await this.rows(response, controller.signal);
330
+ } catch (e) {
331
+ const timedOut = controller.signal.aborted || e instanceof QueryTimeoutError;
332
+ if (timedOut && statementId !== void 0) await this.cancel(statementId);
333
+ if (controller.signal.aborted) throw new QueryTimeoutError(timeoutMs);
334
+ throw e;
335
+ } finally {
336
+ clearTimeout(timer);
337
+ }
338
+ }
339
+ /** The rows of a finished statement, following its chunks. */
340
+ async rows(first, signal) {
341
+ const info = first.manifest?.schema?.columns ?? [];
342
+ this.lastColumns = info.map((c) => c.name);
343
+ const rows = [];
344
+ const take = (data) => {
345
+ for (const row of data ?? []) rows.push(row.map((text, i) => convertValue(text, info[i]?.type_name)));
346
+ };
347
+ take(first.result?.data_array);
348
+ let next = first.result?.next_chunk_index;
349
+ while (next !== void 0 && next !== null) {
350
+ const chunk = await this.call("GET", `${API}/${first.statement_id}/result/chunks/${next}`, signal);
351
+ take(chunk.data_array);
352
+ next = chunk.next_chunk_index;
353
+ }
354
+ return rows;
355
+ }
356
+ /** Ask Databricks to stop a statement. Best effort: the query is already given up on. */
357
+ async cancel(statementId) {
358
+ try {
359
+ await this.call("POST", `${API}/${statementId}/cancel`, void 0, {});
360
+ } catch {
361
+ }
362
+ }
363
+ async call(method, path, signal, body) {
364
+ const { host, token, headers, fetch: custom } = this.config;
365
+ const bearer = typeof token === "function" ? await token() : token;
366
+ const response = await (custom ?? fetch)(host.replace(/\/+$/, "") + path, {
367
+ method,
368
+ headers: {
369
+ "Content-Type": "application/json",
370
+ ...bearer ? { Authorization: `Bearer ${bearer}` } : {},
371
+ ...headers
372
+ },
373
+ body: body === void 0 ? void 0 : JSON.stringify(body),
374
+ signal
375
+ });
376
+ const text = await response.text();
377
+ let parsed;
378
+ try {
379
+ parsed = text ? JSON.parse(text) : {};
380
+ } catch {
381
+ parsed = void 0;
382
+ }
383
+ if (!response.ok) {
384
+ const detail = parsed;
385
+ throw new DatabricksQueryError(
386
+ detail?.message ?? `Databricks request failed: ${response.status} ${response.statusText}`,
387
+ detail?.error_code
388
+ );
389
+ }
390
+ return parsed;
391
+ }
392
+ };
119
393
  export {
120
394
  AggregateOperation,
121
395
  AggregateOperator,
396
+ Aggregates,
122
397
  Alias,
398
+ Arithmetic,
399
+ ArithmeticOperation,
400
+ ArithmeticOperator,
123
401
  Attribute,
124
402
  BiTemporalColumns,
125
403
  BinaryOperation,
404
+ BooleanAggregates,
126
405
  BooleanAttribute,
127
406
  BooleanConstantOperation,
128
407
  BusinessDateAndProcessingTemporalColumns,
408
+ CaseOperation,
129
409
  Column,
130
410
  ColumnWithJoin,
411
+ Comparable,
131
412
  ComparisonOperation,
132
413
  ComparisonOperator,
414
+ ConcatOperation,
133
415
  ConstantOperation,
134
416
  CountAllOperation,
417
+ DATABRICKS,
418
+ DATE_ONLY_PATTERN,
135
419
  DEFAULT_TIMEOUT_MS,
420
+ DUCKDB,
136
421
  DataCatalog,
137
422
  DataStore,
138
423
  Database,
424
+ DatabricksConnect,
425
+ DatabricksQueryError,
139
426
  DateArithmeticOperation,
140
427
  DateAttribute,
141
428
  DateConstantOperation,
142
429
  DateDiffOperation,
143
430
  DateExtractOperation,
431
+ DateOnly,
144
432
  DatePart,
145
433
  DateTimeAttribute,
146
434
  DateTimeConstantOperation,
435
+ DateTruncOperation,
147
436
  DecimalAttribute,
148
437
  DecimalConstantOperation,
149
438
  DoubleAttribute,
@@ -152,20 +441,27 @@ export {
152
441
  FloatAttribute,
153
442
  FloatConstantOperation,
154
443
  ForeignKey,
444
+ InOperation,
155
445
  IntegerAttribute,
156
446
  IntegerConstantOperation,
157
447
  IsNotNullOperation,
158
448
  IsNullOperation,
159
449
  JoinOperation,
160
450
  JoinTreeNodeOperation,
451
+ LIKE_ESCAPE,
161
452
  LogicalOperation,
162
453
  LogicalOperator,
163
454
  MilestonedTable,
164
455
  MilestoningColumns,
456
+ NUMERIC_FUNCTIONS,
165
457
  NoOperation,
166
458
  NotExistsOperation,
459
+ NotInOperation,
167
460
  NumericAttribute,
461
+ NumericConstantOperation,
462
+ NumericFunctionOperation,
168
463
  Operation,
464
+ POSTGRES,
169
465
  ProcessingTemporalColumns,
170
466
  QueryTimeoutError,
171
467
  RelatedFinder,
@@ -179,21 +475,35 @@ export {
179
475
  SortOperation,
180
476
  StringAttribute,
181
477
  StringConstantOperation,
478
+ StringFunctionOperation,
479
+ StringPredicates,
182
480
  Table,
183
481
  UnaryOperation,
184
482
  WindowFunction,
185
483
  WindowFunctionOperation,
186
484
  WindowSpecification,
485
+ applyMixins,
187
486
  clearRunner,
487
+ concat,
488
+ constant,
489
+ containsAggregate,
490
+ containsAggregateOrWindow,
188
491
  convertInputsAndSelect,
189
492
  convertInputsAndSelectForDateRange,
493
+ countAll,
494
+ dialectOf,
190
495
  embeddedUnder,
496
+ escapeLike,
191
497
  getRelatedFinderClass,
192
498
  getRunner,
499
+ operandOf,
193
500
  registerRelatedFinderClass,
194
501
  registerRunner,
502
+ sample,
195
503
  selectSqlToString,
196
504
  titleCase,
197
- toSql
505
+ toSql,
506
+ valueOperand,
507
+ when
198
508
  };
199
509
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/datafinder/naming.ts","../src/datafinder/embedded.ts","../src/datafinder/finder.ts"],"sourcesContent":["/** Python's `str.title()`: uppercase the first letter of each alphabetic run and lowercase the rest. */\nexport function titleCase(value: string): string {\n return value.replace(/[A-Za-z]+/g, w => w[0].toUpperCase() + w.slice(1).toLowerCase());\n}\n","import type { Attribute } from './attribute';\n\n/**\n * Join-less alternates for a related class's properties, keyed by dotted property path relative to\n * that class (e.g. `name`, `branch.city`). The attributes point at flat columns on the owning table.\n */\nexport type EmbeddedAttributes = Record<string, Attribute>;\n\n/** The alternates under `prefix` (e.g. `branch.`), re-keyed relative to it; undefined when there are none. */\nexport function embeddedUnder(embedded: EmbeddedAttributes | undefined, prefix: string): EmbeddedAttributes | undefined {\n if (!embedded) return undefined;\n const result: EmbeddedAttributes = {};\n for (const [key, attr] of Object.entries(embedded)) {\n if (key.startsWith(prefix)) result[key.slice(prefix.length)] = attr;\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n","import { ExistsOperation, NotExistsOperation, JoinTreeNodeOperation } from '../model/relational';\nimport { titleCase } from './naming';\n\n/**\n * The display-name prefix for a column reached through a join: the relation names from the root, so\n * `account().branch().city()` is \"Account Branch City\" and not just \"Branch City\".\n */\nexport function displayPrefix(relationName: string, parentJoin?: JoinTreeNodeOperation): string {\n const names = [relationName];\n for (let node = parentJoin; node !== undefined; node = node.parent) names.push(node.join.name);\n return names.reverse().map(titleCase).join(' ');\n}\n\nexport class RelatedFinder {\n constructor(private readonly _node: JoinTreeNodeOperation) {}\n\n exists(): ExistsOperation {\n return new ExistsOperation(this._node);\n }\n\n notExists(): NotExistsOperation {\n return new NotExistsOperation(this._node);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACO,SAAS,UAAU,OAAuB;AAC/C,SAAO,MAAM,QAAQ,cAAc,OAAK,EAAE,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,EAAE,YAAY,CAAC;AACvF;;;ACMO,SAAS,cAAc,UAA0C,QAAgD;AACtH,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,SAA6B,CAAC;AACpC,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,QAAQ,GAAG;AAClD,QAAI,IAAI,WAAW,MAAM,EAAG,QAAO,IAAI,MAAM,OAAO,MAAM,CAAC,IAAI;AAAA,EACjE;AACA,SAAO,OAAO,KAAK,MAAM,EAAE,SAAS,IAAI,SAAS;AACnD;;;ACHO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAA6B,OAA8B;AAA9B;AAAA,EAA+B;AAAA,EAA/B;AAAA,EAE7B,SAA0B;AACxB,WAAO,IAAI,gBAAgB,KAAK,KAAK;AAAA,EACvC;AAAA,EAEA,YAAgC;AAC9B,WAAO,IAAI,mBAAmB,KAAK,KAAK;AAAA,EAC1C;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/datafinder/expressions.ts","../src/datafinder/conditional.ts","../src/datafinder/naming.ts","../src/datafinder/embedded.ts","../src/datafinder/finder.ts","../src/datafinder/databricks-runner.ts"],"sourcesContent":["/** Expressions that are not a column of a finder: values to select next to the columns. */\nimport {\n BooleanConstantOperation,\n CountAllOperation,\n ConstantOperation,\n DateConstantOperation,\n DateOnly,\n DateTimeConstantOperation,\n FloatConstantOperation,\n IntegerConstantOperation,\n NumericConstantOperation,\n StringConstantOperation,\n} from '../model/relational';\n\n/**\n * A fixed value as a column: `f.findAll(null, null, [f.name(), constant('EU').alias('Region')])`.\n * A number is a `NumericConstantOperation`, which takes part in arithmetic: `constant(100).minus(f.price())`.\n * A `DateOnly` is a date and any other `Date` a timestamp. It is named \"Constant\" unless `alias` gives it a name.\n */\nexport function constant(value: number): NumericConstantOperation;\nexport function constant(value: boolean | string | Date): ConstantOperation;\nexport function constant(value: boolean | number | string | Date): ConstantOperation;\nexport function constant(value: boolean | number | string | Date): ConstantOperation {\n if (typeof value === 'boolean') return new BooleanConstantOperation(value);\n if (typeof value === 'number' && Number.isFinite(value)) {\n return Number.isInteger(value) ? new IntegerConstantOperation(value) : new FloatConstantOperation(value);\n }\n if (typeof value === 'string') return new StringConstantOperation(value);\n if (value instanceof DateOnly) return new DateConstantOperation(value); // before Date: DateOnly is a Date\n if (value instanceof Date) return new DateTimeConstantOperation(value);\n throw new TypeError(`A constant column holds a boolean, a finite number, a string or a date, not ${value === null ? 'null' : typeof value}`);\n}\n\n/**\n * The number of rows in the group, `COUNT(*)`: `f.findAll(null, null, [f.category(), countAll()]).groupBy(f.category())`.\n * Unlike `count()` of a column it also counts rows where that column is missing.\n */\nexport function countAll(): CountAllOperation {\n return new CountAllOperation('');\n}\n","/**\n * A value that depends on a condition, written as in polars:\n * `when(f.age().gt(30)).then('senior').otherwise('junior')`.\n */\nimport { Attribute } from './attribute';\nimport { constant } from './expressions';\nimport {\n CaseOperation,\n ComparisonOperation,\n ExistsOperation,\n InOperation,\n IsNotNullOperation,\n IsNullOperation,\n LogicalOperation,\n NotExistsOperation,\n NotInOperation,\n Operation,\n RelationalOperationElement,\n} from '../model/relational';\n\nconst CONDITIONS = [\n ComparisonOperation, LogicalOperation, IsNullOperation, IsNotNullOperation,\n InOperation, NotInOperation, ExistsOperation, NotExistsOperation,\n];\n\n/** What a branch can be: a column or expression as it is, a plain value as a constant. */\nexport type Branch = Attribute | RelationalOperationElement | boolean | number | string | Date;\n\n/**\n * Something that is true or false for a row, which a `when` can test: a comparison, a null check, a membership\n * test, `exists`, or `and` / `or` of those. Checked when `when` is called.\n */\nexport type Condition = Operation | ExistsOperation | NotExistsOperation;\n\ntype Case = [Condition, RelationalOperationElement];\n\nfunction value(branch: Branch): RelationalOperationElement {\n if (branch instanceof Attribute) return branch.cwj();\n if (branch instanceof RelationalOperationElement) return branch;\n try {\n return constant(branch);\n } catch {\n throw new TypeError(`A branch is a column, an expression or a value, not ${branch === null ? 'null' : typeof branch}`);\n }\n}\n\nfunction checked(condition: unknown): Condition {\n if (!CONDITIONS.some(c => condition instanceof c)) {\n throw new TypeError('The condition is a comparison, a null check, a membership test, exists, or and/or of those');\n }\n return condition as Condition;\n}\n\n/** The cases in order as a conditional: each later case is what the one before falls back to. */\nfunction chain(cases: Case[], fallback?: RelationalOperationElement): CaseOperation {\n const [[condition, then], ...rest] = cases;\n return new CaseOperation(condition, then, rest.length > 0 ? chain(rest, fallback) : fallback);\n}\n\n/**\n * `when(condition).then(value)`: a column on its own (missing where the condition does not hold), or continued\n * with another `when` or closed with `otherwise`.\n */\nexport class Then extends CaseOperation {\n constructor(private readonly cases: Case[]) {\n const first = chain(cases);\n super(first.condition, first.then, first.fallback);\n }\n\n /** Another case, tried when the ones before it do not hold. */\n when(condition: Condition): When {\n return new When(checked(condition), this.cases);\n }\n\n /** The value when none of the cases hold. */\n otherwise(branch: Branch): CaseOperation {\n return chain(this.cases, value(branch));\n }\n}\n\nexport class When {\n constructor(private readonly condition: Condition, private readonly earlier: Case[] = []) {}\n\n /** The value where the condition holds. A value is a column, an expression or a plain value. */\n then(branch: Branch): Then {\n return new Then([...this.earlier, [this.condition, value(branch)]]);\n }\n}\n\n/**\n * Start a conditional: `when(f.category().eq('Technology')).then('tech').otherwise('other')`.\n *\n * Further cases follow with `.when(...).then(...)`; with no `otherwise` the value is missing (NULL). A condition\n * that is NULL for a row (a comparison with a missing value) is not true, so that row takes the next case.\n */\nexport function when(condition: Condition): When {\n return new When(checked(condition));\n}\n","/** Python's `str.title()`: uppercase the first letter of each alphabetic run and lowercase the rest. */\nexport function titleCase(value: string): string {\n return value.replace(/[A-Za-z]+/g, w => w[0].toUpperCase() + w.slice(1).toLowerCase());\n}\n","import type { Attribute } from './attribute';\n\n/**\n * Join-less alternates for a related class's properties, keyed by dotted property path relative to\n * that class (e.g. `name`, `branch.city`). The attributes point at flat columns on the owning table.\n */\nexport type EmbeddedAttributes = Record<string, Attribute>;\n\n/** The alternates under `prefix` (e.g. `branch.`), re-keyed relative to it; undefined when there are none. */\nexport function embeddedUnder(embedded: EmbeddedAttributes | undefined, prefix: string): EmbeddedAttributes | undefined {\n if (!embedded) return undefined;\n const result: EmbeddedAttributes = {};\n for (const [key, attr] of Object.entries(embedded)) {\n if (key.startsWith(prefix)) result[key.slice(prefix.length)] = attr;\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n","import { ExistsOperation, NotExistsOperation, JoinTreeNodeOperation } from '../model/relational';\nimport { titleCase } from './naming';\n\n/**\n * The display-name prefix for a column reached through a join: the relation names from the root, so\n * `account().branch().city()` is \"Account Branch City\" and not just \"Branch City\".\n */\nexport function displayPrefix(relationName: string, parentJoin?: JoinTreeNodeOperation): string {\n const names = [relationName];\n for (let node = parentJoin; node !== undefined; node = node.parent) names.push(node.join.name);\n return names.reverse().map(titleCase).join(' ');\n}\n\nexport class RelatedFinder {\n constructor(private readonly _node: JoinTreeNodeOperation) {}\n\n exists(): ExistsOperation {\n return new ExistsOperation(this._node);\n }\n\n notExists(): NotExistsOperation {\n return new NotExistsOperation(this._node);\n }\n}\n","/**\n * Runs a query on a Databricks SQL warehouse through the SQL Statement Execution REST API\n * (`/api/2.0/sql/statements`), which is plain HTTPS and so works from a browser as well as Node.\n *\n * A browser cannot call a Databricks workspace directly, as the workspace does not send CORS headers, so\n * `host` is usually a server of your own that forwards `/api/2.0/sql/…` to the workspace (and may add the\n * credentials, in which case no `token` is needed here).\n */\nimport { Attribute } from './attribute';\nimport { DEFAULT_TIMEOUT_MS, QueryRunner, QueryTarget, QueryTimeoutError, Row } from './runner';\nimport { toSql } from './sql-generator';\nimport {\n DateOnly,\n Operation,\n RelationalOperationElement,\n SortOperation,\n Table,\n} from '../model/relational';\n\nexport interface DatabricksConfig {\n /** The workspace URL, or a server that forwards the Statement Execution API to it. No trailing path. */\n host: string;\n /** The SQL warehouse that runs the statements. */\n warehouseId: string;\n /** Sent as the bearer token. A function is called for every request, so a token can be refreshed. */\n token?: string | (() => string | Promise<string>);\n /** The catalog and schema unqualified table names resolve in. */\n catalog?: string;\n schema?: string;\n /** Extra request headers, for a gateway in front of the workspace. */\n headers?: Record<string, string>;\n /** `fetch`, if not the global one. */\n fetch?: typeof fetch;\n /** How long to wait before first asking again whether a statement has finished (it backs off from there). */\n pollIntervalMs?: number;\n}\n\n/** A statement Databricks ran and failed, or the API refused. */\nexport class DatabricksQueryError extends Error {\n constructor(message: string, readonly code?: string, readonly statementId?: string) {\n super(message);\n this.name = 'DatabricksQueryError';\n }\n}\n\ninterface ColumnInfo { name: string; type_name?: string; type_text?: string }\n\n/** A chunk of rows, as the statement itself carries the first and the chunks endpoint the rest. */\ninterface ResultData { data_array?: (string | null)[][]; next_chunk_index?: number }\n\ninterface StatementResponse {\n statement_id: string;\n status: { state: string; error?: { error_code?: string; message?: string } };\n manifest?: { schema?: { columns?: ColumnInfo[] } };\n result?: ResultData;\n}\n\nconst API = '/api/2.0/sql/statements';\nconst MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);\n\n/** A value as Databricks sends it (text, or null) as the JavaScript value for its column type. */\nexport function convertValue(text: string | null, typeName: string | undefined): unknown {\n if (text === null || text === undefined) return null;\n switch ((typeName ?? '').toUpperCase()) {\n case 'BYTE': case 'SHORT': case 'INT': return Number(text);\n case 'LONG': {\n const value = BigInt(text);\n return value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value; // exact when it cannot be a number\n }\n case 'FLOAT': case 'DOUBLE': case 'DECIMAL': return Number(text);\n case 'BOOLEAN': return text.toLowerCase() === 'true';\n case 'DATE': return new DateOnly(text + 'T00:00:00Z');\n case 'TIMESTAMP': case 'TIMESTAMP_NTZ': {\n const zoned = /(Z|[+-]\\d{2}:?\\d{2})$/.test(text);\n return new Date(zoned ? text : text.replace(' ', 'T') + 'Z');\n }\n default: return text; // STRING, and anything structured (ARRAY, MAP, STRUCT, BINARY, INTERVAL) as the text sent\n }\n}\n\nconst sleep = (ms: number) => new Promise<void>(resolve => setTimeout(resolve, ms));\n\nexport class DatabricksConnect implements QueryRunner {\n readonly dialect = 'databricks' as const;\n\n /** Names of the columns of the last query that returned. */\n lastColumns: string[] = [];\n\n constructor(private readonly config: DatabricksConfig) {\n if (!config.host) throw new Error('DatabricksConnect needs the host of a workspace, or of a server in front of it');\n if (!config.warehouseId) throw new Error('DatabricksConnect needs the id of a SQL warehouse');\n }\n\n async select(\n businessDate: Date | null,\n processingDatetime: Date | null,\n columns: (Attribute | RelationalOperationElement)[],\n table: QueryTarget,\n op: RelationalOperationElement,\n orderBy?: SortOperation[],\n groupBy?: Attribute[],\n limit?: number,\n timeoutMs: number = DEFAULT_TIMEOUT_MS,\n businessDateTo: Date | null = null,\n distinct: boolean = false,\n offset?: number,\n having?: Operation,\n ): Promise<Row[]> {\n const statement = toSql(\n businessDate, processingDatetime, columns, table as Table, op, orderBy, groupBy, limit,\n businessDateTo, distinct, offset, having, this.dialect,\n );\n const deadline = Date.now() + timeoutMs;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n let statementId: string | undefined;\n try {\n let response = await this.call('POST', `${API}/`, controller.signal, {\n warehouse_id: this.config.warehouseId,\n statement,\n // the API holds the request for up to 50 s and answers at once if the statement is quicker; a shorter\n // wait than 5 s is not allowed except 0, so poll\n wait_timeout: timeoutMs >= 5000 ? `${Math.min(50, Math.floor(timeoutMs / 1000))}s` : '0s',\n on_wait_timeout: 'CONTINUE',\n disposition: 'INLINE',\n format: 'JSON_ARRAY',\n ...(this.config.catalog ? { catalog: this.config.catalog } : {}),\n ...(this.config.schema ? { schema: this.config.schema } : {}),\n });\n statementId = response.statement_id;\n\n let delay = this.config.pollIntervalMs ?? 250;\n while (response.status.state === 'PENDING' || response.status.state === 'RUNNING') {\n if (Date.now() >= deadline) throw new QueryTimeoutError(timeoutMs);\n await sleep(Math.min(delay, Math.max(0, deadline - Date.now())));\n delay = Math.min(delay * 2, 2000);\n response = await this.call('GET', `${API}/${statementId}`, controller.signal);\n }\n\n if (response.status.state !== 'SUCCEEDED') {\n const error = response.status.error;\n throw new DatabricksQueryError(\n error?.message ?? `The statement ${response.status.state.toLowerCase()}`, error?.error_code, statementId);\n }\n return await this.rows(response, controller.signal);\n } catch (e) {\n const timedOut = controller.signal.aborted || e instanceof QueryTimeoutError;\n if (timedOut && statementId !== undefined) await this.cancel(statementId);\n if (controller.signal.aborted) throw new QueryTimeoutError(timeoutMs);\n throw e;\n } finally {\n clearTimeout(timer);\n }\n }\n\n /** The rows of a finished statement, following its chunks. */\n private async rows(first: StatementResponse, signal: AbortSignal): Promise<Row[]> {\n const info = first.manifest?.schema?.columns ?? [];\n this.lastColumns = info.map(c => c.name);\n const rows: Row[] = [];\n const take = (data: (string | null)[][] | undefined) => {\n for (const row of data ?? []) rows.push(row.map((text, i) => convertValue(text, info[i]?.type_name)));\n };\n take(first.result?.data_array);\n let next = first.result?.next_chunk_index;\n while (next !== undefined && next !== null) {\n const chunk = await this.call<ResultData>('GET', `${API}/${first.statement_id}/result/chunks/${next}`, signal);\n take(chunk.data_array);\n next = chunk.next_chunk_index;\n }\n return rows;\n }\n\n /** Ask Databricks to stop a statement. Best effort: the query is already given up on. */\n private async cancel(statementId: string): Promise<void> {\n try {\n await this.call('POST', `${API}/${statementId}/cancel`, undefined, {});\n } catch {\n // nothing more can be done about it\n }\n }\n\n private async call<T = StatementResponse>(method: 'GET' | 'POST', path: string, signal: AbortSignal | undefined, body?: object): Promise<T> {\n const { host, token, headers, fetch: custom } = this.config;\n const bearer = typeof token === 'function' ? await token() : token;\n const response = await (custom ?? fetch)(host.replace(/\\/+$/, '') + path, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n ...(bearer ? { Authorization: `Bearer ${bearer}` } : {}),\n ...headers,\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal,\n });\n const text = await response.text();\n let parsed: unknown;\n try { parsed = text ? JSON.parse(text) : {}; } catch { parsed = undefined; }\n if (!response.ok) {\n const detail = parsed as { error_code?: string; message?: string } | undefined;\n throw new DatabricksQueryError(\n detail?.message ?? `Databricks request failed: ${response.status} ${response.statusText}`, detail?.error_code);\n }\n return parsed as T;\n }\n}\n"],"mappings":"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","names":["value","value","value"]}