@malloydata/malloy 0.0.3 → 0.0.4

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 (37) hide show
  1. package/dist/lang/ast/ast-expr.d.ts +0 -1
  2. package/dist/lang/ast/ast-main.d.ts +2 -2
  3. package/package.json +1 -1
  4. package/dist/connection_utils.js +0 -56
  5. package/dist/dialect/dialect.js +0 -77
  6. package/dist/dialect/dialect_map.js +0 -35
  7. package/dist/dialect/duckdb.js +0 -347
  8. package/dist/dialect/index.js +0 -27
  9. package/dist/dialect/postgres.js +0 -315
  10. package/dist/dialect/standardsql.js +0 -362
  11. package/dist/index.js +0 -47
  12. package/dist/lang/ast/apply-expr.js +0 -231
  13. package/dist/lang/ast/ast-expr.js +0 -1041
  14. package/dist/lang/ast/ast-main.js +0 -2087
  15. package/dist/lang/ast/ast-time-expr.js +0 -549
  16. package/dist/lang/ast/ast-types.js +0 -215
  17. package/dist/lang/ast/index.js +0 -34
  18. package/dist/lang/ast/time-utils.js +0 -94
  19. package/dist/lang/field-space.js +0 -631
  20. package/dist/lang/field-utils.js +0 -33
  21. package/dist/lang/index.js +0 -22
  22. package/dist/lang/parse-log.js +0 -41
  23. package/dist/lang/reference-list.js +0 -80
  24. package/dist/lang/space-field.js +0 -346
  25. package/dist/lang/test/document-help-context-walker.spec.js +0 -45
  26. package/dist/lang/test/document-symbol-walker.spec.js +0 -100
  27. package/dist/lang/test/field-symbols.spec.js +0 -172
  28. package/dist/lang/test/parse.spec.js +0 -1951
  29. package/dist/lang/test/test-translator.js +0 -334
  30. package/dist/lang/zone.js +0 -97
  31. package/dist/malloy.js +0 -2360
  32. package/dist/model/index.js +0 -34
  33. package/dist/model/malloy_query.js +0 -2994
  34. package/dist/model/malloy_types.js +0 -283
  35. package/dist/model/sql_block.js +0 -41
  36. package/dist/model/utils.js +0 -84
  37. package/dist/runtime_types.js +0 -15
package/dist/malloy.js DELETED
@@ -1,2360 +0,0 @@
1
- "use strict";
2
- /*
3
- * Copyright 2022 Google LLC
4
- *
5
- * This program is free software; you can redistribute it and/or
6
- * modify it under the terms of the GNU General Public License
7
- * version 2 as published by the Free Software Foundation.
8
- *
9
- * This program is distributed in the hope that it will be useful,
10
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- * GNU General Public License for more details.
13
- */
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.CSVWriter = exports.JSONWriter = exports.DataWriter = exports.DataRecord = exports.DataArray = exports.Result = exports.ExploreMaterializer = exports.SQLBlockMaterializer = exports.PreparedResultMaterializer = exports.QueryMaterializer = exports.ModelMaterializer = exports.SingleConnectionRuntime = exports.ConnectionRuntime = exports.Runtime = exports.ExploreField = exports.JoinRelationship = exports.QueryField = exports.Query = exports.StringField = exports.BooleanField = exports.NumberField = exports.TimestampField = exports.DateField = exports.TimestampTimeframe = exports.DateTimeframe = exports.AtomicField = exports.AtomicFieldType = exports.Explore = exports.SourceRelationship = exports.FixedConnectionMap = exports.InMemoryURLReader = exports.EmptyURLReader = exports.PreparedResult = exports.DocumentCompletion = exports.DocumentSymbol = exports.DocumentPosition = exports.DocumentRange = exports.DocumentHighlight = exports.Parse = exports.parseTableURI = exports.PreparedQuery = exports.Model = exports.MalloyError = exports.Malloy = void 0;
16
- const lang_1 = require("./lang");
17
- const model_1 = require("./model");
18
- class Malloy {
19
- // TODO load from file built during release
20
- static get version() {
21
- return "0.0.1";
22
- }
23
- static get log() {
24
- return Malloy._log || console;
25
- }
26
- static setLogger(log) {
27
- Malloy._log = log;
28
- }
29
- static _parse(source, url) {
30
- if (url === undefined) {
31
- url = new URL("internal://internal.malloy");
32
- }
33
- const translator = new lang_1.MalloyTranslator(url.toString(), {
34
- urls: { [url.toString()]: source },
35
- });
36
- return new Parse(translator);
37
- }
38
- static parse({ url, urlReader, source, }) {
39
- if (source !== undefined) {
40
- return Malloy._parse(source, url);
41
- }
42
- else {
43
- if (urlReader === undefined) {
44
- throw new Error("Internal Error: urlReader is required.");
45
- }
46
- if (url === undefined) {
47
- throw new Error("Internal Error: url is required if source not present.");
48
- }
49
- return urlReader.readURL(url).then((source) => {
50
- return Malloy._parse(source, url);
51
- });
52
- }
53
- }
54
- /**
55
- * Compile a parsed Malloy document.
56
- *
57
- * @param urlReader Object capable of reading contents of a URL.
58
- * @param connections Mapping of connection names to objects capable of reading Malloy schemas.
59
- * @param parse The parsed Malloy document.
60
- * @param model A compiled model to build upon (optional).
61
- * @returns A (promise of a) compiled `Model`.
62
- */
63
- static async compile({ urlReader, connections, parse, model, }) {
64
- const translator = parse._translator;
65
- // eslint-disable-next-line no-constant-condition
66
- while (true) {
67
- const result = translator.translate(model === null || model === void 0 ? void 0 : model._modelDef);
68
- if (result.final) {
69
- if (result.translated) {
70
- return new Model(result.translated.modelDef, result.translated.queryList, result.translated.sqlBlocks, (position) => translator.referenceAt(position));
71
- }
72
- else {
73
- const errors = result.errors || [];
74
- const errText = translator.prettyErrors();
75
- throw new MalloyError(`Error(s) compiling model:\n${errText}`, errors);
76
- }
77
- }
78
- else {
79
- // Parse incomplete because some external information is required,
80
- // there might be more than one of these in a single reply ...
81
- if (result.urls) {
82
- for (const neededUrl of result.urls) {
83
- try {
84
- if (neededUrl.startsWith("internal://")) {
85
- throw new Error("In order to use relative imports, you must compile a file via a URL.");
86
- }
87
- const neededText = await urlReader.readURL(new URL(neededUrl));
88
- const urls = { [neededUrl]: neededText };
89
- translator.update({ urls });
90
- }
91
- catch (error) {
92
- translator.update({
93
- errors: { urls: { [neededUrl]: error.message } },
94
- });
95
- }
96
- }
97
- }
98
- if (result.tables) {
99
- // collect tables by connection name since there may be multiple connections
100
- const tablesByConnection = new Map();
101
- for (const connectionTableString of result.tables) {
102
- const { connectionName } = parseTableURI(connectionTableString);
103
- let connectionToTablesMap = tablesByConnection.get(connectionName);
104
- if (!connectionToTablesMap) {
105
- connectionToTablesMap = [connectionTableString];
106
- }
107
- else {
108
- connectionToTablesMap.push(connectionTableString);
109
- }
110
- tablesByConnection.set(connectionName, connectionToTablesMap);
111
- }
112
- // iterate over connections, fetching schema for all missing tables
113
- for (const [connectionName, connectionTableString,] of tablesByConnection) {
114
- try {
115
- const connection = await connections.lookupConnection(connectionName);
116
- // TODO detect if the union of `Object.keys(tables)` and `Object.keys(errors)` is not the same
117
- // as `Object.keys(connectionTableString)`, i.e. that all tables are accounted for. Otherwise
118
- // the translator runs into an infinite loop fetching tables.
119
- const { schemas: tables, errors } = await connection.fetchSchemaForTables(connectionTableString);
120
- translator.update({ tables, errors: { tables: errors } });
121
- }
122
- catch (error) {
123
- // There was an exception getting the connection, associate that error
124
- // with all its tables
125
- const tables = {};
126
- const errors = {};
127
- for (const table of connectionTableString) {
128
- errors[table] = error.toString();
129
- }
130
- translator.update({ tables, errors: { tables: errors } });
131
- }
132
- }
133
- }
134
- if (result.sqlStructs) {
135
- // collect sql refs by connection name since there may be multiple connections
136
- const sqlRefsByConnection = new Map();
137
- for (const missingSQLSchemaRef of result.sqlStructs) {
138
- const connectionName = missingSQLSchemaRef.connection;
139
- // if (connectionName === undefined) {
140
- // throw new Error("Oops have not made it required here yet...");
141
- // }
142
- let connectionToSQLReferencesMap = sqlRefsByConnection.get(connectionName);
143
- if (!connectionToSQLReferencesMap) {
144
- connectionToSQLReferencesMap = [missingSQLSchemaRef];
145
- }
146
- else {
147
- connectionToSQLReferencesMap.push(missingSQLSchemaRef);
148
- }
149
- sqlRefsByConnection.set(connectionName, connectionToSQLReferencesMap);
150
- }
151
- for (const [connectionName, connectionToSQLReferencesMap,] of sqlRefsByConnection) {
152
- try {
153
- const connection = await connections.lookupConnection(connectionName);
154
- // TODO detect if the union of `Object.keys(sqlStructs)` and `Object.keys(errors)` is not the same
155
- // as `Object.keys(connectionToSQLReferencesMap)`, i.e. that all tables are accounted for. Otherwise
156
- // the translator runs into an infinite loop fetching SQL structs.
157
- const { schemas: sqlStructs, errors } = await connection.fetchSchemaForSQLBlocks(connectionToSQLReferencesMap);
158
- translator.update({ sqlStructs });
159
- translator.update({ sqlStructs, errors: { sqlStructs: errors } });
160
- }
161
- catch (error) {
162
- // There was an exception getting the connection, associate that error
163
- // with all its schemas
164
- const sqlStructs = {};
165
- const errors = {};
166
- for (const sqlRef of connectionToSQLReferencesMap) {
167
- errors[sqlRef.name] = error.toString();
168
- }
169
- translator.update({ sqlStructs, errors: { sqlStructs: errors } });
170
- }
171
- }
172
- }
173
- }
174
- }
175
- }
176
- static async runSQLBlockAndFetchResultSchema(connection, sqlBlock, options) {
177
- if (connection.canFetchSchemaAndRunSimultaneously()) {
178
- return connection.runSQLBlockAndFetchResultSchema(sqlBlock, options);
179
- }
180
- const [schema, data] = await Promise.all([
181
- connection
182
- .fetchSchemaForSQLBlocks([sqlBlock])
183
- .then((result) => result.schemas[sqlBlock.name]),
184
- connection.runSQL(sqlBlock.select),
185
- ]);
186
- return { schema, data };
187
- }
188
- static async run({ connections, preparedResult, sqlBlock, connection, options, }) {
189
- if (sqlBlock === undefined && preparedResult === undefined) {
190
- throw new Error("Internal error: sqlBlock or preparedResult must be provided.");
191
- }
192
- const connectionName = (sqlBlock === null || sqlBlock === void 0 ? void 0 : sqlBlock.connection) || (preparedResult === null || preparedResult === void 0 ? void 0 : preparedResult.connectionName);
193
- if (connection === undefined) {
194
- if (connections === undefined) {
195
- throw new Error("Internal Error: Connection or LookupConnection<Connection> must be provided.");
196
- }
197
- connection = await connections.lookupConnection(connectionName);
198
- }
199
- if (sqlBlock !== undefined) {
200
- const { schema, data } = await this.runSQLBlockAndFetchResultSchema(connection, sqlBlock, options);
201
- if (schema.structRelationship.type !== "basetable") {
202
- throw new Error("Expected schema's structRelationship type to be 'basetable'.");
203
- }
204
- return new Result({
205
- structs: [schema],
206
- sql: sqlBlock.select,
207
- result: data.rows,
208
- totalRows: data.totalRows,
209
- lastStageName: schema.name,
210
- // TODO feature-sql-block There is no malloy code...
211
- malloy: "",
212
- connectionName: schema.structRelationship.connectionName,
213
- // TODO feature-sql-block There is no source explore...
214
- sourceExplore: "",
215
- sourceFilters: [],
216
- }, {
217
- name: "empty_model",
218
- exports: [],
219
- contents: {},
220
- });
221
- }
222
- else if (preparedResult !== undefined) {
223
- const result = await connection.runSQL(preparedResult.sql, options);
224
- return new Result({
225
- ...preparedResult._rawQuery,
226
- result: result.rows,
227
- totalRows: result.totalRows,
228
- }, preparedResult._modelDef);
229
- }
230
- else {
231
- throw new Error("Internal error: sqlBlock or preparedResult must be provided.");
232
- }
233
- }
234
- static async *runStream({ connections, preparedResult, sqlBlock, connection, options, }) {
235
- if (sqlBlock === undefined && preparedResult === undefined) {
236
- throw new Error("Internal error: sqlBlock or preparedResult must be provided.");
237
- }
238
- const connectionName = (sqlBlock === null || sqlBlock === void 0 ? void 0 : sqlBlock.connection) || (preparedResult === null || preparedResult === void 0 ? void 0 : preparedResult.connectionName);
239
- if (connection === undefined) {
240
- if (connections === undefined) {
241
- throw new Error("Internal Error: Connection or LookupConnection<Connection> must be provided.");
242
- }
243
- connection = await connections.lookupConnection(connectionName);
244
- }
245
- // TODO is there a better way to handle this case? Just require StreamingConnections?
246
- if (!connection.canStream()) {
247
- throw new Error(`Connection '${connectionName}' cannot stream results.`);
248
- }
249
- let sql;
250
- let resultExplore;
251
- if (sqlBlock !== undefined) {
252
- const schema = (await connection.fetchSchemaForSQLBlocks([sqlBlock]))
253
- .schemas[sqlBlock.name];
254
- if (schema.structRelationship.type !== "basetable") {
255
- throw new Error("Expected schema's structRelationship type to be 'basetable'.");
256
- }
257
- resultExplore = new Explore(schema);
258
- sql = sqlBlock.select;
259
- }
260
- else if (preparedResult !== undefined) {
261
- resultExplore = preparedResult.resultExplore;
262
- sql = preparedResult.sql;
263
- }
264
- else {
265
- throw new Error("Internal error: sqlBlock or preparedResult must be provided.");
266
- }
267
- let index = 0;
268
- for await (const row of connection.runSQLStream(sql, options)) {
269
- yield new DataRecord(row, index, resultExplore, undefined);
270
- index += 1;
271
- }
272
- }
273
- }
274
- exports.Malloy = Malloy;
275
- /**
276
- * A Malloy error, which may contain log messages produced during compilation.
277
- */
278
- class MalloyError extends Error {
279
- constructor(message, log = []) {
280
- super(message);
281
- this.log = log;
282
- }
283
- }
284
- exports.MalloyError = MalloyError;
285
- /**
286
- * A compiled Malloy document.
287
- */
288
- class Model {
289
- constructor(modelDef, queryList, sqlBlocks, referenceAt = () => undefined) {
290
- this.modelDef = modelDef;
291
- this.queryList = queryList;
292
- this.sqlBlocks = sqlBlocks;
293
- this._referenceAt = referenceAt;
294
- }
295
- /**
296
- * Retrieve a document reference for the token at the given position within
297
- * the document that produced this model.
298
- *
299
- * @param position A position within the document.
300
- * @returns A `DocumentReference` at that position if one exists.
301
- */
302
- getReference(position) {
303
- return this._referenceAt(position);
304
- }
305
- /**
306
- * Retrieve a prepared query by the name of a query at the top level of the model.
307
- *
308
- * @param queryName Name of the query to retrieve.
309
- * @returns A prepared query.
310
- */
311
- getPreparedQueryByName(queryName) {
312
- const query = this.modelDef.contents[queryName];
313
- if (query.type === "query") {
314
- return new PreparedQuery(query, this.modelDef, queryName);
315
- }
316
- throw new Error("Given query name does not refer to a named query.");
317
- }
318
- /**
319
- * Retrieve a prepared query by the index of an unnamed query at the top level of a model.
320
- *
321
- * @param index The index of the query to retrieve.
322
- * @returns A prepared query.
323
- */
324
- getPreparedQueryByIndex(index) {
325
- if (index < 0) {
326
- throw new Error(`Invalid index ${index}.`);
327
- }
328
- else if (index >= this.queryList.length) {
329
- throw new Error(`Query index ${index} is out of bounds.`);
330
- }
331
- return new PreparedQuery(this.queryList[index], this.modelDef);
332
- }
333
- /**
334
- * Retrieve a prepared query by the name of a query at the top level of the model.
335
- *
336
- * @param queryName Name of the query to retrieve.
337
- * @returns A prepared query.
338
- */
339
- getSQLBlockByName(sqlBlockName) {
340
- const sqlBlock = this.sqlBlocks.find((sqlBlock) => sqlBlock.as === sqlBlockName);
341
- if (sqlBlock === undefined) {
342
- throw new Error(`No SQL Block named '${sqlBlockName}'`);
343
- }
344
- return sqlBlock;
345
- }
346
- /**
347
- * Retrieve a prepared query by the name of a query at the top level of the model.
348
- *
349
- * @param index Index of the SQL Block to retrieve.
350
- * @returns A prepared query.
351
- */
352
- getSQLBlockByIndex(index) {
353
- const sqlBlock = this.sqlBlocks[index];
354
- if (sqlBlock === undefined) {
355
- throw new Error(`No SQL Block at index ${index}`);
356
- }
357
- return sqlBlock;
358
- }
359
- /**
360
- * Retrieve a prepared query for the final unnamed query at the top level of a model.
361
- *
362
- * @returns A prepared query.
363
- */
364
- get preparedQuery() {
365
- if (this.queryList.length === 0) {
366
- throw new Error("Model has no queries.");
367
- }
368
- return new PreparedQuery(this.queryList[this.queryList.length - 1], this.modelDef);
369
- }
370
- /**
371
- * Retrieve an `Explore` from the model by name.
372
- *
373
- * @param name The name of the `Explore` to retrieve.
374
- * @returns An `Explore`.
375
- */
376
- getExploreByName(name) {
377
- const struct = this.modelDef.contents[name];
378
- if (struct.type === "struct") {
379
- return new Explore(struct);
380
- }
381
- throw new Error(`'name' is not an explore`);
382
- }
383
- /**
384
- * Get an array of `Explore`s contained in the model.
385
- *
386
- * @returns An array of `Explore`s contained in the model.
387
- */
388
- get explores() {
389
- const explores = [];
390
- for (const me in this.modelDef.contents) {
391
- const ent = this.modelDef.contents[me];
392
- if (ent.type === "struct") {
393
- explores.push(new Explore(ent));
394
- }
395
- }
396
- return explores;
397
- }
398
- get exportedExplores() {
399
- return this.explores.filter((explore) => this.modelDef.exports.includes(explore.name));
400
- }
401
- get _modelDef() {
402
- return this.modelDef;
403
- }
404
- }
405
- exports.Model = Model;
406
- /**
407
- * A prepared query which has all the necessary information to produce its SQL.
408
- */
409
- class PreparedQuery {
410
- constructor(query, model, name) {
411
- this._query = query;
412
- this._modelDef = model;
413
- this.name = name;
414
- }
415
- /**
416
- * Generate the SQL for this query.
417
- *
418
- * @returns A fully-prepared query (which contains the generated SQL).
419
- */
420
- get preparedResult() {
421
- const queryModel = new model_1.QueryModel(this._modelDef);
422
- const translatedQuery = queryModel.compileQuery(this._query);
423
- return new PreparedResult({
424
- ...translatedQuery,
425
- queryName: this.name || translatedQuery.queryName,
426
- }, this._modelDef);
427
- }
428
- get dialect() {
429
- const sourceRef = this._query.structRef;
430
- const source = typeof sourceRef === "string"
431
- ? this._modelDef.contents[sourceRef]
432
- : sourceRef;
433
- if (source.type !== "struct") {
434
- throw new Error("Invalid source for query");
435
- }
436
- return source.dialect;
437
- }
438
- }
439
- exports.PreparedQuery = PreparedQuery;
440
- function parseTableURI(tableURI) {
441
- const [firstPart, secondPart] = tableURI.split(":");
442
- if (secondPart) {
443
- return { connectionName: firstPart, tablePath: secondPart };
444
- }
445
- else {
446
- return { tablePath: firstPart };
447
- }
448
- }
449
- exports.parseTableURI = parseTableURI;
450
- /**
451
- * A parsed Malloy document.
452
- */
453
- class Parse {
454
- constructor(translator) {
455
- this.translator = translator;
456
- }
457
- /**
458
- * Retrieve the document highlights for the parsed document.
459
- *
460
- * These highlights represent the parsed tokens contained in the document,
461
- * and may be used for syntax highlighting in an IDE, for example.
462
- *
463
- * @returns An array of document highlights.
464
- */
465
- get highlights() {
466
- return (this.translator.metadata().highlights || []).map((highlight) => new DocumentHighlight(highlight));
467
- }
468
- /**
469
- * Retrieve the symbols defined in the parsed document.
470
- *
471
- * These symbols represent any object defined (e.g. `Query`s and `Explore`s)
472
- * in the document.
473
- *
474
- * @returns An array of document symbols.
475
- */
476
- get symbols() {
477
- return (this.translator.metadata().symbols || []).map((symbol) => new DocumentSymbol(symbol));
478
- }
479
- get _translator() {
480
- return this.translator;
481
- }
482
- completions(position) {
483
- return (this.translator.completions(position).completions || []).map((completion) => new DocumentCompletion(completion));
484
- }
485
- helpContext(position) {
486
- return this.translator.helpContext(position).helpContext;
487
- }
488
- }
489
- exports.Parse = Parse;
490
- /**
491
- * A document highlight.
492
- *
493
- * Represents a parsed token contained in a Malloy document
494
- * and may be used for syntax highlighting in an IDE, for example.
495
- */
496
- class DocumentHighlight {
497
- constructor(documentHighlight) {
498
- this._range = new DocumentRange(new DocumentPosition(documentHighlight.range.start.line, documentHighlight.range.start.character), new DocumentPosition(documentHighlight.range.end.line, documentHighlight.range.end.character));
499
- this._type = documentHighlight.type;
500
- }
501
- /**
502
- * @returns The range of characters this highlight spans within its source document.
503
- */
504
- get range() {
505
- return this._range;
506
- }
507
- /**
508
- * @returns The type of highlight, which may be any `HighlightType`.
509
- */
510
- get type() {
511
- return this._type;
512
- }
513
- }
514
- exports.DocumentHighlight = DocumentHighlight;
515
- /**
516
- * A range of characters within a Malloy document.
517
- */
518
- class DocumentRange {
519
- constructor(start, end) {
520
- this._start = start;
521
- this._end = end;
522
- }
523
- /**
524
- * @returns The position of the first character in the range.
525
- */
526
- get start() {
527
- return this._start;
528
- }
529
- /**
530
- * @returns The position of the last character in the range.
531
- */
532
- get end() {
533
- return this._end;
534
- }
535
- /**
536
- * @returns This range in JSON format.
537
- */
538
- toJSON() {
539
- return {
540
- start: this.start.toJSON(),
541
- end: this.end.toJSON(),
542
- };
543
- }
544
- }
545
- exports.DocumentRange = DocumentRange;
546
- /**
547
- * A position within a Malloy document.
548
- */
549
- class DocumentPosition {
550
- constructor(line, character) {
551
- this._line = line;
552
- this._character = character;
553
- }
554
- /**
555
- * @returns The line number of the position.
556
- */
557
- get line() {
558
- return this._line;
559
- }
560
- /**
561
- * @returns The character index on the line `this.getLine()`.
562
- */
563
- get character() {
564
- return this._character;
565
- }
566
- /**
567
- * @returns This position in JSON format.
568
- */
569
- toJSON() {
570
- return { line: this.line, character: this.character };
571
- }
572
- }
573
- exports.DocumentPosition = DocumentPosition;
574
- /**
575
- * A symbol defined in a Malloy document.
576
- *
577
- * Represents any object defined (e.g. `Query`s and `Explore`s) in the document.
578
- */
579
- class DocumentSymbol {
580
- constructor(documentSymbol) {
581
- this._range = new DocumentRange(new DocumentPosition(documentSymbol.range.start.line, documentSymbol.range.start.character), new DocumentPosition(documentSymbol.range.end.line, documentSymbol.range.end.character));
582
- this._type = documentSymbol.type;
583
- this._name = documentSymbol.name;
584
- this._children = documentSymbol.children.map((child) => new DocumentSymbol(child));
585
- }
586
- /**
587
- * @returns The range of characters in the source Malloy document that define this symbol.
588
- */
589
- get range() {
590
- return this._range;
591
- }
592
- /**
593
- * @returns The type of symbol.
594
- *
595
- * Possible values are: `"explore"`, `"query"`, `"field"`, `"turtle"`, `"join"`, or `"unnamed_query"`.
596
- */
597
- get type() {
598
- return this._type;
599
- }
600
- /**
601
- * @returns The name of this symbol, e.g. the `Explore` name or `Query` name.
602
- *
603
- * For type `"unnamed_query"`, `getName()` is `"unnamed_query"`.
604
- */
605
- get name() {
606
- return this._name;
607
- }
608
- /**
609
- * @returns An array of document symbols defined inside this document symbol,
610
- * e.g. fields in an `Explore`.
611
- */
612
- get children() {
613
- return this._children;
614
- }
615
- }
616
- exports.DocumentSymbol = DocumentSymbol;
617
- class DocumentCompletion {
618
- constructor(completion) {
619
- this.type = completion.type;
620
- this.text = completion.text;
621
- }
622
- }
623
- exports.DocumentCompletion = DocumentCompletion;
624
- /**
625
- * A fully-prepared query containing SQL and metadata required to run the query.
626
- */
627
- class PreparedResult {
628
- constructor(query, modelDef) {
629
- this.inner = query;
630
- this.modelDef = modelDef;
631
- }
632
- /**
633
- * @returns The name of the connection this query should be run against.
634
- */
635
- get connectionName() {
636
- return this.inner.connectionName;
637
- }
638
- get _rawQuery() {
639
- return this.inner;
640
- }
641
- get _modelDef() {
642
- return this.modelDef;
643
- }
644
- /**
645
- * @returns The SQL that should be run against the SQL runner
646
- * with the connection name `this.getConnectionName()`.
647
- */
648
- get sql() {
649
- return this.inner.sql;
650
- }
651
- /**
652
- * @returns The `Explore` representing the data that will be returned by running this query.
653
- */
654
- get resultExplore() {
655
- if (this.inner.structs.length === 0) {
656
- throw new Error("Malformed query result.");
657
- }
658
- const explore = this.inner.structs[this.inner.structs.length - 1];
659
- const namedExplore = {
660
- ...explore,
661
- name: this.inner.queryName || explore.name,
662
- };
663
- // TODO `sourceExplore` is not fully-implemented yet -- it cannot
664
- // handle cases where the source of the query is something other than
665
- // a named explore.
666
- try {
667
- return new Explore(namedExplore, this.sourceExplore);
668
- }
669
- catch (error) {
670
- return new Explore(namedExplore);
671
- }
672
- }
673
- get sourceExplore() {
674
- const name = this.inner.sourceExplore;
675
- const explore = this.modelDef.contents[name];
676
- if (explore === undefined) {
677
- throw new Error("Malformed query result.");
678
- }
679
- if (explore.type === "struct") {
680
- return new Explore(explore);
681
- }
682
- throw new Error(`'${name} is not an explore`);
683
- }
684
- get _sourceExploreName() {
685
- return this.inner.sourceExplore;
686
- }
687
- get _sourceFilters() {
688
- return this.inner.sourceFilters || [];
689
- }
690
- }
691
- exports.PreparedResult = PreparedResult;
692
- /**
693
- * A URL reader which always throws an error when a URL's contents is requested.
694
- *
695
- * Useful for scenarios in which `import` statements are not required.
696
- */
697
- class EmptyURLReader {
698
- async readURL(_url) {
699
- throw new Error("No files.");
700
- }
701
- }
702
- exports.EmptyURLReader = EmptyURLReader;
703
- /**
704
- * A URL reader backed by an in-memory mapping of URL contents.
705
- */
706
- class InMemoryURLReader {
707
- constructor(files) {
708
- this.files = files;
709
- }
710
- async readURL(url) {
711
- const file = this.files.get(url.toString());
712
- if (file !== undefined) {
713
- return Promise.resolve(file);
714
- }
715
- else {
716
- throw new Error(`File not found '${url}'`);
717
- }
718
- }
719
- }
720
- exports.InMemoryURLReader = InMemoryURLReader;
721
- /**
722
- * A fixed mapping of connection names to connections.
723
- */
724
- class FixedConnectionMap {
725
- constructor(connections, defaultConnectionName) {
726
- this.connections = connections;
727
- this.defaultConnectionName = defaultConnectionName;
728
- }
729
- /**
730
- * Get a connection by name.
731
- *
732
- * @param connectionName The name of the connection to look up.
733
- * @returns A `Connection`
734
- * @throws An `Error` if no connection with the given name exists.
735
- */
736
- async getConnection(connectionName) {
737
- if (connectionName === undefined) {
738
- if (this.defaultConnectionName !== undefined) {
739
- connectionName = this.defaultConnectionName;
740
- }
741
- else {
742
- throw new Error("No default connection.");
743
- }
744
- }
745
- const connection = this.connections.get(connectionName);
746
- if (connection !== undefined) {
747
- return Promise.resolve(connection);
748
- }
749
- else {
750
- throw new Error(`No connection found with name ${connectionName}.`);
751
- }
752
- }
753
- async lookupConnection(connectionName) {
754
- return this.getConnection(connectionName);
755
- }
756
- static fromArray(connections) {
757
- return new FixedConnectionMap(new Map(connections.map((connection) => [connection.name, connection])));
758
- }
759
- }
760
- exports.FixedConnectionMap = FixedConnectionMap;
761
- /**
762
- * The relationship of an `Explore` to its source.
763
- */
764
- var SourceRelationship;
765
- (function (SourceRelationship) {
766
- /**
767
- * The `Explore` is nested data within the source's rows.
768
- */
769
- SourceRelationship["Nested"] = "nested";
770
- /**
771
- * The `Explore` is the base table.
772
- */
773
- SourceRelationship["BaseTable"] = "base_table";
774
- /**
775
- * The `Explore` is joined to its source
776
- */
777
- SourceRelationship["Cross"] = "cross";
778
- SourceRelationship["One"] = "one";
779
- SourceRelationship["Many"] = "many";
780
- // TODO document this
781
- SourceRelationship["Inline"] = "inline";
782
- })(SourceRelationship = exports.SourceRelationship || (exports.SourceRelationship = {}));
783
- class Entity {
784
- constructor(name, parent, source) {
785
- this._name = name;
786
- this._parent = parent;
787
- this._source = source;
788
- }
789
- get source() {
790
- return this.source;
791
- }
792
- get name() {
793
- return this._name;
794
- }
795
- get sourceClasses() {
796
- const sourceClasses = [];
797
- if (this.source) {
798
- sourceClasses.push(this.source.name);
799
- }
800
- sourceClasses.push(this.name);
801
- return sourceClasses;
802
- }
803
- hasParentExplore() {
804
- return this._parent !== undefined;
805
- }
806
- isExplore() {
807
- return this instanceof Explore;
808
- }
809
- isQuery() {
810
- return this instanceof QueryField;
811
- }
812
- }
813
- class Explore extends Entity {
814
- constructor(structDef, parentExplore, source) {
815
- super(structDef.as || structDef.name, parentExplore, source);
816
- this._structDef = structDef;
817
- this._parentExplore = parentExplore;
818
- this.sourceExplore = source;
819
- }
820
- get source() {
821
- return this.sourceExplore;
822
- }
823
- isIntrinsic() {
824
- return (0, model_1.FieldIsIntrinsic)(this._structDef);
825
- }
826
- /**
827
- * @returns The name of the entity.
828
- */
829
- get name() {
830
- return this.structDef.as || this.structDef.name;
831
- }
832
- getQueryByName(name) {
833
- const internalQuery = {
834
- type: "query",
835
- structRef: this.structDef,
836
- pipeline: [
837
- {
838
- type: "reduce",
839
- fields: [name],
840
- },
841
- ],
842
- };
843
- return new PreparedQuery(internalQuery, this.modelDef, name);
844
- }
845
- get modelDef() {
846
- return {
847
- name: "generated_model",
848
- exports: [],
849
- contents: { [this.structDef.name]: this.structDef },
850
- };
851
- }
852
- getSingleExploreModel() {
853
- return new Model(this.modelDef, [], []);
854
- }
855
- get fieldMap() {
856
- var _a;
857
- if (this._fieldMap === undefined) {
858
- const sourceFields = ((_a = this.source) === null || _a === void 0 ? void 0 : _a.fieldMap) || new Map();
859
- this._fieldMap = new Map(this.structDef.fields.map((fieldDef) => {
860
- const name = fieldDef.as || fieldDef.name;
861
- const sourceField = sourceFields.get(fieldDef.name);
862
- if (fieldDef.type === "struct") {
863
- return [name, new ExploreField(fieldDef, this, sourceField)];
864
- }
865
- else if (fieldDef.type === "turtle") {
866
- return [name, new QueryField(fieldDef, this, sourceField)];
867
- }
868
- else {
869
- if (fieldDef.type === "string") {
870
- return [name, new StringField(fieldDef, this, sourceField)];
871
- }
872
- else if (fieldDef.type === "number") {
873
- return [name, new NumberField(fieldDef, this, sourceField)];
874
- }
875
- else if (fieldDef.type === "date") {
876
- // TODO this is a hack
877
- // Is this a bug? The extraction functions don't seem like they should return a
878
- // field of type "date". Rather, they should be of type "number".
879
- if (fieldDef.timeframe &&
880
- ["day_of_month", "day_of_week", "day_of_year"].includes(fieldDef.timeframe)) {
881
- return [
882
- name,
883
- new NumberField({ ...fieldDef, type: "number" }, this, sourceField),
884
- ];
885
- }
886
- return [name, new DateField(fieldDef, this, sourceField)];
887
- }
888
- else if (fieldDef.type === "timestamp") {
889
- return [name, new TimestampField(fieldDef, this, sourceField)];
890
- }
891
- else if (fieldDef.type === "boolean") {
892
- return [name, new BooleanField(fieldDef, this, sourceField)];
893
- }
894
- }
895
- }));
896
- }
897
- return this._fieldMap;
898
- }
899
- get allFields() {
900
- return [...this.fieldMap.values()];
901
- }
902
- get intrinsicFields() {
903
- return [...this.fieldMap.values()].filter((f) => f.isIntrinsic());
904
- }
905
- getFieldByName(fieldName) {
906
- const field = this.fieldMap.get(fieldName);
907
- if (field === undefined) {
908
- throw new Error(`No such field ${fieldName}.`);
909
- }
910
- return field;
911
- }
912
- getFieldByNameIfExists(fieldName) {
913
- return this.fieldMap.get(fieldName);
914
- }
915
- get primaryKey() {
916
- return this.structDef.primaryKey;
917
- }
918
- get parentExplore() {
919
- return this._parentExplore;
920
- }
921
- get sourceRelationship() {
922
- switch (this.structDef.structRelationship.type) {
923
- case "many":
924
- return SourceRelationship.Many;
925
- case "one":
926
- return SourceRelationship.One;
927
- case "cross":
928
- return SourceRelationship.Cross;
929
- case "inline":
930
- return SourceRelationship.Inline;
931
- case "nested":
932
- return SourceRelationship.Nested;
933
- case "basetable":
934
- return SourceRelationship.BaseTable;
935
- }
936
- }
937
- hasParentExplore() {
938
- return this instanceof ExploreField;
939
- }
940
- // TODO wrapper type for FilterExpression
941
- get filters() {
942
- var _a;
943
- return ((_a = this.structDef.resultMetadata) === null || _a === void 0 ? void 0 : _a.filterList) || [];
944
- }
945
- get limit() {
946
- var _a;
947
- return (_a = this.structDef.resultMetadata) === null || _a === void 0 ? void 0 : _a.limit;
948
- }
949
- get structDef() {
950
- return this._structDef;
951
- }
952
- }
953
- exports.Explore = Explore;
954
- var AtomicFieldType;
955
- (function (AtomicFieldType) {
956
- AtomicFieldType["String"] = "string";
957
- AtomicFieldType["Number"] = "number";
958
- AtomicFieldType["Boolean"] = "boolean";
959
- AtomicFieldType["Date"] = "date";
960
- AtomicFieldType["Timestamp"] = "timestamp";
961
- })(AtomicFieldType = exports.AtomicFieldType || (exports.AtomicFieldType = {}));
962
- class AtomicField extends Entity {
963
- constructor(fieldTypeDef, parent, source) {
964
- super(fieldTypeDef.as || fieldTypeDef.name, parent, source);
965
- this.fieldTypeDef = fieldTypeDef;
966
- this.parent = parent;
967
- }
968
- get type() {
969
- switch (this.fieldTypeDef.type) {
970
- case "string":
971
- return AtomicFieldType.String;
972
- case "boolean":
973
- return AtomicFieldType.Boolean;
974
- case "date":
975
- return AtomicFieldType.Date;
976
- case "timestamp":
977
- return AtomicFieldType.Timestamp;
978
- case "number":
979
- return AtomicFieldType.Number;
980
- }
981
- }
982
- isIntrinsic() {
983
- return (0, model_1.FieldIsIntrinsic)(this.fieldTypeDef);
984
- }
985
- isQueryField() {
986
- return false;
987
- }
988
- isExploreField() {
989
- return false;
990
- }
991
- isAtomicField() {
992
- return true;
993
- }
994
- isAggregate() {
995
- return !!this.fieldTypeDef.aggregate;
996
- }
997
- get sourceField() {
998
- // TODO
999
- throw new Error();
1000
- }
1001
- get sourceClasses() {
1002
- const sourceField = this.fieldTypeDef.name || this.fieldTypeDef.as;
1003
- return sourceField ? [sourceField] : [];
1004
- }
1005
- // was the field generated from a measure in the previous query
1006
- sourceWasMeasure() {
1007
- var _a;
1008
- return ((_a = this.fieldTypeDef.resultMetadata) === null || _a === void 0 ? void 0 : _a.fieldKind) === "measure";
1009
- }
1010
- sourceWasMeasureLike() {
1011
- var _a, _b;
1012
- return (((_a = this.fieldTypeDef.resultMetadata) === null || _a === void 0 ? void 0 : _a.fieldKind) === "measure" ||
1013
- ((_b = this.fieldTypeDef.resultMetadata) === null || _b === void 0 ? void 0 : _b.fieldKind) === "struct");
1014
- }
1015
- sourceWasDimension() {
1016
- var _a;
1017
- return ((_a = this.fieldTypeDef.resultMetadata) === null || _a === void 0 ? void 0 : _a.fieldKind) === "dimension";
1018
- }
1019
- hasParentExplore() {
1020
- return true;
1021
- }
1022
- isString() {
1023
- return this instanceof StringField;
1024
- }
1025
- isNumber() {
1026
- return this instanceof NumberField;
1027
- }
1028
- isDate() {
1029
- return this instanceof DateField;
1030
- }
1031
- isBoolean() {
1032
- return this instanceof BooleanField;
1033
- }
1034
- isTimestamp() {
1035
- return this instanceof TimestampField;
1036
- }
1037
- get parentExplore() {
1038
- return this.parent;
1039
- }
1040
- get expression() {
1041
- var _a, _b;
1042
- return (((_a = this.fieldTypeDef.resultMetadata) === null || _a === void 0 ? void 0 : _a.sourceExpression) ||
1043
- ((_b = this.fieldTypeDef.resultMetadata) === null || _b === void 0 ? void 0 : _b.sourceField) ||
1044
- this.name);
1045
- }
1046
- }
1047
- exports.AtomicField = AtomicField;
1048
- var DateTimeframe;
1049
- (function (DateTimeframe) {
1050
- DateTimeframe["Day"] = "day";
1051
- DateTimeframe["Week"] = "week";
1052
- DateTimeframe["Month"] = "month";
1053
- DateTimeframe["Quarter"] = "quarter";
1054
- DateTimeframe["Year"] = "year";
1055
- })(DateTimeframe = exports.DateTimeframe || (exports.DateTimeframe = {}));
1056
- var TimestampTimeframe;
1057
- (function (TimestampTimeframe) {
1058
- TimestampTimeframe["Day"] = "day";
1059
- TimestampTimeframe["Week"] = "week";
1060
- TimestampTimeframe["Month"] = "month";
1061
- TimestampTimeframe["Quarter"] = "quarter";
1062
- TimestampTimeframe["Year"] = "year";
1063
- TimestampTimeframe["Second"] = "second";
1064
- TimestampTimeframe["Hour"] = "hour";
1065
- TimestampTimeframe["Minute"] = "minute";
1066
- })(TimestampTimeframe = exports.TimestampTimeframe || (exports.TimestampTimeframe = {}));
1067
- class DateField extends AtomicField {
1068
- constructor(fieldDateDef, parent, source) {
1069
- super(fieldDateDef, parent, source);
1070
- this.fieldDateDef = fieldDateDef;
1071
- }
1072
- get timeframe() {
1073
- if (this.fieldDateDef.timeframe === undefined) {
1074
- return undefined;
1075
- }
1076
- switch (this.fieldDateDef.timeframe) {
1077
- case "day":
1078
- return DateTimeframe.Day;
1079
- case "week":
1080
- return DateTimeframe.Week;
1081
- case "month":
1082
- return DateTimeframe.Month;
1083
- case "quarter":
1084
- return DateTimeframe.Quarter;
1085
- case "year":
1086
- return DateTimeframe.Year;
1087
- }
1088
- }
1089
- }
1090
- exports.DateField = DateField;
1091
- class TimestampField extends AtomicField {
1092
- constructor(fieldTimestampDef, parent, source) {
1093
- super(fieldTimestampDef, parent, source);
1094
- this.fieldTimestampDef = fieldTimestampDef;
1095
- }
1096
- get timeframe() {
1097
- if (this.fieldTimestampDef.timeframe === undefined) {
1098
- return undefined;
1099
- }
1100
- switch (this.fieldTimestampDef.timeframe) {
1101
- case "day":
1102
- return TimestampTimeframe.Day;
1103
- case "week":
1104
- return TimestampTimeframe.Week;
1105
- case "month":
1106
- return TimestampTimeframe.Month;
1107
- case "quarter":
1108
- return TimestampTimeframe.Quarter;
1109
- case "year":
1110
- return TimestampTimeframe.Year;
1111
- case "second":
1112
- return TimestampTimeframe.Second;
1113
- case "hour":
1114
- return TimestampTimeframe.Hour;
1115
- case "minute":
1116
- return TimestampTimeframe.Minute;
1117
- }
1118
- }
1119
- }
1120
- exports.TimestampField = TimestampField;
1121
- class NumberField extends AtomicField {
1122
- constructor(fieldNumberDef, parent, source) {
1123
- super(fieldNumberDef, parent, source);
1124
- this.fieldNumberDef = fieldNumberDef;
1125
- }
1126
- }
1127
- exports.NumberField = NumberField;
1128
- class BooleanField extends AtomicField {
1129
- constructor(fieldBooleanDef, parent, source) {
1130
- super(fieldBooleanDef, parent, source);
1131
- this.fieldBooleanDef = fieldBooleanDef;
1132
- }
1133
- }
1134
- exports.BooleanField = BooleanField;
1135
- class StringField extends AtomicField {
1136
- constructor(fieldStringDef, parent, source) {
1137
- super(fieldStringDef, parent, source);
1138
- this.fieldStringDef = fieldStringDef;
1139
- }
1140
- }
1141
- exports.StringField = StringField;
1142
- class Query extends Entity {
1143
- constructor(turtleDef, parent, source) {
1144
- super(turtleDef.as || turtleDef.name, parent, source);
1145
- this.turtleDef = turtleDef;
1146
- }
1147
- get source() {
1148
- return this.sourceQuery;
1149
- }
1150
- isIntrinsic() {
1151
- return false;
1152
- }
1153
- }
1154
- exports.Query = Query;
1155
- class QueryField extends Query {
1156
- constructor(turtleDef, parent, source) {
1157
- super(turtleDef, parent, source);
1158
- this.parent = parent;
1159
- }
1160
- isQueryField() {
1161
- return true;
1162
- }
1163
- isExploreField() {
1164
- return false;
1165
- }
1166
- isAtomicField() {
1167
- return false;
1168
- }
1169
- get sourceClasses() {
1170
- const sourceField = this.turtleDef.name || this.turtleDef.as;
1171
- return sourceField ? [sourceField] : [];
1172
- }
1173
- hasParentExplore() {
1174
- return true;
1175
- }
1176
- get parentExplore() {
1177
- return this.parent;
1178
- }
1179
- get expression() {
1180
- return this.name;
1181
- }
1182
- }
1183
- exports.QueryField = QueryField;
1184
- var JoinRelationship;
1185
- (function (JoinRelationship) {
1186
- JoinRelationship["OneToOne"] = "one_to_one";
1187
- JoinRelationship["OneToMany"] = "one_to_many";
1188
- JoinRelationship["ManyToOne"] = "many_to_one";
1189
- })(JoinRelationship = exports.JoinRelationship || (exports.JoinRelationship = {}));
1190
- class ExploreField extends Explore {
1191
- constructor(structDef, parentExplore, source) {
1192
- super(structDef, parentExplore, source);
1193
- this._parentExplore = parentExplore;
1194
- }
1195
- get joinRelationship() {
1196
- switch (this.structDef.structRelationship.type) {
1197
- case "one":
1198
- return JoinRelationship.OneToMany;
1199
- case "many":
1200
- case "cross":
1201
- return JoinRelationship.ManyToOne;
1202
- case "inline":
1203
- return JoinRelationship.OneToOne;
1204
- case "nested":
1205
- return JoinRelationship.ManyToOne;
1206
- default:
1207
- throw new Error("An explore field must have a join relationship.");
1208
- }
1209
- }
1210
- isQueryField() {
1211
- return false;
1212
- }
1213
- isExploreField() {
1214
- return true;
1215
- }
1216
- isAtomicField() {
1217
- return false;
1218
- }
1219
- get parentExplore() {
1220
- return this._parentExplore;
1221
- }
1222
- get sourceClasses() {
1223
- const sourceField = this.structDef.name || this.structDef.as;
1224
- return sourceField ? [sourceField] : [];
1225
- }
1226
- }
1227
- exports.ExploreField = ExploreField;
1228
- /**
1229
- * An environment for compiling and running Malloy queries.
1230
- */
1231
- class Runtime {
1232
- constructor(...args) {
1233
- let urlReader;
1234
- let connections;
1235
- for (const arg of args) {
1236
- if (isURLReader(arg)) {
1237
- urlReader = arg;
1238
- }
1239
- else if (isLookupConnection(arg)) {
1240
- connections = arg;
1241
- }
1242
- else {
1243
- connections = {
1244
- lookupConnection: () => Promise.resolve(arg),
1245
- };
1246
- }
1247
- }
1248
- if (urlReader === undefined) {
1249
- urlReader = new EmptyURLReader();
1250
- }
1251
- if (connections === undefined) {
1252
- throw new Error("A LookupConnection<Connection> or Connection is required.");
1253
- }
1254
- this._urlReader = urlReader;
1255
- this._connections = connections;
1256
- }
1257
- /**
1258
- * @returns The `URLReader` for this runtime instance.
1259
- */
1260
- get urlReader() {
1261
- return this._urlReader;
1262
- }
1263
- /**
1264
- * @returns The `LookupConnection<Connection>` for this runtime instance.
1265
- */
1266
- get connections() {
1267
- return this._connections;
1268
- }
1269
- /**
1270
- * Load a Malloy model by URL or contents.
1271
- *
1272
- * @param source The model URL or contents to load and (eventually) compile.
1273
- * @returns A `ModelMaterializer` capable of materializing the requested model,
1274
- * or loading further related objects.
1275
- */
1276
- loadModel(source) {
1277
- return new ModelMaterializer(this, async () => {
1278
- const parse = source instanceof URL
1279
- ? await Malloy.parse({
1280
- url: source,
1281
- urlReader: this.urlReader,
1282
- })
1283
- : Malloy.parse({
1284
- source,
1285
- });
1286
- return Malloy.compile({
1287
- urlReader: this.urlReader,
1288
- connections: this.connections,
1289
- parse,
1290
- });
1291
- });
1292
- }
1293
- // TODO Consider formalizing this. Perhaps as a `withModel` method,
1294
- // as well as a `Model.fromModelDefinition` if we choose to expose
1295
- // `ModelDef` to the world formally. For now, this should only
1296
- // be used in tests.
1297
- _loadModelFromModelDef(modelDef) {
1298
- return new ModelMaterializer(this, async function materialize() {
1299
- return new Model(modelDef, [], []);
1300
- });
1301
- }
1302
- /**
1303
- * Load a Malloy query by URL or contents.
1304
- *
1305
- * @param query The query URL or contents to load and (eventually) compile.
1306
- * @returns A `QueryMaterializer` capable of materializing the requested query, running it,
1307
- * or loading further related objects.
1308
- */
1309
- loadQuery(query) {
1310
- return this.loadModel(query).loadFinalQuery();
1311
- }
1312
- /**
1313
- * Load a Malloy query by the URL or contents of a Malloy model document
1314
- * and the index of an unnamed query contained in the model.
1315
- *
1316
- * @param model The model URL or contents to load and (eventually) compile to retrieve the requested query.
1317
- * @param index The index of the query to use within the model.
1318
- * @returns A `QueryMaterializer` capable of materializing the requested query, running it,
1319
- * or loading further related objects.
1320
- */
1321
- loadQueryByIndex(model, index) {
1322
- return this.loadModel(model).loadQueryByIndex(index);
1323
- }
1324
- /**
1325
- * Load a Malloy query by the URL or contents of a Malloy model document
1326
- * and the name of a query contained in the model.
1327
- *
1328
- * @param model The model URL or contents to load and (eventually) compile to retrieve the requested query.
1329
- * @param name The name of the query to use within the model.
1330
- * @returns A `QueryMaterializer` capable of materializing the requested query, running it,
1331
- * or loading further related objects.
1332
- */
1333
- loadQueryByName(model, name) {
1334
- return this.loadModel(model).loadQueryByName(name);
1335
- }
1336
- /**
1337
- * Load a SQL block by the URL or contents of a Malloy model document
1338
- * and the name of a query contained in the model.
1339
- *
1340
- * @param model The model URL or contents to load and (eventually) compile to retrieve the requested query.
1341
- * @param name The name of the sql block to use within the model.
1342
- * @returns A `SQLBlockMaterializer` capable of materializing the requested query, running it,
1343
- * or loading further related objects.
1344
- */
1345
- loadSQLBlockByName(model, name) {
1346
- return this.loadModel(model).loadSQLBlockByName(name);
1347
- }
1348
- /**
1349
- * Load a SQL block by the URL or contents of a Malloy model document
1350
- * and the name of a query contained in the model.
1351
- *
1352
- * @param model The model URL or contents to load and (eventually) compile to retrieve the requested query.
1353
- * @param index The index of the SQL block to use within the model. Note: named blocks are indexable, too.
1354
- * @returns A `SQLBlockMaterializer` capable of materializing the requested query, running it,
1355
- * or loading further related objects.
1356
- */
1357
- loadSQLBlockByIndex(model, index) {
1358
- return this.loadModel(model).loadSQLBlockByIndex(index);
1359
- }
1360
- // TODO maybe use overloads for the alternative parameters
1361
- /**
1362
- * Compile a Malloy model by URL or contents.
1363
- *
1364
- * @param source The URL or contents of a Malloy model document to compile.
1365
- * @returns A promise of a compiled `Model`.
1366
- */
1367
- getModel(source) {
1368
- return this.loadModel(source).getModel();
1369
- }
1370
- /**
1371
- * Compile a Malloy query by URL or contents.
1372
- *
1373
- * @param query The URL or contents of a Malloy query document to compile.
1374
- * @returns A promise of a compiled `PreparedQuery`.
1375
- */
1376
- getQuery(query) {
1377
- return this.loadQuery(query).getPreparedQuery();
1378
- }
1379
- /**
1380
- * Compile a Malloy query by the URL or contents of a model document
1381
- * and the index of an unnamed query contained within the model.
1382
- *
1383
- * @param model The URL or contents of a Malloy model document to compile.
1384
- * @param index The index of an unnamed query contained within the model.
1385
- * @returns A promise of a compiled `PreparedQuery`.
1386
- */
1387
- getQueryByIndex(model, index) {
1388
- return this.loadQueryByIndex(model, index).getPreparedQuery();
1389
- }
1390
- /**
1391
- * Compile a Malloy query by the URL or contents of a model document
1392
- * and the name of a query contained within the model.
1393
- *
1394
- * @param model The URL or contents of a Malloy model document to compile.
1395
- * @param name The name of a query contained within the model.
1396
- * @returns A promise of a compiled `PreparedQuery`.
1397
- */
1398
- getQueryByName(model, name) {
1399
- return this.loadQueryByName(model, name).getPreparedQuery();
1400
- }
1401
- /**
1402
- * Get a SQL block by the URL or contents of a Malloy model document
1403
- * and the name of a SQL block contained in the model.
1404
- *
1405
- * @param model The model URL or contents to load and (eventually) compile to retrieve the requested query.
1406
- * @param name The name of the sql block to use within the model.
1407
- * @returns A promise of a `SQLBlock`.
1408
- */
1409
- getSQLBlockByName(model, name) {
1410
- return this.loadSQLBlockByName(model, name).getSQLBlock();
1411
- }
1412
- /**
1413
- * Get a SQL block by the URL or contents of a Malloy model document
1414
- * and the name of a query contained in the model.
1415
- *
1416
- * @param model The model URL or contents to load and (eventually) compile to retrieve the requested query.
1417
- * @param index The index of the SQL block to use within the model. Note: named blocks are indexable, too.
1418
- * @returns A promise of a `SQLBlock`.
1419
- */
1420
- getSQLBlockByIndex(model, index) {
1421
- return this.loadSQLBlockByIndex(model, index).getSQLBlock();
1422
- }
1423
- }
1424
- exports.Runtime = Runtime;
1425
- class ConnectionRuntime extends Runtime {
1426
- constructor(urlsOrConnections, maybeConnections) {
1427
- if (maybeConnections === undefined) {
1428
- const connections = urlsOrConnections;
1429
- super(FixedConnectionMap.fromArray(connections));
1430
- this.rawConnections = connections;
1431
- }
1432
- else {
1433
- const connections = maybeConnections;
1434
- super(urlsOrConnections, FixedConnectionMap.fromArray(connections));
1435
- this.rawConnections = connections;
1436
- }
1437
- }
1438
- }
1439
- exports.ConnectionRuntime = ConnectionRuntime;
1440
- class SingleConnectionRuntime extends Runtime {
1441
- constructor(urlsOrConnections, maybeConnections) {
1442
- if (maybeConnections === undefined) {
1443
- const connection = urlsOrConnections;
1444
- super(connection);
1445
- this.connection = connection;
1446
- }
1447
- else {
1448
- const connection = maybeConnections;
1449
- super(urlsOrConnections, connection);
1450
- this.connection = connection;
1451
- }
1452
- }
1453
- }
1454
- exports.SingleConnectionRuntime = SingleConnectionRuntime;
1455
- class FluentState {
1456
- constructor(runtime, materialize) {
1457
- this.runtime = runtime;
1458
- this._materialize = materialize;
1459
- }
1460
- materialize() {
1461
- if (this.materialized === undefined) {
1462
- return this.rematerialize();
1463
- }
1464
- return this.materialized;
1465
- }
1466
- rematerialize() {
1467
- this.materialized = this._materialize();
1468
- return this.materialized;
1469
- }
1470
- makeQueryMaterializer(materialize) {
1471
- return new QueryMaterializer(this.runtime, materialize);
1472
- }
1473
- makeExploreMaterializer(materialize) {
1474
- return new ExploreMaterializer(this.runtime, materialize);
1475
- }
1476
- makePreparedResultMaterializer(materialize) {
1477
- return new PreparedResultMaterializer(this.runtime, materialize);
1478
- }
1479
- makeSQLBlockMaterializer(materialize) {
1480
- return new SQLBlockMaterializer(this.runtime, materialize);
1481
- }
1482
- }
1483
- /**
1484
- * An object representing the task of loading a `Model`, capable of
1485
- * materializing that model (via `getModel()`) or extending the task to load
1486
- * queries or explores (via e.g. `loadFinalQuery()`, `loadQuery`, `loadExploreByName`, etc.).
1487
- */
1488
- class ModelMaterializer extends FluentState {
1489
- /**
1490
- * Load the final (unnamed) Malloy query contained within this loaded `Model`.
1491
- *
1492
- * @returns A `QueryMaterializer` capable of materializing the requested query, running it,
1493
- * or loading further related objects.
1494
- */
1495
- loadFinalQuery() {
1496
- return this.makeQueryMaterializer(async () => {
1497
- return (await this.materialize()).preparedQuery;
1498
- });
1499
- }
1500
- /**
1501
- * Load an unnamed query contained within this loaded `Model` by index.
1502
- *
1503
- * @param index The index of the query to load.
1504
- * @returns A `QueryMaterializer` capable of materializing the requested query, running it,
1505
- * or loading further related objects.
1506
- */
1507
- loadQueryByIndex(index) {
1508
- return this.makeQueryMaterializer(async () => {
1509
- return (await this.materialize()).getPreparedQueryByIndex(index);
1510
- });
1511
- }
1512
- /**
1513
- * Load a query contained within this loaded `Model` by its name.
1514
- *
1515
- * @param name The name of the query to load.
1516
- * @returns A `QueryMaterializer` capable of materializing the requested query, running it,
1517
- * or loading further related objects.
1518
- */
1519
- loadQueryByName(name) {
1520
- return this.makeQueryMaterializer(async () => {
1521
- return (await this.materialize()).getPreparedQueryByName(name);
1522
- });
1523
- }
1524
- /**
1525
- * Load a query against this loaded `Model` by its URL or contents.
1526
- *
1527
- * @param query The URL or contents of the query to load and (eventually) compile.
1528
- * @returns A `QueryMaterializer` capable of materializing the requested query, running it,
1529
- * or loading further related objects.
1530
- */
1531
- loadQuery(query) {
1532
- return this.makeQueryMaterializer(async () => {
1533
- const urlReader = this.runtime.urlReader;
1534
- const connections = this.runtime.connections;
1535
- const parse = query instanceof URL
1536
- ? await Malloy.parse({
1537
- url: query,
1538
- urlReader,
1539
- })
1540
- : Malloy.parse({
1541
- source: query,
1542
- });
1543
- const model = await this.getModel();
1544
- const queryModel = await Malloy.compile({
1545
- urlReader,
1546
- connections,
1547
- parse,
1548
- model,
1549
- });
1550
- return queryModel.preparedQuery;
1551
- });
1552
- }
1553
- async search(sourceName, searchTerm, limit = 1000, searchField = undefined) {
1554
- const model = await this.materialize();
1555
- const queryModel = new model_1.QueryModel(model._modelDef);
1556
- const schema = model.getExploreByName(sourceName).structDef;
1557
- if (schema.structRelationship.type !== "basetable") {
1558
- throw new Error("Expected schema's structRelationship type to be 'basetable'.");
1559
- }
1560
- const connectionName = schema.structRelationship.connectionName;
1561
- const connection = await this.runtime.connections.lookupConnection(connectionName);
1562
- return await queryModel.searchIndex(connection, sourceName, searchTerm, limit, searchField);
1563
- }
1564
- async searchValueMap(sourceName, limit = 10) {
1565
- const model = await this.materialize();
1566
- const schema = model.getExploreByName(sourceName);
1567
- if (schema.structDef.structRelationship.type !== "basetable") {
1568
- throw new Error("Expected schema's structRelationship type to be 'basetable'.");
1569
- }
1570
- let indexQuery = "{index: *}";
1571
- if (schema.getFieldByNameIfExists("search_index")) {
1572
- indexQuery = "search_index";
1573
- }
1574
- const searchMapMalloy = `
1575
- query: ${sourceName}
1576
- -> ${indexQuery}
1577
- -> {
1578
- where: fieldType = 'string'
1579
- group_by: fieldName
1580
- aggregate: cardinality is count(distinct fieldValue)
1581
- nest: values is {
1582
- project: fieldValue, weight
1583
- order_by: weight desc
1584
- limit: ${limit}
1585
- }
1586
- limit: 1000
1587
- }
1588
- `;
1589
- const result = await this.loadQuery(searchMapMalloy).run({
1590
- rowLimit: 1000,
1591
- });
1592
- return result._queryResult.result;
1593
- }
1594
- /**
1595
- * Load a SQL Block by name.
1596
- *
1597
- * @param name The name of the SQL Block to load.
1598
- * @returns A `SQLBlockMaterializer` capable of materializing the requested sql block, running it,
1599
- * or loading further related objects.
1600
- */
1601
- loadSQLBlockByName(name) {
1602
- return this.makeSQLBlockMaterializer(async () => {
1603
- return (await this.materialize()).getSQLBlockByName(name);
1604
- });
1605
- }
1606
- /**
1607
- * Load a SQL Block by index.
1608
- *
1609
- * @param index The index of the SQL Block to load. Note: named SQL blocks are indexable, too.
1610
- * @returns A `SQLBlockMaterializer` capable of materializing the requested sql block, running it,
1611
- * or loading further related objects.
1612
- *
1613
- * TODO feature-sql-block Should named SQL blocks be indexable? This is not the way unnamed queries work.
1614
- */
1615
- loadSQLBlockByIndex(index) {
1616
- return this.makeSQLBlockMaterializer(async () => {
1617
- return (await this.materialize()).getSQLBlockByIndex(index);
1618
- });
1619
- }
1620
- /**
1621
- * Materialize the final query contained within this loaded `Model`.
1622
- *
1623
- * @returns A promise to a prepared query.
1624
- */
1625
- getFinalQuery() {
1626
- return this.loadFinalQuery().getPreparedQuery();
1627
- }
1628
- /**
1629
- * Materialize an unnamed query contained within this loaded `Model` by index.
1630
- *
1631
- * @param index The index of the query contained within this loaded `Model`.
1632
- * @returns A promise to a prepared query.
1633
- */
1634
- getQueryByIndex(index) {
1635
- return this.loadQueryByIndex(index).getPreparedQuery();
1636
- }
1637
- /**
1638
- * Materialize a query contained within this loaded `Model` by name.
1639
- *
1640
- * @param name The name of the query contained within this loaded `Model`.
1641
- * @returns A promise to a prepared query.
1642
- */
1643
- getQueryByName(name) {
1644
- return this.loadQueryByName(name).getPreparedQuery();
1645
- }
1646
- /**
1647
- * Materialize a query against this loaded `Model` by its URL or contents.
1648
- *
1649
- * @param query The URL or contents of a query document to compile.
1650
- * @returns A promise to a prepared query.
1651
- */
1652
- getQuery(query) {
1653
- return this.loadQuery(query).getPreparedQuery();
1654
- }
1655
- /**
1656
- * Get a SQL Block by name.
1657
- *
1658
- * @param name The name of the SQL Block to load.
1659
- * @returns A promise of a `SQLBlock`.
1660
- */
1661
- getSQLBlockByName(name) {
1662
- return this.loadSQLBlockByName(name).getSQLBlock();
1663
- }
1664
- /**
1665
- * Get a SQL Block by index.
1666
- *
1667
- * @param index The index of the SQL Block to load. Note: named SQL blocks are indexable, too.
1668
- * @returns A promise of a `SQLBlock`.
1669
- *
1670
- * TODO feature-sql-block Should named SQL blocks be indexable? This is not the way unnamed queries work.
1671
- */
1672
- getSQLBlockByIndex(index) {
1673
- return this.loadSQLBlockByIndex(index).getSQLBlock();
1674
- }
1675
- // TODO Consider formalizing this. Perhaps as a `withQuery` method,
1676
- // as well as a `PreparedQuery.fromQueryDefinition` if we choose to expose
1677
- // `InternalQuery` to the world formally. For now, this should only
1678
- // be used in tests.
1679
- _loadQueryFromQueryDef(query) {
1680
- return this.makeQueryMaterializer(async () => {
1681
- const model = await this.materialize();
1682
- return new PreparedQuery(query, model._modelDef);
1683
- });
1684
- }
1685
- /**
1686
- * Load an explore contained within this loaded `Model` by name.
1687
- *
1688
- * @param name The name of the explore contained within this loaded `Model`.
1689
- * @returns An `ExploreMaterializer` capable of materializing the requested explore,
1690
- * or loading further related objects.
1691
- */
1692
- loadExploreByName(name) {
1693
- return this.makeExploreMaterializer(async () => {
1694
- return (await this.materialize()).getExploreByName(name);
1695
- });
1696
- }
1697
- /**
1698
- * Materialize an explore contained within this loaded `Model` by its name.
1699
- *
1700
- * @param query The name of an explore within this loaded `Model`.
1701
- * @returns A promise to an explore.
1702
- */
1703
- getExploreByName(name) {
1704
- return this.loadExploreByName(name).getExplore();
1705
- }
1706
- /**
1707
- * Compile and materialize this loaded `Model`.
1708
- *
1709
- * @returns A promise to the compiled model that is loaded.
1710
- */
1711
- getModel() {
1712
- return this.materialize();
1713
- }
1714
- }
1715
- exports.ModelMaterializer = ModelMaterializer;
1716
- /**
1717
- * An object representing the task of loading a `Query`, capable of
1718
- * materializing the query (via `getPreparedQuery()`) or extending the task to load
1719
- * prepared results or run the query (via e.g. `loadPreparedResult()` or `run()`).
1720
- */
1721
- class QueryMaterializer extends FluentState {
1722
- /**
1723
- * Run this loaded `Query`.
1724
- *
1725
- * @returns The query results from running this loaded query.
1726
- */
1727
- async run(options) {
1728
- const connections = this.runtime.connections;
1729
- const preparedResult = await this.getPreparedResult();
1730
- return Malloy.run({ connections, preparedResult, options });
1731
- }
1732
- async *runStream(options) {
1733
- const preparedResult = await this.getPreparedResult();
1734
- const connections = this.runtime.connections;
1735
- const stream = Malloy.runStream({ connections, preparedResult, options });
1736
- for await (const row of stream) {
1737
- yield row;
1738
- }
1739
- }
1740
- /**
1741
- * Load the prepared result of this loaded query.
1742
- *
1743
- * @returns A `PreparedResultMaterializer` capable of materializing the requested
1744
- * prepared query or running it.
1745
- */
1746
- loadPreparedResult() {
1747
- return this.makePreparedResultMaterializer(async () => {
1748
- return (await this.materialize()).preparedResult;
1749
- });
1750
- }
1751
- /**
1752
- * Materialize the prepared result of this loaded query.
1753
- *
1754
- * @returns A promise of the prepared result of this loaded query.
1755
- */
1756
- getPreparedResult() {
1757
- return this.loadPreparedResult().getPreparedResult();
1758
- }
1759
- /**
1760
- * Materialize the SQL of this loaded query.
1761
- *
1762
- * @returns A promise of the SQL string.
1763
- */
1764
- async getSQL() {
1765
- return (await this.getPreparedResult()).sql;
1766
- }
1767
- /**
1768
- * Materialize this loaded query.
1769
- *
1770
- * @returns A promise of the `PreparedQuery`.
1771
- */
1772
- getPreparedQuery() {
1773
- return this.materialize();
1774
- }
1775
- }
1776
- exports.QueryMaterializer = QueryMaterializer;
1777
- /**
1778
- * An object representing the task of loading a `PreparedResult`, capable of
1779
- * materializing the prepared result (via `getPreparedResult()`) or extending the task run
1780
- * the query.
1781
- */
1782
- class PreparedResultMaterializer extends FluentState {
1783
- /**
1784
- * Run this prepared result.
1785
- *
1786
- * @returns A promise to the query result data.
1787
- */
1788
- async run(options) {
1789
- const preparedResult = await this.getPreparedResult();
1790
- const connections = this.runtime.connections;
1791
- return Malloy.run({ connections, preparedResult, options });
1792
- }
1793
- async *runStream(options) {
1794
- const preparedResult = await this.getPreparedResult();
1795
- const connections = this.runtime.connections;
1796
- const stream = Malloy.runStream({ connections, preparedResult, options });
1797
- for await (const row of stream) {
1798
- yield row;
1799
- }
1800
- }
1801
- /**
1802
- * Materialize this loaded prepared result.
1803
- *
1804
- * @returns A promise of a prepared result.
1805
- */
1806
- getPreparedResult() {
1807
- return this.materialize();
1808
- }
1809
- /**
1810
- * Materialize the SQL of this loaded prepared result.
1811
- *
1812
- * @returns A promise to the SQL string.
1813
- */
1814
- async getSQL() {
1815
- return (await this.getPreparedResult()).sql;
1816
- }
1817
- }
1818
- exports.PreparedResultMaterializer = PreparedResultMaterializer;
1819
- /**
1820
- * An object representing the task of loading a `SQLBlock`, capable of
1821
- * materializing the SQLBlock (via `getSQLBlock()`) or extending the task run
1822
- * the query.
1823
- */
1824
- class SQLBlockMaterializer extends FluentState {
1825
- /**
1826
- * Run this SQL block.
1827
- *
1828
- * @returns A promise to the query result data.
1829
- */
1830
- async run(options) {
1831
- const sqlBlock = await this.getSQLBlock();
1832
- const connections = this.runtime.connections;
1833
- return Malloy.run({
1834
- connections,
1835
- sqlBlock,
1836
- options,
1837
- });
1838
- }
1839
- async *runStream(options) {
1840
- const sqlBlock = await this.getSQLBlock();
1841
- const connections = this.runtime.connections;
1842
- const stream = Malloy.runStream({ connections, sqlBlock, options });
1843
- for await (const row of stream) {
1844
- yield row;
1845
- }
1846
- }
1847
- /**
1848
- * Materialize this loaded SQL block.
1849
- *
1850
- * @returns A promise of a SQL block.
1851
- */
1852
- getSQLBlock() {
1853
- return this.materialize();
1854
- }
1855
- /**
1856
- * Materialize the SQL of this loaded SQL block.
1857
- *
1858
- * @returns A promise to the SQL string.
1859
- */
1860
- async getSQL() {
1861
- const sqlBlock = await this.getSQLBlock();
1862
- return sqlBlock.select;
1863
- }
1864
- }
1865
- exports.SQLBlockMaterializer = SQLBlockMaterializer;
1866
- /**
1867
- * An object representing the task of loading an `Explore`, capable of
1868
- * materializing the explore (via `getExplore()`) or extending the task to produce
1869
- * related queries.
1870
- */
1871
- class ExploreMaterializer extends FluentState {
1872
- /**
1873
- * Load a query contained within this loaded explore.
1874
- *
1875
- * @param name The name of the query to load.
1876
- * @returns A `QueryMaterializer` capable of materializing the requested query, running it,
1877
- * or loading further related objects.
1878
- */
1879
- loadQueryByName(name) {
1880
- return this.makeQueryMaterializer(async () => {
1881
- return (await this.materialize()).getQueryByName(name);
1882
- });
1883
- }
1884
- /**
1885
- * Materialize a query contained within this loaded explore.
1886
- *
1887
- * @param name The name of the query to materialize.
1888
- * @returns A promise to the requested prepared query.
1889
- */
1890
- getQueryByName(name) {
1891
- return this.loadQueryByName(name).getPreparedQuery();
1892
- }
1893
- /**
1894
- * Materialize this loaded explore.
1895
- *
1896
- * @returns A promise to the compiled `Explore`.
1897
- */
1898
- getExplore() {
1899
- return this.materialize();
1900
- }
1901
- }
1902
- exports.ExploreMaterializer = ExploreMaterializer;
1903
- /**
1904
- * The result of running a Malloy query.
1905
- *
1906
- * A `Result` is a `PreparedResult` along with the data retrieved from running the query.
1907
- */
1908
- class Result extends PreparedResult {
1909
- constructor(queryResult, modelDef) {
1910
- super(queryResult, modelDef);
1911
- this.inner = queryResult;
1912
- }
1913
- get _queryResult() {
1914
- return this.inner;
1915
- }
1916
- /**
1917
- * @returns The result data.
1918
- */
1919
- get data() {
1920
- return new DataArray(this.inner.result, this.resultExplore, undefined);
1921
- }
1922
- get totalRows() {
1923
- return this.inner.totalRows;
1924
- }
1925
- toJSON() {
1926
- return { queryResult: this.inner, modelDef: this._modelDef };
1927
- }
1928
- static fromJSON({ queryResult, modelDef }) {
1929
- return new Result(queryResult, modelDef);
1930
- }
1931
- }
1932
- exports.Result = Result;
1933
- class Data {
1934
- constructor(field) {
1935
- this._field = field;
1936
- }
1937
- get field() {
1938
- return this._field;
1939
- }
1940
- isString() {
1941
- return this instanceof DataString;
1942
- }
1943
- get string() {
1944
- if (this.isString()) {
1945
- return this;
1946
- }
1947
- throw new Error("Not a string.");
1948
- }
1949
- isBoolean() {
1950
- return this instanceof DataBoolean;
1951
- }
1952
- get boolean() {
1953
- if (this.isBoolean()) {
1954
- return this;
1955
- }
1956
- throw new Error("Not a boolean.");
1957
- }
1958
- isNumber() {
1959
- return this instanceof DataNumber;
1960
- }
1961
- get number() {
1962
- if (this.isNumber()) {
1963
- return this;
1964
- }
1965
- throw new Error("Not a number.");
1966
- }
1967
- isTimestamp() {
1968
- return this instanceof DataTimestamp;
1969
- }
1970
- get timestamp() {
1971
- if (this.isTimestamp()) {
1972
- return this;
1973
- }
1974
- throw new Error("Not a timestamp.");
1975
- }
1976
- isDate() {
1977
- return this instanceof DataDate;
1978
- }
1979
- get date() {
1980
- if (this.isDate()) {
1981
- return this;
1982
- }
1983
- throw new Error("Not a date.");
1984
- }
1985
- isNull() {
1986
- return this instanceof DataNull;
1987
- }
1988
- isBytes() {
1989
- return this instanceof DataBytes;
1990
- }
1991
- get bytes() {
1992
- if (this.isBytes()) {
1993
- return this;
1994
- }
1995
- throw new Error("Not bytes.");
1996
- }
1997
- isRecord() {
1998
- return this instanceof DataRecord;
1999
- }
2000
- get record() {
2001
- if (this.isRecord()) {
2002
- return this;
2003
- }
2004
- throw new Error("Not a record.");
2005
- }
2006
- isArray() {
2007
- return this instanceof DataArray;
2008
- }
2009
- get array() {
2010
- if (this.isArray()) {
2011
- return this;
2012
- }
2013
- throw new Error("Not an array.");
2014
- }
2015
- isArrayOrRecord() {
2016
- if (this instanceof DataArray || this instanceof DataRecord) {
2017
- return this;
2018
- }
2019
- throw new Error("No Array or Record");
2020
- }
2021
- }
2022
- class ScalarData extends Data {
2023
- constructor(value, field) {
2024
- super(field);
2025
- this._value = value;
2026
- this._field = field;
2027
- }
2028
- get value() {
2029
- return this._value;
2030
- }
2031
- get field() {
2032
- return this._field;
2033
- }
2034
- }
2035
- class DataString extends ScalarData {
2036
- constructor(value, field) {
2037
- super(value, field);
2038
- this._field = field;
2039
- }
2040
- get field() {
2041
- return this._field;
2042
- }
2043
- }
2044
- class DataBoolean extends ScalarData {
2045
- constructor(value, field) {
2046
- super(value, field);
2047
- this._field = field;
2048
- }
2049
- get field() {
2050
- return this._field;
2051
- }
2052
- }
2053
- class DataNumber extends ScalarData {
2054
- constructor(value, field) {
2055
- super(value, field);
2056
- this._field = field;
2057
- }
2058
- get field() {
2059
- return this._field;
2060
- }
2061
- }
2062
- class DataTimestamp extends ScalarData {
2063
- constructor(value, field) {
2064
- super(value, field);
2065
- this._field = field;
2066
- }
2067
- get value() {
2068
- // TODO properly map the data from BQ/Postgres types
2069
- if (this._value instanceof Date) {
2070
- return this._value;
2071
- }
2072
- else if (typeof this._value === "number") {
2073
- return new Date(super.value);
2074
- }
2075
- else if (typeof this._value !== "string") {
2076
- return new Date(this._value.value);
2077
- }
2078
- else {
2079
- return new Date(super.value);
2080
- }
2081
- }
2082
- get field() {
2083
- return this._field;
2084
- }
2085
- }
2086
- class DataDate extends ScalarData {
2087
- constructor(value, field) {
2088
- super(value, field);
2089
- this._field = field;
2090
- }
2091
- get value() {
2092
- // TODO properly map the data from BQ/Postgres types
2093
- if (this._value instanceof Date) {
2094
- return this._value;
2095
- }
2096
- else if (typeof this._value !== "string") {
2097
- return new Date(this._value.value);
2098
- }
2099
- else {
2100
- return new Date(super.value);
2101
- }
2102
- }
2103
- get field() {
2104
- return this._field;
2105
- }
2106
- }
2107
- class DataBytes extends ScalarData {
2108
- }
2109
- class DataNull extends Data {
2110
- get value() {
2111
- return null;
2112
- }
2113
- }
2114
- class DataArray extends Data {
2115
- constructor(queryData, field, parent) {
2116
- super(field);
2117
- this.parent = parent;
2118
- this.queryData = queryData;
2119
- this._field = field;
2120
- }
2121
- /**
2122
- * @returns The `Explore` that describes the structure of this data.
2123
- */
2124
- get field() {
2125
- return this._field;
2126
- }
2127
- /**
2128
- * @returns The raw object form of the data.
2129
- */
2130
- toObject() {
2131
- return this.queryData;
2132
- }
2133
- path(...path) {
2134
- return getPath(this, path);
2135
- }
2136
- row(index) {
2137
- return new DataRecord(this.queryData[index], index, this.field, this);
2138
- }
2139
- get rowCount() {
2140
- return this.queryData.length;
2141
- }
2142
- get value() {
2143
- return this.toObject();
2144
- }
2145
- [Symbol.iterator]() {
2146
- let currentIndex = 0;
2147
- const queryData = this.queryData;
2148
- const getRow = (index) => this.row(index);
2149
- return {
2150
- next() {
2151
- if (currentIndex < queryData.length) {
2152
- return { value: getRow(currentIndex++), done: false };
2153
- }
2154
- else {
2155
- return { value: undefined, done: true };
2156
- }
2157
- },
2158
- };
2159
- }
2160
- async *inMemoryStream() {
2161
- for (let i = 0; i < this.queryData.length; i++) {
2162
- yield this.row(i);
2163
- }
2164
- }
2165
- }
2166
- exports.DataArray = DataArray;
2167
- function getPath(data, path) {
2168
- for (const segment of path) {
2169
- if (typeof segment === "number") {
2170
- data = data.array.row(segment);
2171
- }
2172
- else {
2173
- data = data.record.cell(segment);
2174
- }
2175
- }
2176
- return data;
2177
- }
2178
- class DataRecord extends Data {
2179
- constructor(queryDataRow, index, field, parent) {
2180
- super(field);
2181
- this.parent = parent;
2182
- this.queryDataRow = queryDataRow;
2183
- this._field = field;
2184
- this.index = index;
2185
- }
2186
- toObject() {
2187
- return this.queryDataRow;
2188
- }
2189
- path(...path) {
2190
- return getPath(this, path);
2191
- }
2192
- cell(fieldOrName) {
2193
- const fieldName = typeof fieldOrName === "string" ? fieldOrName : fieldOrName.name;
2194
- const field = this._field.getFieldByName(fieldName);
2195
- const value = this.queryDataRow[fieldName];
2196
- if (value === null) {
2197
- return new DataNull(field);
2198
- }
2199
- if (field.isAtomicField()) {
2200
- if (field.isBoolean()) {
2201
- return new DataBoolean(value, field);
2202
- }
2203
- else if (field.isDate()) {
2204
- return new DataDate(value, field);
2205
- }
2206
- else if (field.isTimestamp()) {
2207
- return new DataTimestamp(value, field);
2208
- }
2209
- else if (field.isNumber()) {
2210
- return new DataNumber(value, field);
2211
- }
2212
- else if (field.isString()) {
2213
- return new DataString(value, field);
2214
- }
2215
- }
2216
- else if (field.isExploreField()) {
2217
- if (Array.isArray(value)) {
2218
- return new DataArray(value, field, this);
2219
- }
2220
- else {
2221
- return new DataRecord(value, undefined, field, this);
2222
- }
2223
- }
2224
- throw new Error(`Internal Error: could not construct data column for field '${fieldName}'.`);
2225
- }
2226
- get value() {
2227
- throw new Error("Not implemented;");
2228
- }
2229
- // Non repeating values show up as DataRecords
2230
- get field() {
2231
- return this._field;
2232
- }
2233
- // Allow iteration over non repeating values to simplify end user code.
2234
- [Symbol.iterator]() {
2235
- let returned = false;
2236
- const getSelf = () => {
2237
- return this;
2238
- };
2239
- return {
2240
- next() {
2241
- if (!returned) {
2242
- returned = true;
2243
- return {
2244
- value: getSelf(),
2245
- done: false,
2246
- };
2247
- }
2248
- else {
2249
- return { value: undefined, done: true };
2250
- }
2251
- },
2252
- };
2253
- }
2254
- }
2255
- exports.DataRecord = DataRecord;
2256
- function isURLReader(thing) {
2257
- return "readURL" in thing;
2258
- }
2259
- function isLookupConnection(thing) {
2260
- return "lookupConnection" in thing;
2261
- }
2262
- class DataWriter {
2263
- constructor(stream) {
2264
- this.stream = stream;
2265
- }
2266
- }
2267
- exports.DataWriter = DataWriter;
2268
- class JSONWriter extends DataWriter {
2269
- async process(data) {
2270
- this.stream.write("[\n");
2271
- for await (const row of data) {
2272
- if (row.index !== undefined && row.index > 0) {
2273
- this.stream.write(",\n");
2274
- }
2275
- const json = JSON.stringify(row.toObject(), null, 2);
2276
- const jsonLines = json.split("\n");
2277
- for (let i = 0; i < jsonLines.length; i++) {
2278
- const line = jsonLines[i];
2279
- this.stream.write(` ${line}`);
2280
- if (i < jsonLines.length - 1) {
2281
- this.stream.write("\n");
2282
- }
2283
- }
2284
- }
2285
- this.stream.write("\n]\n");
2286
- this.stream.close();
2287
- }
2288
- }
2289
- exports.JSONWriter = JSONWriter;
2290
- class CSVWriter extends DataWriter {
2291
- constructor() {
2292
- super(...arguments);
2293
- this.columnSeparator = ",";
2294
- this.rowSeparator = "\n";
2295
- this.quoteCharacter = '"';
2296
- this.includeHeader = true;
2297
- }
2298
- escape(value) {
2299
- const hasInnerQuote = value.includes(this.quoteCharacter);
2300
- const hasInnerCommas = value.includes(this.columnSeparator);
2301
- const hasNewline = value.includes(this.rowSeparator);
2302
- const needsQuoting = hasInnerCommas || hasInnerQuote || hasNewline;
2303
- if (hasInnerQuote) {
2304
- value = value.replace(new RegExp(this.quoteCharacter, "g"), this.quoteCharacter + this.quoteCharacter);
2305
- }
2306
- if (needsQuoting) {
2307
- value = this.quoteCharacter + value + this.quoteCharacter;
2308
- }
2309
- return value;
2310
- }
2311
- stringify(cell) {
2312
- if (cell.isNull()) {
2313
- return "";
2314
- }
2315
- else if (cell.isArray() ||
2316
- cell.isRecord() ||
2317
- cell.isBoolean() ||
2318
- cell.isNumber()) {
2319
- return JSON.stringify(cell.value);
2320
- }
2321
- else if (cell.isDate() || cell.isTimestamp()) {
2322
- return cell.value.toISOString();
2323
- }
2324
- else if (cell.isString()) {
2325
- return cell.value;
2326
- }
2327
- else {
2328
- return `${cell.value}`;
2329
- }
2330
- }
2331
- async process(data) {
2332
- let fields;
2333
- for await (const row of data) {
2334
- if (fields === undefined) {
2335
- fields = row.field.allFields;
2336
- if (this.includeHeader) {
2337
- for (let fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
2338
- const field = fields[fieldIndex];
2339
- this.stream.write(this.escape(field.name));
2340
- if (fieldIndex !== fields.length - 1) {
2341
- this.stream.write(this.columnSeparator);
2342
- }
2343
- }
2344
- this.stream.write(this.rowSeparator);
2345
- }
2346
- }
2347
- for (let fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
2348
- const field = fields[fieldIndex];
2349
- this.stream.write(this.escape(this.stringify(row.cell(field))));
2350
- if (fieldIndex !== fields.length - 1) {
2351
- this.stream.write(this.columnSeparator);
2352
- }
2353
- }
2354
- this.stream.write(this.rowSeparator);
2355
- }
2356
- this.stream.close();
2357
- }
2358
- }
2359
- exports.CSVWriter = CSVWriter;
2360
- //# sourceMappingURL=malloy.js.map