everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
204 lines (202 loc) • 7.69 kB
JavaScript
let node_fs = require("node:fs");
let node_path = require("node:path");
//#region src/db/core.ts
const DEFAULT_MIGRATION_JOURNAL = {
schema: "drizzle",
table: "__drizzle_migrations"
};
const PER_PLUGIN_ISOLATION = false;
function normalizeSlug(name) {
return (name.split("/").pop() ?? name).replace(/^@/, "").replace(/[^a-zA-Z0-9_-]/g, "_").replace(/-plugin$/i, "").replace(/-/g, "_").toLowerCase();
}
function getMigrationSlug(dir) {
if (!dir) return normalizeSlug(process.env.npm_package_name ?? "unknown");
let current = dir;
for (let i = 0; i < 10; i++) {
const pkgPath = (0, node_path.join)(current, "package.json");
if ((0, node_fs.existsSync)(pkgPath)) try {
return normalizeSlug(JSON.parse((0, node_fs.readFileSync)(pkgPath, "utf-8")).name ?? current);
} catch {
return normalizeSlug(current);
}
const parent = (0, node_path.dirname)(current);
if (parent === current) break;
current = parent;
}
return normalizeSlug(dir);
}
function getMigrationStorage(slug, options) {
const s = normalizeSlug(slug ?? getMigrationSlug());
if (options?.isolated ?? PER_PLUGIN_ISOLATION) return {
schema: DEFAULT_MIGRATION_JOURNAL.schema,
table: `__drizzle_migrations_${s}`,
slug: s
};
return {
schema: DEFAULT_MIGRATION_JOURNAL.schema,
table: DEFAULT_MIGRATION_JOURNAL.table,
slug: s
};
}
/**
* Format a JavaScript string array as a PostgreSQL text array literal for use
* with Drizzle's `sql` tag. Example return:
* `'{"h1","h2"}'::text[]`
*
* Usage: sql`WHERE col = ANY(${toSqlArray(values)})`
*
* Drizzle's default parameter binding does not handle array types correctly
* with the pg driver (it emits `ANY(($1))` with a single string, which
* Postgres rejects as a malformed array literal).
*/
function toSqlArray(arr) {
if (arr.length === 0) return `'{}'::text[]`;
return `'{${arr.map((v) => v.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")).map((v) => `"${v}"`).join(",")}}'::text[]`;
}
function pluginMigrationSlug(key) {
return normalizeSlug(key);
}
function getDatabaseUrlSecretName(slug) {
return `${slug.toUpperCase().replace(/-/g, "_")}_DATABASE_URL`;
}
const DUPLICATE_OBJECT_SQLSTATES = [
"42710",
"42701",
"42P07"
];
/**
* Walk `error` and its `cause` chain (bounded), invoking `visit` on each link.
* Postgres driver errors arrive wrapped by drizzle/Effect at varying depths,
* so every error-shape predicate below shares this traversal.
*/
function visitCauses(error, depth, visit) {
let current = error;
for (let i = 0; i < depth && current; i++) {
if (typeof current === "object" && current !== null && visit(current)) return true;
current = current?.cause;
}
return false;
}
/**
* pg_catalog unique indexes that can surface a concurrent-DDL race as SQLSTATE
* 23505 instead of a duplicate-object class. When two connections run
* `CREATE TABLE <name>` at the same time, the loser fails its insert into
* `pg_type` ("duplicate key value violates unique constraint
* `pg_type_typname_nsp_index`") rather than seeing 42P07, because the winner's
* table is not yet committed. The same shape exists for schemas and other
* relations.
*/
const CONCURRENT_DDL_CONSTRAINTS = /* @__PURE__ */ new Set([
"pg_type_typname_nsp_index",
"pg_namespace_nspname_index",
"pg_class_relname_nsp_index"
]);
/**
* Whether a SQLSTATE 23505 unique violation is the concurrent-DDL catalog
* collision signature rather than a data-level constraint on a user table.
* Data-level violations must keep failing loudly; only the pg_catalog indexes
* above are treated as duplicate-DDL tolerance candidates.
*/
function isConcurrentDdlUniqueViolation(error) {
return visitCauses(error, 6, (link) => {
const { code, constraint, message } = link;
if (code !== "23505") return false;
if (typeof constraint === "string" && CONCURRENT_DDL_CONSTRAINTS.has(constraint)) return true;
if (typeof message !== "string") return false;
for (const name of CONCURRENT_DDL_CONSTRAINTS) if (message.includes(name)) return true;
return false;
});
}
const RETRYABLE_SQLSTATES = /* @__PURE__ */ new Set([
"42P06",
"42710",
"42701",
"42P07",
"23505",
"40001",
"40P01",
"55P03"
]);
const RETRYABLE_DRIVER_CODES = /* @__PURE__ */ new Set([
"ECONNREFUSED",
"ECONNRESET",
"EPIPE",
"ETIMEDOUT",
"ENOTFOUND",
"EAI_AGAIN"
]);
function matchesRetryableStates(error, states) {
return visitCauses(error, 6, (link) => {
const code = link.code;
if (typeof code !== "string") return false;
return states.has(code) || code.startsWith("08") || RETRYABLE_DRIVER_CODES.has(code);
});
}
/**
* Decide whether a failed migration-init statement (schema/journal creation)
* is worth retrying. Covers the concurrent `CREATE SCHEMA IF NOT EXISTS`
* race (unique violation on `pg_namespace`, duplicate-object errors),
* serialization/deadlock errors, and transient connection failures.
*/
function isRetryableMigrationError(error) {
return matchesRetryableStates(error, RETRYABLE_SQLSTATES);
}
const RETRYABLE_STATEMENT_SQLSTATES = /* @__PURE__ */ new Set([
"40001",
"40P01",
"55P03"
]);
/**
* Decide whether a failed migration *statement* (inside its transaction) is
* worth retrying. Deliberately narrower than `isRetryableMigrationError`:
* duplicate-object classes are tolerated at the SAVEPOINT level, and a 23505
* is either the concurrent-DDL catalog collision (also tolerated) or a
* deterministic data-level violation (retrying is pointless) — so only
* lock/serialization/transient-connection states justify re-running the
* transaction.
*/
function isRetryableMigrationExecutionError(error) {
return matchesRetryableStates(error, RETRYABLE_STATEMENT_SQLSTATES);
}
const PG_QUERY_QUEUE_DEPRECATION = "client.query() when the client is already executing a query";
let pgWarningFilterInstalled = false;
/**
* Silence pg's query-queue deprecation warning (fires once per process from
* pg-pool's internal dispatch under concurrent boot load — node-postgres#3612,
* #3617). Node's default warning handler prints even when user listeners are
* attached, so it is removed first; every other warning is re-printed here.
*/
function suppressPgQueryQueueDeprecation() {
if (pgWarningFilterInstalled) return;
if (typeof process === "undefined" || typeof process.on !== "function") return;
pgWarningFilterInstalled = true;
process.removeAllListeners("warning");
process.on("warning", (warning) => {
if (warning.name === "DeprecationWarning" && warning.message.includes(PG_QUERY_QUEUE_DEPRECATION)) return;
console.error(warning.stack || `${warning.name}: ${warning.message}`);
});
}
function extractExpectedTables(migrations) {
const tables = /* @__PURE__ */ new Set();
const re = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:"([^"]+)"\.)?"([^"]+)"/gi;
for (const migration of migrations) for (const stmt of migration.sql) for (const match of stmt.matchAll(re)) {
const tableName = match[2];
if (tableName) tables.add(tableName);
}
return [...tables];
}
//#endregion
exports.DUPLICATE_OBJECT_SQLSTATES = DUPLICATE_OBJECT_SQLSTATES;
exports.extractExpectedTables = extractExpectedTables;
exports.getDatabaseUrlSecretName = getDatabaseUrlSecretName;
exports.getMigrationSlug = getMigrationSlug;
exports.getMigrationStorage = getMigrationStorage;
exports.isConcurrentDdlUniqueViolation = isConcurrentDdlUniqueViolation;
exports.isRetryableMigrationError = isRetryableMigrationError;
exports.isRetryableMigrationExecutionError = isRetryableMigrationExecutionError;
exports.normalizeSlug = normalizeSlug;
exports.pluginMigrationSlug = pluginMigrationSlug;
exports.suppressPgQueryQueueDeprecation = suppressPgQueryQueueDeprecation;
exports.toSqlArray = toSqlArray;
exports.visitCauses = visitCauses;
//# sourceMappingURL=core.cjs.map