From e39b008b4160313e8694829d024384ae8bb223a7 Mon Sep 17 00:00:00 2001 From: Radoslav Dimitrov Date: Tue, 30 Sep 2025 15:47:18 +0300 Subject: [PATCH] Ensure we populate sane defaults for NULL values (#583) ## Motivation and Context The following PR tries to ensure sane defaults for entries that for one reason or another have NULL values for some of their properties. ## How Has This Been Tested? ## Breaking Changes ## Types of changes - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update ## Checklist - [ ] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [ ] My code follows the repository's style guidelines - [ ] New and existing tests pass locally - [ ] I have added appropriate error handling - [ ] I have added or updated documentation as needed ## Additional context --------- Signed-off-by: Radoslav Dimitrov --- .../008_separate_official_metadata.sql | 56 ++++++++++++++++--- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/internal/database/migrations/008_separate_official_metadata.sql b/internal/database/migrations/008_separate_official_metadata.sql index 767a7bb..a0b4af4 100644 --- a/internal/database/migrations/008_separate_official_metadata.sql +++ b/internal/database/migrations/008_separate_official_metadata.sql @@ -6,7 +6,7 @@ BEGIN; -- Add new columns for official metadata and core identifiers ALTER TABLE servers ADD COLUMN server_name VARCHAR(255); ALTER TABLE servers ADD COLUMN version VARCHAR(255); -ALTER TABLE servers ADD COLUMN status VARCHAR(50); +ALTER TABLE servers ADD COLUMN status VARCHAR(50) DEFAULT 'active'; ALTER TABLE servers ADD COLUMN published_at TIMESTAMP WITH TIME ZONE; ALTER TABLE servers ADD COLUMN updated_at TIMESTAMP WITH TIME ZONE; ALTER TABLE servers ADD COLUMN is_latest BOOLEAN; @@ -38,16 +38,16 @@ BEGIN -- Note: status is at top level in old format, not in official_meta UPDATE servers SET - status = COALESCE(NULLIF(rec.value->>'status', 'null'), 'active'), - published_at = (official_meta->>'publishedAt')::TIMESTAMP WITH TIME ZONE, - updated_at = (official_meta->>'updatedAt')::TIMESTAMP WITH TIME ZONE, - is_latest = (official_meta->>'isLatest')::BOOLEAN + status = rec.value->>'status', + published_at = COALESCE((official_meta->>'publishedAt')::TIMESTAMP WITH TIME ZONE, NOW()), + updated_at = COALESCE((official_meta->>'updatedAt')::TIMESTAMP WITH TIME ZONE, NOW()), + is_latest = COALESCE((official_meta->>'isLatest')::BOOLEAN, true) WHERE version_id = rec.version_id; ELSE -- Handle records without official metadata (set defaults) UPDATE servers SET - status = COALESCE(NULLIF(rec.value->>'status', 'null'), 'active'), + status = rec.value->>'status', published_at = NOW(), updated_at = NOW(), is_latest = true @@ -82,11 +82,53 @@ SELECT migrate_official_metadata(); -- Drop the migration function DROP FUNCTION migrate_official_metadata(); +-- Safety check: Normalize invalid status values before adding NOT NULL constraints +-- This handles: NULL (missing field), empty string, string "null", and any invalid values +UPDATE servers +SET status = 'active' +WHERE status IS NULL + OR status = '' + OR status = 'null' + OR status NOT IN ('active', 'deprecated', 'deleted'); + +UPDATE servers SET published_at = NOW() WHERE published_at IS NULL; + +-- Safety check: Ensure updated_at is never NULL +UPDATE servers SET updated_at = NOW() WHERE updated_at IS NULL; + +-- For is_latest: preserve existing true values, handle NULLs deterministically +-- First, for servers where NO version has is_latest=true, mark the most recent as latest +WITH servers_without_latest AS ( + SELECT DISTINCT s1.server_name + FROM servers s1 + WHERE NOT EXISTS ( + SELECT 1 FROM servers s2 + WHERE s2.server_name = s1.server_name + AND s2.is_latest = true + ) +), +latest_versions AS ( + SELECT s.server_name, MAX(s.published_at) as max_published + FROM servers s + INNER JOIN servers_without_latest swl ON s.server_name = swl.server_name + GROUP BY s.server_name +) +UPDATE servers s +SET is_latest = true +FROM latest_versions lv +WHERE s.server_name = lv.server_name + AND s.published_at = lv.max_published + AND s.is_latest IS NULL; + +-- Finally, set remaining NULLs to false +UPDATE servers SET is_latest = false WHERE is_latest IS NULL; + -- Make the new columns NOT NULL now that all records have values ALTER TABLE servers ALTER COLUMN server_name SET NOT NULL; ALTER TABLE servers ALTER COLUMN version SET NOT NULL; ALTER TABLE servers ALTER COLUMN status SET NOT NULL; ALTER TABLE servers ALTER COLUMN published_at SET NOT NULL; +ALTER TABLE servers ALTER COLUMN updated_at SET NOT NULL; ALTER TABLE servers ALTER COLUMN is_latest SET NOT NULL; -- Drop the old primary key constraint @@ -112,7 +154,7 @@ CREATE INDEX idx_servers_name_version ON servers (server_name, version); CREATE INDEX idx_servers_name_latest ON servers (server_name, is_latest) WHERE is_latest = true; CREATE INDEX idx_servers_status ON servers (status); CREATE INDEX idx_servers_published_at ON servers (published_at DESC); -CREATE INDEX idx_servers_updated_at ON servers (updated_at DESC) WHERE updated_at IS NOT NULL; +CREATE INDEX idx_servers_updated_at ON servers (updated_at DESC); -- Ensure only one version per server can be marked as latest CREATE UNIQUE INDEX idx_unique_latest_per_server