diff --git a/src/test.ts b/src/test.ts index b0172063..7aecab7a 100644 --- a/src/test.ts +++ b/src/test.ts @@ -4,11 +4,23 @@ import path from 'node:path'; import { Database as Sqlite } from '@db/sqlite'; import { NDatabase, NostrEvent } from '@nostrify/nostrify'; import { DenoSqlite3Dialect } from '@soapbox/kysely-deno-sqlite'; -import { FileMigrationProvider, Kysely, Migrator } from 'kysely'; +import { + FileMigrationProvider, + Kysely, + Migrator, + PostgresAdapter, + PostgresIntrospector, + PostgresQueryCompiler, +} from 'kysely'; import { finalizeEvent, generateSecretKey } from 'nostr-tools'; +import { DittoDB } from '@/db/DittoDB.ts'; import { DittoTables } from '@/db/DittoTables.ts'; import { purifyEvent } from '@/storages/hydrate.ts'; +import { PostgreSQLDriver } from 'kysely_deno_postgres'; +import { Pool } from 'postgres'; +import { KyselyLogger } from '@/db/KyselyLogger.ts'; +import { EventsDB } from '@/storages/EventsDB.ts'; /** Import an event fixture by name in tests. */ export async function eventFixture(name: string): Promise { @@ -62,3 +74,84 @@ export async function getTestDB() { [Symbol.asyncDispose]: () => kysely.destroy(), }; } + +/** Create an database for testing. */ +export const createTestDB = async (databaseUrl?: string) => { + databaseUrl ??= Deno.env.get('DATABASE_URL') ?? 'sqlite://:memory:'; + + const dialect: 'sqlite' | 'postgres' = (() => { + const protocol = databaseUrl.split(':')[0]; + switch (protocol) { + case 'sqlite': + return 'sqlite'; + case 'postgres': + return protocol; + case 'postgresql': + return 'postgres'; + default: + throw new Error(`Unsupported protocol: ${protocol}`); + } + })(); + + let kysely: Kysely; + + if (dialect === 'sqlite') { + Deno.env.set('DATABASE_URL', 'sqlite://:memory:'); // hack, refactor all, 021 migration + + kysely = new Kysely({ + dialect: new DenoSqlite3Dialect({ + database: new Sqlite(':memory:'), + }), + }); + } else { + //kysely = await DittoDB.getInstance(); + kysely = new Kysely({ + dialect: { + createAdapter() { + return new PostgresAdapter(); + }, + createDriver() { + return new PostgreSQLDriver(new Pool(databaseUrl, 10, true)); + }, + createIntrospector(db: Kysely) { + return new PostgresIntrospector(db); + }, + createQueryCompiler() { + return new PostgresQueryCompiler(); + }, + }, + log: KyselyLogger, + }); + } + await DittoDB.migrate(kysely); + + const store = new EventsDB(kysely); + + return { + store, + kysely, + [Symbol.asyncDispose]: async () => { + if (dialect === 'postgres') { + for ( + const table of [ + 'author_stats', + 'event_stats', + 'event_zaps', + 'kysely_migration', + 'kysely_migration_lock', + 'nip46_tokens', + 'pubkey_domains', + 'unattached_media', + 'nostr_events', + 'nostr_tags', + 'nostr_pgfts', + 'event_zaps', + ] + ) { + await kysely.schema.dropTable(table).ifExists().cascade().execute(); + } + await kysely.destroy(); + } + }, + }; +};