Files
FEDEO/backend/tests/helpers/collaboration-db.ts

54 lines
3.1 KiB
TypeScript

import { randomUUID } from "node:crypto"
import { readFile } from "node:fs/promises"
import { Pool } from "pg"
import { drizzle } from "drizzle-orm/node-postgres"
import { getTableColumns, getTableName } from "drizzle-orm"
import * as schema from "../../db/schema"
export const testDatabaseUrl = process.env.COLLABORATION_TEST_DATABASE_URL
/** Always creates and drops a private schema in the explicitly designated disposable test database. */
export async function collaborationDatabase(migrations: string[] = []) {
if (!testDatabaseUrl || new URL(testDatabaseUrl).pathname !== "/collaboration_test") {
throw new Error("Tests require COLLABORATION_TEST_DATABASE_URL ending in /collaboration_test")
}
const namespace = `collaboration_test_${randomUUID().replaceAll("-", "")}`
const admin = new Pool({ connectionString: testDatabaseUrl, max: 1 })
await admin.query(`CREATE SCHEMA "${namespace}"`)
const pool = new Pool({ connectionString: testDatabaseUrl, options: `-c search_path=${namespace}`, max: 6 })
const db = drizzle(pool, { schema })
try {
await pool.query("CREATE TYPE locked_tenant AS ENUM ('none', 'maintenance_tenant')")
for (const table of [schema.authUsers, schema.authTenantUsers, schema.authProfiles, schema.authRoles,
schema.authUserRoles, schema.authRolePermissions, schema.projects, schema.communicationRooms]) {
const columns = Object.values(getTableColumns(table)).map((column: any) => {
let suffix = column.primary ? " PRIMARY KEY" : ""
if (column.name === "id" && column.getSQLType() === "uuid") suffix += " DEFAULT gen_random_uuid()"
if (column.columnType === "PgTimestamp") suffix += " DEFAULT now()"
if (column.getSQLType() === "boolean") suffix += ` DEFAULT ${column.default === true ? "true" : "false"}`
return `"${column.name}" ${column.getSQLType()}${suffix}`
})
await pool.query(`CREATE TABLE "${getTableName(table)}" (${columns.join(",")})`)
}
await pool.query(`CREATE TABLE tenants (id bigint PRIMARY KEY, name text, locked text, locked_by_export_job_id uuid)`)
await pool.query(`CREATE UNIQUE INDEX ON communication_rooms (tenant_id, key)`)
await pool.query(await readFile(new URL("../../db/migrations/0070_native_communication_chat.sql", import.meta.url), "utf8"))
const steps = [...migrations]
if (!steps.includes("0075_project_collaboration.sql")) steps.unshift("0075_project_collaboration.sql")
if (!steps.includes("0081_chat_media_reactions.sql")) steps.push("0081_chat_media_reactions.sql")
for (const name of steps) {
await pool.query(await readFile(new URL(`../../db/migrations/${name}`, import.meta.url), "utf8"))
}
return { db, pool, close: async () => {
await pool.end()
await admin.query(`DROP SCHEMA "${namespace}" CASCADE`)
await admin.end()
} }
} catch (error) {
await pool.end()
await admin.query(`DROP SCHEMA "${namespace}" CASCADE`)
await admin.end()
throw error
}
}