feat(migrate): migration_map idempotency ledger
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
11
lib/db/migrations/018_migration_map.sql
Normal file
11
lib/db/migrations/018_migration_map.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- 018_migration_map.sql — idempotency ledger for void-migrate. Maps a source row
|
||||
-- to the Void 2 entity it created, so re-running an import never duplicates.
|
||||
CREATE TABLE migration_map (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
source text NOT NULL, -- 'void1' | 'bookstack' | 'karakeep' | 'plans'
|
||||
source_id text NOT NULL, -- e.g. 'wiki_pages:42'
|
||||
entity_type text NOT NULL, -- 'page' | 'project' | 'task' | 'conversation' | 'message'
|
||||
entity_id uuid NOT NULL,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE (source, source_id, entity_type)
|
||||
);
|
||||
15
lib/db/repos/migration_map.js
Normal file
15
lib/db/repos/migration_map.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { pool } from '../pool.js';
|
||||
|
||||
export async function seen(source, source_id, entity_type) {
|
||||
const { rows: [r] } = await pool.query(
|
||||
`SELECT entity_id FROM migration_map WHERE source=$1 AND source_id=$2 AND entity_type=$3`,
|
||||
[source, source_id, entity_type]);
|
||||
return r ? r.entity_id : null;
|
||||
}
|
||||
|
||||
export async function record(source, source_id, entity_type, entity_id) {
|
||||
await pool.query(
|
||||
`INSERT INTO migration_map(source, source_id, entity_type, entity_id) VALUES($1,$2,$3,$4)
|
||||
ON CONFLICT (source, source_id, entity_type) DO NOTHING`,
|
||||
[source, source_id, entity_type, entity_id]);
|
||||
}
|
||||
Reference in New Issue
Block a user