import { SqliteError } from "@rocicorp/zero-sqlite3";
import { listTables } from "../../../db/lite-tables.js";
import { runSchemaMigrations } from "../../../db/migration-lite.js";
import { AutoResetSignal } from "../../change-streamer/schema/tables.js";
import { populateFromExistingTables } from "../../replicator/schema/column-metadata.js";
import { recordEvent, CREATE_RUNTIME_EVENTS_TABLE } from "../../replicator/schema/replication-state.js";
import { CREATE_TABLE_METADATA_TABLE } from "../../replicator/schema/table-metadata.js";
async function initReplica(log, debugName, dbPath, initialSync) {
  const setupMigration = {
    migrateSchema: (log2, tx) => initialSync(log2, tx),
    minSafeVersion: 1
  };
  try {
    await runSchemaMigrations(
      log,
      debugName,
      dbPath,
      setupMigration,
      schemaVersionMigrationMap
    );
  } catch (e) {
    if (e instanceof SqliteError && e.code === "SQLITE_CORRUPT") {
      throw new AutoResetSignal(e.message);
    }
    throw e;
  }
}
async function upgradeReplica(log, debugName, dbPath) {
  await runSchemaMigrations(
    log,
    debugName,
    dbPath,
    // setupMigration should never be invoked
    {
      migrateSchema: () => {
        throw new Error(
          "This should only be called for already synced replicas"
        );
      }
    },
    schemaVersionMigrationMap
  );
}
const CREATE_V6_COLUMN_METADATA_TABLE = (
  /*sql*/
  `
  CREATE TABLE "_zero.column_metadata" (
    table_name TEXT NOT NULL,
    column_name TEXT NOT NULL,
    upstream_type TEXT NOT NULL,
    is_not_null INTEGER NOT NULL,
    is_enum INTEGER NOT NULL,
    is_array INTEGER NOT NULL,
    character_max_length INTEGER,
    PRIMARY KEY (table_name, column_name)
  );
`
);
const CREATE_V7_CHANGE_LOG = (
  /*sql*/
  `
  CREATE TABLE "_zero.changeLog2" (
    "stateVersion"              TEXT NOT NULL,
    "pos"                       INT  NOT NULL,
    "table"                     TEXT NOT NULL,
    "rowKey"                    TEXT NOT NULL,
    "op"                        TEXT NOT NULL,
    PRIMARY KEY("stateVersion", "pos"),
    UNIQUE("table", "rowKey")
  );
`
);
const schemaVersionMigrationMap = {
  // There's no incremental migration from v1. Just reset the replica.
  4: {
    migrateSchema: () => {
      throw new AutoResetSignal("upgrading replica to new schema");
    },
    minSafeVersion: 3
  },
  5: {
    migrateSchema: (_, db) => {
      db.exec(CREATE_RUNTIME_EVENTS_TABLE);
    },
    migrateData: (_, db) => {
      recordEvent(db, "upgrade");
    }
  },
  // Revised in the migration to v8 because the v6 code was incomplete.
  6: {},
  7: {
    migrateSchema: (_, db) => {
      db.exec(`DELETE FROM "_zero.changeLog"`);
      db.exec(CREATE_V7_CHANGE_LOG);
    }
  },
  8: {
    migrateSchema: (_, db) => {
      const tableExists = db.prepare(
        `SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = '_zero.column_metadata'`
      ).get();
      if (!tableExists) {
        db.exec(CREATE_V6_COLUMN_METADATA_TABLE);
      }
    },
    migrateData: (_, db) => {
      db.exec(
        /*sql*/
        `DELETE FROM "_zero.column_metadata"`
      );
      const tables = listTables(db, false);
      populateFromExistingTables(db, tables);
    }
  },
  9: {
    migrateSchema: (_, db) => {
      db.exec(
        /*sql*/
        `
        ALTER TABLE "_zero.changeLog2" 
          ADD COLUMN "backfillingColumnVersions" TEXT DEFAULT '{}';
        ALTER TABLE "_zero.column_metadata"
          ADD COLUMN backfill TEXT;
      ` + CREATE_TABLE_METADATA_TABLE
      );
    }
  },
  10: {
    migrateSchema: (_, db) => {
      db.exec(
        /*sql*/
        `
        ALTER TABLE "_zero.replicationConfig" 
          ADD COLUMN "initialSyncContext" TEXT DEFAULT '{}';
      `
      );
    }
  }
};
export {
  CREATE_V6_COLUMN_METADATA_TABLE,
  CREATE_V7_CHANGE_LOG,
  initReplica,
  schemaVersionMigrationMap,
  upgradeReplica
};
//# sourceMappingURL=replica-schema.js.map
