Skip to content
Draft
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
10 changes: 5 additions & 5 deletions backend/docs/db/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

\restrict dummy

-- Dumped from database version 15.15 (Debian 15.15-1.pgdg13+1)
-- Dumped by pg_dump version 16.11 (Debian 16.11-1.pgdg13+1)
-- Dumped from database version 15.17 (Debian 15.17-1.pgdg13+1)
-- Dumped by pg_dump version 16.13 (Debian 16.13-1.pgdg13+1)

SET statement_timeout = 0;
SET lock_timeout = 0;
Expand Down Expand Up @@ -426,8 +426,7 @@ CREATE TABLE public.sequence_entries (
submitted_at timestamp without time zone NOT NULL,
released_at timestamp without time zone,
is_revocation boolean DEFAULT false NOT NULL,
original_data jsonb,
version_comment text
original_data jsonb
);


Expand Down Expand Up @@ -468,11 +467,12 @@ CREATE VIEW public.sequence_entries_view AS
se.released_at,
se.is_revocation,
se.original_data,
se.version_comment,
sepd.started_processing_at,
sepd.finished_processing_at,
sepd.processed_data,
CASE
WHEN (se.is_revocation AND (se.original_data IS NOT NULL)) THEN jsonb_build_object('metadata', COALESCE((se.original_data -> 'metadata'::text), '{}'::jsonb), 'unalignedNucleotideSequences', '{}'::jsonb, 'alignedNucleotideSequences', '{}'::jsonb, 'nucleotideInsertions', '{}'::jsonb, 'alignedAminoAcidSequences', '{}'::jsonb, 'aminoAcidInsertions', '{}'::jsonb, 'files', 'null'::jsonb)
WHEN se.is_revocation THEN NULL::jsonb
WHEN (aem.external_metadata IS NULL) THEN sepd.processed_data
ELSE (sepd.processed_data || jsonb_build_object('metadata', ((sepd.processed_data -> 'metadata'::text) || aem.external_metadata)))
END AS joint_metadata,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,6 @@ open class ReleasedDataModel(
)
},
) +
conditionalMetadata(
rawProcessedData.isRevocation,
{
mapOf(
"versionComment" to TextNode(rawProcessedData.versionComment),
)
},
) +
conditionalMetadata(
earliestReleaseDate != null,
{
Comment on lines 168 to 170

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep revocation versionComment out of schema filtering

Removing the dedicated revocation versionComment merge here makes the value depend entirely on processedData.metadata, but that path is normalized by ProcessedMetadataPostprocessor.filterOutExtraFieldsAndAddNulls, which drops metadata keys not present in the organism schema. In environments/configs where versionComment is not part of schema metadata (for example the backend test configs), revocation comments will silently disappear from released data after this change. Previously this code guaranteed the field by injecting it after postprocessing.

Useful? React with 👍 / 👎.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import org.loculus.backend.api.FileIdAndNameAndReadUrl
import org.loculus.backend.api.GeneticSequence
import org.loculus.backend.api.GetSequenceResponse
import org.loculus.backend.api.Organism
import org.loculus.backend.api.OriginalData
import org.loculus.backend.api.OriginalDataWithFileUrls
import org.loculus.backend.api.PreprocessingStatus.IN_PROCESSING
import org.loculus.backend.api.PreprocessingStatus.PROCESSED
Expand Down Expand Up @@ -736,7 +737,6 @@ class SubmissionDatabaseService(
SequenceEntriesView.accessionColumn,
SequenceEntriesView.versionColumn,
SequenceEntriesView.isRevocationColumn,
SequenceEntriesView.versionCommentColumn,
SequenceEntriesView.jointDataColumn,
SequenceEntriesView.submitterColumn,
SequenceEntriesView.groupIdColumn,
Expand Down Expand Up @@ -779,7 +779,6 @@ class SubmissionDatabaseService(
DataUseTermsType.fromString(it[DataUseTermsTable.dataUseTermsTypeColumn]),
it[DataUseTermsTable.restrictedUntilColumn],
),
versionComment = it[SequenceEntriesView.versionCommentColumn],
dataUseTermsChangeDate = it[DataUseTermsTable.changeDateColumn],
)
}
Expand Down Expand Up @@ -955,16 +954,14 @@ class SubmissionDatabaseService(

SequenceEntriesTable.insert(
SequenceEntriesTable.select(
SequenceEntriesTable.accessionColumn, SequenceEntriesTable.versionColumn.plus(1),
when (versionComment) {
null -> Op.nullOp()
else -> stringParam(versionComment)
},
SequenceEntriesTable.accessionColumn,
SequenceEntriesTable.versionColumn.plus(1),
SequenceEntriesTable.submissionIdColumn,
stringParam(authenticatedUser.username),
SequenceEntriesTable.groupIdColumn,
dateTimeParam(dateProvider.getCurrentDateTime()),
booleanParam(true), SequenceEntriesTable.organismColumn,
booleanParam(true),
SequenceEntriesTable.organismColumn,
).where {
(
SequenceEntriesTable.accessionColumn inList
Expand All @@ -975,7 +972,6 @@ class SubmissionDatabaseService(
columns = listOf(
SequenceEntriesTable.accessionColumn,
SequenceEntriesTable.versionColumn,
SequenceEntriesTable.versionCommentColumn,
SequenceEntriesTable.submissionIdColumn,
SequenceEntriesTable.submitterColumn,
SequenceEntriesTable.groupIdColumn,
Expand All @@ -985,6 +981,25 @@ class SubmissionDatabaseService(
),
)

if (versionComment != null) {
val originalData = compressionService.compressSequencesInOriginalData(
OriginalData(
metadata = mapOf("versionComment" to versionComment),
unalignedNucleotideSequences = emptyMap(),
),
organism,
)
SequenceEntriesTable.update(
where = {
(SequenceEntriesTable.accessionColumn inList accessions) and
SequenceEntriesTable.isMaxVersion and
(SequenceEntriesTable.isRevocationColumn eq true)
},
) {
it[originalDataColumn] = originalData
}
}

auditLogger.log(
authenticatedUser.username,
"Revoked ${accessions.size} sequences: " +
Expand Down Expand Up @@ -1525,7 +1540,6 @@ data class RawProcessedData(
override val accession: Accession,
override val version: Version,
val isRevocation: Boolean,
val versionComment: String?,
val submitter: String,
val groupId: Int,
val groupName: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ object SequenceEntriesTable : Table(SEQUENCE_ENTRIES_TABLE_NAME) {

val accessionColumn = varchar("accession", 255)
val versionColumn = long("version")
val versionCommentColumn = varchar("version_comment", 255).nullable()
val organismColumn = varchar("organism", 255)
val submissionIdColumn = varchar("submission_id", 255)
val submitterColumn = varchar("submitter", 255)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ object SequenceEntriesView : Table(SEQUENCE_ENTRIES_VIEW_NAME) {
val statusColumn = varchar("status", 255)
val processingResultColumn = varchar("processing_result", 255).nullable()
val isRevocationColumn = bool("is_revocation").default(false)
val versionCommentColumn = varchar("version_comment", 255).nullable()
val errorsColumn = jacksonSerializableJsonb<List<PreprocessingAnnotation>>("errors").nullable()
val warningsColumn = jacksonSerializableJsonb<List<PreprocessingAnnotation>>("warnings").nullable()
val pipelineVersionColumn = long("pipeline_version").nullable()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
-- Moves revocation versionComment from the dedicated version_comment column
-- into the original_data JSONB metadata, and updates the view to automatically
-- construct joint_metadata for revocations from original_data.
-- This unifies how versionComment is stored for both revisions and revocations.

-- Step 1: For existing revocations with non-null version_comment and no original_data,
-- create original_data with versionComment in metadata
UPDATE sequence_entries
SET original_data = jsonb_build_object(
'metadata', jsonb_build_object('versionComment', version_comment),
'unalignedNucleotideSequences', '{}'::jsonb
)
WHERE is_revocation = true AND version_comment IS NOT NULL AND original_data IS NULL;

-- For revocations that already have original_data (unlikely but safe),
-- merge versionComment into existing metadata
UPDATE sequence_entries
SET original_data = jsonb_set(
original_data,
'{metadata}',
COALESCE(original_data -> 'metadata', '{}'::jsonb) || jsonb_build_object('versionComment', version_comment)
)
WHERE is_revocation = true AND version_comment IS NOT NULL AND original_data IS NOT NULL;

-- Step 2: Drop the view (must be done before dropping the column)
DROP VIEW IF EXISTS sequence_entries_view;

-- Step 3: Drop the version_comment column
ALTER TABLE sequence_entries DROP COLUMN version_comment;

-- Step 4: Recreate the view without version_comment.
-- For revocations, joint_metadata is constructed from original_data
-- so versionComment survives pipeline version changes.
CREATE VIEW sequence_entries_view AS
SELECT
se.accession,
se.version,
se.organism,
se.submission_id,
se.submitter,
se.approver,
se.group_id,
se.submitted_at,
se.released_at,
se.is_revocation,
se.original_data,
sepd.started_processing_at,
sepd.finished_processing_at,
sepd.processed_data,
CASE
WHEN se.is_revocation AND se.original_data IS NOT NULL THEN
jsonb_build_object(
'metadata', COALESCE(se.original_data -> 'metadata', '{}'::jsonb),
'unalignedNucleotideSequences', '{}'::jsonb,
'alignedNucleotideSequences', '{}'::jsonb,
'nucleotideInsertions', '{}'::jsonb,
'alignedAminoAcidSequences', '{}'::jsonb,
'aminoAcidInsertions', '{}'::jsonb,
'files', 'null'::jsonb
)
WHEN se.is_revocation THEN NULL
WHEN aem.external_metadata IS NULL THEN sepd.processed_data
ELSE sepd.processed_data ||
jsonb_build_object('metadata', (sepd.processed_data -> 'metadata') || aem.external_metadata)
END AS joint_metadata,
CASE
WHEN se.is_revocation THEN cpp.version
ELSE sepd.pipeline_version
END AS pipeline_version,
sepd.errors,
sepd.warnings,
CASE
WHEN se.released_at IS NOT NULL THEN 'APPROVED_FOR_RELEASE'
WHEN se.is_revocation THEN 'PROCESSED'
WHEN sepd.processing_status = 'IN_PROCESSING' THEN 'IN_PROCESSING'
WHEN sepd.processing_status = 'PROCESSED' THEN 'PROCESSED'
ELSE 'RECEIVED'
END AS status,
CASE
WHEN sepd.processing_status = 'IN_PROCESSING' THEN NULL
WHEN sepd.errors IS NOT NULL AND jsonb_array_length(sepd.errors) > 0 THEN 'HAS_ERRORS'
WHEN sepd.warnings IS NOT NULL AND jsonb_array_length(sepd.warnings) > 0 THEN 'HAS_WARNINGS'
ELSE 'NO_ISSUES'
END AS processing_result
FROM sequence_entries se
LEFT JOIN current_processing_pipeline cpp
ON se.organism = cpp.organism
LEFT JOIN sequence_entries_preprocessed_data sepd
ON se.accession = sepd.accession
AND se.version = sepd.version
AND sepd.pipeline_version = cpp.version
LEFT JOIN (
SELECT
em.accession,
em.version,
jsonb_merge_agg(em.external_metadata) AS external_metadata
FROM external_metadata em
GROUP BY em.accession, em.version
) aem
ON aem.accession = se.accession
AND aem.version = se.version;
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ fun row(
files = null,
),
isRevocation = false,
versionComment = null,
submitter = "foo",
submissionId = "foo",
submittedAtTimestamp = releasedAt,
Expand Down
Loading