@malloydata/malloy 0.0.240-dev250311155207 → 0.0.240-dev250311202829
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.
- package/dist/api/asynchronous.js +4 -4
- package/dist/api/asynchronous.spec.js +6 -4
- package/dist/api/connection.d.ts +1 -1
- package/dist/api/core.d.ts +1 -0
- package/dist/api/core.js +28 -1
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +6 -1
- package/dist/api/sessioned.js +1 -2
- package/dist/api/stateless.spec.js +6 -0
- package/dist/api/util.d.ts +9 -0
- package/dist/api/util.js +215 -0
- package/dist/index.d.ts +1 -1
- package/dist/malloy.d.ts +1 -1
- package/dist/malloy.js +1 -5
- package/dist/model/malloy_query.d.ts +1 -0
- package/dist/model/malloy_query.js +6 -2
- package/dist/to_stable.d.ts +2 -1
- package/dist/to_stable.js +34 -3
- package/package.json +3 -3
package/dist/api/asynchronous.js
CHANGED
|
@@ -121,7 +121,7 @@ async function compileModel(request, fetchers) {
|
|
|
121
121
|
// eslint-disable-next-line no-constant-condition
|
|
122
122
|
while (true) {
|
|
123
123
|
const result = Core.statedCompileModel(state);
|
|
124
|
-
if (result.model) {
|
|
124
|
+
if (result.model || Core.hasErrors(result.logs)) {
|
|
125
125
|
return result;
|
|
126
126
|
}
|
|
127
127
|
const needs = await fetchNeeds(result.compiler_needs, fetchers);
|
|
@@ -134,7 +134,7 @@ async function compileSource(request, fetchers) {
|
|
|
134
134
|
// eslint-disable-next-line no-constant-condition
|
|
135
135
|
while (true) {
|
|
136
136
|
const result = Core.statedCompileSource(state, request.name);
|
|
137
|
-
if (result.source) {
|
|
137
|
+
if (result.source || Core.hasErrors(result.logs)) {
|
|
138
138
|
return result;
|
|
139
139
|
}
|
|
140
140
|
const needs = await fetchNeeds(result.compiler_needs, fetchers);
|
|
@@ -147,7 +147,7 @@ async function compileQuery(request, fetchers) {
|
|
|
147
147
|
// eslint-disable-next-line no-constant-condition
|
|
148
148
|
while (true) {
|
|
149
149
|
const result = Core.statedCompileQuery(state);
|
|
150
|
-
if (result.result) {
|
|
150
|
+
if (result.result || Core.hasErrors(result.logs)) {
|
|
151
151
|
return result;
|
|
152
152
|
}
|
|
153
153
|
const needs = await fetchNeeds(result.compiler_needs, fetchers);
|
|
@@ -177,7 +177,7 @@ async function runQuery(request, fetchers) {
|
|
|
177
177
|
}
|
|
178
178
|
try {
|
|
179
179
|
const connection = await fetchers.connections.lookupConnection(compiled.result.connection_name);
|
|
180
|
-
const data = await connection.runSQL(compiled.result.sql);
|
|
180
|
+
const data = await connection.runSQL(compiled.result.sql, compiled.result.schema);
|
|
181
181
|
return {
|
|
182
182
|
...compiled,
|
|
183
183
|
result: {
|
|
@@ -146,13 +146,15 @@ ORDER BY 1 asc NULLS LAST
|
|
|
146
146
|
describe('run query', () => {
|
|
147
147
|
test('run query with table dependency', async () => {
|
|
148
148
|
const data = {
|
|
149
|
-
kind: '
|
|
150
|
-
|
|
149
|
+
kind: 'array_cell',
|
|
150
|
+
array_value: [
|
|
151
151
|
{
|
|
152
|
-
|
|
152
|
+
kind: 'record_cell',
|
|
153
|
+
record_value: [{ kind: 'string_cell', string_value: 'WN' }],
|
|
153
154
|
},
|
|
154
155
|
{
|
|
155
|
-
|
|
156
|
+
kind: 'record_cell',
|
|
157
|
+
record_value: [{ kind: 'string_cell', string_value: 'AA' }],
|
|
156
158
|
},
|
|
157
159
|
],
|
|
158
160
|
};
|
package/dist/api/connection.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface InfoConnection {
|
|
|
5
5
|
get dialectName(): string;
|
|
6
6
|
}
|
|
7
7
|
export interface Connection extends InfoConnection {
|
|
8
|
-
runSQL(sql: string): Promise<Malloy.Data>;
|
|
8
|
+
runSQL(sql: string, schema: Malloy.Schema): Promise<Malloy.Data>;
|
|
9
9
|
}
|
|
10
10
|
export interface LookupConnection<T extends InfoConnection> {
|
|
11
11
|
lookupConnection(connectionName?: string): Promise<T>;
|
package/dist/api/core.d.ts
CHANGED
|
@@ -33,5 +33,6 @@ export declare function _statedCompileModel(state: CompileModelState): CompileRe
|
|
|
33
33
|
export declare const DEFAULT_LOG_RANGE: Malloy.DocumentRange;
|
|
34
34
|
export declare function compileModel(request: Malloy.CompileModelRequest, state?: CompileModelState): Malloy.CompileModelResponse;
|
|
35
35
|
export declare function compileSource(request: Malloy.CompileSourceRequest): Malloy.CompileSourceResponse;
|
|
36
|
+
export declare function hasErrors(log: Malloy.LogMessage[] | undefined): boolean;
|
|
36
37
|
export declare function newCompileQueryState(request: Malloy.CompileQueryRequest): CompileModelState;
|
|
37
38
|
export declare function statedCompileQuery(state: CompileModelState): Malloy.CompileQueryResponse;
|
package/dist/api/core.js
CHANGED
|
@@ -29,12 +29,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
29
29
|
return result;
|
|
30
30
|
};
|
|
31
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
-
exports.statedCompileQuery = exports.newCompileQueryState = exports.compileSource = exports.compileModel = exports.DEFAULT_LOG_RANGE = exports._statedCompileModel = exports.statedCompileSource = exports.statedCompileModel = exports.newCompileSourceState = exports.newCompileModelState = exports.updateCompileModelState = exports.compileQuery = void 0;
|
|
32
|
+
exports.statedCompileQuery = exports.newCompileQueryState = exports.hasErrors = exports.compileSource = exports.compileModel = exports.DEFAULT_LOG_RANGE = exports._statedCompileModel = exports.statedCompileSource = exports.statedCompileModel = exports.newCompileSourceState = exports.newCompileModelState = exports.updateCompileModelState = exports.compileQuery = void 0;
|
|
33
33
|
const Malloy = __importStar(require("@malloydata/malloy-interfaces"));
|
|
34
34
|
const lang_1 = require("../lang");
|
|
35
35
|
const model_1 = require("../model");
|
|
36
36
|
const to_stable_1 = require("../to_stable");
|
|
37
37
|
const sql_block_1 = require("../model/sql_block");
|
|
38
|
+
const annotation_1 = require("../annotation");
|
|
39
|
+
const malloy_tag_1 = require("@malloydata/malloy-tag");
|
|
38
40
|
// TODO find where this should go...
|
|
39
41
|
function tableKey(connectionName, tablePath) {
|
|
40
42
|
return `${connectionName}:${tablePath}`;
|
|
@@ -371,6 +373,11 @@ function extractSource(result, name, defaultURL) {
|
|
|
371
373
|
return { compiler_needs: result.compilerNeeds, logs };
|
|
372
374
|
}
|
|
373
375
|
}
|
|
376
|
+
function hasErrors(log) {
|
|
377
|
+
var _a;
|
|
378
|
+
return (_a = log === null || log === void 0 ? void 0 : log.some(m => m.severity === 'error')) !== null && _a !== void 0 ? _a : false;
|
|
379
|
+
}
|
|
380
|
+
exports.hasErrors = hasErrors;
|
|
374
381
|
// Given a StableQueryDef and the URL to a model, run it and return a StableResult
|
|
375
382
|
// Given a StableQueryDef and the URL to a model, compile it and return a StableResultDef
|
|
376
383
|
// Given a StableQueryDef and the URL to a model, validate it and return a list of StableErrors
|
|
@@ -393,6 +400,7 @@ function newCompileQueryState(request) {
|
|
|
393
400
|
}
|
|
394
401
|
exports.newCompileQueryState = newCompileQueryState;
|
|
395
402
|
function statedCompileQuery(state) {
|
|
403
|
+
var _a;
|
|
396
404
|
const result = _statedCompileModel(state);
|
|
397
405
|
// TODO this can expose the internal URL... is there a better way to handle URL-less errors from the compiler?
|
|
398
406
|
const defaultURL = state.translator.sourceURL;
|
|
@@ -415,14 +423,33 @@ function statedCompileQuery(state) {
|
|
|
415
423
|
const index = queries.length - 1;
|
|
416
424
|
const query = result.modelDef.queryList[index];
|
|
417
425
|
const schema = result.model.anonymous_queries[index].schema;
|
|
426
|
+
const annotations = (_a = result.model.anonymous_queries[index].annotations) !== null && _a !== void 0 ? _a : [];
|
|
418
427
|
try {
|
|
419
428
|
const queryModel = new model_1.QueryModel(result.modelDef);
|
|
420
429
|
const translatedQuery = queryModel.compileQuery(query);
|
|
430
|
+
const modelAnnotations = (0, annotation_1.annotationToTaglines)(result.modelDef.annotation).map(l => ({
|
|
431
|
+
value: l,
|
|
432
|
+
}));
|
|
433
|
+
annotations.push({
|
|
434
|
+
value: malloy_tag_1.Tag.withPrefix('#(malloy) ')
|
|
435
|
+
.set(['source_name'], translatedQuery.sourceExplore)
|
|
436
|
+
.toString(),
|
|
437
|
+
});
|
|
438
|
+
if (translatedQuery.queryName) {
|
|
439
|
+
annotations.push({
|
|
440
|
+
value: malloy_tag_1.Tag.withPrefix('#(malloy) ')
|
|
441
|
+
.set(['query_name'], translatedQuery.queryName)
|
|
442
|
+
.toString(),
|
|
443
|
+
});
|
|
444
|
+
}
|
|
421
445
|
return {
|
|
422
446
|
result: {
|
|
423
447
|
sql: translatedQuery.sql,
|
|
424
448
|
schema,
|
|
425
449
|
connection_name: translatedQuery.connectionName,
|
|
450
|
+
annotations: annotations.length > 0 ? annotations : undefined,
|
|
451
|
+
model_annotations: modelAnnotations.length > 0 ? modelAnnotations : undefined,
|
|
452
|
+
query_timezone: translatedQuery.queryTimezone,
|
|
426
453
|
},
|
|
427
454
|
};
|
|
428
455
|
}
|
package/dist/api/index.d.ts
CHANGED
package/dist/api/index.js
CHANGED
|
@@ -22,8 +22,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
26
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
27
|
+
};
|
|
25
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.asynchronous = exports.stateless = exports.sessioned = void 0;
|
|
29
|
+
exports.util = exports.asynchronous = exports.stateless = exports.sessioned = void 0;
|
|
27
30
|
/*
|
|
28
31
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
29
32
|
*
|
|
@@ -33,4 +36,6 @@ exports.asynchronous = exports.stateless = exports.sessioned = void 0;
|
|
|
33
36
|
exports.sessioned = __importStar(require("./sessioned"));
|
|
34
37
|
exports.stateless = __importStar(require("./stateless"));
|
|
35
38
|
exports.asynchronous = __importStar(require("./asynchronous"));
|
|
39
|
+
__exportStar(require("./connection"), exports);
|
|
40
|
+
exports.util = __importStar(require("./util"));
|
|
36
41
|
//# sourceMappingURL=index.js.map
|
package/dist/api/sessioned.js
CHANGED
|
@@ -131,8 +131,7 @@ class SessionManager {
|
|
|
131
131
|
this.sessions.delete(sessionId);
|
|
132
132
|
}
|
|
133
133
|
hasErrors(log) {
|
|
134
|
-
|
|
135
|
-
return (_a = log === null || log === void 0 ? void 0 : log.some(m => m.severity === 'error')) !== null && _a !== void 0 ? _a : false;
|
|
134
|
+
return Core.hasErrors(log);
|
|
136
135
|
}
|
|
137
136
|
compileModel(request, options) {
|
|
138
137
|
const sessionInfo = {
|
|
@@ -269,6 +269,7 @@ describe('api', () => {
|
|
|
269
269
|
const result = (0, stateless_1.compileQuery)({
|
|
270
270
|
model_url: 'file://test.malloy',
|
|
271
271
|
query: {
|
|
272
|
+
annotations: [{ value: '#(test) hello' }],
|
|
272
273
|
definition: {
|
|
273
274
|
kind: 'arrow',
|
|
274
275
|
source_reference: { name: 'flights' },
|
|
@@ -313,6 +314,11 @@ describe('api', () => {
|
|
|
313
314
|
const expected = {
|
|
314
315
|
result: {
|
|
315
316
|
connection_name: 'connection',
|
|
317
|
+
annotations: [
|
|
318
|
+
{ value: '#(test) hello\n' },
|
|
319
|
+
{ value: '#(malloy) ordered_by = [{ carrier = asc }]\n' },
|
|
320
|
+
{ value: '#(malloy) source_name = flights\n' },
|
|
321
|
+
],
|
|
316
322
|
sql: `SELECT \n\
|
|
317
323
|
base."carrier" as "carrier"
|
|
318
324
|
FROM flights as base
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { InfoConnection as LegacyInfoConnection, Connection as LegacyConnection } from '../connection';
|
|
2
|
+
import { Result } from '../malloy';
|
|
3
|
+
import { QueryData } from '../model';
|
|
4
|
+
import { Connection, InfoConnection } from './connection';
|
|
5
|
+
import * as Malloy from '@malloydata/malloy-interfaces';
|
|
6
|
+
export declare function wrapLegacyInfoConnection(connection: LegacyInfoConnection): InfoConnection;
|
|
7
|
+
export declare function wrapLegacyConnection(connection: LegacyConnection): Connection;
|
|
8
|
+
export declare function mapData(data: QueryData, schema: Malloy.Schema): Malloy.Data;
|
|
9
|
+
export declare function wrapResult(result: Result): Malloy.Result;
|
package/dist/api/util.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.wrapResult = exports.mapData = exports.wrapLegacyConnection = exports.wrapLegacyInfoConnection = void 0;
|
|
10
|
+
const malloy_tag_1 = require("@malloydata/malloy-tag");
|
|
11
|
+
const annotation_1 = require("../annotation");
|
|
12
|
+
const to_stable_1 = require("../to_stable");
|
|
13
|
+
const luxon_1 = require("luxon");
|
|
14
|
+
function wrapLegacyInfoConnection(connection) {
|
|
15
|
+
return {
|
|
16
|
+
get dialectName() {
|
|
17
|
+
return connection.dialectName;
|
|
18
|
+
},
|
|
19
|
+
async fetchSchemaForSQLQuery(sql) {
|
|
20
|
+
const result = await connection.fetchSchemaForSQLStruct({ connection: connection.name, selectStr: sql }, {});
|
|
21
|
+
const table = result.structDef;
|
|
22
|
+
if (table === undefined) {
|
|
23
|
+
throw new Error(result.error);
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
fields: (0, to_stable_1.convertFieldInfos)(table, table.fields),
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
async fetchSchemaForTable(tableName) {
|
|
30
|
+
const key = `${connection.name}:${tableName}`;
|
|
31
|
+
const result = await connection.fetchSchemaForTables({ [key]: tableName }, {});
|
|
32
|
+
const table = result.schemas[key];
|
|
33
|
+
if (table === undefined) {
|
|
34
|
+
throw new Error(result.errors[key]);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
fields: (0, to_stable_1.convertFieldInfos)(table, table.fields),
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
exports.wrapLegacyInfoConnection = wrapLegacyInfoConnection;
|
|
43
|
+
function wrapLegacyConnection(connection) {
|
|
44
|
+
return {
|
|
45
|
+
...wrapLegacyInfoConnection(connection),
|
|
46
|
+
runSQL: async (sql, schema) => {
|
|
47
|
+
const result = await connection.runSQL(sql);
|
|
48
|
+
return mapData(result.rows, schema);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
exports.wrapLegacyConnection = wrapLegacyConnection;
|
|
53
|
+
function valueToDate(value) {
|
|
54
|
+
// TODO properly map the data from BQ/Postgres types
|
|
55
|
+
if (value instanceof Date) {
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
+
const valAsAny = value;
|
|
60
|
+
if (valAsAny.constructor.name === 'Date') {
|
|
61
|
+
// For some reason duckdb TSTZ values come back as objects which do not
|
|
62
|
+
// pass "instance of" but do seem date like.
|
|
63
|
+
return new Date(value);
|
|
64
|
+
}
|
|
65
|
+
else if (typeof value === 'number') {
|
|
66
|
+
return new Date(value);
|
|
67
|
+
}
|
|
68
|
+
else if (typeof value !== 'string') {
|
|
69
|
+
return new Date(value.value);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// Postgres timestamps end up here, and ideally we would know the system
|
|
73
|
+
// timezone of the postgres instance to correctly create a Date() object
|
|
74
|
+
// which represents the same instant in time, but we don't have the data
|
|
75
|
+
// flow to implement that. This may be a problem at some future day,
|
|
76
|
+
// so here is a comment, for that day.
|
|
77
|
+
let parsed = luxon_1.DateTime.fromISO(value, { zone: 'UTC' });
|
|
78
|
+
if (!parsed.isValid) {
|
|
79
|
+
parsed = luxon_1.DateTime.fromSQL(value, { zone: 'UTC' });
|
|
80
|
+
}
|
|
81
|
+
return parsed.toJSDate();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function mapData(data, schema) {
|
|
85
|
+
function mapValue(value, field) {
|
|
86
|
+
if (value === null) {
|
|
87
|
+
return { kind: 'null_cell' };
|
|
88
|
+
}
|
|
89
|
+
else if (field.type.kind === 'date_type' ||
|
|
90
|
+
field.type.kind === 'timestamp_type') {
|
|
91
|
+
const time_value = valueToDate(value).toISOString();
|
|
92
|
+
if (field.type.kind === 'date_type') {
|
|
93
|
+
return { kind: 'date_cell', date_value: time_value };
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return { kind: 'timestamp_cell', timestamp_value: time_value };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else if (field.type.kind === 'boolean_type') {
|
|
100
|
+
if (typeof value === 'number') {
|
|
101
|
+
return { kind: 'boolean_cell', boolean_value: value !== 0 };
|
|
102
|
+
}
|
|
103
|
+
if (typeof value !== 'boolean') {
|
|
104
|
+
throw new Error(`Invalid boolean ${value}`);
|
|
105
|
+
}
|
|
106
|
+
return { kind: 'boolean_cell', boolean_value: value };
|
|
107
|
+
}
|
|
108
|
+
else if (field.type.kind === 'number_type') {
|
|
109
|
+
if (typeof value !== 'number') {
|
|
110
|
+
throw new Error(`Invalid number ${value}`);
|
|
111
|
+
}
|
|
112
|
+
return { kind: 'number_cell', number_value: value };
|
|
113
|
+
}
|
|
114
|
+
else if (field.type.kind === 'string_type') {
|
|
115
|
+
if (typeof value !== 'string') {
|
|
116
|
+
throw new Error(`Invalid string ${value}`);
|
|
117
|
+
}
|
|
118
|
+
return { kind: 'string_cell', string_value: value };
|
|
119
|
+
}
|
|
120
|
+
else if (field.type.kind === 'array_type') {
|
|
121
|
+
if (!Array.isArray(value)) {
|
|
122
|
+
throw new Error(`Invalid array ${value}`);
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
kind: 'array_cell',
|
|
126
|
+
array_value: value.map(value => mapValue(value, {
|
|
127
|
+
name: 'array_element',
|
|
128
|
+
type: field.type.element_type,
|
|
129
|
+
})),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
else if (field.type.kind === 'json_type') {
|
|
133
|
+
return { kind: 'json_cell', json_value: JSON.stringify(value) };
|
|
134
|
+
}
|
|
135
|
+
else if (field.type.kind === 'sql_native_type') {
|
|
136
|
+
return { kind: 'sql_native_cell', sql_native_value: JSON.stringify(value) };
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
const type = field.type;
|
|
140
|
+
if (type.kind !== 'record_type') {
|
|
141
|
+
throw new Error(`Invalid record in result ${JSON.stringify(field)}, ${JSON.stringify(value)}`);
|
|
142
|
+
}
|
|
143
|
+
return mapRow(value, {
|
|
144
|
+
kind: 'join',
|
|
145
|
+
relationship: 'many',
|
|
146
|
+
name: 'array_element',
|
|
147
|
+
schema: {
|
|
148
|
+
fields: type.fields.map(f => ({ kind: 'dimension', ...f })),
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function mapRow(row, field) {
|
|
154
|
+
const cells = [];
|
|
155
|
+
for (const f of field.schema.fields) {
|
|
156
|
+
const value = row[f.name];
|
|
157
|
+
if (f.kind !== 'dimension') {
|
|
158
|
+
throw new Error('Invalid result -- expected all fields to be dimensions');
|
|
159
|
+
}
|
|
160
|
+
const cell = mapValue(value, f);
|
|
161
|
+
cells.push(cell);
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
kind: 'record_cell',
|
|
165
|
+
record_value: cells,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
const rootField = {
|
|
169
|
+
kind: 'join',
|
|
170
|
+
schema,
|
|
171
|
+
name: 'root',
|
|
172
|
+
relationship: 'one',
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
kind: 'array_cell',
|
|
176
|
+
array_value: data.map(row => mapRow(row, rootField)),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
exports.mapData = mapData;
|
|
180
|
+
function wrapResult(result) {
|
|
181
|
+
const structs = result._queryResult.structs;
|
|
182
|
+
const struct = structs[structs.length - 1];
|
|
183
|
+
const schema = { fields: (0, to_stable_1.convertFieldInfos)(struct, struct.fields) };
|
|
184
|
+
const annotations = (0, annotation_1.annotationToTaglines)(result.annotation).map(l => ({
|
|
185
|
+
value: l,
|
|
186
|
+
}));
|
|
187
|
+
const metadataAnnot = struct.resultMetadata
|
|
188
|
+
? (0, to_stable_1.getResultStructMetadataAnnotation)(struct, struct.resultMetadata)
|
|
189
|
+
: undefined;
|
|
190
|
+
if (metadataAnnot) {
|
|
191
|
+
annotations.push(metadataAnnot);
|
|
192
|
+
}
|
|
193
|
+
annotations.push(...(struct.resultMetadata ? [] : []));
|
|
194
|
+
if (result.sourceExplore) {
|
|
195
|
+
annotations.push({
|
|
196
|
+
value: malloy_tag_1.Tag.withPrefix('#(malloy) ')
|
|
197
|
+
.set(['source_name'], result.sourceExplore.name)
|
|
198
|
+
.toString(),
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
annotations.push({
|
|
202
|
+
value: malloy_tag_1.Tag.withPrefix('#(malloy) ')
|
|
203
|
+
.set(['query_name'], result.resultExplore.name)
|
|
204
|
+
.toString(),
|
|
205
|
+
});
|
|
206
|
+
return {
|
|
207
|
+
schema,
|
|
208
|
+
data: mapData(result.data.toObject(), schema),
|
|
209
|
+
connection_name: result.connectionName,
|
|
210
|
+
annotations: annotations.length > 0 ? annotations : undefined,
|
|
211
|
+
query_timezone: result.data.field.queryTimezone,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
exports.wrapResult = wrapResult;
|
|
215
|
+
//# sourceMappingURL=util.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { isSourceDef, Segment, isLeafAtomic, isJoined, isJoinedSource, isSamplin
|
|
|
5
5
|
export { MalloyTranslator, } from './lang';
|
|
6
6
|
export type { LogMessage, TranslateResponse } from './lang';
|
|
7
7
|
export { Model, Malloy, Runtime, AtomicFieldType, ConnectionRuntime, SingleConnectionRuntime, EmptyURLReader, InMemoryURLReader, FixedConnectionMap, MalloyError, JoinRelationship, SourceRelationship, DateTimeframe, TimestampTimeframe, PreparedResult, Result, QueryMaterializer, CSVWriter, JSONWriter, Parse, DataWriter, Explore, InMemoryModelCache, CacheManager, } from './malloy';
|
|
8
|
-
export type { PreparedQuery, Field, AtomicField, ExploreField, QueryField, SortableField, DataArray, DataRecord, DataColumn, DataArrayOrRecord, Loggable, ModelMaterializer, DocumentTablePath, DocumentSymbol, ResultJSON, PreparedResultMaterializer, ExploreMaterializer, WriteStream, SerializedExplore, ModelCache, CachedModel, DateField, TimestampField, } from './malloy';
|
|
8
|
+
export type { PreparedQuery, Field, AtomicField, ExploreField, QueryField, SortableField, DataArray, DataRecord, DataColumn, DataArrayOrRecord, Loggable, ModelMaterializer, DocumentTablePath, DocumentSymbol, ResultJSON, PreparedResultJSON, PreparedResultMaterializer, ExploreMaterializer, WriteStream, SerializedExplore, ModelCache, CachedModel, DateField, TimestampField, } from './malloy';
|
|
9
9
|
export type { QueryOptionsReader, RunSQLOptions } from './run_sql_options';
|
|
10
10
|
export type { EventStream, ModelString, ModelURL, QueryString, QueryURL, URLReader, InvalidationKey, } from './runtime_types';
|
|
11
11
|
export type { Connection, ConnectionConfig, ConnectionFactory, ConnectionParameter, ConnectionParameterValue, ConnectionConfigSchema, FetchSchemaOptions, InfoConnection, LookupConnection, PersistSQLResults, PooledConnection, TestableConnection, StreamingConnection, } from './connection/types';
|
package/dist/malloy.d.ts
CHANGED
|
@@ -482,7 +482,7 @@ export declare class PreparedResult implements Taggable {
|
|
|
482
482
|
* @return The `Explore` representing the data that will be returned by running this query.
|
|
483
483
|
*/
|
|
484
484
|
get resultExplore(): Explore;
|
|
485
|
-
get sourceExplore(): Explore;
|
|
485
|
+
get sourceExplore(): Explore | undefined;
|
|
486
486
|
get _sourceExploreName(): string;
|
|
487
487
|
get _sourceFilters(): FilterCondition[];
|
|
488
488
|
}
|
package/dist/malloy.js
CHANGED
|
@@ -864,13 +864,9 @@ class PreparedResult {
|
|
|
864
864
|
get sourceExplore() {
|
|
865
865
|
const name = this.inner.sourceExplore;
|
|
866
866
|
const explore = this.modelDef.contents[name];
|
|
867
|
-
if (explore
|
|
868
|
-
throw new Error('Malformed query result.');
|
|
869
|
-
}
|
|
870
|
-
if ((0, model_1.isSourceDef)(explore)) {
|
|
867
|
+
if (explore && (0, model_1.isSourceDef)(explore)) {
|
|
871
868
|
return new Explore(explore);
|
|
872
869
|
}
|
|
873
|
-
throw new Error(`'${name} is not an explore`);
|
|
874
870
|
}
|
|
875
871
|
get _sourceExploreName() {
|
|
876
872
|
return this.inner.sourceExplore;
|
|
@@ -289,6 +289,7 @@ declare class QueryQuery extends QueryField {
|
|
|
289
289
|
generateTurtlePipelineSQL(fi: FieldInstanceResult, stageWriter: StageWriter, sourceSQLExpression: string): {
|
|
290
290
|
structDef: QueryResultDef;
|
|
291
291
|
pipeOut: any;
|
|
292
|
+
repeatedResultType: RepeatedResultType;
|
|
292
293
|
};
|
|
293
294
|
generateComplexSQL(stageWriter: StageWriter): string;
|
|
294
295
|
generateSQL(stageWriter: StageWriter): string;
|
|
@@ -1934,8 +1934,8 @@ class QueryQuery extends QueryField {
|
|
|
1934
1934
|
for (const [name, fi] of resultStruct.allFields) {
|
|
1935
1935
|
const resultMetadata = this.getResultMetadata(fi);
|
|
1936
1936
|
if (fi instanceof FieldInstanceResult) {
|
|
1937
|
-
const { structDef } = this.generateTurtlePipelineSQL(fi, new StageWriter(true, undefined), '<nosource>');
|
|
1938
|
-
if (
|
|
1937
|
+
const { structDef, repeatedResultType } = this.generateTurtlePipelineSQL(fi, new StageWriter(true, undefined), '<nosource>');
|
|
1938
|
+
if (repeatedResultType === 'nested') {
|
|
1939
1939
|
const multiLineNest = {
|
|
1940
1940
|
...structDef,
|
|
1941
1941
|
type: 'array',
|
|
@@ -2716,6 +2716,7 @@ class QueryQuery extends QueryField {
|
|
|
2716
2716
|
const repeatedResultType = fi.getRepeatedResultType();
|
|
2717
2717
|
const hasPipeline = fi.turtleDef.pipeline.length > 1;
|
|
2718
2718
|
let pipeOut;
|
|
2719
|
+
let outputRepeatedResultType = repeatedResultType;
|
|
2719
2720
|
if (hasPipeline) {
|
|
2720
2721
|
const pipeline = [...fi.turtleDef.pipeline];
|
|
2721
2722
|
pipeline.shift();
|
|
@@ -2735,6 +2736,7 @@ class QueryQuery extends QueryField {
|
|
|
2735
2736
|
const qs = new QueryStruct(inputStruct, undefined, { model: this.parent.getModel() }, this.parent.prepareResultOptions);
|
|
2736
2737
|
const q = QueryQuery.makeQuery(newTurtle, qs, stageWriter, this.isJoinedSubquery);
|
|
2737
2738
|
pipeOut = q.generateSQLFromPipeline(stageWriter);
|
|
2739
|
+
outputRepeatedResultType = q.rootResult.getRepeatedResultType();
|
|
2738
2740
|
// console.log(stageWriter.generateSQLStages());
|
|
2739
2741
|
structDef = pipeOut.outputStruct;
|
|
2740
2742
|
}
|
|
@@ -2742,6 +2744,7 @@ class QueryQuery extends QueryField {
|
|
|
2742
2744
|
return {
|
|
2743
2745
|
structDef,
|
|
2744
2746
|
pipeOut,
|
|
2747
|
+
repeatedResultType: outputRepeatedResultType,
|
|
2745
2748
|
};
|
|
2746
2749
|
}
|
|
2747
2750
|
generateComplexSQL(stageWriter) {
|
|
@@ -3706,6 +3709,7 @@ class QueryModel {
|
|
|
3706
3709
|
queryName: query.name,
|
|
3707
3710
|
connectionName: ret.connectionName,
|
|
3708
3711
|
annotation: query.annotation,
|
|
3712
|
+
queryTimezone: ret.structs[0].queryTimezone,
|
|
3709
3713
|
};
|
|
3710
3714
|
}
|
|
3711
3715
|
async searchIndex(connection, explore, searchValue, limit = 1000, searchField = undefined) {
|
package/dist/to_stable.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as Malloy from '@malloydata/malloy-interfaces';
|
|
2
|
-
import { FieldDef, ModelDef, SourceDef } from './model';
|
|
2
|
+
import { FieldDef, ModelDef, ResultStructMetadataDef, SourceDef } from './model';
|
|
3
3
|
export declare function modelDefToModelInfo(modelDef: ModelDef): Malloy.ModelInfo;
|
|
4
4
|
export declare function convertFieldInfos(source: SourceDef, fields: FieldDef[]): Malloy.FieldInfo[];
|
|
5
|
+
export declare function getResultStructMetadataAnnotation(field: SourceDef, resultMetadata: ResultStructMetadataDef): Malloy.Annotation | undefined;
|
package/dist/to_stable.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
2
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.convertFieldInfos = exports.modelDefToModelInfo = void 0;
|
|
9
|
+
exports.getResultStructMetadataAnnotation = exports.convertFieldInfos = exports.modelDefToModelInfo = void 0;
|
|
4
10
|
const model_1 = require("./model");
|
|
5
11
|
const malloy_query_1 = require("./model/malloy_query");
|
|
6
12
|
const annotation_1 = require("./annotation");
|
|
@@ -146,6 +152,13 @@ function getResultMetadataAnnotation(field, resultMetadata) {
|
|
|
146
152
|
tag.set(['calculation']);
|
|
147
153
|
hasAny = true;
|
|
148
154
|
}
|
|
155
|
+
if (resultMetadata.filterList) {
|
|
156
|
+
const drillFilters = resultMetadata.filterList
|
|
157
|
+
.filter(f => f.expressionType === 'scalar')
|
|
158
|
+
.map(f => f.code);
|
|
159
|
+
tag.set(['drill_filters'], drillFilters);
|
|
160
|
+
hasAny = true;
|
|
161
|
+
}
|
|
149
162
|
if (resultMetadata.fieldKind === 'dimension') {
|
|
150
163
|
const dot = '.';
|
|
151
164
|
// If field is joined-in from another table i.e. of type `tableName.columnName`,
|
|
@@ -153,7 +166,7 @@ function getResultMetadataAnnotation(field, resultMetadata) {
|
|
|
153
166
|
const drillExpression = (resultMetadata === null || resultMetadata === void 0 ? void 0 : resultMetadata.sourceExpression) ||
|
|
154
167
|
((resultMetadata === null || resultMetadata === void 0 ? void 0 : resultMetadata.sourceField.includes(dot))
|
|
155
168
|
? resultMetadata === null || resultMetadata === void 0 ? void 0 : resultMetadata.sourceField
|
|
156
|
-
: field.name);
|
|
169
|
+
: identifierCode(field.name));
|
|
157
170
|
tag.set(['drill_expression'], drillExpression);
|
|
158
171
|
hasAny = true;
|
|
159
172
|
}
|
|
@@ -163,6 +176,14 @@ function getResultMetadataAnnotation(field, resultMetadata) {
|
|
|
163
176
|
}
|
|
164
177
|
: undefined;
|
|
165
178
|
}
|
|
179
|
+
function escapeIdentifier(str) {
|
|
180
|
+
return str.replace(/\\/g, '\\\\').replace(/`/g, '\\`');
|
|
181
|
+
}
|
|
182
|
+
function identifierCode(name) {
|
|
183
|
+
if (name.match(/^[A-Za-z_][0-9A-Za-z_]*$/))
|
|
184
|
+
return name;
|
|
185
|
+
return `\`${escapeIdentifier(name)}\``;
|
|
186
|
+
}
|
|
166
187
|
function getResultStructMetadataAnnotation(field, resultMetadata) {
|
|
167
188
|
var _a, _b;
|
|
168
189
|
const tag = malloy_tag_1.Tag.withPrefix('#(malloy) ');
|
|
@@ -171,11 +192,20 @@ function getResultStructMetadataAnnotation(field, resultMetadata) {
|
|
|
171
192
|
tag.set(['limit'], resultMetadata.limit);
|
|
172
193
|
hasAny = true;
|
|
173
194
|
}
|
|
195
|
+
if (resultMetadata.filterList) {
|
|
196
|
+
const drillFilters = resultMetadata.filterList
|
|
197
|
+
.filter(f => f.expressionType === 'scalar')
|
|
198
|
+
.map(f => f.code);
|
|
199
|
+
if (drillFilters.length > 0) {
|
|
200
|
+
tag.set(['drill_filters'], drillFilters);
|
|
201
|
+
hasAny = true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
174
204
|
if (resultMetadata.orderBy) {
|
|
175
205
|
for (let i = 0; i < resultMetadata.orderBy.length; i++) {
|
|
176
206
|
const orderBy = resultMetadata.orderBy[i];
|
|
177
207
|
const orderByField = typeof orderBy.field === 'number'
|
|
178
|
-
? (_a = field.fields[orderBy.field].as) !== null && _a !== void 0 ? _a : field.fields[orderBy.field].name
|
|
208
|
+
? (_a = field.fields[orderBy.field - 1].as) !== null && _a !== void 0 ? _a : field.fields[orderBy.field - 1].name
|
|
179
209
|
: orderBy.field;
|
|
180
210
|
const direction = (_b = orderBy.dir) !== null && _b !== void 0 ? _b : null;
|
|
181
211
|
tag.set(['ordered_by', i, orderByField], direction);
|
|
@@ -188,6 +218,7 @@ function getResultStructMetadataAnnotation(field, resultMetadata) {
|
|
|
188
218
|
}
|
|
189
219
|
: undefined;
|
|
190
220
|
}
|
|
221
|
+
exports.getResultStructMetadataAnnotation = getResultStructMetadataAnnotation;
|
|
191
222
|
function typeDefToType(field) {
|
|
192
223
|
if ((0, model_1.isLeafAtomic)(field)) {
|
|
193
224
|
switch (field.type) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malloydata/malloy",
|
|
3
|
-
"version": "0.0.240-
|
|
3
|
+
"version": "0.0.240-dev250311202829",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"generate-version-file": "VERSION=$(npm pkg get version --workspaces=false | tr -d \\\")\necho \"// generated with 'generate-version-file' script; do not edit manually\\nexport const MALLOY_VERSION = '$VERSION';\" > src/version.ts"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@malloydata/malloy-interfaces": "^0.0.240-
|
|
45
|
-
"@malloydata/malloy-tag": "^0.0.240-
|
|
44
|
+
"@malloydata/malloy-interfaces": "^0.0.240-dev250311202829",
|
|
45
|
+
"@malloydata/malloy-tag": "^0.0.240-dev250311202829",
|
|
46
46
|
"antlr4ts": "^0.5.0-alpha.4",
|
|
47
47
|
"assert": "^2.0.0",
|
|
48
48
|
"jest-diff": "^29.6.2",
|