@devbro/neko-sql 0.1.31 → 0.1.34
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 +65 -5
- package/dist/{Blueprint-D3WHeqRS.d.mts → Blueprint-g4SmS1bH.d.mts} +6 -0
- package/dist/Blueprint.d.mts +1 -1
- package/dist/Connection.d.mts +1 -1
- package/dist/Expression.d.mts +1 -1
- package/dist/Migration.d.mts +1 -1
- package/dist/Query.d.mts +1 -1
- package/dist/Query.mjs +3 -1
- package/dist/Query.mjs.map +1 -1
- package/dist/QueryGrammar.d.mts +1 -1
- package/dist/QueryGrammar.mjs +8 -0
- package/dist/QueryGrammar.mjs.map +1 -1
- package/dist/Schema.d.mts +1 -1
- package/dist/SchemaGrammar.d.mts +1 -1
- package/dist/databases/index.d.mts +9 -1
- package/dist/databases/index.mjs +2 -0
- package/dist/databases/index.mjs.map +1 -1
- package/dist/databases/mysql/MysqlConnection.d.mts +41 -0
- package/dist/databases/mysql/MysqlConnection.mjs +208 -0
- package/dist/databases/mysql/MysqlConnection.mjs.map +1 -0
- package/dist/databases/mysql/MysqlQueryGrammar.d.mts +13 -0
- package/dist/databases/mysql/MysqlQueryGrammar.mjs +18 -0
- package/dist/databases/mysql/MysqlQueryGrammar.mjs.map +1 -0
- package/dist/databases/mysql/MysqlSchemaGrammar.d.mts +8 -0
- package/dist/databases/mysql/MysqlSchemaGrammar.mjs +58 -0
- package/dist/databases/mysql/MysqlSchemaGrammar.mjs.map +1 -0
- package/dist/databases/mysql/index.d.mts +6 -0
- package/dist/databases/mysql/index.mjs +4 -0
- package/dist/databases/mysql/index.mjs.map +1 -0
- package/dist/databases/postgresql/PostgresqlConnection.d.mts +2 -2
- package/dist/databases/postgresql/PostgresqlConnection.mjs +27 -11
- package/dist/databases/postgresql/PostgresqlConnection.mjs.map +1 -1
- package/dist/databases/postgresql/PostgresqlQueryGrammar.d.mts +1 -1
- package/dist/databases/postgresql/PostgresqlSchemaGrammar.d.mts +1 -1
- package/dist/databases/postgresql/index.d.mts +1 -1
- package/dist/databases/sqlite/SqliteConnection.d.mts +132 -0
- package/dist/databases/sqlite/SqliteConnection.mjs +242 -0
- package/dist/databases/sqlite/SqliteConnection.mjs.map +1 -0
- package/dist/databases/sqlite/SqliteQueryGrammar.d.mts +17 -0
- package/dist/databases/sqlite/SqliteQueryGrammar.mjs +40 -0
- package/dist/databases/sqlite/SqliteQueryGrammar.mjs.map +1 -0
- package/dist/databases/sqlite/SqliteSchemaGrammar.d.mts +8 -0
- package/dist/databases/sqlite/SqliteSchemaGrammar.mjs +58 -0
- package/dist/databases/sqlite/SqliteSchemaGrammar.mjs.map +1 -0
- package/dist/databases/sqlite/index.d.mts +6 -0
- package/dist/databases/sqlite/index.mjs +4 -0
- package/dist/databases/sqlite/index.mjs.map +1 -0
- package/dist/index.d.mts +9 -1
- package/dist/index.js +642 -14
- package/dist/index.js.map +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -37,13 +37,19 @@ __export(index_exports, {
|
|
|
37
37
|
ForeignKeyConstraint: () => ForeignKeyConstraint,
|
|
38
38
|
IndexConstraint: () => IndexConstraint,
|
|
39
39
|
Migration: () => Migration,
|
|
40
|
+
MysqlConnection: () => MysqlConnection,
|
|
41
|
+
MysqlQueryGrammar: () => MysqlQueryGrammar,
|
|
42
|
+
MysqlSchemaGrammar: () => MysqlSchemaGrammar,
|
|
40
43
|
PostgresqlConnection: () => PostgresqlConnection,
|
|
41
44
|
PostgresqlQueryGrammar: () => PostgresqlQueryGrammar,
|
|
42
45
|
PostgresqlSchemaGrammar: () => PostgresqlSchemaGrammar,
|
|
43
46
|
Query: () => Query,
|
|
44
47
|
QueryGrammar: () => QueryGrammar,
|
|
45
48
|
Schema: () => Schema,
|
|
46
|
-
SchemaGrammar: () => SchemaGrammar
|
|
49
|
+
SchemaGrammar: () => SchemaGrammar,
|
|
50
|
+
SqliteConnection: () => SqliteConnection,
|
|
51
|
+
SqliteQueryGrammar: () => SqliteQueryGrammar,
|
|
52
|
+
SqliteSchemaGrammar: () => SqliteSchemaGrammar
|
|
47
53
|
});
|
|
48
54
|
module.exports = __toCommonJS(index_exports);
|
|
49
55
|
|
|
@@ -198,7 +204,9 @@ var Query = class _Query {
|
|
|
198
204
|
}
|
|
199
205
|
async insertGetId(data, options = { primaryKey: ["id"] }) {
|
|
200
206
|
const csql = this.grammar.compileInsertGetId(this, data, options);
|
|
201
|
-
|
|
207
|
+
let rc = await this.connection?.runQuery(csql);
|
|
208
|
+
rc = this.grammar.postProcessGetInsertId(rc);
|
|
209
|
+
return rc;
|
|
202
210
|
}
|
|
203
211
|
async update(data) {
|
|
204
212
|
const csql = this.grammar.compileUpdate(this, data);
|
|
@@ -584,6 +592,14 @@ var QueryGrammar = class {
|
|
|
584
592
|
bindings: w.bindings
|
|
585
593
|
};
|
|
586
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* post process result from database
|
|
597
|
+
* @param result result from database
|
|
598
|
+
* @returns post processed result
|
|
599
|
+
*/
|
|
600
|
+
postProcessGetInsertId(result) {
|
|
601
|
+
return result;
|
|
602
|
+
}
|
|
587
603
|
};
|
|
588
604
|
|
|
589
605
|
// src/databases/postgresql/PostgresqlQueryGrammar.mts
|
|
@@ -1221,7 +1237,8 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
|
|
|
1221
1237
|
}
|
|
1222
1238
|
}
|
|
1223
1239
|
async connect() {
|
|
1224
|
-
this.eventManager.emit("connect")
|
|
1240
|
+
this.eventManager.emit("connect").catch(() => {
|
|
1241
|
+
});
|
|
1225
1242
|
this.connection = await _PostgresqlConnection.pool.connect();
|
|
1226
1243
|
return true;
|
|
1227
1244
|
}
|
|
@@ -1234,7 +1251,8 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
|
|
|
1234
1251
|
if (sql.parts && sql.parts.length > 0) {
|
|
1235
1252
|
sql2 = sql.parts.map((v) => v === "?" ? "$" + counter++ : v).join(" ");
|
|
1236
1253
|
}
|
|
1237
|
-
this.eventManager.emit("query", { sql: sql2, bindings: sql.bindings })
|
|
1254
|
+
this.eventManager.emit("query", { sql: sql2, bindings: sql.bindings }).catch(() => {
|
|
1255
|
+
});
|
|
1238
1256
|
if (!this.isConnected()) {
|
|
1239
1257
|
await this.connect();
|
|
1240
1258
|
}
|
|
@@ -1250,7 +1268,8 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
|
|
|
1250
1268
|
}
|
|
1251
1269
|
await this.connection?.release();
|
|
1252
1270
|
this.connection = void 0;
|
|
1253
|
-
this.eventManager.emit("disconnect")
|
|
1271
|
+
this.eventManager.emit("disconnect").catch(() => {
|
|
1272
|
+
});
|
|
1254
1273
|
return true;
|
|
1255
1274
|
}
|
|
1256
1275
|
getQuery() {
|
|
@@ -1274,9 +1293,8 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
|
|
|
1274
1293
|
async rollback() {
|
|
1275
1294
|
await this.runQuery({ sql: "ROLLBACK", bindings: [], parts: ["ROLLBACK"] });
|
|
1276
1295
|
}
|
|
1277
|
-
static
|
|
1278
|
-
_PostgresqlConnection.pool.end();
|
|
1279
|
-
return;
|
|
1296
|
+
static destroy() {
|
|
1297
|
+
return _PostgresqlConnection.pool.end();
|
|
1280
1298
|
}
|
|
1281
1299
|
isConnected() {
|
|
1282
1300
|
return this.connection !== void 0;
|
|
@@ -1311,9 +1329,11 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
|
|
|
1311
1329
|
}
|
|
1312
1330
|
async createDatabase(name) {
|
|
1313
1331
|
if (this.isConnected()) {
|
|
1314
|
-
|
|
1332
|
+
const safeName2 = this.validateAndEscapeIdentifier(name);
|
|
1333
|
+
await this.runQuery(`CREATE DATABASE ${safeName2}`);
|
|
1334
|
+
return;
|
|
1315
1335
|
}
|
|
1316
|
-
|
|
1336
|
+
const conn = new import_pg.Client({
|
|
1317
1337
|
..._PostgresqlConnection.pool.options,
|
|
1318
1338
|
database: "postgres"
|
|
1319
1339
|
});
|
|
@@ -1324,9 +1344,11 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
|
|
|
1324
1344
|
}
|
|
1325
1345
|
async dropDatabase(name) {
|
|
1326
1346
|
if (this.isConnected()) {
|
|
1327
|
-
|
|
1347
|
+
const safeName2 = this.validateAndEscapeIdentifier(name);
|
|
1348
|
+
await this.runQuery(`DROP DATABASE ${safeName2}`);
|
|
1349
|
+
return;
|
|
1328
1350
|
}
|
|
1329
|
-
|
|
1351
|
+
const conn = new import_pg.Client({
|
|
1330
1352
|
..._PostgresqlConnection.pool.options,
|
|
1331
1353
|
database: "postgres"
|
|
1332
1354
|
// connect to default 'postgres' database to drop others
|
|
@@ -1347,7 +1369,17 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
|
|
|
1347
1369
|
}
|
|
1348
1370
|
async existsDatabase(name) {
|
|
1349
1371
|
if (!this.isConnected()) {
|
|
1350
|
-
|
|
1372
|
+
const conn = new import_pg.Client({
|
|
1373
|
+
..._PostgresqlConnection.pool.options,
|
|
1374
|
+
database: "postgres"
|
|
1375
|
+
});
|
|
1376
|
+
await conn.connect();
|
|
1377
|
+
const safeName = this.validateAndEscapeIdentifier(name);
|
|
1378
|
+
const result2 = await conn.query("SELECT 1 FROM pg_database WHERE datname = $1", [
|
|
1379
|
+
safeName
|
|
1380
|
+
]);
|
|
1381
|
+
await conn.end();
|
|
1382
|
+
return result2.rows.length > 0;
|
|
1351
1383
|
}
|
|
1352
1384
|
const result = await this.connection.query("SELECT 1 FROM pg_database WHERE datname = $1", [
|
|
1353
1385
|
name
|
|
@@ -1356,6 +1388,596 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
|
|
|
1356
1388
|
}
|
|
1357
1389
|
};
|
|
1358
1390
|
|
|
1391
|
+
// src/databases/sqlite/SqliteConnection.mts
|
|
1392
|
+
var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
|
|
1393
|
+
|
|
1394
|
+
// src/databases/sqlite/SqliteQueryGrammar.mts
|
|
1395
|
+
var import_neko_helper4 = require("@devbro/neko-helper");
|
|
1396
|
+
var SqliteQueryGrammar = class extends QueryGrammar {
|
|
1397
|
+
static {
|
|
1398
|
+
__name(this, "SqliteQueryGrammar");
|
|
1399
|
+
}
|
|
1400
|
+
constructor() {
|
|
1401
|
+
super();
|
|
1402
|
+
}
|
|
1403
|
+
toSql(query) {
|
|
1404
|
+
return super.toSql(query);
|
|
1405
|
+
}
|
|
1406
|
+
compileInsert(query, data) {
|
|
1407
|
+
return super.compileInsert(query, data);
|
|
1408
|
+
}
|
|
1409
|
+
compileInsertGetId(query, data, options = { primaryKey: ["id"] }) {
|
|
1410
|
+
const rc = super.compileInsert(query, data);
|
|
1411
|
+
rc.sql += ` RETURNING ${options.primaryKey.join(", ")}`;
|
|
1412
|
+
rc.parts = rc.parts.concat(["RETURNING", ...import_neko_helper4.Arr.intersperse(options.primaryKey, ",")]);
|
|
1413
|
+
return rc;
|
|
1414
|
+
}
|
|
1415
|
+
compileUpdate(query, data) {
|
|
1416
|
+
return super.compileUpdate(query, data);
|
|
1417
|
+
}
|
|
1418
|
+
compileDelete(query) {
|
|
1419
|
+
return super.compileDelete(query);
|
|
1420
|
+
}
|
|
1421
|
+
compileUpsert(query, data, conflictFields, updateFields) {
|
|
1422
|
+
return super.compileUpsert(query, data, conflictFields, updateFields);
|
|
1423
|
+
}
|
|
1424
|
+
compileCount(query) {
|
|
1425
|
+
return super.compileCount(query);
|
|
1426
|
+
}
|
|
1427
|
+
};
|
|
1428
|
+
|
|
1429
|
+
// src/databases/sqlite/SqliteSchemaGrammar.mts
|
|
1430
|
+
var SqliteSchemaGrammar = class extends SchemaGrammar {
|
|
1431
|
+
static {
|
|
1432
|
+
__name(this, "SqliteSchemaGrammar");
|
|
1433
|
+
}
|
|
1434
|
+
compileColumn(column) {
|
|
1435
|
+
const rc = [`${column.columnName}`];
|
|
1436
|
+
if (column.properties.type === "string") {
|
|
1437
|
+
rc.push("varchar(" + column.properties.length + ")");
|
|
1438
|
+
} else if (column.properties.type === "char") {
|
|
1439
|
+
rc.push("char");
|
|
1440
|
+
} else if (column.properties.type === "boolean") {
|
|
1441
|
+
rc.push("boolean");
|
|
1442
|
+
} else if (column.properties.type === "integer") {
|
|
1443
|
+
rc.push("integer");
|
|
1444
|
+
} else if (column.properties.type === "text") {
|
|
1445
|
+
rc.push("text");
|
|
1446
|
+
} else if (column.properties.type === "timestamp") {
|
|
1447
|
+
rc.push("timestamp");
|
|
1448
|
+
} else if (column.properties.type === "timestampz") {
|
|
1449
|
+
rc.push("timestamp with time zone");
|
|
1450
|
+
} else if (column.properties.type === "serial") {
|
|
1451
|
+
rc.push("INTEGER");
|
|
1452
|
+
} else if (column.properties.type === "float") {
|
|
1453
|
+
rc.push("float");
|
|
1454
|
+
} else if (column.properties.type === "double") {
|
|
1455
|
+
rc.push("double precision");
|
|
1456
|
+
} else if (column.properties.type === "date") {
|
|
1457
|
+
rc.push("date");
|
|
1458
|
+
} else if (column.properties.type === "json") {
|
|
1459
|
+
rc.push("json");
|
|
1460
|
+
} else if (column.properties.type === "jsonb") {
|
|
1461
|
+
rc.push("jsonb");
|
|
1462
|
+
} else if (column.properties.type === "raw") {
|
|
1463
|
+
return column.columnName;
|
|
1464
|
+
} else {
|
|
1465
|
+
throw new Error("Unknown column type: " + column.properties.type);
|
|
1466
|
+
}
|
|
1467
|
+
if (column.properties.nullable) {
|
|
1468
|
+
rc.push("null");
|
|
1469
|
+
} else {
|
|
1470
|
+
rc.push("not null");
|
|
1471
|
+
}
|
|
1472
|
+
if (column.properties.unique) {
|
|
1473
|
+
rc.push("unique");
|
|
1474
|
+
}
|
|
1475
|
+
if (column.properties.default !== null) {
|
|
1476
|
+
rc.push("default " + this.escape(column.properties.default));
|
|
1477
|
+
}
|
|
1478
|
+
return rc.join(" ");
|
|
1479
|
+
}
|
|
1480
|
+
};
|
|
1481
|
+
|
|
1482
|
+
// src/databases/sqlite/SqliteConnection.mts
|
|
1483
|
+
var import_neko_helper5 = require("@devbro/neko-helper");
|
|
1484
|
+
var fs = __toESM(require("fs"), 1);
|
|
1485
|
+
var SqliteConnection = class _SqliteConnection extends Connection {
|
|
1486
|
+
static {
|
|
1487
|
+
__name(this, "SqliteConnection");
|
|
1488
|
+
}
|
|
1489
|
+
eventManager = new import_neko_helper5.EventManager();
|
|
1490
|
+
on(event, listener) {
|
|
1491
|
+
this.eventManager.on(event, listener);
|
|
1492
|
+
return this;
|
|
1493
|
+
}
|
|
1494
|
+
off(event, listener) {
|
|
1495
|
+
this.eventManager.off(event, listener);
|
|
1496
|
+
return this;
|
|
1497
|
+
}
|
|
1498
|
+
emit(event, ...args) {
|
|
1499
|
+
return this.eventManager.emit(event, ...args);
|
|
1500
|
+
}
|
|
1501
|
+
connection;
|
|
1502
|
+
config;
|
|
1503
|
+
/** Default configuration values for SQLite connections */
|
|
1504
|
+
static defaults = {
|
|
1505
|
+
readonly: false,
|
|
1506
|
+
fileMustExist: false,
|
|
1507
|
+
timeout: 5e3
|
|
1508
|
+
};
|
|
1509
|
+
constructor(params) {
|
|
1510
|
+
super();
|
|
1511
|
+
this.config = { ..._SqliteConnection.defaults, ...params };
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Establishes a connection to the SQLite database
|
|
1515
|
+
* Creates or opens the database file specified in the configuration
|
|
1516
|
+
*/
|
|
1517
|
+
async connect() {
|
|
1518
|
+
this.eventManager.emit("connect").catch(() => {
|
|
1519
|
+
});
|
|
1520
|
+
this.connection = new import_better_sqlite3.default(this.config.filename, {
|
|
1521
|
+
readonly: this.config.readonly,
|
|
1522
|
+
fileMustExist: this.config.fileMustExist,
|
|
1523
|
+
timeout: this.config.timeout,
|
|
1524
|
+
verbose: this.config.verbose
|
|
1525
|
+
});
|
|
1526
|
+
return true;
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1529
|
+
* Executes a SQL query against the database
|
|
1530
|
+
* Automatically detects SELECT queries and queries with RETURNING clauses
|
|
1531
|
+
*
|
|
1532
|
+
* @param sql - Compiled SQL or raw SQL string to execute
|
|
1533
|
+
* @returns Query results (rows for SELECT, run info for INSERT/UPDATE/DELETE)
|
|
1534
|
+
*/
|
|
1535
|
+
async runQuery(sql) {
|
|
1536
|
+
if (typeof sql === "string") {
|
|
1537
|
+
sql = { sql, bindings: [], parts: [sql] };
|
|
1538
|
+
}
|
|
1539
|
+
this.eventManager.emit("query", { sql: sql.sql, bindings: sql.bindings }).catch(() => {
|
|
1540
|
+
});
|
|
1541
|
+
if (!this.isConnected()) {
|
|
1542
|
+
await this.connect();
|
|
1543
|
+
}
|
|
1544
|
+
try {
|
|
1545
|
+
const stmt = this.connection.prepare(sql.sql);
|
|
1546
|
+
const sqlUpper = sql.sql.trim().toUpperCase();
|
|
1547
|
+
if (sqlUpper.startsWith("SELECT") || sqlUpper.includes("RETURNING")) {
|
|
1548
|
+
return stmt.all(...sql.bindings);
|
|
1549
|
+
} else {
|
|
1550
|
+
const result = stmt.run(...sql.bindings);
|
|
1551
|
+
return result;
|
|
1552
|
+
}
|
|
1553
|
+
} catch (error) {
|
|
1554
|
+
this.eventManager.emit("error", error).catch(() => {
|
|
1555
|
+
});
|
|
1556
|
+
throw error;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
/**
|
|
1560
|
+
* Executes a query and returns an iterator for streaming results
|
|
1561
|
+
* Useful for large result sets to avoid loading all rows into memory
|
|
1562
|
+
*
|
|
1563
|
+
* @param sql - Compiled SQL to execute
|
|
1564
|
+
* @returns Iterator over query results
|
|
1565
|
+
*/
|
|
1566
|
+
async runCursor(sql) {
|
|
1567
|
+
if (!this.isConnected()) {
|
|
1568
|
+
await this.connect();
|
|
1569
|
+
}
|
|
1570
|
+
const stmt = this.connection.prepare(sql.sql);
|
|
1571
|
+
return stmt.iterate(...sql.bindings);
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Closes the database connection
|
|
1575
|
+
*/
|
|
1576
|
+
async disconnect() {
|
|
1577
|
+
if (this.connection === void 0) {
|
|
1578
|
+
return true;
|
|
1579
|
+
}
|
|
1580
|
+
this.connection.close();
|
|
1581
|
+
this.connection = void 0;
|
|
1582
|
+
this.eventManager.emit("disconnect").catch(() => {
|
|
1583
|
+
});
|
|
1584
|
+
return true;
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Creates a new query builder instance for this connection
|
|
1588
|
+
*/
|
|
1589
|
+
getQuery() {
|
|
1590
|
+
return new Query(this, new SqliteQueryGrammar());
|
|
1591
|
+
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Creates a new schema builder instance for this connection
|
|
1594
|
+
*/
|
|
1595
|
+
getSchema() {
|
|
1596
|
+
return new Schema(this, new SqliteSchemaGrammar());
|
|
1597
|
+
}
|
|
1598
|
+
/**
|
|
1599
|
+
* Gets the query grammar for building SQL statements
|
|
1600
|
+
*/
|
|
1601
|
+
getQueryGrammar() {
|
|
1602
|
+
return new SqliteQueryGrammar();
|
|
1603
|
+
}
|
|
1604
|
+
/**
|
|
1605
|
+
* Gets the schema grammar for building DDL statements
|
|
1606
|
+
*/
|
|
1607
|
+
getSchemaGrammar() {
|
|
1608
|
+
return new SqliteSchemaGrammar();
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* Starts a new database transaction
|
|
1612
|
+
*/
|
|
1613
|
+
async beginTransaction() {
|
|
1614
|
+
await this.runQuery({
|
|
1615
|
+
sql: "BEGIN TRANSACTION",
|
|
1616
|
+
bindings: [],
|
|
1617
|
+
parts: ["BEGIN", "TRANSACTION"]
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
/**
|
|
1621
|
+
* Commits the current transaction
|
|
1622
|
+
*/
|
|
1623
|
+
async commit() {
|
|
1624
|
+
await this.runQuery({ sql: "COMMIT", bindings: [], parts: ["COMMIT"] });
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Rolls back the current transaction
|
|
1628
|
+
*/
|
|
1629
|
+
async rollback() {
|
|
1630
|
+
await this.runQuery({ sql: "ROLLBACK", bindings: [], parts: ["ROLLBACK"] });
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Checks if the database connection is active
|
|
1634
|
+
*/
|
|
1635
|
+
isConnected() {
|
|
1636
|
+
return this.connection !== void 0 && this.connection.open;
|
|
1637
|
+
}
|
|
1638
|
+
/**
|
|
1639
|
+
* Validates and escapes a SQLite identifier (database name, table name, etc.)
|
|
1640
|
+
* Uses a whitelist approach to ensure only safe characters are allowed
|
|
1641
|
+
*
|
|
1642
|
+
* @param name - The identifier to validate and escape
|
|
1643
|
+
* @returns The escaped identifier, quoted if it's a reserved keyword
|
|
1644
|
+
* @throws Error if the identifier contains invalid characters
|
|
1645
|
+
*/
|
|
1646
|
+
validateAndEscapeIdentifier(name) {
|
|
1647
|
+
const validIdentifierPattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
1648
|
+
if (!validIdentifierPattern.test(name)) {
|
|
1649
|
+
throw new Error(
|
|
1650
|
+
`Invalid identifier: "${name}". Identifiers must start with a letter or underscore and contain only letters, digits, and underscores.`
|
|
1651
|
+
);
|
|
1652
|
+
}
|
|
1653
|
+
const reservedKeywords = /* @__PURE__ */ new Set([
|
|
1654
|
+
"table",
|
|
1655
|
+
"database",
|
|
1656
|
+
"order",
|
|
1657
|
+
"group",
|
|
1658
|
+
"select",
|
|
1659
|
+
"insert",
|
|
1660
|
+
"update",
|
|
1661
|
+
"delete",
|
|
1662
|
+
"index",
|
|
1663
|
+
"from",
|
|
1664
|
+
"where"
|
|
1665
|
+
]);
|
|
1666
|
+
if (reservedKeywords.has(name.toLowerCase())) {
|
|
1667
|
+
const escapedName = name.replace(/"/g, '""');
|
|
1668
|
+
return `"${escapedName}"`;
|
|
1669
|
+
}
|
|
1670
|
+
return name;
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* Creates a new SQLite database file
|
|
1674
|
+
*
|
|
1675
|
+
* @param name - Name or path of the database file to create
|
|
1676
|
+
*/
|
|
1677
|
+
async createDatabase(name) {
|
|
1678
|
+
const dbPath = name.endsWith(".db") ? name : `${name}.db`;
|
|
1679
|
+
const tempDb = new import_better_sqlite3.default(dbPath);
|
|
1680
|
+
tempDb.close();
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* Deletes a SQLite database file
|
|
1684
|
+
*
|
|
1685
|
+
* @param name - Name or path of the database file to delete
|
|
1686
|
+
*/
|
|
1687
|
+
async dropDatabase(name) {
|
|
1688
|
+
const dbPath = name.endsWith(".db") ? name : `${name}.db`;
|
|
1689
|
+
if (fs.existsSync(dbPath)) {
|
|
1690
|
+
fs.unlinkSync(dbPath);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* Lists available databases
|
|
1695
|
+
* For SQLite, this returns the current database filename
|
|
1696
|
+
*
|
|
1697
|
+
* @returns Array containing the current database filename
|
|
1698
|
+
*/
|
|
1699
|
+
async listDatabases() {
|
|
1700
|
+
return [this.config.filename];
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* Checks if a database file exists
|
|
1704
|
+
*
|
|
1705
|
+
* @param name - Name or path of the database file to check
|
|
1706
|
+
* @returns True if the database file exists, false otherwise
|
|
1707
|
+
*/
|
|
1708
|
+
async existsDatabase(name) {
|
|
1709
|
+
const dbPath = name.endsWith(".db") ? name : `${name}.db`;
|
|
1710
|
+
return fs.existsSync(dbPath);
|
|
1711
|
+
}
|
|
1712
|
+
};
|
|
1713
|
+
|
|
1714
|
+
// src/databases/mysql/MysqlConnection.mts
|
|
1715
|
+
var import_promise = __toESM(require("mysql2/promise"), 1);
|
|
1716
|
+
|
|
1717
|
+
// src/databases/mysql/MysqlQueryGrammar.mts
|
|
1718
|
+
var MysqlQueryGrammar = class extends QueryGrammar {
|
|
1719
|
+
static {
|
|
1720
|
+
__name(this, "MysqlQueryGrammar");
|
|
1721
|
+
}
|
|
1722
|
+
compileInsertGetId(query, data, options = { primaryKey: ["id"] }) {
|
|
1723
|
+
return super.compileInsert(query, data);
|
|
1724
|
+
}
|
|
1725
|
+
postProcessGetInsertId(result) {
|
|
1726
|
+
return [{ id: result.insertId }];
|
|
1727
|
+
}
|
|
1728
|
+
};
|
|
1729
|
+
|
|
1730
|
+
// src/databases/mysql/MysqlSchemaGrammar.mts
|
|
1731
|
+
var MysqlSchemaGrammar = class extends SchemaGrammar {
|
|
1732
|
+
static {
|
|
1733
|
+
__name(this, "MysqlSchemaGrammar");
|
|
1734
|
+
}
|
|
1735
|
+
compileColumn(column) {
|
|
1736
|
+
const rc = [`${column.columnName}`];
|
|
1737
|
+
if (column.properties.type === "string") {
|
|
1738
|
+
rc.push("varchar(" + column.properties.length + ")");
|
|
1739
|
+
} else if (column.properties.type === "char") {
|
|
1740
|
+
rc.push("char");
|
|
1741
|
+
} else if (column.properties.type === "boolean") {
|
|
1742
|
+
rc.push("boolean");
|
|
1743
|
+
} else if (column.properties.type === "integer") {
|
|
1744
|
+
rc.push("integer");
|
|
1745
|
+
} else if (column.properties.type === "text") {
|
|
1746
|
+
rc.push("text");
|
|
1747
|
+
} else if (column.properties.type === "timestamp") {
|
|
1748
|
+
rc.push("TIMESTAMP");
|
|
1749
|
+
} else if (column.properties.type === "timestampz") {
|
|
1750
|
+
rc.push("TIMESTAMP");
|
|
1751
|
+
} else if (column.properties.type === "serial") {
|
|
1752
|
+
rc.push("INT AUTO_INCREMENT");
|
|
1753
|
+
} else if (column.properties.type === "float") {
|
|
1754
|
+
rc.push("float");
|
|
1755
|
+
} else if (column.properties.type === "double") {
|
|
1756
|
+
rc.push("double precision");
|
|
1757
|
+
} else if (column.properties.type === "date") {
|
|
1758
|
+
rc.push("date");
|
|
1759
|
+
} else if (column.properties.type === "json") {
|
|
1760
|
+
rc.push("json");
|
|
1761
|
+
} else if (column.properties.type === "jsonb") {
|
|
1762
|
+
rc.push("jsonb");
|
|
1763
|
+
} else if (column.properties.type === "raw") {
|
|
1764
|
+
return column.columnName;
|
|
1765
|
+
} else {
|
|
1766
|
+
throw new Error("Unknown column type: " + column.properties.type);
|
|
1767
|
+
}
|
|
1768
|
+
if (column.properties.nullable) {
|
|
1769
|
+
rc.push("null");
|
|
1770
|
+
} else {
|
|
1771
|
+
rc.push("NOT NULL");
|
|
1772
|
+
}
|
|
1773
|
+
if (column.properties.unique) {
|
|
1774
|
+
rc.push("unique");
|
|
1775
|
+
}
|
|
1776
|
+
if (column.properties.default !== null) {
|
|
1777
|
+
rc.push("default " + this.escape(column.properties.default));
|
|
1778
|
+
}
|
|
1779
|
+
return rc.join(" ");
|
|
1780
|
+
}
|
|
1781
|
+
};
|
|
1782
|
+
|
|
1783
|
+
// src/databases/mysql/MysqlConnection.mts
|
|
1784
|
+
var import_neko_helper6 = require("@devbro/neko-helper");
|
|
1785
|
+
var MysqlConnection = class _MysqlConnection extends Connection {
|
|
1786
|
+
static {
|
|
1787
|
+
__name(this, "MysqlConnection");
|
|
1788
|
+
}
|
|
1789
|
+
eventManager = new import_neko_helper6.EventManager();
|
|
1790
|
+
on(event, listener) {
|
|
1791
|
+
this.eventManager.on(event, listener);
|
|
1792
|
+
return this;
|
|
1793
|
+
}
|
|
1794
|
+
off(event, listener) {
|
|
1795
|
+
this.eventManager.off(event, listener);
|
|
1796
|
+
return this;
|
|
1797
|
+
}
|
|
1798
|
+
emit(event, ...args) {
|
|
1799
|
+
return this.eventManager.emit(event, ...args);
|
|
1800
|
+
}
|
|
1801
|
+
connection;
|
|
1802
|
+
static pool;
|
|
1803
|
+
static poolConfig;
|
|
1804
|
+
static defaults = {
|
|
1805
|
+
port: 3306,
|
|
1806
|
+
connectionLimit: 20,
|
|
1807
|
+
waitForConnections: true,
|
|
1808
|
+
queueLimit: 0,
|
|
1809
|
+
enableKeepAlive: true,
|
|
1810
|
+
keepAliveInitialDelay: 0
|
|
1811
|
+
};
|
|
1812
|
+
constructor(params) {
|
|
1813
|
+
super();
|
|
1814
|
+
if (!_MysqlConnection.pool) {
|
|
1815
|
+
_MysqlConnection.poolConfig = { ..._MysqlConnection.defaults, ...params };
|
|
1816
|
+
_MysqlConnection.pool = import_promise.default.createPool(_MysqlConnection.poolConfig);
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
async connect() {
|
|
1820
|
+
this.eventManager.emit("connect").catch(() => {
|
|
1821
|
+
});
|
|
1822
|
+
this.connection = await _MysqlConnection.pool.getConnection();
|
|
1823
|
+
return true;
|
|
1824
|
+
}
|
|
1825
|
+
async runQuery(sql) {
|
|
1826
|
+
if (typeof sql === "string") {
|
|
1827
|
+
sql = { sql, bindings: [], parts: [sql] };
|
|
1828
|
+
}
|
|
1829
|
+
this.eventManager.emit("query", { sql: sql.sql, bindings: sql.bindings }).catch(() => {
|
|
1830
|
+
});
|
|
1831
|
+
if (!this.isConnected()) {
|
|
1832
|
+
await this.connect();
|
|
1833
|
+
}
|
|
1834
|
+
const result = await this.connection.query(sql.sql, sql.bindings);
|
|
1835
|
+
return result[0];
|
|
1836
|
+
}
|
|
1837
|
+
async runCursor(sql) {
|
|
1838
|
+
return this.runQuery(sql);
|
|
1839
|
+
}
|
|
1840
|
+
async disconnect() {
|
|
1841
|
+
if (this.connection === void 0) {
|
|
1842
|
+
return true;
|
|
1843
|
+
}
|
|
1844
|
+
this.connection.release();
|
|
1845
|
+
this.connection = void 0;
|
|
1846
|
+
this.eventManager.emit("disconnect").catch(() => {
|
|
1847
|
+
});
|
|
1848
|
+
return true;
|
|
1849
|
+
}
|
|
1850
|
+
getQuery() {
|
|
1851
|
+
return new Query(this, new MysqlQueryGrammar());
|
|
1852
|
+
}
|
|
1853
|
+
getSchema() {
|
|
1854
|
+
return new Schema(this, new MysqlSchemaGrammar());
|
|
1855
|
+
}
|
|
1856
|
+
getQueryGrammar() {
|
|
1857
|
+
return new MysqlQueryGrammar();
|
|
1858
|
+
}
|
|
1859
|
+
getSchemaGrammar() {
|
|
1860
|
+
return new MysqlSchemaGrammar();
|
|
1861
|
+
}
|
|
1862
|
+
async beginTransaction() {
|
|
1863
|
+
await this.runQuery({
|
|
1864
|
+
sql: "BEGIN",
|
|
1865
|
+
bindings: [],
|
|
1866
|
+
parts: ["BEGIN"]
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1869
|
+
async commit() {
|
|
1870
|
+
await this.runQuery({ sql: "COMMIT", bindings: [], parts: ["COMMIT"] });
|
|
1871
|
+
}
|
|
1872
|
+
async rollback() {
|
|
1873
|
+
await this.runQuery({ sql: "ROLLBACK", bindings: [], parts: ["ROLLBACK"] });
|
|
1874
|
+
}
|
|
1875
|
+
static destroy() {
|
|
1876
|
+
return _MysqlConnection.pool.end();
|
|
1877
|
+
}
|
|
1878
|
+
isConnected() {
|
|
1879
|
+
return this.connection !== void 0;
|
|
1880
|
+
}
|
|
1881
|
+
/**
|
|
1882
|
+
* Validates and escapes a MySQL identifier (database name, table name, etc.)
|
|
1883
|
+
* Uses a whitelist approach to ensure only safe characters are allowed
|
|
1884
|
+
*/
|
|
1885
|
+
validateAndEscapeIdentifier(name) {
|
|
1886
|
+
const validIdentifierPattern = /^[a-zA-Z0-9_$]+$/;
|
|
1887
|
+
if (!validIdentifierPattern.test(name)) {
|
|
1888
|
+
throw new Error(
|
|
1889
|
+
`Invalid identifier: "${name}". Identifiers must contain only letters, digits, underscores, and dollar signs.`
|
|
1890
|
+
);
|
|
1891
|
+
}
|
|
1892
|
+
const reservedKeywords = /* @__PURE__ */ new Set([
|
|
1893
|
+
"database",
|
|
1894
|
+
"table",
|
|
1895
|
+
"user",
|
|
1896
|
+
"order",
|
|
1897
|
+
"group",
|
|
1898
|
+
"select",
|
|
1899
|
+
"insert",
|
|
1900
|
+
"update",
|
|
1901
|
+
"delete",
|
|
1902
|
+
"from",
|
|
1903
|
+
"where",
|
|
1904
|
+
"index",
|
|
1905
|
+
"key"
|
|
1906
|
+
]);
|
|
1907
|
+
if (reservedKeywords.has(name.toLowerCase())) {
|
|
1908
|
+
const escapedName = name.replace(/`/g, "``");
|
|
1909
|
+
return `\`${escapedName}\``;
|
|
1910
|
+
}
|
|
1911
|
+
return name;
|
|
1912
|
+
}
|
|
1913
|
+
async createDatabase(name) {
|
|
1914
|
+
if (!this.isConnected()) {
|
|
1915
|
+
const tempConn2 = await import_promise.default.createConnection({
|
|
1916
|
+
host: _MysqlConnection.poolConfig.host,
|
|
1917
|
+
user: _MysqlConnection.poolConfig.user,
|
|
1918
|
+
password: _MysqlConnection.poolConfig.password,
|
|
1919
|
+
port: _MysqlConnection.poolConfig.port
|
|
1920
|
+
});
|
|
1921
|
+
const safeName2 = this.validateAndEscapeIdentifier(name);
|
|
1922
|
+
console.log(safeName2);
|
|
1923
|
+
let [rows] = await tempConn2.query(`CREATE DATABASE ${safeName2}`);
|
|
1924
|
+
await tempConn2.end();
|
|
1925
|
+
return;
|
|
1926
|
+
}
|
|
1927
|
+
const tempConn = await import_promise.default.createConnection({
|
|
1928
|
+
host: _MysqlConnection.poolConfig.host,
|
|
1929
|
+
user: _MysqlConnection.poolConfig.user,
|
|
1930
|
+
password: _MysqlConnection.poolConfig.password,
|
|
1931
|
+
port: _MysqlConnection.poolConfig.port
|
|
1932
|
+
});
|
|
1933
|
+
const safeName = this.validateAndEscapeIdentifier(name);
|
|
1934
|
+
await tempConn.query(`CREATE DATABASE ${safeName}`);
|
|
1935
|
+
await tempConn.end();
|
|
1936
|
+
}
|
|
1937
|
+
async dropDatabase(name) {
|
|
1938
|
+
if (this.isConnected()) {
|
|
1939
|
+
throw new Error("Cannot drop database while connected.");
|
|
1940
|
+
}
|
|
1941
|
+
const tempConn = await import_promise.default.createConnection({
|
|
1942
|
+
host: _MysqlConnection.poolConfig.host,
|
|
1943
|
+
user: _MysqlConnection.poolConfig.user,
|
|
1944
|
+
password: _MysqlConnection.poolConfig.password,
|
|
1945
|
+
port: _MysqlConnection.poolConfig.port
|
|
1946
|
+
});
|
|
1947
|
+
const safeName = this.validateAndEscapeIdentifier(name);
|
|
1948
|
+
await tempConn.query(`DROP DATABASE ${safeName}`);
|
|
1949
|
+
await tempConn.end();
|
|
1950
|
+
}
|
|
1951
|
+
async listDatabases() {
|
|
1952
|
+
if (!this.isConnected()) {
|
|
1953
|
+
await this.connect();
|
|
1954
|
+
}
|
|
1955
|
+
const [rows] = await this.connection.query("SHOW DATABASES");
|
|
1956
|
+
return rows.map((row) => row.Database);
|
|
1957
|
+
}
|
|
1958
|
+
async existsDatabase(name) {
|
|
1959
|
+
if (!this.isConnected()) {
|
|
1960
|
+
const tempConn = await import_promise.default.createConnection({
|
|
1961
|
+
host: _MysqlConnection.poolConfig.host,
|
|
1962
|
+
user: _MysqlConnection.poolConfig.user,
|
|
1963
|
+
password: _MysqlConnection.poolConfig.password,
|
|
1964
|
+
port: _MysqlConnection.poolConfig.port
|
|
1965
|
+
});
|
|
1966
|
+
let [rows2] = await tempConn.query(
|
|
1967
|
+
"SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ?",
|
|
1968
|
+
[name]
|
|
1969
|
+
);
|
|
1970
|
+
await tempConn.end();
|
|
1971
|
+
return rows2.length > 0;
|
|
1972
|
+
}
|
|
1973
|
+
const [rows] = await this.connection.query(
|
|
1974
|
+
"SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ?",
|
|
1975
|
+
[name]
|
|
1976
|
+
);
|
|
1977
|
+
return rows.length > 0;
|
|
1978
|
+
}
|
|
1979
|
+
};
|
|
1980
|
+
|
|
1359
1981
|
// src/Migration.mts
|
|
1360
1982
|
var Migration = class {
|
|
1361
1983
|
static {
|
|
@@ -1370,12 +1992,18 @@ var Migration = class {
|
|
|
1370
1992
|
ForeignKeyConstraint,
|
|
1371
1993
|
IndexConstraint,
|
|
1372
1994
|
Migration,
|
|
1995
|
+
MysqlConnection,
|
|
1996
|
+
MysqlQueryGrammar,
|
|
1997
|
+
MysqlSchemaGrammar,
|
|
1373
1998
|
PostgresqlConnection,
|
|
1374
1999
|
PostgresqlQueryGrammar,
|
|
1375
2000
|
PostgresqlSchemaGrammar,
|
|
1376
2001
|
Query,
|
|
1377
2002
|
QueryGrammar,
|
|
1378
2003
|
Schema,
|
|
1379
|
-
SchemaGrammar
|
|
2004
|
+
SchemaGrammar,
|
|
2005
|
+
SqliteConnection,
|
|
2006
|
+
SqliteQueryGrammar,
|
|
2007
|
+
SqliteSchemaGrammar
|
|
1380
2008
|
});
|
|
1381
2009
|
//# sourceMappingURL=index.js.map
|