@devbro/neko-sql 0.1.32 → 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.
Files changed (46) hide show
  1. package/README.md +23 -3
  2. package/dist/{Blueprint-D3WHeqRS.d.mts → Blueprint-g4SmS1bH.d.mts} +6 -0
  3. package/dist/Blueprint.d.mts +1 -1
  4. package/dist/Connection.d.mts +1 -1
  5. package/dist/Expression.d.mts +1 -1
  6. package/dist/Migration.d.mts +1 -1
  7. package/dist/Query.d.mts +1 -1
  8. package/dist/Query.mjs +3 -1
  9. package/dist/Query.mjs.map +1 -1
  10. package/dist/QueryGrammar.d.mts +1 -1
  11. package/dist/QueryGrammar.mjs +8 -0
  12. package/dist/QueryGrammar.mjs.map +1 -1
  13. package/dist/Schema.d.mts +1 -1
  14. package/dist/SchemaGrammar.d.mts +1 -1
  15. package/dist/databases/index.d.mts +5 -1
  16. package/dist/databases/index.mjs +1 -0
  17. package/dist/databases/index.mjs.map +1 -1
  18. package/dist/databases/mysql/MysqlConnection.d.mts +41 -0
  19. package/dist/databases/mysql/MysqlConnection.mjs +208 -0
  20. package/dist/databases/mysql/MysqlConnection.mjs.map +1 -0
  21. package/dist/databases/mysql/MysqlQueryGrammar.d.mts +13 -0
  22. package/dist/databases/mysql/MysqlQueryGrammar.mjs +18 -0
  23. package/dist/databases/mysql/MysqlQueryGrammar.mjs.map +1 -0
  24. package/dist/databases/mysql/MysqlSchemaGrammar.d.mts +8 -0
  25. package/dist/databases/mysql/MysqlSchemaGrammar.mjs +58 -0
  26. package/dist/databases/mysql/MysqlSchemaGrammar.mjs.map +1 -0
  27. package/dist/databases/mysql/index.d.mts +6 -0
  28. package/dist/databases/mysql/index.mjs +4 -0
  29. package/dist/databases/mysql/index.mjs.map +1 -0
  30. package/dist/databases/postgresql/PostgresqlConnection.d.mts +1 -1
  31. package/dist/databases/postgresql/PostgresqlConnection.mjs +17 -3
  32. package/dist/databases/postgresql/PostgresqlConnection.mjs.map +1 -1
  33. package/dist/databases/postgresql/PostgresqlQueryGrammar.d.mts +1 -1
  34. package/dist/databases/postgresql/PostgresqlSchemaGrammar.d.mts +1 -1
  35. package/dist/databases/postgresql/index.d.mts +1 -1
  36. package/dist/databases/sqlite/SqliteConnection.d.mts +1 -1
  37. package/dist/databases/sqlite/SqliteQueryGrammar.d.mts +1 -1
  38. package/dist/databases/sqlite/SqliteSchemaGrammar.d.mts +2 -1
  39. package/dist/databases/sqlite/SqliteSchemaGrammar.mjs +46 -0
  40. package/dist/databases/sqlite/SqliteSchemaGrammar.mjs.map +1 -1
  41. package/dist/databases/sqlite/index.d.mts +1 -1
  42. package/dist/index.d.mts +5 -1
  43. package/dist/index.js +347 -4
  44. package/dist/index.js.map +1 -1
  45. package/dist/types.d.mts +1 -1
  46. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -37,6 +37,9 @@ __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,
@@ -201,7 +204,9 @@ var Query = class _Query {
201
204
  }
202
205
  async insertGetId(data, options = { primaryKey: ["id"] }) {
203
206
  const csql = this.grammar.compileInsertGetId(this, data, options);
204
- return await this.connection?.runQuery(csql);
207
+ let rc = await this.connection?.runQuery(csql);
208
+ rc = this.grammar.postProcessGetInsertId(rc);
209
+ return rc;
205
210
  }
206
211
  async update(data) {
207
212
  const csql = this.grammar.compileUpdate(this, data);
@@ -587,6 +592,14 @@ var QueryGrammar = class {
587
592
  bindings: w.bindings
588
593
  };
589
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
+ }
590
603
  };
591
604
 
592
605
  // src/databases/postgresql/PostgresqlQueryGrammar.mts
@@ -1316,7 +1329,9 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
1316
1329
  }
1317
1330
  async createDatabase(name) {
1318
1331
  if (this.isConnected()) {
1319
- throw new Error("Cannot create database while connected.");
1332
+ const safeName2 = this.validateAndEscapeIdentifier(name);
1333
+ await this.runQuery(`CREATE DATABASE ${safeName2}`);
1334
+ return;
1320
1335
  }
1321
1336
  const conn = new import_pg.Client({
1322
1337
  ..._PostgresqlConnection.pool.options,
@@ -1329,7 +1344,9 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
1329
1344
  }
1330
1345
  async dropDatabase(name) {
1331
1346
  if (this.isConnected()) {
1332
- throw new Error("Cannot drop database while connected.");
1347
+ const safeName2 = this.validateAndEscapeIdentifier(name);
1348
+ await this.runQuery(`DROP DATABASE ${safeName2}`);
1349
+ return;
1333
1350
  }
1334
1351
  const conn = new import_pg.Client({
1335
1352
  ..._PostgresqlConnection.pool.options,
@@ -1352,7 +1369,17 @@ var PostgresqlConnection = class _PostgresqlConnection extends Connection {
1352
1369
  }
1353
1370
  async existsDatabase(name) {
1354
1371
  if (!this.isConnected()) {
1355
- await this.connect();
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;
1356
1383
  }
1357
1384
  const result = await this.connection.query("SELECT 1 FROM pg_database WHERE datname = $1", [
1358
1385
  name
@@ -1404,6 +1431,52 @@ var SqliteSchemaGrammar = class extends SchemaGrammar {
1404
1431
  static {
1405
1432
  __name(this, "SqliteSchemaGrammar");
1406
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
+ }
1407
1480
  };
1408
1481
 
1409
1482
  // src/databases/sqlite/SqliteConnection.mts
@@ -1638,6 +1711,273 @@ var SqliteConnection = class _SqliteConnection extends Connection {
1638
1711
  }
1639
1712
  };
1640
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
+
1641
1981
  // src/Migration.mts
1642
1982
  var Migration = class {
1643
1983
  static {
@@ -1652,6 +1992,9 @@ var Migration = class {
1652
1992
  ForeignKeyConstraint,
1653
1993
  IndexConstraint,
1654
1994
  Migration,
1995
+ MysqlConnection,
1996
+ MysqlQueryGrammar,
1997
+ MysqlSchemaGrammar,
1655
1998
  PostgresqlConnection,
1656
1999
  PostgresqlQueryGrammar,
1657
2000
  PostgresqlSchemaGrammar,