Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/commands/migrations/v0_29_1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,15 @@ async function phaseBBackfill(opts: OrchestratorOpts): Promise<OrchestratorPhase
try {
const { createEngine } = await import('../../core/engine-factory.ts');
const { loadConfig, toEngineConfig } = await import('../../core/config.ts');
const { connectWithRetry } = await import('../../core/db.ts');
const { backfillEffectiveDate } = await import('../../core/backfill-effective-date.ts');
const cfg = loadConfig();
if (!cfg) throw new Error('No gbrain config; run `gbrain init` first.');
const engine = await createEngine(toEngineConfig(cfg));
const engineCfg = toEngineConfig(cfg);
const engine = await createEngine(engineCfg);
await connectWithRetry(engine, engineCfg, {
noRetry: process.argv.includes('--no-retry-connect') || process.env.GBRAIN_NO_RETRY_CONNECT === '1',
});

let totalExamined = 0;
let totalUpdated = 0;
Expand All @@ -63,6 +68,8 @@ async function phaseBBackfill(opts: OrchestratorOpts): Promise<OrchestratorPhase
},
});

await engine.disconnect();

return {
name: 'backfill_effective_date',
status: 'complete',
Expand All @@ -80,9 +87,14 @@ async function phaseCVerify(opts: OrchestratorOpts): Promise<OrchestratorPhaseRe
try {
const { createEngine } = await import('../../core/engine-factory.ts');
const { loadConfig, toEngineConfig } = await import('../../core/config.ts');
const { connectWithRetry } = await import('../../core/db.ts');
const cfg = loadConfig();
if (!cfg) throw new Error('No gbrain config; run `gbrain init` first.');
const engine = await createEngine(toEngineConfig(cfg));
const engineCfg = toEngineConfig(cfg);
const engine = await createEngine(engineCfg);
await connectWithRetry(engine, engineCfg, {
noRetry: process.argv.includes('--no-retry-connect') || process.env.GBRAIN_NO_RETRY_CONNECT === '1',
});
// Count rows where effective_date is still NULL but frontmatter HAS a
// parseable date — those are the rows the backfill should have touched
// but didn't. (Rows that fall through to 'fallback' have non-null
Expand All @@ -92,12 +104,14 @@ async function phaseCVerify(opts: OrchestratorOpts): Promise<OrchestratorPhaseRe
);
const remaining = Number(rows[0]?.count ?? 0);
if (remaining > 0) {
await engine.disconnect();
return {
name: 'verify',
status: 'failed',
detail: `${remaining} pages still have NULL effective_date (backfill incomplete)`,
};
}
await engine.disconnect();
return { name: 'verify', status: 'complete', detail: '0 pages with NULL effective_date' };
} catch (e) {
return { name: 'verify', status: 'failed', detail: e instanceof Error ? e.message : String(e) };
Expand Down
12 changes: 10 additions & 2 deletions src/core/pglite-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,16 @@ CREATE INDEX IF NOT EXISTS idx_pages_source_id ON pages(source_id);
CREATE INDEX IF NOT EXISTS pages_deleted_at_purge_idx
ON pages (deleted_at) WHERE deleted_at IS NOT NULL;
-- v0.29.1: expression index for since/until date-range filters.
CREATE INDEX IF NOT EXISTS pages_coalesce_date_idx
ON pages ((COALESCE(effective_date, updated_at)));
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name = 'pages' AND column_name = 'effective_date'
) THEN
EXECUTE 'CREATE INDEX IF NOT EXISTS pages_coalesce_date_idx ON pages ((COALESCE(effective_date, updated_at)))';
END IF;
END $$;

-- ============================================================
-- content_chunks: chunked content with embeddings
Expand Down
12 changes: 10 additions & 2 deletions src/core/schema-embedded.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,16 @@ CREATE INDEX IF NOT EXISTS pages_deleted_at_purge_idx
-- COALESCE(effective_date, updated_at). A partial index on effective_date
-- alone would NOT help — the planner can't use it for the negative side of
-- the COALESCE. Expression index is what actually accelerates the filter.
CREATE INDEX IF NOT EXISTS pages_coalesce_date_idx
ON pages ((COALESCE(effective_date, updated_at)));
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name = 'pages' AND column_name = 'effective_date'
) THEN
EXECUTE 'CREATE INDEX IF NOT EXISTS pages_coalesce_date_idx ON pages ((COALESCE(effective_date, updated_at)))';
END IF;
END $$;

-- ============================================================
-- content_chunks: chunked content with embeddings
Expand Down
12 changes: 10 additions & 2 deletions src/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,16 @@ CREATE INDEX IF NOT EXISTS pages_deleted_at_purge_idx
-- COALESCE(effective_date, updated_at). A partial index on effective_date
-- alone would NOT help — the planner can't use it for the negative side of
-- the COALESCE. Expression index is what actually accelerates the filter.
CREATE INDEX IF NOT EXISTS pages_coalesce_date_idx
ON pages ((COALESCE(effective_date, updated_at)));
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name = 'pages' AND column_name = 'effective_date'
) THEN
EXECUTE 'CREATE INDEX IF NOT EXISTS pages_coalesce_date_idx ON pages ((COALESCE(effective_date, updated_at)))';
END IF;
END $$;

-- ============================================================
-- content_chunks: chunked content with embeddings
Expand Down