@malloydata/db-trino 0.0.227 → 0.0.228-dev250116203644
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/index.d.ts +1 -1
- package/dist/index.js +1 -2
- package/dist/trino_connection.d.ts +2 -21
- package/dist/trino_connection.js +44 -101
- package/dist/trino_connection.spec.js +23 -15
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export type { BaseRunner } from './trino_connection';
|
|
2
|
-
export { PrestoConnection,
|
|
2
|
+
export { PrestoConnection, TrinoConnection, TrinoPrestoConnection, } from './trino_connection';
|
|
3
3
|
export { TrinoExecutor } from './trino_executor';
|
package/dist/index.js
CHANGED
|
@@ -22,10 +22,9 @@
|
|
|
22
22
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.TrinoExecutor = exports.TrinoPrestoConnection = exports.TrinoConnection = exports.
|
|
25
|
+
exports.TrinoExecutor = exports.TrinoPrestoConnection = exports.TrinoConnection = exports.PrestoConnection = void 0;
|
|
26
26
|
var trino_connection_1 = require("./trino_connection");
|
|
27
27
|
Object.defineProperty(exports, "PrestoConnection", { enumerable: true, get: function () { return trino_connection_1.PrestoConnection; } });
|
|
28
|
-
Object.defineProperty(exports, "PrestoExplainParser", { enumerable: true, get: function () { return trino_connection_1.PrestoExplainParser; } });
|
|
29
28
|
Object.defineProperty(exports, "TrinoConnection", { enumerable: true, get: function () { return trino_connection_1.TrinoConnection; } });
|
|
30
29
|
Object.defineProperty(exports, "TrinoPrestoConnection", { enumerable: true, get: function () { return trino_connection_1.TrinoPrestoConnection; } });
|
|
31
30
|
var trino_executor_1 = require("./trino_executor");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Connection, ConnectionConfig, MalloyQueryData, PersistSQLResults, QueryData, QueryOptionsReader, QueryRunStats, RunSQLOptions, TrinoDialect, StructDef, TableSourceDef, SQLSourceDef, AtomicTypeDef,
|
|
1
|
+
import { Connection, ConnectionConfig, MalloyQueryData, PersistSQLResults, QueryData, QueryOptionsReader, QueryRunStats, RunSQLOptions, TrinoDialect, StructDef, TableSourceDef, SQLSourceDef, AtomicTypeDef, FieldDef } from '@malloydata/malloy';
|
|
2
2
|
import { BaseConnection } from '@malloydata/malloy/connection';
|
|
3
3
|
export interface TrinoManagerOptions {
|
|
4
4
|
credentials?: {
|
|
@@ -54,8 +54,7 @@ export declare abstract class TrinoPrestoConnection extends BaseConnection imple
|
|
|
54
54
|
fetchSelectSchema(sqlRef: SQLSourceDef): Promise<SQLSourceDef>;
|
|
55
55
|
protected abstract fillStructDefForSqlBlockSchema(sql: string, structDef: StructDef): Promise<void>;
|
|
56
56
|
protected executeAndWait(sqlBlock: string): Promise<void>;
|
|
57
|
-
|
|
58
|
-
malloyTypeFromTrinoType(name: string, trinoType: string): AtomicTypeDef;
|
|
57
|
+
malloyTypeFromTrinoType(trinoType: string): AtomicTypeDef;
|
|
59
58
|
structDefFromSchema(rows: string[][], structDef: StructDef): void;
|
|
60
59
|
protected loadSchemaForSqlBlock(sqlBlock: string, structDef: StructDef, element: string): Promise<StructDef>;
|
|
61
60
|
estimateQueryCost(_sqlCommand: string): Promise<QueryRunStats>;
|
|
@@ -75,21 +74,3 @@ export declare class TrinoConnection extends TrinoPrestoConnection {
|
|
|
75
74
|
constructor(option: TrinoConnectionOptions, queryOptions?: QueryOptionsReader);
|
|
76
75
|
protected fillStructDefForSqlBlockSchema(sql: string, structDef: StructDef): Promise<void>;
|
|
77
76
|
}
|
|
78
|
-
/**
|
|
79
|
-
* A hand built parser for schema lines, roughly this grammar
|
|
80
|
-
* SCHEMA_LINE: - Output [PlanName N] [NAME_LIST] => [TYPE_LIST]
|
|
81
|
-
* NAME_LIST: NAME (, NAME)*
|
|
82
|
-
* TYPE_LIST: TYPE_SPEC (, TYPE_SPEC)*
|
|
83
|
-
* TYPE_SPEC: exprN ':' TYPE
|
|
84
|
-
* TYPE: REC_TYPE | ARRAY_TYPE | SQL_TYPE
|
|
85
|
-
* ARRAY_TYPE: ARRAY '(' TYPE ')'
|
|
86
|
-
* REC_TYPE: REC '(' "name" TYPE (, "name" TYPE)* ')'
|
|
87
|
-
*/
|
|
88
|
-
export declare class PrestoExplainParser extends TinyParser {
|
|
89
|
-
readonly input: string;
|
|
90
|
-
readonly dialect: Dialect;
|
|
91
|
-
constructor(input: string, dialect: Dialect);
|
|
92
|
-
fieldNameList(): string[];
|
|
93
|
-
parseExplain(): FieldDef[];
|
|
94
|
-
typeDef(): AtomicTypeDef;
|
|
95
|
-
}
|
package/dist/trino_connection.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.
|
|
25
|
+
exports.TrinoConnection = exports.PrestoConnection = exports.TrinoPrestoConnection = void 0;
|
|
26
26
|
const malloy_1 = require("@malloydata/malloy");
|
|
27
27
|
const connection_1 = require("@malloydata/malloy/connection");
|
|
28
28
|
const presto_js_client_1 = require("@prestodb/presto-js-client");
|
|
@@ -182,7 +182,7 @@ class TrinoPrestoConnection extends connection_1.BaseConnection {
|
|
|
182
182
|
}
|
|
183
183
|
const inputRows = r.rows;
|
|
184
184
|
const columns = r.columns;
|
|
185
|
-
const malloyColumns = columns.map(c => this.malloyTypeFromTrinoType(c.
|
|
185
|
+
const malloyColumns = columns.map(c => (0, malloy_1.mkFieldDef)(this.malloyTypeFromTrinoType(c.type), c.name));
|
|
186
186
|
const malloyRows = [];
|
|
187
187
|
const rows = inputRows !== null && inputRows !== void 0 ? inputRows : [];
|
|
188
188
|
for (const row of rows) {
|
|
@@ -249,96 +249,15 @@ class TrinoPrestoConnection extends connection_1.BaseConnection {
|
|
|
249
249
|
// TODO: make sure failure is handled correctly.
|
|
250
250
|
//while (!(await result.next()).done);
|
|
251
251
|
}
|
|
252
|
-
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
let column = '';
|
|
256
|
-
let eatSpaces = true;
|
|
257
|
-
for (let idx = 0; idx < s.length; idx++) {
|
|
258
|
-
const c = s.charAt(idx);
|
|
259
|
-
if (eatSpaces && c === ' ') {
|
|
260
|
-
// Eat space
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
eatSpaces = false;
|
|
264
|
-
if (!parens && c === ',') {
|
|
265
|
-
columns.push(column);
|
|
266
|
-
column = '';
|
|
267
|
-
eatSpaces = true;
|
|
268
|
-
}
|
|
269
|
-
else {
|
|
270
|
-
column += c;
|
|
271
|
-
}
|
|
272
|
-
if (c === '(') {
|
|
273
|
-
parens += 1;
|
|
274
|
-
}
|
|
275
|
-
else if (c === ')') {
|
|
276
|
-
parens -= 1;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
columns.push(column);
|
|
281
|
-
return columns;
|
|
282
|
-
}
|
|
283
|
-
malloyTypeFromTrinoType(name, trinoType) {
|
|
284
|
-
// Arrays look like `array(type)`
|
|
285
|
-
const arrayMatch = trinoType.match(/^(([^,])+\s)?array\((.*)\)$/);
|
|
286
|
-
// Structs look like `row(name type, name type)`
|
|
287
|
-
const structMatch = trinoType.match(/^(([^,])+\s)?row\((.*)\)$/);
|
|
288
|
-
if (arrayMatch) {
|
|
289
|
-
const arrayType = arrayMatch[3];
|
|
290
|
-
const innerType = this.malloyTypeFromTrinoType(name, arrayType);
|
|
291
|
-
if (innerType.type === 'record') {
|
|
292
|
-
const complexStruct = {
|
|
293
|
-
type: 'array',
|
|
294
|
-
elementTypeDef: { type: 'record_element' },
|
|
295
|
-
fields: innerType.fields,
|
|
296
|
-
};
|
|
297
|
-
return complexStruct;
|
|
298
|
-
}
|
|
299
|
-
else {
|
|
300
|
-
const arrayStruct = {
|
|
301
|
-
type: 'array',
|
|
302
|
-
elementTypeDef: innerType,
|
|
303
|
-
};
|
|
304
|
-
return arrayStruct;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
else if (structMatch) {
|
|
308
|
-
// TODO: Trino doesn't quote or escape commas in field names,
|
|
309
|
-
// so some magic is going to need to be applied before we get here
|
|
310
|
-
// to avoid confusion if a field name contains a comma
|
|
311
|
-
const innerTypes = this.splitColumns(structMatch[3]);
|
|
312
|
-
const recordType = {
|
|
313
|
-
type: 'record',
|
|
314
|
-
fields: [],
|
|
315
|
-
};
|
|
316
|
-
for (let innerType of innerTypes) {
|
|
317
|
-
// TODO: Handle time zone type annotation, which is an
|
|
318
|
-
// exception to the types not containing spaces assumption
|
|
319
|
-
innerType = innerType.replace(/ with time zone$/, '');
|
|
320
|
-
let parts = innerType.match(/^(.+?)\s((array\(|row\().*)$/);
|
|
321
|
-
if (parts === null) {
|
|
322
|
-
parts = innerType.match(/^(.+)\s(\S+)$/);
|
|
323
|
-
}
|
|
324
|
-
if (parts) {
|
|
325
|
-
// remove quotes from the name
|
|
326
|
-
const innerName = parts[1].replace(/^"(.+(?="$))"$/, '$1');
|
|
327
|
-
const innerTrinoType = parts[2];
|
|
328
|
-
const innerMalloyType = this.malloyTypeFromTrinoType(innerName, innerTrinoType);
|
|
329
|
-
recordType.fields.push((0, malloy_1.mkFieldDef)(innerMalloyType, innerName));
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
return recordType;
|
|
333
|
-
}
|
|
334
|
-
return this.dialect.sqlTypeToMalloyType(trinoType);
|
|
252
|
+
malloyTypeFromTrinoType(trinoType) {
|
|
253
|
+
const typeParse = new TrinoPrestoSchemaParser(trinoType, this.dialect);
|
|
254
|
+
return typeParse.typeDef();
|
|
335
255
|
}
|
|
336
256
|
structDefFromSchema(rows, structDef) {
|
|
337
257
|
for (const row of rows) {
|
|
338
258
|
const name = row[0];
|
|
339
259
|
const type = row[4] || row[1];
|
|
340
|
-
const malloyType = this.malloyTypeFromTrinoType(
|
|
341
|
-
// console.log('>', row, '\n<', malloyType);
|
|
260
|
+
const malloyType = (0, malloy_1.mkFieldDef)(this.malloyTypeFromTrinoType(type), name);
|
|
342
261
|
structDef.fields.push((0, malloy_1.mkFieldDef)(malloyType, name));
|
|
343
262
|
}
|
|
344
263
|
}
|
|
@@ -408,8 +327,8 @@ class PrestoConnection extends TrinoPrestoConnection {
|
|
|
408
327
|
if ((lines === null || lines === void 0 ? void 0 : lines.length) === 0) {
|
|
409
328
|
throw new Error('Received invalid explain result when trying to fetch schema.');
|
|
410
329
|
}
|
|
411
|
-
const schemaDesc = new
|
|
412
|
-
structDef.fields = schemaDesc.
|
|
330
|
+
const schemaDesc = new TrinoPrestoSchemaParser(lines[0], this.dialect);
|
|
331
|
+
structDef.fields = schemaDesc.parseQueryPlan();
|
|
413
332
|
}
|
|
414
333
|
unpackArray(data) {
|
|
415
334
|
return JSON.parse(data);
|
|
@@ -428,23 +347,26 @@ class TrinoConnection extends TrinoPrestoConnection {
|
|
|
428
347
|
}
|
|
429
348
|
exports.TrinoConnection = TrinoConnection;
|
|
430
349
|
/**
|
|
431
|
-
* A hand built parser for schema lines,
|
|
350
|
+
* A hand built parser for schema lines, it parses two things ...
|
|
351
|
+
* A presto query plan
|
|
432
352
|
* SCHEMA_LINE: - Output [PlanName N] [NAME_LIST] => [TYPE_LIST]
|
|
433
353
|
* NAME_LIST: NAME (, NAME)*
|
|
434
354
|
* TYPE_LIST: TYPE_SPEC (, TYPE_SPEC)*
|
|
435
355
|
* TYPE_SPEC: exprN ':' TYPE
|
|
356
|
+
*
|
|
357
|
+
* And a presto/trino type
|
|
436
358
|
* TYPE: REC_TYPE | ARRAY_TYPE | SQL_TYPE
|
|
437
359
|
* ARRAY_TYPE: ARRAY '(' TYPE ')'
|
|
438
360
|
* REC_TYPE: REC '(' "name" TYPE (, "name" TYPE)* ')'
|
|
439
361
|
*/
|
|
440
|
-
class
|
|
362
|
+
class TrinoPrestoSchemaParser extends malloy_1.TinyParser {
|
|
441
363
|
constructor(input, dialect) {
|
|
442
364
|
super(input, {
|
|
443
365
|
space: /^\s+/,
|
|
444
366
|
arrow: /^=>/,
|
|
445
367
|
char: /^[,:[\]()-]/,
|
|
446
368
|
id: /^\w+/,
|
|
447
|
-
quoted_name: /^"
|
|
369
|
+
quoted_name: /^"(\\"|[^"])*"/,
|
|
448
370
|
});
|
|
449
371
|
this.input = input;
|
|
450
372
|
this.dialect = dialect;
|
|
@@ -467,7 +389,7 @@ class PrestoExplainParser extends malloy_1.TinyParser {
|
|
|
467
389
|
}
|
|
468
390
|
return fieldNames;
|
|
469
391
|
}
|
|
470
|
-
|
|
392
|
+
parseQueryPlan() {
|
|
471
393
|
const fieldNames = this.fieldNameList();
|
|
472
394
|
const fields = [];
|
|
473
395
|
this.next('arrow', '[');
|
|
@@ -498,7 +420,10 @@ class PrestoExplainParser extends malloy_1.TinyParser {
|
|
|
498
420
|
else if (typToken.text === 'row' && this.next('(')) {
|
|
499
421
|
const fields = [];
|
|
500
422
|
for (;;) {
|
|
501
|
-
const name = this.next(
|
|
423
|
+
const name = this.next();
|
|
424
|
+
if (name.type !== 'id' && name.type !== 'quoted_name') {
|
|
425
|
+
throw this.parseError(`Expected property name, got '${name.type}'`);
|
|
426
|
+
}
|
|
502
427
|
const getDef = this.typeDef();
|
|
503
428
|
fields.push((0, malloy_1.mkFieldDef)(getDef, name.text));
|
|
504
429
|
const sep = this.next();
|
|
@@ -527,20 +452,38 @@ class PrestoExplainParser extends malloy_1.TinyParser {
|
|
|
527
452
|
: { type: 'array', elementTypeDef: elType };
|
|
528
453
|
}
|
|
529
454
|
else if (typToken.type === 'id') {
|
|
530
|
-
const sqlType = typToken.text;
|
|
531
|
-
const def = this.dialect.sqlTypeToMalloyType(sqlType);
|
|
532
|
-
if (def === undefined) {
|
|
533
|
-
throw this.parseError(`Can't parse presto type ${sqlType}`);
|
|
534
|
-
}
|
|
455
|
+
const sqlType = typToken.text.toLowerCase();
|
|
535
456
|
if (sqlType === 'varchar') {
|
|
536
457
|
if (this.peek().type === '(') {
|
|
537
458
|
this.next('(', 'id', ')');
|
|
538
459
|
}
|
|
539
460
|
}
|
|
540
|
-
|
|
461
|
+
else if (sqlType === 'timestamp') {
|
|
462
|
+
if (this.peek().text === '(') {
|
|
463
|
+
this.next('(', 'id', ')');
|
|
464
|
+
}
|
|
465
|
+
if (this.peek().text === 'with') {
|
|
466
|
+
this.nextText('with', 'time', 'zone');
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
const typeDef = this.dialect.sqlTypeToMalloyType(sqlType);
|
|
470
|
+
if (typeDef.type === 'number' && sqlType === 'decimal') {
|
|
471
|
+
this.next('(', 'id');
|
|
472
|
+
if (this.peek().type === ',') {
|
|
473
|
+
this.next(',', 'id');
|
|
474
|
+
typeDef.numberType = 'float';
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
typeDef.numberType = 'integer';
|
|
478
|
+
}
|
|
479
|
+
this.next(')');
|
|
480
|
+
}
|
|
481
|
+
if (typeDef === undefined) {
|
|
482
|
+
throw this.parseError(`Can't parse presto type ${sqlType}`);
|
|
483
|
+
}
|
|
484
|
+
return typeDef;
|
|
541
485
|
}
|
|
542
486
|
throw this.parseError(`'${typToken.text}' unexpected while looking for a type`);
|
|
543
487
|
}
|
|
544
488
|
}
|
|
545
|
-
exports.PrestoExplainParser = PrestoExplainParser;
|
|
546
489
|
//# sourceMappingURL=trino_connection.js.map
|
|
@@ -49,29 +49,47 @@ describe('Trino connection', () => {
|
|
|
49
49
|
});
|
|
50
50
|
describe('schema parser', () => {
|
|
51
51
|
it('parses arrays', () => {
|
|
52
|
-
expect(connection.malloyTypeFromTrinoType(
|
|
52
|
+
expect(connection.malloyTypeFromTrinoType(ARRAY_SCHEMA)).toEqual({
|
|
53
53
|
type: 'array',
|
|
54
54
|
elementTypeDef: intType,
|
|
55
55
|
});
|
|
56
56
|
});
|
|
57
57
|
it('parses inline', () => {
|
|
58
|
-
expect(connection.malloyTypeFromTrinoType(
|
|
58
|
+
expect(connection.malloyTypeFromTrinoType(INLINE_SCHEMA)).toEqual({
|
|
59
59
|
'type': 'record',
|
|
60
60
|
'fields': recordSchema,
|
|
61
61
|
});
|
|
62
62
|
});
|
|
63
63
|
it('parses nested', () => {
|
|
64
|
-
expect(connection.malloyTypeFromTrinoType(
|
|
64
|
+
expect(connection.malloyTypeFromTrinoType(NESTED_SCHEMA)).toEqual({
|
|
65
65
|
'type': 'array',
|
|
66
66
|
'elementTypeDef': { type: 'record_element' },
|
|
67
67
|
'fields': recordSchema,
|
|
68
68
|
});
|
|
69
69
|
});
|
|
70
70
|
it('parses a simple type', () => {
|
|
71
|
-
expect(connection.malloyTypeFromTrinoType('
|
|
71
|
+
expect(connection.malloyTypeFromTrinoType('varchar(60)')).toEqual(stringType);
|
|
72
|
+
});
|
|
73
|
+
it('parses a decimal integer type', () => {
|
|
74
|
+
expect(connection.malloyTypeFromTrinoType('decimal(10)')).toEqual({
|
|
75
|
+
type: 'number',
|
|
76
|
+
numberType: 'integer',
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
it('parses a decimal float type', () => {
|
|
80
|
+
expect(connection.malloyTypeFromTrinoType('decimal(10,10)')).toEqual({
|
|
81
|
+
type: 'number',
|
|
82
|
+
numberType: 'float',
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
it('parses row with timestamp(3)', () => {
|
|
86
|
+
expect(connection.malloyTypeFromTrinoType('row(la_time timestamp(3))')).toEqual({
|
|
87
|
+
type: 'record',
|
|
88
|
+
fields: [{ name: 'la_time', type: 'timestamp' }],
|
|
89
|
+
});
|
|
72
90
|
});
|
|
73
91
|
it('parses deep nesting', () => {
|
|
74
|
-
expect(connection.malloyTypeFromTrinoType(
|
|
92
|
+
expect(connection.malloyTypeFromTrinoType(DEEP_SCHEMA)).toEqual({
|
|
75
93
|
'type': 'array',
|
|
76
94
|
'elementTypeDef': { type: 'record_element' },
|
|
77
95
|
'fields': [
|
|
@@ -90,15 +108,5 @@ describe('Trino connection', () => {
|
|
|
90
108
|
});
|
|
91
109
|
});
|
|
92
110
|
});
|
|
93
|
-
describe('splitColumns', () => {
|
|
94
|
-
it('handles internal rows', () => {
|
|
95
|
-
const nested = 'popular_name varchar, airport_count double, by_state array(row(state varchar, airport_count double))';
|
|
96
|
-
expect(connection.splitColumns(nested)).toEqual([
|
|
97
|
-
'popular_name varchar',
|
|
98
|
-
'airport_count double',
|
|
99
|
-
'by_state array(row(state varchar, airport_count double))',
|
|
100
|
-
]);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
111
|
});
|
|
104
112
|
//# sourceMappingURL=trino_connection.spec.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malloydata/db-trino",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.228-dev250116203644",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"prepublishOnly": "npm run build"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@malloydata/malloy": "^0.0.
|
|
25
|
+
"@malloydata/malloy": "^0.0.228-dev250116203644",
|
|
26
26
|
"@prestodb/presto-js-client": "^1.0.0",
|
|
27
27
|
"gaxios": "^4.2.0",
|
|
28
28
|
"trino-client": "^0.2.2"
|