"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createLocalKysely = createLocalKysely;
const node_fs_1 = require("node:fs");
const promises_1 = require("node:fs/promises");
const path = __importStar(require("node:path"));
const node_path_1 = require("node:path");
const pglite_1 = require("@electric-sql/pglite");
const kysely_1 = require("kysely");
const kysely_codegen_1 = __importDefault(require("kysely-codegen"));
const kysely_pglite_1 = require("kysely-pglite");
async function migrate(root, client) {
    console.log('migrating pglite ....');
    const glob = new Bun.Glob('initial/*.sql');
    for await (const migration of glob.scan(root)) {
        await client.exec(await Bun.file((0, node_path_1.join)(root, migration)).text());
    }
}
async function migrateKysely(root, kysely) {
    console.log('init migrating kysely ....');
    const migrator = new kysely_1.Migrator({
        db: kysely,
        migrationTableSchema: 'core',
        migrationTableName: 'kysely_migration',
        migrationLockTableName: 'kysely_migration_lock',
        provider: new kysely_1.FileMigrationProvider({
            fs: node_fs_1.promises,
            path,
            // This needs to be an absolute path.
            migrationFolder: path.join(root, 'migrations'),
        }),
    });
    console.log('migrating kysely ....');
    const { error, results } = await migrator.migrateToLatest().catch(() => {
        console.error('failed to migrate');
        process.exit(1);
    });
    for (const it of results ?? []) {
        if (it.status === 'Success') {
            console.log(`migration "${it.migrationName}" was executed successfully`);
        }
        else if (it.status === 'Error') {
            console.error(`failed to execute migration "${it.migrationName}"`);
        }
    }
    if (error) {
        console.error('failed to migrate');
        console.error(error);
        process.exit(1);
    }
}
async function generateDump(root, dumpPath) {
    const dataExists = await (0, promises_1.exists)(dumpPath).catch(() => false);
    if (!dataExists) {
        console.log('Creating initial dump');
        const main = new pglite_1.PGlite();
        await migrate(root, main).catch(async (err) => {
            console.error('failed to migrate initial dump');
            await Bun.write('../logs/migrate-initial-dump.json', JSON.stringify(err, null, 2));
            process.exit(1);
        });
        const { dialect } = new kysely_pglite_1.KyselyPGlite(main);
        const kysely = new kysely_1.Kysely({
            dialect,
            plugins: [new kysely_1.CamelCasePlugin()],
        });
        await migrateKysely(root, kysely).catch(() => {
            console.error('failed to migrate kysely');
            process.exit(1);
        });
        await kysely_codegen_1.default
            .generate({
            db: kysely,
            outFile: path.join(root, 'src/v1.generated.ts'),
            defaultSchemas: ['xxx'],
            camelCase: true,
            dialect: kysely_codegen_1.default.getDialect('postgres'),
        })
            .catch(() => {
            console.error('failed to generate kysely');
            process.exit(1);
        });
        const content = await main.dumpDataDir('none').catch(() => {
            console.error('failed to dump data');
            process.exit(1);
        });
        await Bun.write(dumpPath, content).catch(() => {
            console.error('failed to write dump');
            process.exit(1);
        });
        return content;
    }
    return Bun.file(dumpPath);
}
async function createLocalKysely(root, dumpPath) {
    let isDestroyed = false;
    const now = performance.now();
    const dump = await generateDump(root, dumpPath);
    const pglite = new pglite_1.PGlite({ loadDataDir: dump });
    // warm up
    await pglite.sql `SELECT 1`;
    const { dialect } = new kysely_pglite_1.KyselyPGlite(pglite);
    const kysely = new kysely_1.Kysely({
        dialect,
        plugins: [new kysely_1.CamelCasePlugin()],
    });
    const originalDestroy = kysely.destroy.bind(kysely);
    kysely.destroy = async () => {
        if (isDestroyed)
            return;
        isDestroyed = true;
        const destroyTime = performance.now();
        await originalDestroy().catch(() => undefined);
        await pglite.close().catch(() => undefined);
        console.log(`Database destroyed: ${Math.round(performance.now() - destroyTime)}ms`);
    };
    console.log(`Database initialized: ${Math.round(performance.now() - now)}ms`);
    return kysely;
}
//# sourceMappingURL=generate.js.map