var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import initCozoDb, { CozoDb } from 'cyb-cozo-lib-wasm';
import { toListOfObjects, clearIndexedDBStore } from './utils';
import initializeScript from './migrations/schema.cozo';
import { createCozoDbCommandFactory } from './cozoDbCommandFactory';
const DB_NAME = 'cyb-cozo-idb';
const DB_STORE_NAME = 'cozodb';
const DB_VERSION = '1.1';
function createCozoDb() {
    let db;
    let dbSchema = {};
    let commandFactory;
    let onIndexedDbWrite;
    const loadCozoDb = () => __awaiter(this, void 0, void 0, function* () {
        db = yield CozoDb.new_from_indexed_db(DB_NAME, DB_STORE_NAME, onIndexedDbWrite);
        yield initDbSchema();
        commandFactory = createCozoDbCommandFactory(dbSchema);
    });
    function init(onWrite) {
        return __awaiter(this, void 0, void 0, function* () {
            onIndexedDbWrite = onWrite;
            yield initCozoDb();
            yield loadCozoDb();
        });
    }
    const getRelations = () => __awaiter(this, void 0, void 0, function* () {
        const result = yield runCommand('::relations');
        if (result.ok !== true) {
            throw new Error(result.message);
        }
        return result.rows.map((row) => row[0]);
    });
    const initDbSchema = () => __awaiter(this, void 0, void 0, function* () {
        let relations = yield getRelations();
        if (relations.length === 0) {
            console.log('CozoDb: apply DB schema', initializeScript);
            const result = yield runCommand(initializeScript);
            if (!result.ok) {
                throw new Error(`DB SCHEMA INITIALIZATION FAILED. \r\n ${result.message}`);
            }
            relations = yield getRelations();
        }
        const schemasMap = yield Promise.all(relations.map((table) => __awaiter(this, void 0, void 0, function* () {
            const columnResult = yield runCommand(`::columns ${table}`);
            if (!columnResult.ok) {
                throw new Error(columnResult.message);
            }
            const fields = toListOfObjects(columnResult);
            const keys = fields.filter((c) => c.is_key).map((c) => c.column);
            const values = fields.filter((c) => !c.is_key).map((c) => c.column);
            const columns = fields.reduce((obj, field) => {
                obj[field.column] = field;
                return obj;
            }, {});
            const tableSchema = {
                keys,
                values,
                columns,
            };
            return [table, tableSchema];
        })));
        dbSchema = Object.fromEntries(schemasMap);
        console.log('CozoDb schema initialized: ', dbSchema, relations, schemasMap);
    });
    const getVersion = () => __awaiter(this, void 0, void 0, function* () {
        const versionData = yield get('config', ['value'], ['key = "DB_VERSION"'], ['key']);
        if (versionData.ok === false) {
            throw new Error(versionData.message);
        }
        return versionData.rows[0][0] || DB_VERSION;
    });
    const migrate = () => __awaiter(this, void 0, void 0, function* () {
        if (!dbSchema.config || !dbSchema.sync_status.keys.includes('owner_id')) {
            console.log('💀 HARD RESET experemental db...');
            yield clearIndexedDBStore(DB_NAME, DB_STORE_NAME);
            yield init(onIndexedDbWrite);
            yield put('config', [
                {
                    key: 'DB_VERSION',
                    group_key: 'system',
                    value: DB_VERSION,
                },
            ]);
        }
    });
    const runCommand = (command, immutable = false) => __awaiter(this, void 0, void 0, function* () {
        if (!db) {
            throw new Error('DB is not initialized');
        }
        const resultStr = yield db.run(command, '', immutable);
        const result = JSON.parse(resultStr);
        return result;
    });
    const put = (tableName, array) => __awaiter(this, void 0, void 0, function* () { return runCommand(commandFactory.generatePut(tableName, array)); });
    const rm = (tableName, keyValues) => __awaiter(this, void 0, void 0, function* () { return runCommand(commandFactory.generateRm(tableName, keyValues)); });
    const update = (tableName, array) => __awaiter(this, void 0, void 0, function* () { return runCommand(commandFactory.generateUpdate(tableName, array)); });
    const get = (tableName, selectFields = [], conditions = [], conditionFields = [], options = {}) => __awaiter(this, void 0, void 0, function* () {
        return runCommand(commandFactory.generateGet(tableName, conditions, selectFields, conditionFields, options), true);
    });
    const importRelations = (content) => JSON.parse(db.import_relations(content));
    const exportRelations = (relations) => JSON.parse(db.export_relations(JSON.stringify({ relations })));
    return {
        init,
        put,
        get,
        rm,
        update,
        runCommand,
        getCommandFactory: () => commandFactory,
        importRelations,
        exportRelations,
    };
}
export default createCozoDb();
//# sourceMappingURL=cozoDb.js.map