@deepagents/text2sql 2.1.0 → 2.2.0
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/README.md +46 -4
- package/dist/bin/sql.js +674 -116
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +344 -24
- package/dist/index.js.map +4 -4
- package/dist/lib/adapters/adapter.d.ts.map +1 -1
- package/dist/lib/adapters/bigquery/index.js +68 -21
- package/dist/lib/adapters/bigquery/index.js.map +2 -2
- package/dist/lib/adapters/mysql/index.js +68 -21
- package/dist/lib/adapters/mysql/index.js.map +2 -2
- package/dist/lib/adapters/postgres/index.js +68 -21
- package/dist/lib/adapters/postgres/index.js.map +2 -2
- package/dist/lib/adapters/runtime-scope.d.ts +2 -0
- package/dist/lib/adapters/runtime-scope.d.ts.map +1 -1
- package/dist/lib/adapters/spreadsheet/index.js +68 -21
- package/dist/lib/adapters/spreadsheet/index.js.map +2 -2
- package/dist/lib/adapters/sqlite/index.js +68 -21
- package/dist/lib/adapters/sqlite/index.js.map +2 -2
- package/dist/lib/adapters/sqlserver/index.js +68 -21
- package/dist/lib/adapters/sqlserver/index.js.map +2 -2
- package/dist/lib/sql-command.d.ts +32 -0
- package/dist/lib/sql-command.d.ts.map +1 -0
- package/dist/lib/sql.d.ts +32 -8
- package/dist/lib/sql.d.ts.map +1 -1
- package/dist/lib/synthesis/index.js.map +2 -2
- package/package.json +4 -4
|
@@ -174,6 +174,13 @@ function createGroundingContext(options = {}) {
|
|
|
174
174
|
import nodeSqlParser from "node-sql-parser";
|
|
175
175
|
var { Parser } = nodeSqlParser;
|
|
176
176
|
var parser = new Parser();
|
|
177
|
+
function parseStatementTypes(sql, dialect) {
|
|
178
|
+
const ast = parser.astify(sql, { database: dialect });
|
|
179
|
+
const statements = Array.isArray(ast) ? ast : [ast];
|
|
180
|
+
return statements.flatMap(
|
|
181
|
+
(statement) => isAstLike(statement) && typeof statement.type === "string" ? [statement.type] : []
|
|
182
|
+
);
|
|
183
|
+
}
|
|
177
184
|
function extractBaseEntityReferences(sql, dialect) {
|
|
178
185
|
const ast = parser.astify(sql, { database: dialect });
|
|
179
186
|
const state = {
|
|
@@ -299,6 +306,22 @@ function caseFold(value) {
|
|
|
299
306
|
}
|
|
300
307
|
|
|
301
308
|
// packages/text2sql/src/lib/adapters/adapter.ts
|
|
309
|
+
var PARSER_DIALECTS_BY_FORMATTER_LANGUAGE = {
|
|
310
|
+
sqlite: ["sqlite", "mysql"],
|
|
311
|
+
postgresql: ["postgresql"],
|
|
312
|
+
bigquery: ["bigquery"],
|
|
313
|
+
transactsql: ["transactsql"],
|
|
314
|
+
mysql: ["mysql"]
|
|
315
|
+
};
|
|
316
|
+
function parserDialectsFor(formatterLanguage) {
|
|
317
|
+
const candidates = PARSER_DIALECTS_BY_FORMATTER_LANGUAGE[formatterLanguage];
|
|
318
|
+
if (!candidates) {
|
|
319
|
+
throw new TypeError(
|
|
320
|
+
`No scope dialect mapping for formatter language "${formatterLanguage}". Add it to PARSER_DIALECTS_BY_FORMATTER_LANGUAGE in adapter.ts.`
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
return candidates;
|
|
324
|
+
}
|
|
302
325
|
var Adapter = class {
|
|
303
326
|
/**
|
|
304
327
|
* Introspect the database schema and return context fragments.
|
|
@@ -520,10 +543,49 @@ var Adapter = class {
|
|
|
520
543
|
return sql.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\([().*])/g, "$1").replace(/\\(?=$)/gm, "");
|
|
521
544
|
}
|
|
522
545
|
#checkReadOnly(sql) {
|
|
523
|
-
const
|
|
524
|
-
if (
|
|
546
|
+
const statementTypes = this.#readParsedStatementTypes(sql);
|
|
547
|
+
if (statementTypes) {
|
|
548
|
+
if (statementTypes.length === 1 && statementTypes[0] === "select") {
|
|
549
|
+
return null;
|
|
550
|
+
}
|
|
525
551
|
return "only SELECT or WITH queries allowed";
|
|
526
552
|
}
|
|
553
|
+
const keyword = this.#firstStatementKeyword(sql);
|
|
554
|
+
if (keyword === "SELECT" || keyword === "WITH") return null;
|
|
555
|
+
return "only SELECT or WITH queries allowed";
|
|
556
|
+
}
|
|
557
|
+
#readParsedStatementTypes(sql) {
|
|
558
|
+
for (const dialect of parserDialectsFor(this.formatterLanguage)) {
|
|
559
|
+
try {
|
|
560
|
+
return parseStatementTypes(sql, dialect);
|
|
561
|
+
} catch {
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return null;
|
|
565
|
+
}
|
|
566
|
+
#firstStatementKeyword(sql) {
|
|
567
|
+
let offset = 0;
|
|
568
|
+
while (offset < sql.length) {
|
|
569
|
+
if (/\s/.test(sql[offset])) {
|
|
570
|
+
offset++;
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
if (sql.startsWith("--", offset)) {
|
|
574
|
+
offset += 2;
|
|
575
|
+
while (offset < sql.length && sql[offset] !== "\n" && sql[offset] !== "\r") {
|
|
576
|
+
offset++;
|
|
577
|
+
}
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
580
|
+
if (sql.startsWith("/*", offset)) {
|
|
581
|
+
const commentEnd = sql.indexOf("*/", offset + 2);
|
|
582
|
+
if (commentEnd === -1) return null;
|
|
583
|
+
offset = commentEnd + 2;
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
const keyword = /^[A-Za-z]+/.exec(sql.slice(offset));
|
|
587
|
+
return keyword ? keyword[0].toUpperCase() : null;
|
|
588
|
+
}
|
|
527
589
|
return null;
|
|
528
590
|
}
|
|
529
591
|
#cachedAllowedEntities = null;
|
|
@@ -533,36 +595,21 @@ var Adapter = class {
|
|
|
533
595
|
return this.#cachedAllowedEntities;
|
|
534
596
|
}
|
|
535
597
|
async #checkScope(sql, allowedEntities) {
|
|
536
|
-
const
|
|
537
|
-
const scopeDialects = {
|
|
538
|
-
sqlite: ["sqlite", "mysql"],
|
|
539
|
-
postgresql: ["postgresql"],
|
|
540
|
-
bigquery: ["bigquery"],
|
|
541
|
-
transactsql: ["transactsql"],
|
|
542
|
-
mysql: ["mysql"]
|
|
543
|
-
};
|
|
544
|
-
const candidates = scopeDialects[dialect];
|
|
545
|
-
if (!candidates) {
|
|
546
|
-
throw new TypeError(
|
|
547
|
-
`No scope dialect mapping for formatter language "${dialect}". Add it to the scopeDialects map in Adapter.#checkScope.`
|
|
548
|
-
);
|
|
549
|
-
}
|
|
598
|
+
const candidates = parserDialectsFor(this.formatterLanguage);
|
|
550
599
|
let references = null;
|
|
551
600
|
let lastError;
|
|
601
|
+
let lastDialect = candidates[0];
|
|
552
602
|
for (const candidate of candidates) {
|
|
553
603
|
try {
|
|
554
604
|
references = extractBaseEntityReferences(sql, candidate);
|
|
555
605
|
break;
|
|
556
606
|
} catch (error) {
|
|
607
|
+
lastDialect = candidate;
|
|
557
608
|
lastError = error;
|
|
558
609
|
}
|
|
559
610
|
}
|
|
560
611
|
if (references === null) {
|
|
561
|
-
return buildScopeParseErrorPayload(
|
|
562
|
-
sql,
|
|
563
|
-
dialect,
|
|
564
|
-
lastError
|
|
565
|
-
);
|
|
612
|
+
return buildScopeParseErrorPayload(sql, lastDialect, lastError);
|
|
566
613
|
}
|
|
567
614
|
if (references.length === 0) return null;
|
|
568
615
|
const allowedQualified = new Set(
|