tempest-db-js 0.2.0 → 0.4.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 +3 -2
- package/dist/bin.cjs +429 -42
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +2 -2
- package/dist/{chunk-QMW4NKMH.js → chunk-43XL66JG.js} +546 -43
- package/dist/chunk-43XL66JG.js.map +1 -0
- package/dist/{chunk-AGDD7K3F.js → chunk-JR4MLFQN.js} +217 -22
- package/dist/chunk-JR4MLFQN.js.map +1 -0
- package/dist/index.cjs +217 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +129 -8
- package/dist/index.d.ts +129 -8
- package/dist/index.js +1 -1
- package/dist/migrations/index.cjs +597 -44
- package/dist/migrations/index.cjs.map +1 -1
- package/dist/migrations/index.d.cts +91 -15
- package/dist/migrations/index.d.ts +91 -15
- package/dist/migrations/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-AGDD7K3F.js.map +0 -1
- package/dist/chunk-QMW4NKMH.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -288,7 +288,9 @@ var DIALECT_ALIASES = {
|
|
|
288
288
|
sqlite3: "sqlite",
|
|
289
289
|
postgresql: "postgresql",
|
|
290
290
|
postgres: "postgresql",
|
|
291
|
-
pg: "postgresql"
|
|
291
|
+
pg: "postgresql",
|
|
292
|
+
mysql: "mysql",
|
|
293
|
+
mariadb: "mysql"
|
|
292
294
|
};
|
|
293
295
|
function splitScheme(scheme) {
|
|
294
296
|
const plus = scheme.indexOf("+");
|
|
@@ -328,10 +330,10 @@ function parseSqlite(raw, driver, rest) {
|
|
|
328
330
|
raw
|
|
329
331
|
};
|
|
330
332
|
}
|
|
331
|
-
function
|
|
333
|
+
function parseNetworkUrl(raw, driver, rest, dialect) {
|
|
332
334
|
let parsed;
|
|
333
335
|
try {
|
|
334
|
-
parsed = new URL(
|
|
336
|
+
parsed = new URL(`${dialect}:${rest}`);
|
|
335
337
|
} catch {
|
|
336
338
|
throw new InvalidDatabaseUrl(raw, "could not parse host/credentials");
|
|
337
339
|
}
|
|
@@ -339,7 +341,7 @@ function parsePostgres(raw, driver, rest) {
|
|
|
339
341
|
const options = {};
|
|
340
342
|
for (const [key, value] of parsed.searchParams) options[key] = value;
|
|
341
343
|
return {
|
|
342
|
-
dialect
|
|
344
|
+
dialect,
|
|
343
345
|
driver,
|
|
344
346
|
host: parsed.hostname || null,
|
|
345
347
|
port: parsed.port ? Number(parsed.port) : null,
|
|
@@ -364,7 +366,8 @@ function parseDatabaseUrl(url) {
|
|
|
364
366
|
throw new InvalidDatabaseUrl(url, `unknown dialect ${JSON.stringify(base)}`);
|
|
365
367
|
}
|
|
366
368
|
const rest = url.slice(schemeEnd + 1);
|
|
367
|
-
|
|
369
|
+
if (dialect === "sqlite") return parseSqlite(url, driver, rest);
|
|
370
|
+
return parseNetworkUrl(url, driver, rest, dialect);
|
|
368
371
|
}
|
|
369
372
|
function detectDialect(url) {
|
|
370
373
|
return parseDatabaseUrl(url).dialect;
|
|
@@ -663,18 +666,30 @@ var BaseDialect = class _BaseDialect {
|
|
|
663
666
|
const rowsSql = node.values.map(() => `(${columns.map(() => this.placeholder(++position)).join(", ")})`).join(", ");
|
|
664
667
|
let sql2 = `INSERT INTO ${this.quoteId(node.table)} (${colSql}) VALUES ${rowsSql}`;
|
|
665
668
|
if (node.onConflict) {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
sql2 += ` ON CONFLICT (${target}) DO UPDATE SET ${assignments}`;
|
|
672
|
-
}
|
|
669
|
+
sql2 += this.renderConflict(
|
|
670
|
+
node.onConflict,
|
|
671
|
+
conflictCols,
|
|
672
|
+
() => this.placeholder(++position)
|
|
673
|
+
);
|
|
673
674
|
}
|
|
674
675
|
sql2 += this.compileReturning(node.returning);
|
|
675
676
|
_BaseDialect.insertTemplates.set(key, sql2);
|
|
676
677
|
return sql2;
|
|
677
678
|
}
|
|
679
|
+
/**
|
|
680
|
+
* Render the conflict-handling clause. Standard SQL (SQLite/PostgreSQL) uses
|
|
681
|
+
* `ON CONFLICT (...) DO NOTHING | DO UPDATE SET ...`; MySQL overrides this.
|
|
682
|
+
*
|
|
683
|
+
* @param onConflict The conflict clause from the node.
|
|
684
|
+
* @param conflictCols The columns to overwrite on `DO UPDATE` (empty for nothing).
|
|
685
|
+
* @param nextPlaceholder Yields the next positional placeholder (advances the count).
|
|
686
|
+
*/
|
|
687
|
+
renderConflict(onConflict, conflictCols, nextPlaceholder) {
|
|
688
|
+
const target = onConflict.target.map((c) => this.quoteId(c)).join(", ");
|
|
689
|
+
if (onConflict.update === "nothing") return ` ON CONFLICT (${target}) DO NOTHING`;
|
|
690
|
+
const assignments = conflictCols.map((c) => `${this.quoteId(c)} = ${nextPlaceholder()}`).join(", ");
|
|
691
|
+
return ` ON CONFLICT (${target}) DO UPDATE SET ${assignments}`;
|
|
692
|
+
}
|
|
678
693
|
compileUpdate(node, params) {
|
|
679
694
|
const sets = Object.entries(node.set).map(([col, value]) => `${this.quoteId(col)} = ${params.bind(value)}`).join(", ");
|
|
680
695
|
let sql2 = `UPDATE ${this.quoteId(node.table)} SET ${sets}`;
|
|
@@ -812,8 +827,46 @@ var PostgresDialect = class extends BaseDialect {
|
|
|
812
827
|
return `${column2} ILIKE ${param}`;
|
|
813
828
|
}
|
|
814
829
|
};
|
|
830
|
+
var mysqlQuotedIds = /* @__PURE__ */ new Map();
|
|
831
|
+
var MysqlDialect = class extends BaseDialect {
|
|
832
|
+
name = "mysql";
|
|
833
|
+
placeholder() {
|
|
834
|
+
return "?";
|
|
835
|
+
}
|
|
836
|
+
ilike(column2, param) {
|
|
837
|
+
return `${column2} LIKE ${param}`;
|
|
838
|
+
}
|
|
839
|
+
quoteId(name) {
|
|
840
|
+
const cached = mysqlQuotedIds.get(name);
|
|
841
|
+
if (cached !== void 0) return cached;
|
|
842
|
+
const quoted = `\`${name.replace(/`/g, "``")}\``;
|
|
843
|
+
mysqlQuotedIds.set(name, quoted);
|
|
844
|
+
return quoted;
|
|
845
|
+
}
|
|
846
|
+
renderConflict(onConflict, conflictCols, nextPlaceholder) {
|
|
847
|
+
if (onConflict.update === "nothing") {
|
|
848
|
+
const col = this.quoteId(onConflict.target[0] ?? "id");
|
|
849
|
+
return ` ON DUPLICATE KEY UPDATE ${col} = ${col}`;
|
|
850
|
+
}
|
|
851
|
+
const assignments = conflictCols.map((c) => `${this.quoteId(c)} = ${nextPlaceholder()}`).join(", ");
|
|
852
|
+
return ` ON DUPLICATE KEY UPDATE ${assignments}`;
|
|
853
|
+
}
|
|
854
|
+
compileReturning(returning) {
|
|
855
|
+
if (returning === null) return "";
|
|
856
|
+
throw new Error(
|
|
857
|
+
"RETURNING is not supported on MySQL \u2014 insert, then SELECT by key (e.g. LAST_INSERT_ID())."
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
};
|
|
815
861
|
function getDialect(name) {
|
|
816
|
-
|
|
862
|
+
switch (name) {
|
|
863
|
+
case "sqlite":
|
|
864
|
+
return new SqliteDialect();
|
|
865
|
+
case "postgresql":
|
|
866
|
+
return new PostgresDialect();
|
|
867
|
+
case "mysql":
|
|
868
|
+
return new MysqlDialect();
|
|
869
|
+
}
|
|
817
870
|
}
|
|
818
871
|
|
|
819
872
|
// src/join.ts
|
|
@@ -1576,12 +1629,76 @@ function createEngine(url, options) {
|
|
|
1576
1629
|
options?.onQuery
|
|
1577
1630
|
);
|
|
1578
1631
|
}
|
|
1632
|
+
if (parsed.dialect === "mysql") {
|
|
1633
|
+
return new AsyncEngine(
|
|
1634
|
+
createMysqlDriver(parsed.raw, options?.pool),
|
|
1635
|
+
"mysql",
|
|
1636
|
+
options?.onQuery
|
|
1637
|
+
);
|
|
1638
|
+
}
|
|
1579
1639
|
return new AsyncEngine(
|
|
1580
1640
|
createPostgresDriver(parsed.raw, options?.pool),
|
|
1581
1641
|
"postgresql",
|
|
1582
1642
|
options?.onQuery
|
|
1583
1643
|
);
|
|
1584
1644
|
}
|
|
1645
|
+
function encodeMysqlParam(value) {
|
|
1646
|
+
if (value === void 0 || value === null) return null;
|
|
1647
|
+
if (typeof value === "boolean") return value ? 1 : 0;
|
|
1648
|
+
if (value instanceof Uint8Array) return value;
|
|
1649
|
+
if (value instanceof Date) return value;
|
|
1650
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
1651
|
+
return value;
|
|
1652
|
+
}
|
|
1653
|
+
function toMysqlResult(rows) {
|
|
1654
|
+
if (Array.isArray(rows)) {
|
|
1655
|
+
return { rows, changes: 0 };
|
|
1656
|
+
}
|
|
1657
|
+
const header = rows;
|
|
1658
|
+
return { rows: [], changes: header.affectedRows ?? 0 };
|
|
1659
|
+
}
|
|
1660
|
+
function createMysqlDriver(url, pool) {
|
|
1661
|
+
let poolHandle;
|
|
1662
|
+
const ensure = async () => {
|
|
1663
|
+
if (poolHandle) return;
|
|
1664
|
+
const moduleName = "mysql2/promise";
|
|
1665
|
+
const mod = await import(
|
|
1666
|
+
/* @vite-ignore */
|
|
1667
|
+
moduleName
|
|
1668
|
+
);
|
|
1669
|
+
const opts = { uri: url };
|
|
1670
|
+
if (pool?.size !== void 0) opts.connectionLimit = pool.size;
|
|
1671
|
+
if (pool?.idleTimeoutMs !== void 0) opts.idleTimeout = pool.idleTimeoutMs;
|
|
1672
|
+
if (pool?.connectTimeoutMs !== void 0) opts.connectTimeout = pool.connectTimeoutMs;
|
|
1673
|
+
poolHandle = mod.createPool(opts);
|
|
1674
|
+
};
|
|
1675
|
+
const runOn = async (queryable, sql2, params) => {
|
|
1676
|
+
const [rows] = await queryable.query(sql2, params.map(encodeMysqlParam));
|
|
1677
|
+
return toMysqlResult(rows);
|
|
1678
|
+
};
|
|
1679
|
+
return {
|
|
1680
|
+
async execute(sql2, params) {
|
|
1681
|
+
await ensure();
|
|
1682
|
+
return runOn(poolHandle, sql2, params);
|
|
1683
|
+
},
|
|
1684
|
+
async reserve() {
|
|
1685
|
+
await ensure();
|
|
1686
|
+
const conn = await poolHandle.getConnection();
|
|
1687
|
+
return {
|
|
1688
|
+
execute: (sql2, params) => runOn(conn, sql2, params),
|
|
1689
|
+
async release() {
|
|
1690
|
+
conn.release();
|
|
1691
|
+
},
|
|
1692
|
+
async close() {
|
|
1693
|
+
conn.release();
|
|
1694
|
+
}
|
|
1695
|
+
};
|
|
1696
|
+
},
|
|
1697
|
+
async close() {
|
|
1698
|
+
if (poolHandle) await poolHandle.end();
|
|
1699
|
+
}
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1585
1702
|
function toPostgresResult(rows) {
|
|
1586
1703
|
const arr = rows;
|
|
1587
1704
|
return { rows: Array.from(arr), changes: arr.count ?? arr.length };
|
|
@@ -1634,7 +1751,8 @@ function createPostgresDriver(url, pool) {
|
|
|
1634
1751
|
var DEFAULT_FLAGS = {
|
|
1635
1752
|
primaryKey: false,
|
|
1636
1753
|
notNull: false,
|
|
1637
|
-
hasDefault: false
|
|
1754
|
+
hasDefault: false,
|
|
1755
|
+
unique: false
|
|
1638
1756
|
};
|
|
1639
1757
|
var sql = {
|
|
1640
1758
|
/** Current timestamp at insert (`CURRENT_TIMESTAMP` / `now()`). */
|
|
@@ -1654,23 +1772,38 @@ var sql = {
|
|
|
1654
1772
|
function isDefaultValue(value) {
|
|
1655
1773
|
return typeof value === "object" && value !== null && "kind" in value && (value.kind === "literal" || value.kind === "expression");
|
|
1656
1774
|
}
|
|
1775
|
+
function parseReference(ref, options) {
|
|
1776
|
+
const dot = ref.lastIndexOf(".");
|
|
1777
|
+
if (dot <= 0 || dot === ref.length - 1) {
|
|
1778
|
+
throw new Error(`Invalid foreign key reference "${ref}"; expected "table.column".`);
|
|
1779
|
+
}
|
|
1780
|
+
return {
|
|
1781
|
+
table: ref.slice(0, dot),
|
|
1782
|
+
column: ref.slice(dot + 1),
|
|
1783
|
+
onDelete: options?.onDelete,
|
|
1784
|
+
onUpdate: options?.onUpdate
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1657
1787
|
var Column = class _Column {
|
|
1658
|
-
constructor(type, flags, defaultValue = null, onUpdateValue = null) {
|
|
1788
|
+
constructor(type, flags, defaultValue = null, onUpdateValue = null, reference = null) {
|
|
1659
1789
|
this.type = type;
|
|
1660
1790
|
this.flags = flags;
|
|
1661
1791
|
this.defaultValue = defaultValue;
|
|
1662
1792
|
this.onUpdateValue = onUpdateValue;
|
|
1793
|
+
this.reference = reference;
|
|
1663
1794
|
}
|
|
1664
1795
|
type;
|
|
1665
1796
|
flags;
|
|
1666
1797
|
defaultValue;
|
|
1667
1798
|
onUpdateValue;
|
|
1799
|
+
reference;
|
|
1668
1800
|
primaryKey() {
|
|
1669
1801
|
return new _Column(
|
|
1670
1802
|
this.type,
|
|
1671
1803
|
{ ...this.flags, primaryKey: true, hasDefault: true },
|
|
1672
1804
|
this.defaultValue,
|
|
1673
|
-
this.onUpdateValue
|
|
1805
|
+
this.onUpdateValue,
|
|
1806
|
+
this.reference
|
|
1674
1807
|
);
|
|
1675
1808
|
}
|
|
1676
1809
|
notNull() {
|
|
@@ -1678,7 +1811,40 @@ var Column = class _Column {
|
|
|
1678
1811
|
this.type,
|
|
1679
1812
|
{ ...this.flags, notNull: true },
|
|
1680
1813
|
this.defaultValue,
|
|
1681
|
-
this.onUpdateValue
|
|
1814
|
+
this.onUpdateValue,
|
|
1815
|
+
this.reference
|
|
1816
|
+
);
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Add a `UNIQUE` constraint to the column (mirrors SQLAlchemy's
|
|
1820
|
+
* `mapped_column(unique=True)`). DDL-only — does not change the inferred type.
|
|
1821
|
+
*/
|
|
1822
|
+
unique() {
|
|
1823
|
+
return new _Column(
|
|
1824
|
+
this.type,
|
|
1825
|
+
{ ...this.flags, unique: true },
|
|
1826
|
+
this.defaultValue,
|
|
1827
|
+
this.onUpdateValue,
|
|
1828
|
+
this.reference
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1831
|
+
/**
|
|
1832
|
+
* Declare a foreign-key reference to another table's column, à la SQLAlchemy's
|
|
1833
|
+
* `mapped_column(ForeignKey("table.column", ondelete=...))`. DDL-only — does
|
|
1834
|
+
* not change the inferred type.
|
|
1835
|
+
*
|
|
1836
|
+
* @param ref The target as `"table.column"` (e.g. `"users.id"`).
|
|
1837
|
+
* @param options Optional `onDelete` / `onUpdate` referential actions.
|
|
1838
|
+
* @returns A new column carrying the reference.
|
|
1839
|
+
* @throws Error When `ref` is not a valid `"table.column"` string.
|
|
1840
|
+
*/
|
|
1841
|
+
references(ref, options) {
|
|
1842
|
+
return new _Column(
|
|
1843
|
+
this.type,
|
|
1844
|
+
this.flags,
|
|
1845
|
+
this.defaultValue,
|
|
1846
|
+
this.onUpdateValue,
|
|
1847
|
+
parseReference(ref, options)
|
|
1682
1848
|
);
|
|
1683
1849
|
}
|
|
1684
1850
|
/**
|
|
@@ -1691,7 +1857,8 @@ var Column = class _Column {
|
|
|
1691
1857
|
this.type,
|
|
1692
1858
|
{ ...this.flags, hasDefault: true },
|
|
1693
1859
|
resolved,
|
|
1694
|
-
this.onUpdateValue
|
|
1860
|
+
this.onUpdateValue,
|
|
1861
|
+
this.reference
|
|
1695
1862
|
);
|
|
1696
1863
|
}
|
|
1697
1864
|
/**
|
|
@@ -1700,7 +1867,7 @@ var Column = class _Column {
|
|
|
1700
1867
|
*/
|
|
1701
1868
|
onUpdate(value) {
|
|
1702
1869
|
const resolved = isDefaultValue(value) ? value : { kind: "literal", value };
|
|
1703
|
-
return new _Column(this.type, this.flags, this.defaultValue, resolved);
|
|
1870
|
+
return new _Column(this.type, this.flags, this.defaultValue, resolved, this.reference);
|
|
1704
1871
|
}
|
|
1705
1872
|
};
|
|
1706
1873
|
function makeColumn(kind, meta = {}) {
|
|
@@ -1754,8 +1921,36 @@ var column = {
|
|
|
1754
1921
|
/** `ENUM(...values)` → a string-literal union of the given values. */
|
|
1755
1922
|
enum: (...values) => makeColumn("enum", { values })
|
|
1756
1923
|
};
|
|
1924
|
+
function unique(...columns) {
|
|
1925
|
+
if (columns.length === 0) {
|
|
1926
|
+
throw new Error("unique() requires at least one column.");
|
|
1927
|
+
}
|
|
1928
|
+
return { kind: "unique", columns };
|
|
1929
|
+
}
|
|
1930
|
+
function foreignKey(columns, refTable, refColumns, options) {
|
|
1931
|
+
if (columns.length === 0 || columns.length !== refColumns.length) {
|
|
1932
|
+
throw new Error(
|
|
1933
|
+
"foreignKey() requires matching, non-empty local and referenced column lists."
|
|
1934
|
+
);
|
|
1935
|
+
}
|
|
1936
|
+
return {
|
|
1937
|
+
kind: "foreignKey",
|
|
1938
|
+
name: options?.name,
|
|
1939
|
+
columns,
|
|
1940
|
+
refTable,
|
|
1941
|
+
refColumns,
|
|
1942
|
+
onDelete: options?.onDelete,
|
|
1943
|
+
onUpdate: options?.onUpdate
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1757
1946
|
var Model = class {
|
|
1758
1947
|
static tablename;
|
|
1948
|
+
/**
|
|
1949
|
+
* Optional table-level constraints (composite unique / foreign keys), returned
|
|
1950
|
+
* by a thunk so forward references resolve lazily. Mirrors SQLAlchemy's
|
|
1951
|
+
* `__table_args__`.
|
|
1952
|
+
*/
|
|
1953
|
+
static tableArgs;
|
|
1759
1954
|
};
|
|
1760
1955
|
var columnsCache = /* @__PURE__ */ new WeakMap();
|
|
1761
1956
|
function columnsOf(model) {
|
|
@@ -1785,6 +1980,7 @@ exports.InsertBuilder = InsertBuilder;
|
|
|
1785
1980
|
exports.InvalidDatabaseUrl = InvalidDatabaseUrl;
|
|
1786
1981
|
exports.JoinBuilder = JoinBuilder;
|
|
1787
1982
|
exports.Model = Model;
|
|
1983
|
+
exports.MysqlDialect = MysqlDialect;
|
|
1788
1984
|
exports.NoResultError = NoResultError;
|
|
1789
1985
|
exports.NodeSqliteDriver = NodeSqliteDriver;
|
|
1790
1986
|
exports.OPERATORS = OPERATORS;
|
|
@@ -1809,6 +2005,7 @@ exports.createEngine = createEngine;
|
|
|
1809
2005
|
exports.createSyncEngine = createSyncEngine;
|
|
1810
2006
|
exports.del = del;
|
|
1811
2007
|
exports.detectDialect = detectDialect;
|
|
2008
|
+
exports.foreignKey = foreignKey;
|
|
1812
2009
|
exports.fromDict = fromDict;
|
|
1813
2010
|
exports.getDialect = getDialect;
|
|
1814
2011
|
exports.hasMany = hasMany;
|
|
@@ -1829,6 +2026,7 @@ exports.sum = sum;
|
|
|
1829
2026
|
exports.toCondNode = toCondNode;
|
|
1830
2027
|
exports.toDict = toDict;
|
|
1831
2028
|
exports.toJSON = toJSON;
|
|
2029
|
+
exports.unique = unique;
|
|
1832
2030
|
exports.update = update;
|
|
1833
2031
|
//# sourceMappingURL=index.cjs.map
|
|
1834
2032
|
//# sourceMappingURL=index.cjs.map
|