@checkdigit/eslint-athena-plugin 1.0.0-PR.2-dcdf
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/LICENSE.txt +21 -0
- package/README.md +17 -0
- package/SECURITY.md +13 -0
- package/dist-mjs/athena/api-locator.mjs +66 -0
- package/dist-mjs/athena/api-matcher.mjs +206 -0
- package/dist-mjs/athena/athena.mjs +165 -0
- package/dist-mjs/athena/column.mjs +1 -0
- package/dist-mjs/athena/context.mjs +21 -0
- package/dist-mjs/athena/index.mjs +1 -0
- package/dist-mjs/athena/service-table.mjs +45 -0
- package/dist-mjs/athena/sql-file.mjs +123 -0
- package/dist-mjs/athena/types.mjs +1 -0
- package/dist-mjs/athena/validate.mjs +619 -0
- package/dist-mjs/athena/visitor.mjs +291 -0
- package/dist-mjs/get-documentation-url.mjs +9 -0
- package/dist-mjs/index.mjs +56 -0
- package/dist-mjs/openapi/deref-schema.mjs +20 -0
- package/dist-mjs/openapi/generate-schema.mjs +375 -0
- package/dist-mjs/openapi/service-schema-generator.mjs +176 -0
- package/dist-mjs/peggy/athena-peggy.mjs +20700 -0
- package/dist-mjs/service.mjs +9 -0
- package/dist-mjs/sql-parser.mjs +28 -0
- package/dist-types/athena/api-locator.d.ts +2 -0
- package/dist-types/athena/api-matcher.d.ts +14 -0
- package/dist-types/athena/athena.d.ts +5 -0
- package/dist-types/athena/column.d.ts +1 -0
- package/dist-types/athena/context.d.ts +21 -0
- package/dist-types/athena/index.d.ts +8 -0
- package/dist-types/athena/service-table.d.ts +8 -0
- package/dist-types/athena/sql-file.d.ts +5 -0
- package/dist-types/athena/types.d.ts +493 -0
- package/dist-types/athena/validate.d.ts +14 -0
- package/dist-types/athena/visitor.d.ts +75 -0
- package/dist-types/get-documentation-url.d.ts +1 -0
- package/dist-types/index.d.ts +5 -0
- package/dist-types/openapi/deref-schema.d.ts +1 -0
- package/dist-types/openapi/generate-schema.d.ts +33 -0
- package/dist-types/openapi/service-schema-generator.d.ts +5 -0
- package/dist-types/peggy/athena-peggy.d.ts +13 -0
- package/dist-types/service.d.ts +2 -0
- package/dist-types/sql-parser.d.ts +25 -0
- package/package.json +1 -0
- package/src/api/v1/swagger.yml +619 -0
- package/src/api/v2/swagger.yml +477 -0
- package/src/athena/api-locator.ts +78 -0
- package/src/athena/api-matcher.ts +323 -0
- package/src/athena/athena.ts +224 -0
- package/src/athena/column.ts +4 -0
- package/src/athena/context.ts +47 -0
- package/src/athena/index.ts +13 -0
- package/src/athena/service-table.ts +78 -0
- package/src/athena/sql-file.ts +161 -0
- package/src/athena/types.ts +568 -0
- package/src/athena/validate.ts +902 -0
- package/src/athena/visitor.ts +406 -0
- package/src/get-documentation-url.ts +7 -0
- package/src/index.ts +67 -0
- package/src/openapi/deref-schema.ts +20 -0
- package/src/openapi/generate-schema.ts +553 -0
- package/src/openapi/service-schema-generator.ts +241 -0
- package/src/peggy/athena-peggy.ts +22149 -0
- package/src/peggy/athena.peggy +2971 -0
- package/src/service.ts +11 -0
- package/src/services/eslintAthenaPlugin/v1/swagger.schema.deref.json +1931 -0
- package/src/services/eslintAthenaPlugin/v2/swagger.schema.deref.json +978 -0
- package/src/sql-parser.ts +53 -0
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
// src/athena/validate.ts
|
|
2
|
+
import { strict as assert } from "node:assert";
|
|
3
|
+
import debug from "debug";
|
|
4
|
+
import { JSONPath } from "jsonpath-plus";
|
|
5
|
+
import { matchApi } from "./api-matcher.mjs";
|
|
6
|
+
import { locateApi } from "./api-locator.mjs";
|
|
7
|
+
import {
|
|
8
|
+
createChildContext
|
|
9
|
+
} from "./context.mjs";
|
|
10
|
+
import { buildServiceTables } from "./service-table.mjs";
|
|
11
|
+
import {
|
|
12
|
+
containsCastToArray,
|
|
13
|
+
containsCastToMap,
|
|
14
|
+
containsLambda,
|
|
15
|
+
extractBracketAccessorPath,
|
|
16
|
+
extractColumnRefs,
|
|
17
|
+
extractJsonExtractCalls,
|
|
18
|
+
extractJsonExtractPath,
|
|
19
|
+
fromClauseItems,
|
|
20
|
+
hasFunctionCalls,
|
|
21
|
+
isBaseFrom,
|
|
22
|
+
isJoin,
|
|
23
|
+
isTableExpr,
|
|
24
|
+
isUnnestFrom,
|
|
25
|
+
isValuesFrom
|
|
26
|
+
} from "./visitor.mjs";
|
|
27
|
+
var SYNTAXT_ERROR = "SyntaxError";
|
|
28
|
+
var ATHENA_ERROR = "AthenaError";
|
|
29
|
+
var AthenaError = class extends Error {
|
|
30
|
+
code;
|
|
31
|
+
ast;
|
|
32
|
+
constructor(code, message, ast) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.code = code;
|
|
35
|
+
this.name = "AthenaError";
|
|
36
|
+
if (ast !== void 0) {
|
|
37
|
+
this.ast = ast;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
function offsetToLoc(text, offset) {
|
|
42
|
+
const prefix = text.slice(0, offset);
|
|
43
|
+
const lines = prefix.split("\n");
|
|
44
|
+
return { line: lines.length, column: lines[lines.length - 1]?.length ?? 0 };
|
|
45
|
+
}
|
|
46
|
+
var log = debug("eslint-athena-plugin:athena");
|
|
47
|
+
var ANONYMOUS_TABLE = "<anonymous>";
|
|
48
|
+
var SUBQUERY_TABLE = "<subquery>";
|
|
49
|
+
function resolvedCol(name, schema, ast) {
|
|
50
|
+
return ast !== void 0 ? { name, schema, ast } : { name, schema };
|
|
51
|
+
}
|
|
52
|
+
function getApiSchemas(serviceName, ctx) {
|
|
53
|
+
let schemas = ctx.apiSchemas.get(serviceName);
|
|
54
|
+
if (schemas === void 0) {
|
|
55
|
+
schemas = locateApi(serviceName);
|
|
56
|
+
ctx.apiSchemas.set(serviceName, schemas);
|
|
57
|
+
}
|
|
58
|
+
return schemas;
|
|
59
|
+
}
|
|
60
|
+
function lookupTables(nameOrAlias, ctx) {
|
|
61
|
+
const canonical = ctx.aliases.get(nameOrAlias) ?? nameOrAlias;
|
|
62
|
+
return ctx.tables.get(nameOrAlias) ?? ctx.tables.get(canonical) ?? [];
|
|
63
|
+
}
|
|
64
|
+
function flattenTables(ctx) {
|
|
65
|
+
return [...ctx.tables.values()].flat();
|
|
66
|
+
}
|
|
67
|
+
function resolveReferencedTables(tableRef, allTables, ctx) {
|
|
68
|
+
return tableRef !== void 0 ? lookupTables(tableRef, ctx) : allTables;
|
|
69
|
+
}
|
|
70
|
+
function resolveColumnRefParts(ref) {
|
|
71
|
+
return {
|
|
72
|
+
tableRef: ref.table ?? void 0,
|
|
73
|
+
colRef: typeof ref.column === "string" ? ref.column : void 0
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function resolveServiceTable(select, item, ctx, storageKey) {
|
|
77
|
+
const { table: tableName } = item;
|
|
78
|
+
const key = storageKey ?? tableName;
|
|
79
|
+
try {
|
|
80
|
+
const apiSchemas = getApiSchemas(tableName, ctx);
|
|
81
|
+
if (apiSchemas.length === 0) {
|
|
82
|
+
throw new AthenaError(
|
|
83
|
+
ATHENA_ERROR,
|
|
84
|
+
`service not found: "${tableName}" (no swagger schema located)`,
|
|
85
|
+
item
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
const operations = matchApi(select, item, apiSchemas) ?? [];
|
|
89
|
+
ctx.tables.set(key, buildServiceTables(tableName, operations));
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (error instanceof AthenaError) {
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
throw new AthenaError(
|
|
95
|
+
ATHENA_ERROR,
|
|
96
|
+
error instanceof Error ? error.message : String(error),
|
|
97
|
+
item
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function getFunctionAliasName(as) {
|
|
102
|
+
return as?.name.name[0]?.value;
|
|
103
|
+
}
|
|
104
|
+
function extractColumnAliasName(arg) {
|
|
105
|
+
const colRef = arg;
|
|
106
|
+
if (typeof colRef.column === "string") {
|
|
107
|
+
return colRef.column;
|
|
108
|
+
}
|
|
109
|
+
const fnNode = arg;
|
|
110
|
+
if (fnNode.type === "function" && fnNode.args?.value?.length === 0) {
|
|
111
|
+
return fnNode.name?.name?.[0]?.value?.toLowerCase();
|
|
112
|
+
}
|
|
113
|
+
return void 0;
|
|
114
|
+
}
|
|
115
|
+
function isStandaloneUnnest(node) {
|
|
116
|
+
return isUnnestFrom(node) && typeof node.expr.column !== "string";
|
|
117
|
+
}
|
|
118
|
+
function aliasAsSingleton(alias) {
|
|
119
|
+
return alias !== void 0 ? [alias] : [];
|
|
120
|
+
}
|
|
121
|
+
function fromItemTableNames(item) {
|
|
122
|
+
if (isBaseFrom(item) || isJoin(item)) {
|
|
123
|
+
return item.as !== null ? [item.as, item.table] : [item.table];
|
|
124
|
+
}
|
|
125
|
+
if (isTableExpr(item)) {
|
|
126
|
+
return [typeof item.as === "string" ? item.as : SUBQUERY_TABLE];
|
|
127
|
+
}
|
|
128
|
+
if (isValuesFrom(item)) {
|
|
129
|
+
return aliasAsSingleton(getFunctionAliasName(item.as));
|
|
130
|
+
}
|
|
131
|
+
const unknownItem = item;
|
|
132
|
+
if (isStandaloneUnnest(unknownItem)) {
|
|
133
|
+
return aliasAsSingleton(getFunctionAliasName(unknownItem.as ?? void 0));
|
|
134
|
+
}
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
function restrictToFromClause(select, ctx) {
|
|
138
|
+
const fromNames = new Set(
|
|
139
|
+
fromClauseItems(select).flatMap(fromItemTableNames)
|
|
140
|
+
);
|
|
141
|
+
for (const name of [...ctx.tables.keys()]) {
|
|
142
|
+
if (!fromNames.has(name)) {
|
|
143
|
+
ctx.tables.delete(name);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function tableIsResolved(tableName, storageKey, ctx) {
|
|
148
|
+
return ctx.tables.has(storageKey) || ctx.tables.has(tableName);
|
|
149
|
+
}
|
|
150
|
+
function registerAliasedTable(tableAlias, columns, ctx) {
|
|
151
|
+
ctx.tables.set(tableAlias, [{ name: tableAlias, columns }]);
|
|
152
|
+
}
|
|
153
|
+
function resolveTableOrJoinItem(select, item, ctx) {
|
|
154
|
+
const { table: tableName, as: alias } = item;
|
|
155
|
+
if (alias !== null) {
|
|
156
|
+
ctx.aliases.set(alias, tableName);
|
|
157
|
+
}
|
|
158
|
+
const storageKey = alias ?? tableName;
|
|
159
|
+
if (!tableIsResolved(tableName, storageKey, ctx)) {
|
|
160
|
+
resolveServiceTable(select, item, ctx, alias ?? void 0);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function resolveFromClause(select, ctx) {
|
|
164
|
+
for (const item of fromClauseItems(select)) {
|
|
165
|
+
const unknownItem = item;
|
|
166
|
+
if (isStandaloneUnnest(unknownItem)) {
|
|
167
|
+
const tableAlias = getFunctionAliasName(unknownItem.as ?? void 0);
|
|
168
|
+
if (tableAlias !== void 0) {
|
|
169
|
+
const columns = new Map(
|
|
170
|
+
(unknownItem.as?.args.value ?? []).map((columnRef) => {
|
|
171
|
+
const colName = extractColumnAliasName(columnRef) ?? "";
|
|
172
|
+
return [colName, [resolvedCol(colName, {})]];
|
|
173
|
+
})
|
|
174
|
+
);
|
|
175
|
+
registerAliasedTable(tableAlias, columns, ctx);
|
|
176
|
+
}
|
|
177
|
+
} else if (isUnnestFrom(unknownItem)) {
|
|
178
|
+
} else if (isValuesFrom(item)) {
|
|
179
|
+
const tableAlias = getFunctionAliasName(item.as);
|
|
180
|
+
if (tableAlias !== void 0) {
|
|
181
|
+
const columns = new Map(
|
|
182
|
+
item.as.args.value.map((columnRef) => [
|
|
183
|
+
columnRef.column,
|
|
184
|
+
[resolvedCol(columnRef.column, {})]
|
|
185
|
+
])
|
|
186
|
+
);
|
|
187
|
+
registerAliasedTable(tableAlias, columns, ctx);
|
|
188
|
+
}
|
|
189
|
+
} else if (isTableExpr(item)) {
|
|
190
|
+
const alias = typeof item.as === "string" ? item.as : SUBQUERY_TABLE;
|
|
191
|
+
checkSelect(item.expr.ast, ctx, alias);
|
|
192
|
+
} else if (isJoin(item) || isBaseFrom(item)) {
|
|
193
|
+
resolveTableOrJoinItem(select, item, ctx);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function extractUnnestMappings(select) {
|
|
198
|
+
const mappings = [];
|
|
199
|
+
for (const item of fromClauseItems(select)) {
|
|
200
|
+
if (!isUnnestFrom(item)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const fromColumn = typeof item.expr.column === "string" ? item.expr.column : void 0;
|
|
204
|
+
if (fromColumn === void 0) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
const aliasArgs = item.as?.args.value ?? [];
|
|
208
|
+
const toColumns = [];
|
|
209
|
+
for (const col of aliasArgs) {
|
|
210
|
+
const colName = extractColumnAliasName(col);
|
|
211
|
+
if (colName !== void 0) {
|
|
212
|
+
toColumns.push(colName);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
assert.ok(
|
|
216
|
+
toColumns.length > 0,
|
|
217
|
+
"UNNEST alias must have at least one column name"
|
|
218
|
+
);
|
|
219
|
+
const tableAlias = getFunctionAliasName(item.as ?? void 0);
|
|
220
|
+
mappings.push({
|
|
221
|
+
fromColumn,
|
|
222
|
+
toColumns,
|
|
223
|
+
...tableAlias !== void 0 ? { tableAlias } : {},
|
|
224
|
+
ast: item.expr
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return mappings;
|
|
228
|
+
}
|
|
229
|
+
function buildUnnestColumnMap(fromColumn, toColumns, sourceSchema, sourceAst, ast, hasKnownApiOperation) {
|
|
230
|
+
if (sourceSchema?.type === "array") {
|
|
231
|
+
const [toColumn] = toColumns;
|
|
232
|
+
assert.ok(toColumn !== void 0);
|
|
233
|
+
return /* @__PURE__ */ new Map([
|
|
234
|
+
[toColumn, [resolvedCol(toColumn, sourceSchema.items, sourceAst)]]
|
|
235
|
+
]);
|
|
236
|
+
}
|
|
237
|
+
if (sourceSchema?.type === "object") {
|
|
238
|
+
const [keyColumn, valueColumn] = toColumns;
|
|
239
|
+
assert.ok(
|
|
240
|
+
keyColumn !== void 0 && valueColumn !== void 0,
|
|
241
|
+
`UNNEST of map column '${fromColumn}' requires exactly two alias columns (key, value)`
|
|
242
|
+
);
|
|
243
|
+
const addlProps = sourceSchema["additionalProperties"];
|
|
244
|
+
const valueSchema = typeof addlProps === "object" && addlProps !== null ? addlProps : { type: "string" };
|
|
245
|
+
return /* @__PURE__ */ new Map([
|
|
246
|
+
[keyColumn, [resolvedCol(keyColumn, { type: "string" }, sourceAst)]],
|
|
247
|
+
[valueColumn, [resolvedCol(valueColumn, valueSchema, sourceAst)]]
|
|
248
|
+
]);
|
|
249
|
+
}
|
|
250
|
+
if (!hasKnownApiOperation) {
|
|
251
|
+
return new Map(
|
|
252
|
+
toColumns.map((toColumn) => [toColumn, [resolvedCol(toColumn, {})]])
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
throw new AthenaError(
|
|
256
|
+
ATHENA_ERROR,
|
|
257
|
+
`UNNEST source column '${fromColumn}' must resolve to an array or map schema`,
|
|
258
|
+
ast
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
function applyUnnestPre(mappings, ctx) {
|
|
262
|
+
const deferred = [];
|
|
263
|
+
for (const { fromColumn, toColumns, tableAlias, ast } of mappings) {
|
|
264
|
+
const ownerTable = flattenTables(ctx).find(
|
|
265
|
+
(table) => table.columns.has(fromColumn)
|
|
266
|
+
);
|
|
267
|
+
if (ownerTable === void 0) {
|
|
268
|
+
deferred.push({
|
|
269
|
+
fromColumn,
|
|
270
|
+
toColumns,
|
|
271
|
+
...tableAlias !== void 0 ? { tableAlias } : {},
|
|
272
|
+
ast
|
|
273
|
+
});
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const sourceColumns = ownerTable.columns.get(fromColumn) ?? [];
|
|
277
|
+
const unnestTableName = `${ownerTable.name ?? ANONYMOUS_TABLE}:<unnested>`;
|
|
278
|
+
const apiOperation = ownerTable.apiOperation !== void 0 ? { apiOperation: ownerTable.apiOperation } : {};
|
|
279
|
+
const unnestColumns = buildUnnestColumnMap(
|
|
280
|
+
fromColumn,
|
|
281
|
+
toColumns,
|
|
282
|
+
sourceColumns[0]?.schema,
|
|
283
|
+
sourceColumns[0]?.ast,
|
|
284
|
+
ast,
|
|
285
|
+
ownerTable.apiOperation !== void 0
|
|
286
|
+
);
|
|
287
|
+
const unnestEntry = [
|
|
288
|
+
{ name: unnestTableName, ...apiOperation, columns: unnestColumns }
|
|
289
|
+
];
|
|
290
|
+
ctx.tables.set(unnestTableName, unnestEntry);
|
|
291
|
+
if (tableAlias !== void 0) {
|
|
292
|
+
ctx.tables.set(tableAlias, unnestEntry);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return deferred;
|
|
296
|
+
}
|
|
297
|
+
function applyUnnestPost(mappings, columns) {
|
|
298
|
+
for (const { fromColumn, toColumns, ast } of mappings) {
|
|
299
|
+
const sourceColumns = columns.get(fromColumn);
|
|
300
|
+
if (sourceColumns === void 0) {
|
|
301
|
+
throw new AthenaError(
|
|
302
|
+
ATHENA_ERROR,
|
|
303
|
+
`UNNEST source column '${fromColumn}' not found in SELECT`,
|
|
304
|
+
ast
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
const unnestColumns = buildUnnestColumnMap(
|
|
308
|
+
fromColumn,
|
|
309
|
+
toColumns,
|
|
310
|
+
sourceColumns[0]?.schema,
|
|
311
|
+
sourceColumns[0]?.ast,
|
|
312
|
+
ast,
|
|
313
|
+
true
|
|
314
|
+
);
|
|
315
|
+
for (const [key, value] of unnestColumns) {
|
|
316
|
+
columns.set(key, value);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function resolveDefaultSchemaColumn(columnAlias, indexedName, columnAST, columns) {
|
|
321
|
+
const name = columnAlias ?? indexedName;
|
|
322
|
+
columns.set(name, [
|
|
323
|
+
resolvedCol(name, { type: "string" }, columnAST)
|
|
324
|
+
]);
|
|
325
|
+
}
|
|
326
|
+
function expandWildcard(referencedTables, columns) {
|
|
327
|
+
for (const table of referencedTables) {
|
|
328
|
+
for (const [colName, cols] of table.columns) {
|
|
329
|
+
columns.set(colName, cols);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
function schemaPropertyHint(resolvedColumns) {
|
|
334
|
+
if (resolvedColumns.length === 0) {
|
|
335
|
+
return "";
|
|
336
|
+
}
|
|
337
|
+
const firstSchema = resolvedColumns[0]?.schema;
|
|
338
|
+
if (!resolvedColumns.every(
|
|
339
|
+
(col) => JSON.stringify(col.schema) === JSON.stringify(firstSchema)
|
|
340
|
+
)) {
|
|
341
|
+
return "";
|
|
342
|
+
}
|
|
343
|
+
if (firstSchema?.type !== "object" || firstSchema.properties === void 0) {
|
|
344
|
+
return "";
|
|
345
|
+
}
|
|
346
|
+
const propNames = Object.keys(firstSchema.properties);
|
|
347
|
+
return propNames.length > 0 ? `; available properties: ${propNames.join(", ")}` : "";
|
|
348
|
+
}
|
|
349
|
+
function resolveSchemaAtPath(colRef, propertyAccessor, resolvedColumns, ast) {
|
|
350
|
+
const adjustedPath = `$.${propertyAccessor.substring(1).replace(/(?<sep>\.|\[)/gu, "..properties$<sep>")}`;
|
|
351
|
+
log("adjusted path", adjustedPath);
|
|
352
|
+
const extractedSchemas = resolvedColumns.flatMap(
|
|
353
|
+
(col) => JSONPath({ json: col.schema, path: adjustedPath })
|
|
354
|
+
);
|
|
355
|
+
log("extracted schemas", extractedSchemas);
|
|
356
|
+
if (extractedSchemas.length === 0) {
|
|
357
|
+
throw new AthenaError(
|
|
358
|
+
ATHENA_ERROR,
|
|
359
|
+
`Column "${colRef}" has no property at path "${propertyAccessor}"${schemaPropertyHint(resolvedColumns)}`,
|
|
360
|
+
ast
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
return extractedSchemas;
|
|
364
|
+
}
|
|
365
|
+
function navigateSchemaPath(colRef, propertyAccessor, resolvedColumns, colName, columnAST, columns) {
|
|
366
|
+
const errorAst = extractJsonExtractCalls(columnAST)[0]?.fnNode ?? columnAST;
|
|
367
|
+
const extractedSchemas = resolveSchemaAtPath(
|
|
368
|
+
colRef,
|
|
369
|
+
propertyAccessor,
|
|
370
|
+
resolvedColumns,
|
|
371
|
+
errorAst
|
|
372
|
+
);
|
|
373
|
+
columns.set(
|
|
374
|
+
colName,
|
|
375
|
+
extractedSchemas.map(
|
|
376
|
+
(schema) => resolvedCol(colName, schema, columnAST)
|
|
377
|
+
)
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
function throwUnknownTableError(tableRef, colRef, ctx, ref) {
|
|
381
|
+
throw new AthenaError(
|
|
382
|
+
ATHENA_ERROR,
|
|
383
|
+
`Table or alias "${tableRef ?? colRef}" does not exist. Known tables: ${[...ctx.tables.keys()].join(", ")}`,
|
|
384
|
+
ref
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
function resolveReferencedTablesOrThrow(tableRef, colRef, allTables, ctx, ref) {
|
|
388
|
+
const referencedTables = resolveReferencedTables(tableRef, allTables, ctx);
|
|
389
|
+
if (referencedTables.length === 0) {
|
|
390
|
+
throwUnknownTableError(tableRef, colRef, ctx, ref);
|
|
391
|
+
}
|
|
392
|
+
return referencedTables;
|
|
393
|
+
}
|
|
394
|
+
function lookupColumnOrThrow(colRef, ref, referencedTables) {
|
|
395
|
+
const resolvedColumns = referencedTables.flatMap(
|
|
396
|
+
(table) => table.columns.get(colRef) ?? []
|
|
397
|
+
);
|
|
398
|
+
if (resolvedColumns.length === 0) {
|
|
399
|
+
const tableNames = [
|
|
400
|
+
...new Set(
|
|
401
|
+
referencedTables.map(
|
|
402
|
+
(referenceTable) => referenceTable.name ?? ANONYMOUS_TABLE
|
|
403
|
+
)
|
|
404
|
+
)
|
|
405
|
+
].join(", ");
|
|
406
|
+
const availableCols = [
|
|
407
|
+
...new Set(
|
|
408
|
+
referencedTables.flatMap((table) => [...table.columns.keys()])
|
|
409
|
+
)
|
|
410
|
+
].join(", ");
|
|
411
|
+
throw new AthenaError(
|
|
412
|
+
ATHENA_ERROR,
|
|
413
|
+
`Column "${colRef}" does not exist in table(s) ${tableNames}. Available columns: ${availableCols}`,
|
|
414
|
+
ref
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
return resolvedColumns;
|
|
418
|
+
}
|
|
419
|
+
function checkColumnRefsExist(ast, allTables, ctx, selectColumns) {
|
|
420
|
+
if (containsLambda(ast)) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
for (const ref of extractColumnRefs(ast)) {
|
|
424
|
+
const { tableRef, colRef } = resolveColumnRefParts(ref);
|
|
425
|
+
if (colRef === void 0 || colRef === "*") {
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
if (tableRef === void 0 && selectColumns?.has(colRef) === true) {
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
const referencedTables = resolveReferencedTablesOrThrow(
|
|
432
|
+
tableRef,
|
|
433
|
+
colRef,
|
|
434
|
+
allTables,
|
|
435
|
+
ctx,
|
|
436
|
+
ref
|
|
437
|
+
);
|
|
438
|
+
lookupColumnOrThrow(colRef, ref, referencedTables);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function validateComplexColumnExpression(columnAST, allTables, ctx) {
|
|
442
|
+
for (const { ref, path, fnNode } of extractJsonExtractCalls(columnAST)) {
|
|
443
|
+
const { tableRef, colRef } = resolveColumnRefParts(ref);
|
|
444
|
+
if (colRef === void 0) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
const referencedTables = resolveReferencedTables(tableRef, allTables, ctx);
|
|
448
|
+
const resolvedColumns = referencedTables.flatMap(
|
|
449
|
+
(table) => table.columns.get(colRef) ?? []
|
|
450
|
+
);
|
|
451
|
+
if (resolvedColumns.length > 0) {
|
|
452
|
+
resolveSchemaAtPath(colRef, path, resolvedColumns, fnNode);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
function resolveSingleColumnRef(columnAST, columnAlias, indexedName, ref, allTables, ctx, columns) {
|
|
457
|
+
const { tableRef, colRef } = resolveColumnRefParts(ref);
|
|
458
|
+
assert.ok(colRef !== void 0, "column_ref must have a string column name");
|
|
459
|
+
const referencedTables = resolveReferencedTablesOrThrow(
|
|
460
|
+
tableRef,
|
|
461
|
+
colRef,
|
|
462
|
+
allTables,
|
|
463
|
+
ctx,
|
|
464
|
+
ref
|
|
465
|
+
);
|
|
466
|
+
if (colRef === "*") {
|
|
467
|
+
expandWildcard(referencedTables, columns);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
const withFunctions = hasFunctionCalls(columnAST);
|
|
471
|
+
const colName = columnAlias ?? (withFunctions ? indexedName : colRef);
|
|
472
|
+
const resolvedColumns = lookupColumnOrThrow(colRef, ref, referencedTables);
|
|
473
|
+
const propertyAccessor = extractJsonExtractPath(columnAST) ?? extractBracketAccessorPath(columnAST);
|
|
474
|
+
if (propertyAccessor !== void 0) {
|
|
475
|
+
navigateSchemaPath(
|
|
476
|
+
colRef,
|
|
477
|
+
propertyAccessor,
|
|
478
|
+
resolvedColumns,
|
|
479
|
+
colName,
|
|
480
|
+
columnAST,
|
|
481
|
+
columns
|
|
482
|
+
);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
columns.set(
|
|
486
|
+
colName,
|
|
487
|
+
resolvedColumns.map(
|
|
488
|
+
(col) => resolvedCol(colName, col.schema, columnAST)
|
|
489
|
+
)
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
function applySchemaTypeOverride(columnAST, columnAlias, indexedName, columns, predicate, schemaType) {
|
|
493
|
+
if (!predicate(columnAST)) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const colName = columnAlias ?? indexedName;
|
|
497
|
+
const existing = columns.get(colName);
|
|
498
|
+
if (existing !== void 0 && existing[0]?.schema.type !== schemaType) {
|
|
499
|
+
columns.set(
|
|
500
|
+
colName,
|
|
501
|
+
existing.map(
|
|
502
|
+
(col) => resolvedCol(col.name, { type: schemaType }, col.ast)
|
|
503
|
+
)
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function validateClauseExpression(expression, allTables, ctx, selectColumns) {
|
|
508
|
+
checkColumnRefsExist(expression, allTables, ctx, selectColumns);
|
|
509
|
+
validateComplexColumnExpression(expression, allTables, ctx);
|
|
510
|
+
}
|
|
511
|
+
function resolveSelectColumns(select, ctx) {
|
|
512
|
+
const allTables = flattenTables(ctx);
|
|
513
|
+
const columns = /* @__PURE__ */ new Map();
|
|
514
|
+
for (const [index, columnAST] of select.columns.entries()) {
|
|
515
|
+
log("resolving column", columnAST);
|
|
516
|
+
const columnAlias = columnAST.as ?? void 0;
|
|
517
|
+
const indexedName = `_col${String(index)}`;
|
|
518
|
+
const columnRefs = extractColumnRefs(columnAST);
|
|
519
|
+
if (columnRefs.length !== 1) {
|
|
520
|
+
validateClauseExpression(columnAST, allTables, ctx);
|
|
521
|
+
resolveDefaultSchemaColumn(columnAlias, indexedName, columnAST, columns);
|
|
522
|
+
} else {
|
|
523
|
+
const [ref] = columnRefs;
|
|
524
|
+
assert.ok(ref !== void 0);
|
|
525
|
+
resolveSingleColumnRef(
|
|
526
|
+
columnAST,
|
|
527
|
+
columnAlias,
|
|
528
|
+
indexedName,
|
|
529
|
+
ref,
|
|
530
|
+
allTables,
|
|
531
|
+
ctx,
|
|
532
|
+
columns
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
applySchemaTypeOverride(
|
|
536
|
+
columnAST,
|
|
537
|
+
columnAlias,
|
|
538
|
+
indexedName,
|
|
539
|
+
columns,
|
|
540
|
+
containsCastToArray,
|
|
541
|
+
"array"
|
|
542
|
+
);
|
|
543
|
+
applySchemaTypeOverride(
|
|
544
|
+
columnAST,
|
|
545
|
+
columnAlias,
|
|
546
|
+
indexedName,
|
|
547
|
+
columns,
|
|
548
|
+
containsCastToMap,
|
|
549
|
+
"object"
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
return columns;
|
|
553
|
+
}
|
|
554
|
+
function checkSelect(selectAST, ctx, withTableName) {
|
|
555
|
+
const select = "stmt" in selectAST ? selectAST.stmt.ast : selectAST;
|
|
556
|
+
const selectCtx = createChildContext(ctx);
|
|
557
|
+
resolveFromClause(select, selectCtx);
|
|
558
|
+
restrictToFromClause(select, selectCtx);
|
|
559
|
+
const unnestMappings = extractUnnestMappings(select);
|
|
560
|
+
const deferredUnnest = applyUnnestPre(unnestMappings, selectCtx);
|
|
561
|
+
const columns = resolveSelectColumns(select, selectCtx);
|
|
562
|
+
applyUnnestPost(deferredUnnest, columns);
|
|
563
|
+
log("resolved columns", [...columns.keys()]);
|
|
564
|
+
const allTables = flattenTables(selectCtx);
|
|
565
|
+
for (const item of fromClauseItems(select)) {
|
|
566
|
+
const onExpr = item.on;
|
|
567
|
+
if (onExpr !== void 0) {
|
|
568
|
+
validateClauseExpression(onExpr, allTables, selectCtx);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
if (select.where !== null) {
|
|
572
|
+
validateClauseExpression(select.where, allTables, selectCtx);
|
|
573
|
+
}
|
|
574
|
+
if (select.having !== null) {
|
|
575
|
+
validateClauseExpression(select.having, allTables, selectCtx, columns);
|
|
576
|
+
}
|
|
577
|
+
for (const orderItem of select.orderby ?? []) {
|
|
578
|
+
validateClauseExpression(orderItem.expr, allTables, selectCtx, columns);
|
|
579
|
+
}
|
|
580
|
+
if (select.groupby?.columns !== void 0) {
|
|
581
|
+
for (const groupCol of select.groupby.columns) {
|
|
582
|
+
validateClauseExpression(groupCol, allTables, selectCtx, columns);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (select._next !== void 0) {
|
|
586
|
+
const nextColumns = checkSelect(select._next, ctx, withTableName);
|
|
587
|
+
if (columns.size !== nextColumns.size) {
|
|
588
|
+
throw new AthenaError(
|
|
589
|
+
ATHENA_ERROR,
|
|
590
|
+
`UNION ALL parts have different number of columns: ${columns.size.toString()} vs ${nextColumns.size.toString()}`,
|
|
591
|
+
select._next
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
if (withTableName !== void 0) {
|
|
596
|
+
const resolvedTable = { name: withTableName, columns };
|
|
597
|
+
ctx.tables.set(withTableName, [resolvedTable]);
|
|
598
|
+
}
|
|
599
|
+
return columns;
|
|
600
|
+
}
|
|
601
|
+
function checkAthenaAst(ast, ctx) {
|
|
602
|
+
assert.ok(ast.type === "select");
|
|
603
|
+
const select = ast;
|
|
604
|
+
if (select.with !== null) {
|
|
605
|
+
for (const withItem of select.with) {
|
|
606
|
+
checkSelect(withItem.stmt.ast, ctx, withItem.name.value);
|
|
607
|
+
}
|
|
608
|
+
select.with = null;
|
|
609
|
+
}
|
|
610
|
+
checkSelect(select, ctx);
|
|
611
|
+
}
|
|
612
|
+
export {
|
|
613
|
+
ATHENA_ERROR,
|
|
614
|
+
AthenaError,
|
|
615
|
+
SYNTAXT_ERROR,
|
|
616
|
+
checkAthenaAst,
|
|
617
|
+
offsetToLoc
|
|
618
|
+
};
|
|
619
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F0aGVuYS92YWxpZGF0ZS50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFVQSxTQUFTLFVBQVUsY0FBYztBQUVqQyxPQUFPLFdBQVc7QUFDbEIsU0FBUyxnQkFBZ0I7QUFJekIsU0FBUyxnQkFBZ0I7QUFDekIsU0FBUyxpQkFBaUI7QUFDMUI7QUFBQSxFQUNFO0FBQUEsT0FJSztBQUNQLFNBQVMsMEJBQTBCO0FBQ25DO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUVLO0FBRUEsSUFBTSxnQkFBZ0I7QUFDdEIsSUFBTSxlQUFlO0FBRXJCLElBQU0sY0FBTixjQUEwQixNQUFNO0FBQUEsRUFDOUI7QUFBQSxFQUNBO0FBQUEsRUFDUCxZQUFZLE1BQWMsU0FBaUIsS0FBYztBQUN2RCxVQUFNLE9BQU87QUFDYixTQUFLLE9BQU87QUFDWixTQUFLLE9BQU87QUFDWixRQUFJLFFBQVEsUUFBVztBQUNyQixXQUFLLE1BQU07QUFBQSxJQUNiO0FBQUEsRUFDRjtBQUNGO0FBR08sU0FBUyxZQUNkLE1BQ0EsUUFDa0M7QUFDbEMsUUFBTSxTQUFTLEtBQUssTUFBTSxHQUFHLE1BQU07QUFDbkMsUUFBTSxRQUFRLE9BQU8sTUFBTSxJQUFJO0FBQy9CLFNBQU8sRUFBRSxNQUFNLE1BQU0sUUFBUSxRQUFRLE1BQU0sTUFBTSxTQUFTLENBQUMsR0FBRyxVQUFVLEVBQUU7QUFDNUU7QUFFQSxJQUFNLE1BQU0sTUFBTSw2QkFBNkI7QUFDL0MsSUFBTSxrQkFBa0I7QUFDeEIsSUFBTSxpQkFBaUI7QUFNdkIsU0FBUyxZQUNQLE1BQ0EsUUFDQSxLQUNnQjtBQUNoQixTQUFPLFFBQVEsU0FBWSxFQUFFLE1BQU0sUUFBUSxJQUFJLElBQUks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
|