@pineliner/odb-client 1.0.3 → 1.0.5
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/database/sql-parser.d.ts +1 -1
- package/dist/database/sql-parser.d.ts.map +1 -1
- package/dist/database/types.d.ts +3 -1
- package/dist/database/types.d.ts.map +1 -1
- package/dist/index.cjs +80 -57
- package/dist/index.js +80 -57
- package/package.json +1 -1
- package/src/database/adapters/bun-sqlite.ts +35 -8
- package/src/database/adapters/libsql.ts +17 -3
- package/src/database/adapters/odblite.ts +26 -2
- package/src/database/sql-parser.ts +26 -64
- package/src/database/types.ts +4 -2
|
@@ -7,7 +7,7 @@ export interface SQLParserOptions {
|
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* Parse SQL file into statements, separating PRAGMA from regular SQL
|
|
10
|
-
* Uses
|
|
10
|
+
* Uses custom parser that handles BEGIN...END blocks
|
|
11
11
|
*/
|
|
12
12
|
export declare function parseSQL(sqlContent: string, options?: SQLParserOptions): ParsedStatements;
|
|
13
13
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql-parser.d.ts","sourceRoot":"","sources":["../../src/database/sql-parser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sql-parser.d.ts","sourceRoot":"","sources":["../../src/database/sql-parser.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,iBAAiB,EAAE,MAAM,EAAE,CAAA;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,gBAAgB,CA0B7F;AAoFD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAG/D"}
|
package/dist/database/types.d.ts
CHANGED
|
@@ -19,13 +19,15 @@ export interface QueryResult<T = any> {
|
|
|
19
19
|
* All backends implement this through adapters
|
|
20
20
|
*/
|
|
21
21
|
export interface Connection {
|
|
22
|
-
|
|
22
|
+
sql<T = any>(strings: TemplateStringsArray, ...values: any[]): Promise<QueryResult<T>>;
|
|
23
|
+
query<T = any>(sql: string, params?: any[]): Promise<QueryResult<T>>;
|
|
23
24
|
execute(sql: string | {
|
|
24
25
|
sql: string;
|
|
25
26
|
args?: any[];
|
|
26
27
|
}, params?: any[]): Promise<QueryResult>;
|
|
27
28
|
prepare(sql: string): PreparedStatement;
|
|
28
29
|
transaction<T>(fn: (tx: Connection) => Promise<T>): Promise<T>;
|
|
30
|
+
begin<T>(fn: (tx: Connection) => Promise<T>): Promise<T>;
|
|
29
31
|
close(): Promise<void>;
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/database/types.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,cAAc,GACd,WAAW,GACX,WAAW,CAAA;AAEf;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE7D;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAClC,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IAEzB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/database/types.ts"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1120,26 +1120,41 @@ const external_bun_sqlite_namespaceObject = require("bun:sqlite");
|
|
|
1120
1120
|
}
|
|
1121
1121
|
/**
|
|
1122
1122
|
* Template tag query (postgres.js-like)
|
|
1123
|
-
*/ async
|
|
1123
|
+
*/ async sql(strings, ...values) {
|
|
1124
1124
|
// Build SQL from template
|
|
1125
|
-
const
|
|
1126
|
-
return this.execute(
|
|
1125
|
+
const sqlStr = strings.reduce((acc, str, i)=>acc + str + (i < values.length ? '?' : ''), '');
|
|
1126
|
+
return this.execute(sqlStr, values);
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Query with SQL string and parameters (alias for execute)
|
|
1130
|
+
*/ async query(sql, params = []) {
|
|
1131
|
+
return this.execute(sql, params);
|
|
1127
1132
|
}
|
|
1128
1133
|
/**
|
|
1129
1134
|
* Execute SQL with parameters
|
|
1130
1135
|
*/ async execute(sql, params = []) {
|
|
1131
1136
|
try {
|
|
1132
|
-
|
|
1133
|
-
|
|
1137
|
+
// Handle object format { sql, args }
|
|
1138
|
+
let sqlStr;
|
|
1139
|
+
let sqlParams;
|
|
1140
|
+
if ('object' == typeof sql) {
|
|
1141
|
+
sqlStr = sql.sql;
|
|
1142
|
+
sqlParams = sql.args || [];
|
|
1143
|
+
} else {
|
|
1144
|
+
sqlStr = sql;
|
|
1145
|
+
sqlParams = params;
|
|
1146
|
+
}
|
|
1147
|
+
const stmt = this.db.query(sqlStr);
|
|
1148
|
+
const isSelect = sqlStr.trim().toUpperCase().startsWith('SELECT') || sqlStr.trim().toUpperCase().includes('RETURNING');
|
|
1134
1149
|
if (isSelect) {
|
|
1135
|
-
const rows = stmt.all(...
|
|
1150
|
+
const rows = stmt.all(...sqlParams);
|
|
1136
1151
|
return {
|
|
1137
1152
|
rows: rows,
|
|
1138
1153
|
rowsAffected: 0
|
|
1139
1154
|
};
|
|
1140
1155
|
}
|
|
1141
1156
|
{
|
|
1142
|
-
const result = stmt.run(...
|
|
1157
|
+
const result = stmt.run(...sqlParams);
|
|
1143
1158
|
return {
|
|
1144
1159
|
rows: [],
|
|
1145
1160
|
rowsAffected: result.changes || 0,
|
|
@@ -1196,6 +1211,11 @@ const external_bun_sqlite_namespaceObject = require("bun:sqlite");
|
|
|
1196
1211
|
}
|
|
1197
1212
|
}
|
|
1198
1213
|
/**
|
|
1214
|
+
* Execute function in transaction (alias for transaction)
|
|
1215
|
+
*/ async begin(fn) {
|
|
1216
|
+
return this.transaction(fn);
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1199
1219
|
* Close connection
|
|
1200
1220
|
*/ async close() {
|
|
1201
1221
|
this.db.close();
|
|
@@ -1246,10 +1266,15 @@ const external_libsql_client_namespaceObject = require("@libsql/client");
|
|
|
1246
1266
|
}
|
|
1247
1267
|
/**
|
|
1248
1268
|
* Template tag query (postgres.js-like)
|
|
1249
|
-
*/ async
|
|
1269
|
+
*/ async sql(strings, ...values) {
|
|
1250
1270
|
// Build SQL from template
|
|
1251
|
-
const
|
|
1252
|
-
return this.execute(
|
|
1271
|
+
const sqlStr = strings.reduce((acc, str, i)=>acc + str + (i < values.length ? '?' : ''), '');
|
|
1272
|
+
return this.execute(sqlStr, values);
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Query with SQL string and parameters (alias for execute)
|
|
1276
|
+
*/ async query(sql, params = []) {
|
|
1277
|
+
return this.execute(sql, params);
|
|
1253
1278
|
}
|
|
1254
1279
|
/**
|
|
1255
1280
|
* Execute SQL with parameters
|
|
@@ -1308,6 +1333,11 @@ const external_libsql_client_namespaceObject = require("@libsql/client");
|
|
|
1308
1333
|
}
|
|
1309
1334
|
}
|
|
1310
1335
|
/**
|
|
1336
|
+
* Execute function in transaction (alias for transaction)
|
|
1337
|
+
*/ async begin(fn) {
|
|
1338
|
+
return this.transaction(fn);
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1311
1341
|
* Close connection
|
|
1312
1342
|
*/ async close() {
|
|
1313
1343
|
// LibSQL client.close() if available in future versions
|
|
@@ -1380,7 +1410,7 @@ const external_libsql_client_namespaceObject = require("@libsql/client");
|
|
|
1380
1410
|
}
|
|
1381
1411
|
/**
|
|
1382
1412
|
* Template tag query (postgres.js-like)
|
|
1383
|
-
*/ async
|
|
1413
|
+
*/ async sql(strings, ...values) {
|
|
1384
1414
|
// ODBLiteClient.sql is a function that returns a Promise
|
|
1385
1415
|
const result = await this.client.sql(strings, ...values);
|
|
1386
1416
|
return {
|
|
@@ -1389,9 +1419,23 @@ const external_libsql_client_namespaceObject = require("@libsql/client");
|
|
|
1389
1419
|
};
|
|
1390
1420
|
}
|
|
1391
1421
|
/**
|
|
1422
|
+
* Query with SQL string and parameters (alias for execute)
|
|
1423
|
+
*/ async query(sql, params = []) {
|
|
1424
|
+
return this.execute(sql, params);
|
|
1425
|
+
}
|
|
1426
|
+
/**
|
|
1392
1427
|
* Execute SQL with parameters
|
|
1393
1428
|
*/ async execute(sql, params = []) {
|
|
1394
1429
|
try {
|
|
1430
|
+
// Handle object format { sql, args }
|
|
1431
|
+
if ('object' == typeof sql) {
|
|
1432
|
+
const result = await this.client.sql.execute(sql.sql, sql.args || []);
|
|
1433
|
+
return {
|
|
1434
|
+
rows: result.rows,
|
|
1435
|
+
rowsAffected: result.rowsAffected || 0
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
// Handle string format
|
|
1395
1439
|
const result = await this.client.sql.execute(sql, params);
|
|
1396
1440
|
return {
|
|
1397
1441
|
rows: result.rows,
|
|
@@ -1435,20 +1479,24 @@ const external_libsql_client_namespaceObject = require("@libsql/client");
|
|
|
1435
1479
|
}
|
|
1436
1480
|
}
|
|
1437
1481
|
/**
|
|
1482
|
+
* Execute function in transaction (alias for transaction)
|
|
1483
|
+
*/ async begin(fn) {
|
|
1484
|
+
return this.transaction(fn);
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1438
1487
|
* Close connection
|
|
1439
1488
|
*/ async close() {
|
|
1440
1489
|
// ODBLiteClient connections are stateless HTTP requests
|
|
1441
1490
|
// No explicit close needed
|
|
1442
1491
|
}
|
|
1443
1492
|
}
|
|
1444
|
-
const external_node_sql_parser_namespaceObject = require("node-sql-parser");
|
|
1445
1493
|
/**
|
|
1446
1494
|
* Parse SQL file into statements, separating PRAGMA from regular SQL
|
|
1447
|
-
* Uses
|
|
1495
|
+
* Uses custom parser that handles BEGIN...END blocks
|
|
1448
1496
|
*/ function parseSQL(sqlContent, options = {}) {
|
|
1449
1497
|
const separatePragma = options.separatePragma ?? true;
|
|
1450
|
-
//
|
|
1451
|
-
const statements =
|
|
1498
|
+
// Split SQL statements manually
|
|
1499
|
+
const statements = splitStatements(sqlContent);
|
|
1452
1500
|
if (!separatePragma) return {
|
|
1453
1501
|
pragmaStatements: [],
|
|
1454
1502
|
regularStatements: statements
|
|
@@ -1465,54 +1513,29 @@ const external_node_sql_parser_namespaceObject = require("node-sql-parser");
|
|
|
1465
1513
|
regularStatements
|
|
1466
1514
|
};
|
|
1467
1515
|
}
|
|
1468
|
-
/**
|
|
1469
|
-
* Split SQL content using node-sql-parser (more robust than custom parser)
|
|
1470
|
-
* Falls back to simple split if parser fails
|
|
1471
|
-
*/ function splitStatementsWithParser(sqlContent) {
|
|
1472
|
-
try {
|
|
1473
|
-
const parser = new external_node_sql_parser_namespaceObject.Parser();
|
|
1474
|
-
// node-sql-parser supports splitting multiple statements
|
|
1475
|
-
// Try to use it, but have fallback for edge cases
|
|
1476
|
-
const opt = {
|
|
1477
|
-
database: 'sqlite',
|
|
1478
|
-
type: 'table'
|
|
1479
|
-
};
|
|
1480
|
-
// Split by semicolons first to handle parser limitations with very large files
|
|
1481
|
-
const roughStatements = sqlContent.split(/;[\s\n]*/).map((s)=>s.trim()).filter((s)=>s.length > 0);
|
|
1482
|
-
const validStatements = [];
|
|
1483
|
-
for (const stmt of roughStatements){
|
|
1484
|
-
// Add semicolon back
|
|
1485
|
-
const fullStmt = stmt + ';';
|
|
1486
|
-
// Skip comments-only statements
|
|
1487
|
-
if (!stmt.trim().startsWith('--') && '' !== stmt.trim()) // Validate with parser (but don't fail if it can't parse complex statements)
|
|
1488
|
-
try {
|
|
1489
|
-
parser.astify(fullStmt, opt);
|
|
1490
|
-
validStatements.push(fullStmt);
|
|
1491
|
-
} catch (parseError) {
|
|
1492
|
-
// If parser can't handle it, include it anyway if it looks like valid SQL
|
|
1493
|
-
// This handles complex statements like CREATE TRIGGER, CREATE VIEW with subqueries
|
|
1494
|
-
if (stmt.match(/^(CREATE|ALTER|DROP|INSERT|UPDATE|DELETE|SELECT|PRAGMA)/i)) validStatements.push(fullStmt);
|
|
1495
|
-
else console.warn(`Skipping potentially invalid statement: ${stmt.substring(0, 50)}...`);
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
return validStatements;
|
|
1499
|
-
} catch (error) {
|
|
1500
|
-
console.warn('node-sql-parser failed, using fallback parser:', error);
|
|
1501
|
-
// Fallback to original simple parser
|
|
1502
|
-
return splitStatements(sqlContent);
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
1516
|
/**
|
|
1506
1517
|
* Split SQL content into individual statements
|
|
1507
|
-
* Handles comments, quotes, and
|
|
1518
|
+
* Handles comments, quotes, semicolons, and BEGIN...END blocks properly
|
|
1508
1519
|
*/ function splitStatements(sqlContent) {
|
|
1509
1520
|
const statements = [];
|
|
1510
1521
|
let currentStatement = '';
|
|
1511
1522
|
let inQuote = false;
|
|
1512
1523
|
let quoteChar = '';
|
|
1524
|
+
let beginEndDepth = 0;
|
|
1513
1525
|
const lines = sqlContent.split('\n');
|
|
1514
1526
|
for (const line of lines){
|
|
1515
1527
|
let processedLine = '';
|
|
1528
|
+
const lineWithoutComments = line.replace(/--.*$/, '');
|
|
1529
|
+
// Track BEGIN...END depth for this line BEFORE processing characters
|
|
1530
|
+
if (!inQuote && lineWithoutComments.trim()) {
|
|
1531
|
+
const beginMatches = lineWithoutComments.match(/\bBEGIN\b/gi);
|
|
1532
|
+
const endMatches = lineWithoutComments.match(/\bEND\b/gi);
|
|
1533
|
+
if (beginMatches) beginEndDepth += beginMatches.length;
|
|
1534
|
+
if (endMatches) {
|
|
1535
|
+
beginEndDepth -= endMatches.length;
|
|
1536
|
+
if (beginEndDepth < 0) beginEndDepth = 0;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1516
1539
|
for(let i = 0; i < line.length; i++){
|
|
1517
1540
|
const char = line[i];
|
|
1518
1541
|
const prevChar = i > 0 ? line[i - 1] : '';
|
|
@@ -1532,11 +1555,11 @@ const external_node_sql_parser_namespaceObject = require("node-sql-parser");
|
|
|
1532
1555
|
}
|
|
1533
1556
|
}
|
|
1534
1557
|
processedLine += char;
|
|
1535
|
-
// Split on semicolon when not in quotes
|
|
1536
|
-
if (';' === char && !inQuote) {
|
|
1558
|
+
// Split on semicolon when not in quotes AND not inside BEGIN...END
|
|
1559
|
+
if (';' === char && !inQuote && 0 === beginEndDepth) {
|
|
1537
1560
|
currentStatement += processedLine;
|
|
1538
1561
|
const stmt = currentStatement.trim();
|
|
1539
|
-
if (stmt) statements.push(stmt);
|
|
1562
|
+
if (stmt && !stmt.startsWith('--')) statements.push(stmt);
|
|
1540
1563
|
currentStatement = '';
|
|
1541
1564
|
processedLine = '';
|
|
1542
1565
|
}
|
|
@@ -1545,7 +1568,7 @@ const external_node_sql_parser_namespaceObject = require("node-sql-parser");
|
|
|
1545
1568
|
}
|
|
1546
1569
|
// Handle remaining statement
|
|
1547
1570
|
const finalStmt = currentStatement.trim();
|
|
1548
|
-
if (finalStmt) statements.push(finalStmt);
|
|
1571
|
+
if (finalStmt && !finalStmt.startsWith('--')) statements.push(finalStmt);
|
|
1549
1572
|
return statements;
|
|
1550
1573
|
}
|
|
1551
1574
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as __WEBPACK_EXTERNAL_MODULE_bun_sqlite__ from "bun:sqlite";
|
|
2
2
|
import * as __WEBPACK_EXTERNAL_MODULE__libsql_client__ from "@libsql/client";
|
|
3
|
-
import * as __WEBPACK_EXTERNAL_MODULE_node_sql_parser__ from "node-sql-parser";
|
|
4
3
|
import * as __WEBPACK_EXTERNAL_MODULE_node_fs__ from "node:fs";
|
|
5
4
|
// Core types for the ODBLite client
|
|
6
5
|
// Error types
|
|
@@ -1047,26 +1046,41 @@ ODBLiteClient.join;
|
|
|
1047
1046
|
}
|
|
1048
1047
|
/**
|
|
1049
1048
|
* Template tag query (postgres.js-like)
|
|
1050
|
-
*/ async
|
|
1049
|
+
*/ async sql(strings, ...values) {
|
|
1051
1050
|
// Build SQL from template
|
|
1052
|
-
const
|
|
1053
|
-
return this.execute(
|
|
1051
|
+
const sqlStr = strings.reduce((acc, str, i)=>acc + str + (i < values.length ? '?' : ''), '');
|
|
1052
|
+
return this.execute(sqlStr, values);
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Query with SQL string and parameters (alias for execute)
|
|
1056
|
+
*/ async query(sql, params = []) {
|
|
1057
|
+
return this.execute(sql, params);
|
|
1054
1058
|
}
|
|
1055
1059
|
/**
|
|
1056
1060
|
* Execute SQL with parameters
|
|
1057
1061
|
*/ async execute(sql, params = []) {
|
|
1058
1062
|
try {
|
|
1059
|
-
|
|
1060
|
-
|
|
1063
|
+
// Handle object format { sql, args }
|
|
1064
|
+
let sqlStr;
|
|
1065
|
+
let sqlParams;
|
|
1066
|
+
if ('object' == typeof sql) {
|
|
1067
|
+
sqlStr = sql.sql;
|
|
1068
|
+
sqlParams = sql.args || [];
|
|
1069
|
+
} else {
|
|
1070
|
+
sqlStr = sql;
|
|
1071
|
+
sqlParams = params;
|
|
1072
|
+
}
|
|
1073
|
+
const stmt = this.db.query(sqlStr);
|
|
1074
|
+
const isSelect = sqlStr.trim().toUpperCase().startsWith('SELECT') || sqlStr.trim().toUpperCase().includes('RETURNING');
|
|
1061
1075
|
if (isSelect) {
|
|
1062
|
-
const rows = stmt.all(...
|
|
1076
|
+
const rows = stmt.all(...sqlParams);
|
|
1063
1077
|
return {
|
|
1064
1078
|
rows: rows,
|
|
1065
1079
|
rowsAffected: 0
|
|
1066
1080
|
};
|
|
1067
1081
|
}
|
|
1068
1082
|
{
|
|
1069
|
-
const result = stmt.run(...
|
|
1083
|
+
const result = stmt.run(...sqlParams);
|
|
1070
1084
|
return {
|
|
1071
1085
|
rows: [],
|
|
1072
1086
|
rowsAffected: result.changes || 0,
|
|
@@ -1123,6 +1137,11 @@ ODBLiteClient.join;
|
|
|
1123
1137
|
}
|
|
1124
1138
|
}
|
|
1125
1139
|
/**
|
|
1140
|
+
* Execute function in transaction (alias for transaction)
|
|
1141
|
+
*/ async begin(fn) {
|
|
1142
|
+
return this.transaction(fn);
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1126
1145
|
* Close connection
|
|
1127
1146
|
*/ async close() {
|
|
1128
1147
|
this.db.close();
|
|
@@ -1172,10 +1191,15 @@ ODBLiteClient.join;
|
|
|
1172
1191
|
}
|
|
1173
1192
|
/**
|
|
1174
1193
|
* Template tag query (postgres.js-like)
|
|
1175
|
-
*/ async
|
|
1194
|
+
*/ async sql(strings, ...values) {
|
|
1176
1195
|
// Build SQL from template
|
|
1177
|
-
const
|
|
1178
|
-
return this.execute(
|
|
1196
|
+
const sqlStr = strings.reduce((acc, str, i)=>acc + str + (i < values.length ? '?' : ''), '');
|
|
1197
|
+
return this.execute(sqlStr, values);
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Query with SQL string and parameters (alias for execute)
|
|
1201
|
+
*/ async query(sql, params = []) {
|
|
1202
|
+
return this.execute(sql, params);
|
|
1179
1203
|
}
|
|
1180
1204
|
/**
|
|
1181
1205
|
* Execute SQL with parameters
|
|
@@ -1234,6 +1258,11 @@ ODBLiteClient.join;
|
|
|
1234
1258
|
}
|
|
1235
1259
|
}
|
|
1236
1260
|
/**
|
|
1261
|
+
* Execute function in transaction (alias for transaction)
|
|
1262
|
+
*/ async begin(fn) {
|
|
1263
|
+
return this.transaction(fn);
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1237
1266
|
* Close connection
|
|
1238
1267
|
*/ async close() {
|
|
1239
1268
|
// LibSQL client.close() if available in future versions
|
|
@@ -1306,7 +1335,7 @@ ODBLiteClient.join;
|
|
|
1306
1335
|
}
|
|
1307
1336
|
/**
|
|
1308
1337
|
* Template tag query (postgres.js-like)
|
|
1309
|
-
*/ async
|
|
1338
|
+
*/ async sql(strings, ...values) {
|
|
1310
1339
|
// ODBLiteClient.sql is a function that returns a Promise
|
|
1311
1340
|
const result = await this.client.sql(strings, ...values);
|
|
1312
1341
|
return {
|
|
@@ -1315,9 +1344,23 @@ ODBLiteClient.join;
|
|
|
1315
1344
|
};
|
|
1316
1345
|
}
|
|
1317
1346
|
/**
|
|
1347
|
+
* Query with SQL string and parameters (alias for execute)
|
|
1348
|
+
*/ async query(sql, params = []) {
|
|
1349
|
+
return this.execute(sql, params);
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1318
1352
|
* Execute SQL with parameters
|
|
1319
1353
|
*/ async execute(sql, params = []) {
|
|
1320
1354
|
try {
|
|
1355
|
+
// Handle object format { sql, args }
|
|
1356
|
+
if ('object' == typeof sql) {
|
|
1357
|
+
const result = await this.client.sql.execute(sql.sql, sql.args || []);
|
|
1358
|
+
return {
|
|
1359
|
+
rows: result.rows,
|
|
1360
|
+
rowsAffected: result.rowsAffected || 0
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
// Handle string format
|
|
1321
1364
|
const result = await this.client.sql.execute(sql, params);
|
|
1322
1365
|
return {
|
|
1323
1366
|
rows: result.rows,
|
|
@@ -1361,6 +1404,11 @@ ODBLiteClient.join;
|
|
|
1361
1404
|
}
|
|
1362
1405
|
}
|
|
1363
1406
|
/**
|
|
1407
|
+
* Execute function in transaction (alias for transaction)
|
|
1408
|
+
*/ async begin(fn) {
|
|
1409
|
+
return this.transaction(fn);
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1364
1412
|
* Close connection
|
|
1365
1413
|
*/ async close() {
|
|
1366
1414
|
// ODBLiteClient connections are stateless HTTP requests
|
|
@@ -1369,11 +1417,11 @@ ODBLiteClient.join;
|
|
|
1369
1417
|
}
|
|
1370
1418
|
/**
|
|
1371
1419
|
* Parse SQL file into statements, separating PRAGMA from regular SQL
|
|
1372
|
-
* Uses
|
|
1420
|
+
* Uses custom parser that handles BEGIN...END blocks
|
|
1373
1421
|
*/ function parseSQL(sqlContent, options = {}) {
|
|
1374
1422
|
const separatePragma = options.separatePragma ?? true;
|
|
1375
|
-
//
|
|
1376
|
-
const statements =
|
|
1423
|
+
// Split SQL statements manually
|
|
1424
|
+
const statements = splitStatements(sqlContent);
|
|
1377
1425
|
if (!separatePragma) return {
|
|
1378
1426
|
pragmaStatements: [],
|
|
1379
1427
|
regularStatements: statements
|
|
@@ -1390,54 +1438,29 @@ ODBLiteClient.join;
|
|
|
1390
1438
|
regularStatements
|
|
1391
1439
|
};
|
|
1392
1440
|
}
|
|
1393
|
-
/**
|
|
1394
|
-
* Split SQL content using node-sql-parser (more robust than custom parser)
|
|
1395
|
-
* Falls back to simple split if parser fails
|
|
1396
|
-
*/ function splitStatementsWithParser(sqlContent) {
|
|
1397
|
-
try {
|
|
1398
|
-
const parser = new __WEBPACK_EXTERNAL_MODULE_node_sql_parser__.Parser();
|
|
1399
|
-
// node-sql-parser supports splitting multiple statements
|
|
1400
|
-
// Try to use it, but have fallback for edge cases
|
|
1401
|
-
const opt = {
|
|
1402
|
-
database: 'sqlite',
|
|
1403
|
-
type: 'table'
|
|
1404
|
-
};
|
|
1405
|
-
// Split by semicolons first to handle parser limitations with very large files
|
|
1406
|
-
const roughStatements = sqlContent.split(/;[\s\n]*/).map((s)=>s.trim()).filter((s)=>s.length > 0);
|
|
1407
|
-
const validStatements = [];
|
|
1408
|
-
for (const stmt of roughStatements){
|
|
1409
|
-
// Add semicolon back
|
|
1410
|
-
const fullStmt = stmt + ';';
|
|
1411
|
-
// Skip comments-only statements
|
|
1412
|
-
if (!stmt.trim().startsWith('--') && '' !== stmt.trim()) // Validate with parser (but don't fail if it can't parse complex statements)
|
|
1413
|
-
try {
|
|
1414
|
-
parser.astify(fullStmt, opt);
|
|
1415
|
-
validStatements.push(fullStmt);
|
|
1416
|
-
} catch (parseError) {
|
|
1417
|
-
// If parser can't handle it, include it anyway if it looks like valid SQL
|
|
1418
|
-
// This handles complex statements like CREATE TRIGGER, CREATE VIEW with subqueries
|
|
1419
|
-
if (stmt.match(/^(CREATE|ALTER|DROP|INSERT|UPDATE|DELETE|SELECT|PRAGMA)/i)) validStatements.push(fullStmt);
|
|
1420
|
-
else console.warn(`Skipping potentially invalid statement: ${stmt.substring(0, 50)}...`);
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
return validStatements;
|
|
1424
|
-
} catch (error) {
|
|
1425
|
-
console.warn('node-sql-parser failed, using fallback parser:', error);
|
|
1426
|
-
// Fallback to original simple parser
|
|
1427
|
-
return splitStatements(sqlContent);
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
1441
|
/**
|
|
1431
1442
|
* Split SQL content into individual statements
|
|
1432
|
-
* Handles comments, quotes, and
|
|
1443
|
+
* Handles comments, quotes, semicolons, and BEGIN...END blocks properly
|
|
1433
1444
|
*/ function splitStatements(sqlContent) {
|
|
1434
1445
|
const statements = [];
|
|
1435
1446
|
let currentStatement = '';
|
|
1436
1447
|
let inQuote = false;
|
|
1437
1448
|
let quoteChar = '';
|
|
1449
|
+
let beginEndDepth = 0;
|
|
1438
1450
|
const lines = sqlContent.split('\n');
|
|
1439
1451
|
for (const line of lines){
|
|
1440
1452
|
let processedLine = '';
|
|
1453
|
+
const lineWithoutComments = line.replace(/--.*$/, '');
|
|
1454
|
+
// Track BEGIN...END depth for this line BEFORE processing characters
|
|
1455
|
+
if (!inQuote && lineWithoutComments.trim()) {
|
|
1456
|
+
const beginMatches = lineWithoutComments.match(/\bBEGIN\b/gi);
|
|
1457
|
+
const endMatches = lineWithoutComments.match(/\bEND\b/gi);
|
|
1458
|
+
if (beginMatches) beginEndDepth += beginMatches.length;
|
|
1459
|
+
if (endMatches) {
|
|
1460
|
+
beginEndDepth -= endMatches.length;
|
|
1461
|
+
if (beginEndDepth < 0) beginEndDepth = 0;
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1441
1464
|
for(let i = 0; i < line.length; i++){
|
|
1442
1465
|
const char = line[i];
|
|
1443
1466
|
const prevChar = i > 0 ? line[i - 1] : '';
|
|
@@ -1457,11 +1480,11 @@ ODBLiteClient.join;
|
|
|
1457
1480
|
}
|
|
1458
1481
|
}
|
|
1459
1482
|
processedLine += char;
|
|
1460
|
-
// Split on semicolon when not in quotes
|
|
1461
|
-
if (';' === char && !inQuote) {
|
|
1483
|
+
// Split on semicolon when not in quotes AND not inside BEGIN...END
|
|
1484
|
+
if (';' === char && !inQuote && 0 === beginEndDepth) {
|
|
1462
1485
|
currentStatement += processedLine;
|
|
1463
1486
|
const stmt = currentStatement.trim();
|
|
1464
|
-
if (stmt) statements.push(stmt);
|
|
1487
|
+
if (stmt && !stmt.startsWith('--')) statements.push(stmt);
|
|
1465
1488
|
currentStatement = '';
|
|
1466
1489
|
processedLine = '';
|
|
1467
1490
|
}
|
|
@@ -1470,7 +1493,7 @@ ODBLiteClient.join;
|
|
|
1470
1493
|
}
|
|
1471
1494
|
// Handle remaining statement
|
|
1472
1495
|
const finalStmt = currentStatement.trim();
|
|
1473
|
-
if (finalStmt) statements.push(finalStmt);
|
|
1496
|
+
if (finalStmt && !finalStmt.startsWith('--')) statements.push(finalStmt);
|
|
1474
1497
|
return statements;
|
|
1475
1498
|
}
|
|
1476
1499
|
/**
|
package/package.json
CHANGED
|
@@ -62,34 +62,54 @@ class BunSQLiteConnection implements Connection {
|
|
|
62
62
|
/**
|
|
63
63
|
* Template tag query (postgres.js-like)
|
|
64
64
|
*/
|
|
65
|
-
async
|
|
65
|
+
async sql<T = any>(
|
|
66
66
|
strings: TemplateStringsArray,
|
|
67
67
|
...values: any[]
|
|
68
68
|
): Promise<QueryResult<T>> {
|
|
69
69
|
// Build SQL from template
|
|
70
|
-
const
|
|
70
|
+
const sqlStr = strings.reduce((acc, str, i) => {
|
|
71
71
|
return acc + str + (i < values.length ? '?' : '')
|
|
72
72
|
}, '')
|
|
73
73
|
|
|
74
|
-
return this.execute(
|
|
74
|
+
return this.execute(sqlStr, values) as Promise<QueryResult<T>>
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Query with SQL string and parameters (alias for execute)
|
|
79
|
+
*/
|
|
80
|
+
async query<T = any>(sql: string, params: any[] = []): Promise<QueryResult<T>> {
|
|
81
|
+
return this.execute(sql, params) as Promise<QueryResult<T>>
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
/**
|
|
78
85
|
* Execute SQL with parameters
|
|
79
86
|
*/
|
|
80
|
-
async execute(sql: string, params: any[] = []): Promise<QueryResult> {
|
|
87
|
+
async execute(sql: string | { sql: string; args?: any[] }, params: any[] = []): Promise<QueryResult> {
|
|
81
88
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
89
|
+
// Handle object format { sql, args }
|
|
90
|
+
let sqlStr: string
|
|
91
|
+
let sqlParams: any[]
|
|
92
|
+
|
|
93
|
+
if (typeof sql === 'object') {
|
|
94
|
+
sqlStr = sql.sql
|
|
95
|
+
sqlParams = sql.args || []
|
|
96
|
+
} else {
|
|
97
|
+
sqlStr = sql
|
|
98
|
+
sqlParams = params
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const stmt = this.db.query(sqlStr)
|
|
102
|
+
const isSelect = sqlStr.trim().toUpperCase().startsWith('SELECT') ||
|
|
103
|
+
sqlStr.trim().toUpperCase().includes('RETURNING')
|
|
84
104
|
|
|
85
105
|
if (isSelect) {
|
|
86
|
-
const rows = stmt.all(...
|
|
106
|
+
const rows = stmt.all(...sqlParams)
|
|
87
107
|
return {
|
|
88
108
|
rows: rows as any[],
|
|
89
109
|
rowsAffected: 0,
|
|
90
110
|
}
|
|
91
111
|
} else {
|
|
92
|
-
const result = stmt.run(...
|
|
112
|
+
const result = stmt.run(...sqlParams)
|
|
93
113
|
return {
|
|
94
114
|
rows: [],
|
|
95
115
|
rowsAffected: result.changes || 0,
|
|
@@ -161,6 +181,13 @@ class BunSQLiteConnection implements Connection {
|
|
|
161
181
|
}
|
|
162
182
|
}
|
|
163
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Execute function in transaction (alias for transaction)
|
|
186
|
+
*/
|
|
187
|
+
async begin<T>(fn: (tx: Connection) => Promise<T>): Promise<T> {
|
|
188
|
+
return this.transaction(fn)
|
|
189
|
+
}
|
|
190
|
+
|
|
164
191
|
/**
|
|
165
192
|
* Close connection
|
|
166
193
|
*/
|
|
@@ -62,16 +62,23 @@ class LibSQLConnection implements Connection {
|
|
|
62
62
|
/**
|
|
63
63
|
* Template tag query (postgres.js-like)
|
|
64
64
|
*/
|
|
65
|
-
async
|
|
65
|
+
async sql<T = any>(
|
|
66
66
|
strings: TemplateStringsArray,
|
|
67
67
|
...values: any[]
|
|
68
68
|
): Promise<QueryResult<T>> {
|
|
69
69
|
// Build SQL from template
|
|
70
|
-
const
|
|
70
|
+
const sqlStr = strings.reduce((acc, str, i) => {
|
|
71
71
|
return acc + str + (i < values.length ? '?' : '')
|
|
72
72
|
}, '')
|
|
73
73
|
|
|
74
|
-
return this.execute(
|
|
74
|
+
return this.execute(sqlStr, values) as Promise<QueryResult<T>>
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Query with SQL string and parameters (alias for execute)
|
|
79
|
+
*/
|
|
80
|
+
async query<T = any>(sql: string, params: any[] = []): Promise<QueryResult<T>> {
|
|
81
|
+
return this.execute(sql, params) as Promise<QueryResult<T>>
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
/**
|
|
@@ -146,6 +153,13 @@ class LibSQLConnection implements Connection {
|
|
|
146
153
|
}
|
|
147
154
|
}
|
|
148
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Execute function in transaction (alias for transaction)
|
|
158
|
+
*/
|
|
159
|
+
async begin<T>(fn: (tx: Connection) => Promise<T>): Promise<T> {
|
|
160
|
+
return this.transaction(fn)
|
|
161
|
+
}
|
|
162
|
+
|
|
149
163
|
/**
|
|
150
164
|
* Close connection
|
|
151
165
|
*/
|
|
@@ -97,7 +97,7 @@ class ODBLiteConnection implements Connection {
|
|
|
97
97
|
/**
|
|
98
98
|
* Template tag query (postgres.js-like)
|
|
99
99
|
*/
|
|
100
|
-
async
|
|
100
|
+
async sql<T = any>(
|
|
101
101
|
strings: TemplateStringsArray,
|
|
102
102
|
...values: any[]
|
|
103
103
|
): Promise<QueryResult<T>> {
|
|
@@ -110,11 +110,28 @@ class ODBLiteConnection implements Connection {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Query with SQL string and parameters (alias for execute)
|
|
115
|
+
*/
|
|
116
|
+
async query<T = any>(sql: string, params: any[] = []): Promise<QueryResult<T>> {
|
|
117
|
+
return this.execute(sql, params) as Promise<QueryResult<T>>
|
|
118
|
+
}
|
|
119
|
+
|
|
113
120
|
/**
|
|
114
121
|
* Execute SQL with parameters
|
|
115
122
|
*/
|
|
116
|
-
async execute(sql: string, params: any[] = []): Promise<QueryResult> {
|
|
123
|
+
async execute(sql: string | { sql: string; args?: any[] }, params: any[] = []): Promise<QueryResult> {
|
|
117
124
|
try {
|
|
125
|
+
// Handle object format { sql, args }
|
|
126
|
+
if (typeof sql === 'object') {
|
|
127
|
+
const result = await this.client.sql.execute(sql.sql, sql.args || [])
|
|
128
|
+
return {
|
|
129
|
+
rows: result.rows,
|
|
130
|
+
rowsAffected: result.rowsAffected || 0,
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Handle string format
|
|
118
135
|
const result = await this.client.sql.execute(sql, params)
|
|
119
136
|
|
|
120
137
|
return {
|
|
@@ -171,6 +188,13 @@ class ODBLiteConnection implements Connection {
|
|
|
171
188
|
}
|
|
172
189
|
}
|
|
173
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Execute function in transaction (alias for transaction)
|
|
193
|
+
*/
|
|
194
|
+
async begin<T>(fn: (tx: Connection) => Promise<T>): Promise<T> {
|
|
195
|
+
return this.transaction(fn)
|
|
196
|
+
}
|
|
197
|
+
|
|
174
198
|
/**
|
|
175
199
|
* Close connection
|
|
176
200
|
*/
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { Parser } from 'node-sql-parser'
|
|
2
|
-
|
|
3
1
|
export interface ParsedStatements {
|
|
4
2
|
pragmaStatements: string[]
|
|
5
3
|
regularStatements: string[]
|
|
@@ -11,13 +9,13 @@ export interface SQLParserOptions {
|
|
|
11
9
|
|
|
12
10
|
/**
|
|
13
11
|
* Parse SQL file into statements, separating PRAGMA from regular SQL
|
|
14
|
-
* Uses
|
|
12
|
+
* Uses custom parser that handles BEGIN...END blocks
|
|
15
13
|
*/
|
|
16
14
|
export function parseSQL(sqlContent: string, options: SQLParserOptions = {}): ParsedStatements {
|
|
17
15
|
const separatePragma = options.separatePragma ?? true
|
|
18
16
|
|
|
19
|
-
//
|
|
20
|
-
const statements =
|
|
17
|
+
// Split SQL statements manually
|
|
18
|
+
const statements = splitStatements(sqlContent)
|
|
21
19
|
|
|
22
20
|
if (!separatePragma) {
|
|
23
21
|
return {
|
|
@@ -41,74 +39,38 @@ export function parseSQL(sqlContent: string, options: SQLParserOptions = {}): Pa
|
|
|
41
39
|
return { pragmaStatements, regularStatements }
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
/**
|
|
45
|
-
* Split SQL content using node-sql-parser (more robust than custom parser)
|
|
46
|
-
* Falls back to simple split if parser fails
|
|
47
|
-
*/
|
|
48
|
-
function splitStatementsWithParser(sqlContent: string): string[] {
|
|
49
|
-
try {
|
|
50
|
-
const parser = new Parser()
|
|
51
|
-
|
|
52
|
-
// node-sql-parser supports splitting multiple statements
|
|
53
|
-
// Try to use it, but have fallback for edge cases
|
|
54
|
-
const opt = {
|
|
55
|
-
database: 'sqlite',
|
|
56
|
-
type: 'table' as any
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Split by semicolons first to handle parser limitations with very large files
|
|
60
|
-
const roughStatements = sqlContent.split(/;[\s\n]*/)
|
|
61
|
-
.map(s => s.trim())
|
|
62
|
-
.filter(s => s.length > 0)
|
|
63
|
-
|
|
64
|
-
const validStatements: string[] = []
|
|
65
|
-
|
|
66
|
-
for (const stmt of roughStatements) {
|
|
67
|
-
// Add semicolon back
|
|
68
|
-
const fullStmt = stmt + ';'
|
|
69
|
-
|
|
70
|
-
// Skip comments-only statements
|
|
71
|
-
if (stmt.trim().startsWith('--') || stmt.trim() === '') {
|
|
72
|
-
continue
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Validate with parser (but don't fail if it can't parse complex statements)
|
|
76
|
-
try {
|
|
77
|
-
parser.astify(fullStmt, opt)
|
|
78
|
-
validStatements.push(fullStmt)
|
|
79
|
-
} catch (parseError) {
|
|
80
|
-
// If parser can't handle it, include it anyway if it looks like valid SQL
|
|
81
|
-
// This handles complex statements like CREATE TRIGGER, CREATE VIEW with subqueries
|
|
82
|
-
if (stmt.match(/^(CREATE|ALTER|DROP|INSERT|UPDATE|DELETE|SELECT|PRAGMA)/i)) {
|
|
83
|
-
validStatements.push(fullStmt)
|
|
84
|
-
} else {
|
|
85
|
-
console.warn(`Skipping potentially invalid statement: ${stmt.substring(0, 50)}...`)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return validStatements
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.warn('node-sql-parser failed, using fallback parser:', error)
|
|
93
|
-
// Fallback to original simple parser
|
|
94
|
-
return splitStatements(sqlContent)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
42
|
/**
|
|
99
43
|
* Split SQL content into individual statements
|
|
100
|
-
* Handles comments, quotes, and
|
|
44
|
+
* Handles comments, quotes, semicolons, and BEGIN...END blocks properly
|
|
101
45
|
*/
|
|
102
46
|
function splitStatements(sqlContent: string): string[] {
|
|
103
47
|
const statements: string[] = []
|
|
104
48
|
let currentStatement = ''
|
|
105
49
|
let inQuote = false
|
|
106
50
|
let quoteChar = ''
|
|
51
|
+
let beginEndDepth = 0
|
|
107
52
|
|
|
108
53
|
const lines = sqlContent.split('\n')
|
|
109
54
|
|
|
110
55
|
for (const line of lines) {
|
|
111
56
|
let processedLine = ''
|
|
57
|
+
const lineWithoutComments = line.replace(/--.*$/, '')
|
|
58
|
+
|
|
59
|
+
// Track BEGIN...END depth for this line BEFORE processing characters
|
|
60
|
+
if (!inQuote && lineWithoutComments.trim()) {
|
|
61
|
+
const beginMatches = lineWithoutComments.match(/\bBEGIN\b/gi)
|
|
62
|
+
const endMatches = lineWithoutComments.match(/\bEND\b/gi)
|
|
63
|
+
|
|
64
|
+
if (beginMatches) {
|
|
65
|
+
beginEndDepth += beginMatches.length
|
|
66
|
+
}
|
|
67
|
+
if (endMatches) {
|
|
68
|
+
beginEndDepth -= endMatches.length
|
|
69
|
+
if (beginEndDepth < 0) {
|
|
70
|
+
beginEndDepth = 0
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
112
74
|
|
|
113
75
|
for (let i = 0; i < line.length; i++) {
|
|
114
76
|
const char = line[i]
|
|
@@ -133,11 +95,11 @@ function splitStatements(sqlContent: string): string[] {
|
|
|
133
95
|
|
|
134
96
|
processedLine += char
|
|
135
97
|
|
|
136
|
-
// Split on semicolon when not in quotes
|
|
137
|
-
if (char === ';' && !inQuote) {
|
|
98
|
+
// Split on semicolon when not in quotes AND not inside BEGIN...END
|
|
99
|
+
if (char === ';' && !inQuote && beginEndDepth === 0) {
|
|
138
100
|
currentStatement += processedLine
|
|
139
101
|
const stmt = currentStatement.trim()
|
|
140
|
-
if (stmt) {
|
|
102
|
+
if (stmt && !stmt.startsWith('--')) {
|
|
141
103
|
statements.push(stmt)
|
|
142
104
|
}
|
|
143
105
|
currentStatement = ''
|
|
@@ -152,7 +114,7 @@ function splitStatements(sqlContent: string): string[] {
|
|
|
152
114
|
|
|
153
115
|
// Handle remaining statement
|
|
154
116
|
const finalStmt = currentStatement.trim()
|
|
155
|
-
if (finalStmt) {
|
|
117
|
+
if (finalStmt && !finalStmt.startsWith('--')) {
|
|
156
118
|
statements.push(finalStmt)
|
|
157
119
|
}
|
|
158
120
|
|
package/src/database/types.ts
CHANGED
|
@@ -31,14 +31,16 @@ export interface QueryResult<T = any> {
|
|
|
31
31
|
*/
|
|
32
32
|
export interface Connection {
|
|
33
33
|
// Template tag queries (postgres.js-like)
|
|
34
|
-
|
|
34
|
+
sql<T = any>(strings: TemplateStringsArray, ...values: any[]): Promise<QueryResult<T>>
|
|
35
35
|
|
|
36
|
-
// Standard query methods (
|
|
36
|
+
// Standard query methods (same as execute)
|
|
37
|
+
query<T = any>(sql: string, params?: any[]): Promise<QueryResult<T>>
|
|
37
38
|
execute(sql: string | { sql: string; args?: any[] }, params?: any[]): Promise<QueryResult>
|
|
38
39
|
prepare(sql: string): PreparedStatement
|
|
39
40
|
|
|
40
41
|
// Transaction support
|
|
41
42
|
transaction<T>(fn: (tx: Connection) => Promise<T>): Promise<T>
|
|
43
|
+
begin<T>(fn: (tx: Connection) => Promise<T>): Promise<T>
|
|
42
44
|
|
|
43
45
|
// Connection management
|
|
44
46
|
close(): Promise<void>
|