Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { SurrealAdapter } from "@suaveplan/surrealdb";
import {
afterAll,
beforeAll,
describe,
expect,
it,
} from "@suaveplan/testing/runner";
import { SurrealDBFixture } from "@suaveplan/testing-integration-surrealdb";
import { SurrealImportStore } from "../../src/store/surreal/surreal-import-store.js";
import type { ImportJobRecord } from "../../src/types/types.js";
let fixture: SurrealDBFixture | null = null;
let adapter: SurrealAdapter | null = null;
function makeRecord(
id: string,
overrides: Partial<ImportJobRecord> = {}
): ImportJobRecord {
const now = new Date().toISOString();
return {
id,
ownerId: "alice",
status: "created",
totalRows: 0,
processedRows: 0,
successCount: 0,
errorCount: 0,
errors: [],
createdAt: now,
updatedAt: now,
...overrides,
};
}
beforeAll(async () => {
fixture = new SurrealDBFixture();
const cfg = await fixture.start();
adapter = new SurrealAdapter({
url: cfg.url,
namespace: cfg.namespace,
database: cfg.database,
username: cfg.username,
password: cfg.password,
});
await adapter.connect();
const surql = await readFile(
join(__dirname, "..", "..", "surql", "tables", "import_job.surql"),
"utf8"
);
await adapter.query(surql);
}, 180_000);
afterAll(async () => {
if (adapter !== null) {
await adapter.disconnect();
adapter = null;
}
if (fixture !== null) {
await fixture.stop();
fixture = null;
}
}, 60_000);
describe("@suaveplan/api-plugin-import — SurrealImportStore integration", () => {
it("round-trips a record through the real SurrealDB instance", {
timeout: 180_000,
}, async () => {
if (adapter === null) throw new Error("fixture not ready");
const store = new SurrealImportStore({ db: adapter });
const record = makeRecord("rt1", {
metadata: { source: "integration" },
errors: [{ row: 1, message: "preflight" }],
});
await store.create(record);
const fetched = await store.get("rt1");
expect(fetched).toBeDefined();
expect(fetched?.ownerId).toBe("alice");
expect(fetched?.metadata).toEqual({ source: "integration" });
expect(fetched?.errors).toEqual([{ row: 1, message: "preflight" }]);
await store.update("rt1", {
status: "completed",
successCount: 1,
completedAt: new Date().toISOString(),
});
const updated = await store.get("rt1");
expect(updated?.status).toBe("completed");
expect(updated?.successCount).toBe(1);
expect(updated?.completedAt).toBeDefined();
const owned = await store.list({ ownerId: "alice" });
expect(owned.some((r) => r.id === "rt1")).toBe(true);
const completed = await store.list({ status: "completed", limit: 5 });
expect(completed.some((r) => r.id === "rt1")).toBe(true);
expect(await store.delete("rt1")).toBe(true);
expect(await store.get("rt1")).toBeUndefined();
expect(await store.delete("rt1")).toBe(false);
});
it("update on missing id surfaces the canonical message against a real instance", {
timeout: 60_000,
}, async () => {
if (adapter === null) throw new Error("fixture not ready");
const store = new SurrealImportStore({ db: adapter });
await expect(
store.update("never-existed", { status: "completed" })
).rejects.toThrow(/Job "never-existed" not found/);
});
it("migration enables canonical writes and rejects invalid status", {
timeout: 60_000,
}, async () => {
if (adapter === null) throw new Error("fixture not ready");
const store = new SurrealImportStore({ db: adapter });
// Canonical write succeeds.
await store.create(makeRecord("mig-canon"));
expect((await store.get("mig-canon"))?.status).toBe("created");
// Direct SurQL with a bogus status MUST be rejected by the
// SCHEMAFULL constraint — this proves the migration is in
// effect.
await expect(
adapter.query(
`CREATE import_job:mig-bogus SET owner_id = 'alice', status = 'bogus', total_rows = 0, processed_rows = 0, success_count = 0, error_count = 0, errors = [], created_at = time::now(), updated_at = time::now()`
)
).rejects.toBeDefined();
await store.delete("mig-canon");
});
});