feat(postgres): implement notes CRUD and export import
CI / lint (pull_request) Successful in 32s
CI / format (pull_request) Failing after 32s
CI / install-and-build (pull_request) Successful in 1m0s
CI / typecheck-tests (pull_request) Successful in 36s
CI / typecheck-source (pull_request) Successful in 37s
CI / test (pull_request) Successful in 41s

Co-Authored-By: gpt-5.6-luna <noreply@openai.com>
This commit is contained in:
2026-07-23 18:49:23 +00:00
co-authored by Codex
parent d7e31dfce9
commit a0a436c4b8
4 changed files with 216 additions and 28 deletions
+20 -6
View File
@@ -21,6 +21,7 @@ interface Rows {
abodes?: Record<string, unknown>[];
residents?: Record<string, unknown>[];
apikeys?: Record<string, unknown>[];
notes?: Record<string, unknown>[];
}
class FakePg implements WrappedPgClient {
@@ -43,6 +44,7 @@ class FakePg implements WrappedPgClient {
if (s.includes('FROM "residents"'))
return (this.#rows.residents ?? []) as R[];
if (s.includes('FROM "apikeys"')) return (this.#rows.apikeys ?? []) as R[];
if (s.includes('FROM "notes"')) return (this.#rows.notes ?? []) as R[];
return [] as R[];
}
@@ -126,6 +128,19 @@ function seededRows(): Rows {
expires_at: null,
},
],
notes: [
{
nid: "nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnn1",
aid: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa1",
name: "Note one",
content: "# Content",
properties: { type: "note" },
created_at: new Date(iso),
created_by: "11111111-1111-1111-1111-111111111111",
updated_at: new Date(iso),
updated_by: null,
},
],
};
}
@@ -145,7 +160,7 @@ function line(kind: string, data: unknown): string {
}
describe("postgres export", () => {
it("streams meta + the four supported kinds, never note", async () => {
it("streams meta and all supported kinds, including notes", async () => {
const db = new PostgresInterface(new FakePg(seededRows()));
const lines = parseLines(await streamToString(db.export()));
@@ -159,7 +174,7 @@ describe("postgres export", () => {
assert.ok(kinds.has("abode"));
assert.ok(kinds.has("resident"));
assert.ok(kinds.has("apikey"));
assert.ok(!kinds.has("note"), "note is unsupported on postgres");
assert.ok(kinds.has("note"));
});
it("emits record kinds grouped in FK-safe EXPORT_KIND_ORDER", async () => {
@@ -204,7 +219,7 @@ describe("postgres export", () => {
});
describe("postgres import", () => {
it("dispatches inserts per kind, skips note, and commits", async () => {
it("dispatches inserts per kind, including note, and commits", async () => {
const fake = new FakePg();
const db = new PostgresInterface(fake);
const source = Readable.from([
@@ -233,7 +248,6 @@ describe("postgres import", () => {
created_at: iso,
expires_at: null,
}),
// note lines are silently skipped on postgres
line("note", {
nid: "nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnn1",
aid: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa1",
@@ -248,14 +262,14 @@ describe("postgres import", () => {
]);
const result = await db.import(source);
assert.deepEqual(result.counts, { user: 1, abode: 1, apikey: 1 });
assert.deepEqual(result.counts, { user: 1, abode: 1, apikey: 1, note: 1 });
assert.ok(fake.committed);
assert.deepEqual(fake.inserts.map((i) => i.table).sort(), [
"abodes",
"apikeys",
"notes",
"users",
]);
assert.ok(!fake.inserts.some((i) => i.table === "notes"), "no note insert");
// apikey gets a freshly-minted token (never exported)
const apikeyInsert = fake.inserts.find((i) => i.table === "apikeys")!;
assert.ok(