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