testPackedTextsReadAsWritten

tcmts.store.test.testPackedTextsReadAsWritten · #72puyaw4 · term

A codebase whose texts are kept compressed (as packed keeps long ones) reads as it did with them as written: definitions, their metadata (docs, shapes, text versions) and namespace nodes.

import { IR_VERSION } from "#codebase/tcmts/core/hash";
import { PACK_FROM, Store, unpacked } from "#codebase/tcmts/store";
import { a, b, stored } from "#codebase/tcmts/store/test/history";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { DatabaseSync } from "node:sqlite";
import { zstdCompressSync } from "node:zlib";

export const testPackedTextsReadAsWritten = () => {
  const long = (s: string) => s.repeat(Math.ceil(PACK_FROM / s.length) + 1);
  const file = path.join(fs.mkdtempSync(path.join(os.tmpdir(), "tcm store ")), "codebase.sqlite");
  const s = new Store(file);
  s.putDefs(
    [
      {
        ...stored(a, `const f = "${long("f")}"`, long("One. ")),
        ir: JSON.stringify(["Code", long("i")]),
        shape: [{ k: "lit", value: long("s") }],
      },
      stored(b, "const g = 2"),
    ],
    "5",
    IR_VERSION,
  );
  s.addName("f", a, "term", "add");
  s.addName("g", b, "term", "add");
  s.endBatch();
  s.setText(
    {
      hash: a,
      sourceText: `const f = "${long("f")}" // f`,
      spans: [],
      reservedNames: [],
      doc: long("Uno. "),
    },
    "update",
  );
  s.endBatch();
  s.close();

  const read = () => {
    const r = new Store(file);
    const ns = r.causal(r.head())!.namespace;
    const out = {
      f: r.getDef(a),
      g: r.getDef(b),
      versions: r.textVersions(a).map((t) => r.textVersion(a, t)),
      docs: r.documentedNames(),
      rows: r.namespaceRows(ns),
      nodes: r.getNamespaces([ns]),
      children: r.namespaceChildren(ns),
      named: r.namespaceDefinitions(ns),
    };
    r.close();
    return out;
  };
  const before = read();

  // every text compressed, short ones too
  const db = new DatabaseSync(file);
  for (const [table, key, columns] of [
    ["definitions", "hash", ["ir", "source_text", "ref_spans"]],
    ["metadata", "rowid", ["value"]],
    ["namespaces", "hash", ["body"]],
  ] as const)
    for (const row of db.prepare(`SELECT ${key} AS k, ${columns.join(", ")} FROM ${table}`).all())
      for (const c of columns)
        db.prepare(`UPDATE ${table} SET ${c} = ? WHERE ${key} = ?`).run(
          zstdCompressSync(unpacked(row[c])),
          row.k as string,
        );
  assert.equal(
    (
      db.prepare("SELECT count(*) AS n FROM definitions WHERE typeof(ir) = 'text'").get() as {
        n: number;
      }
    ).n,
    0,
  );
  db.close();

  assert.deepEqual(read(), before);
  assert.equal(before.f?.doc, long("Uno. "));
  assert.deepEqual(before.f?.shape, [{ k: "lit", value: long("s") }]);
}

uses