Skip to content

Commit d3c43c0

Browse files
anna-parkercorneliusroemerfengelniederhammertheosanderson
authored
feat!(website, prepro, backend, config, integration):multi pathogen - refactor multi segment submission in backend and edit page and have prepro assign segments (#5382)
resolves #4999 #4708, #4734, #5511 partially resolves #5392, #5185 (comment) includes work done in #5398 and #5402 This PR additionally fixes submission, subtype assignment and search for EVs and other multi-path organisms. ### BREAKING CHANGES When users submit to multi-segmented organisms and want to group multiple segments under one metadata entry they are now required to add an additional `fastaIds` column with a space -separated list of the `fastaId`s (fasta header IDs) of the respective sequences. If no `fastaIds` column is supplied the `submissionId` will be used instead and the backend will assume that (as in the single-segmented case) there is a one-to-one mapping of metadata `submissionId` to `fastaId`. This new submission structure was voted for in microbioinfo: https://microbial-bioinfo.slack.com/archives/CB0HYT53M/p1760961465729399 and discussed in https://app.nuclino.com/Loculus/Development/2025-10-20-Weekly-6d5fe89f-8ded-4286-b892-d215e0a498f6 (and in other meetings) Nextclade sort (uses a minimizer index for fast local alignment) or nextclade align (full sequence alignment to reference) will be used to assign segments/subtypes for all multi-segmented and multi-pathogen sequences (this is also done in ingest for grouping segments): ``` segment_classification_method: "minimizer" or "align" minimizer_url: <url_to_minimizer_index_used_by_nextclade_sort> ``` For organisms without a nextclade dataset we still allow the fasta headers to be used to determine the segment/subtype - entries must have the format `<submissionId>_<segmentName>` (as in current set up). As preprocessing now assigns segments it will return a map from the segment (or subtype) to the fastaId in the processedData, the map is called: `sequenceNameToFastaId`. This allows us to surface the segment assignment on the edit page. ### Nextclade Preprocessing pipeline config changes Instead of having a dictionary for the nextclade datasets and servers we make `nucleotideSequences` a dictionary where each item includes all information required to run nextclade. I.e. we change from: ``` nextclade_dataset_name: L: nextstrain/cchfv/linked/L M: nextstrain/cchfv/linked/M S: nextstrain/cchfv/linked/S nextclade_dataset_server: https://raw.githubusercontent.com/nextstrain/nextclade_data/cornelius-cchfv/data_output genes: [RdRp, GPC, NP] ``` to: ``` nextclade_sequence_and_datasets: - name: L nextclade_dataset_name: nextstrain/cchfv/linked/L nextclade_dataset_tag: <optional - was previously incorrectly placed on an organism level> nextclade_dataset_server: <optional overwrites nextclade_dataset_server for this seq> accepted_sort_matches: <optional, used for classify_with_nextclade_sort and require_nextclade_sort_match, if not given nextclade_dataset_name and name are used> gene_prefix: <optional, prefix to add to genes produced by nextclade run, e.g. nextclade labels genes as `AV1` but we expect `EV1_AV1`, here `EV1` would be the prefix > genes: [RdRp] - name: M nextclade_dataset_name: nextstrain/cchfv/linked/M genes: [GPC] - name: S nextclade_dataset_name: nextstrain/cchfv/linked/S genes: [NP] nextclade_dataset_server: https://raw.githubusercontent.com/nextstrain/nextclade_data/cornelius-cchfv/data_output segment_classification_method: <optional, default for multi segmented viruses is align - if you assign segments in ingest for grouping use the same option here as you use there e.g. "minimizer" or "align"> minimizer_url: <optional, url_to_minimizer_index_used_by_nextclade_sort> ``` ### Ingest Pipeline Config changes `minimizer_index` is changed to `minimizer_url` for consistency (can be used in ingest and preprocessing and should both be the same) ### Optional additional Config changes Limit the number of sequences the backend will accept per submission by using - should be added for multi-segmented organisms: ` submissionDataTypes: &defaultSubmissionDataTypes consensusSequences: true maxSequencesPerEntry: 1 ` ### Testing You can use pathoplexus/example_data#16 and pathoplexus/dev_example_data#2 for testing. ### PR Checklist - [x] Update values.schema.json and other READMEs - [x] add fastaId to commonMetadata (ensure it is downloaded in templates): #5561 - [x] Fix how genes are returned (will cause a config update): #5563 - [x] Improve prepro code (less duplication and more tests): #5554 - [x] ingest EVs as single segmented to ensure search works: #5511 - [x] keep tests for alignment NONE case - [x] Create a minimizer for tests using: https://github.com/loculus-project/nextclade-sort-minimizer-creator - [x] Any manual testing that has been done is documented: submission of EVs from test folder were submitted with the same fastaHeader as the submissionId -> this succeeded, additionally the submission of CCHF with a fastaID column in the metadata was tested (also in folder above), additionally revision of a segment was tested - [x] Have preprocessing send back a segment: fastaHeader mapping - ~add integration testing for full EV submission user journey~ -> will be done in a later PR - [x] improve CCHF minimizer (some segments are again not assigned) - [x] discuss if the originalData dictionary should be migrated (persistent DB has segmentName as key, now we have fastaHeader as key) -> decided against - [x] update PPX docs with new multi-segment submission format -> test PR here: pathoplexus/pathoplexus#759 - [x] update example data for demo 🚀 Preview: https://edit-page-anya.loculus.org --------- Co-authored-by: Cornelius Roemer <cornelius.roemer@gmail.com> Co-authored-by: Fabian Engelniederhammer <92720311+fengelniederhammer@users.noreply.github.com> Co-authored-by: Theo Sanderson <theo@sndrsn.co.uk>
1 parent afac5f3 commit d3c43c0

113 files changed

Lines changed: 3193 additions & 1166 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/AGENTS.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
Kotlin dependent packages have already been installed for you.
22

3-
To run tests:
3+
Run tests like this (if you have Docker set up properly):
4+
5+
./gradlew test --console=plain
6+
7+
If that doesn't work due to Docker issues because you're running inside a cloud environment, try this:
48

59
USE_NONDOCKER_INFRA=true ./gradlew test --console=plain
610

@@ -15,4 +19,4 @@ Always ensure the tests and lint pass before committing.
1519

1620

1721
Use conventional commits as titles for PRs, e.g. feat(deployment):xx, fix!(website):xx, chore(backend):xx.
18-
Components include: website, backend, deployment, preprocessing, ingest, deposition.
22+
Components include: website, backend, deployment, preprocessing, ingest, deposition.

backend/docs/db/schema.sql

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,8 @@ CREATE TABLE public.metadata_upload_aux_table (
378378
group_id integer,
379379
uploaded_at timestamp without time zone NOT NULL,
380380
metadata jsonb NOT NULL,
381-
files jsonb
381+
files jsonb,
382+
fasta_ids text[]
382383
);
383384

384385

@@ -538,9 +539,8 @@ ALTER VIEW public.sequence_entries_view OWNER TO postgres;
538539

539540
CREATE TABLE public.sequence_upload_aux_table (
540541
upload_id text NOT NULL,
541-
submission_id text NOT NULL,
542-
segment_name text NOT NULL,
543-
compressed_sequence_data text NOT NULL
542+
compressed_sequence_data text NOT NULL,
543+
fasta_id text NOT NULL
544544
);
545545

546546

@@ -753,7 +753,7 @@ ALTER TABLE ONLY public.sequence_entries_preprocessed_data
753753
--
754754

755755
ALTER TABLE ONLY public.sequence_upload_aux_table
756-
ADD CONSTRAINT sequence_upload_aux_table_pkey PRIMARY KEY (upload_id, submission_id, segment_name);
756+
ADD CONSTRAINT sequence_upload_aux_table_pkey PRIMARY KEY (upload_id, fasta_id);
757757

758758

759759
--

backend/src/main/kotlin/org/loculus/backend/api/SubmissionTypes.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.JsonDeserializer
88
import com.fasterxml.jackson.databind.JsonNode
99
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
1010
import io.swagger.v3.oas.annotations.media.Schema
11+
import org.loculus.backend.model.FastaId
1112
import org.loculus.backend.model.SubmissionId
1213
import org.loculus.backend.service.files.FileId
1314
import org.loculus.backend.utils.Accession
@@ -166,6 +167,11 @@ data class ProcessedData<SequenceType>(
166167
description = "The key is the gene name, the value is a list of amino acid insertions",
167168
)
168169
val aminoAcidInsertions: Map<GeneName, List<Insertion>>,
170+
@Schema(
171+
example = """{"segment1": "fastaHeader1", "segment2": "fastaHeader2"}""",
172+
description = "The key is the segment name, the value is the fastaHeader of the original Data",
173+
)
174+
val sequenceNameToFastaId: Map<SegmentName, String> = emptyMap(),
169175
@Schema(
170176
example = """{"raw_reads": [{"fileId": "s0m3-uUiDd", "name": "data.fastaq"}], "sequencing_logs": []}""",
171177
description = "The key is the file category name, the value is a list of files, with ID and name.",
@@ -300,9 +306,9 @@ data class OriginalDataInternal<SequenceType, FilesType>(
300306
val metadata: Map<String, String>,
301307
@Schema(
302308
example = "{\"segment1\": \"ACTG\", \"segment2\": \"GTCA\"}",
303-
description = "The key is the segment name, the value is the nucleotide sequence",
309+
description = "The key is the fastaID, the value is the nucleotide sequence",
304310
)
305-
val unalignedNucleotideSequences: Map<SegmentName, SequenceType?>,
311+
val unalignedNucleotideSequences: Map<FastaId, SequenceType?>,
306312
@Schema(
307313
example = """{"raw_reads": [{"fileId": "f1le-uuId-asdf", "name": "myfile.fastaq"]}""",
308314
description = "A map from file categories, to lists of files. The files can also have URLs.",

backend/src/main/kotlin/org/loculus/backend/config/Config.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,13 @@ data class Schema(
5151
val externalMetadata: List<ExternalMetadata> = emptyList(),
5252
val earliestReleaseDate: EarliestReleaseDate = EarliestReleaseDate(false, emptyList()),
5353
val submissionDataTypes: SubmissionDataTypes = SubmissionDataTypes(),
54-
val files: List<FileCategory> = emptyList(),
54+
val files: List<FileCategory> = emptyList(), // Allowed file categories for output files
5555
)
5656

5757
data class SubmissionDataTypes(
5858
val consensusSequences: Boolean = true,
59+
val maxSequencesPerEntry: Int? = null, // null means unlimited sequences per entry
60+
// Allowed file categories for submission files
5961
val files: FilesSubmissionDataType = FilesSubmissionDataType(false, emptyList()),
6062
)
6163

backend/src/main/kotlin/org/loculus/backend/config/ReferenceGenome.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ data class ReferenceGenome(val nucleotideSequences: List<ReferenceSequence>, val
2424
?.sequence
2525

2626
private fun shortenSequence(sequence: String) = when {
27-
sequence.length > 10 -> sequence.substring(0, 10) + "..."
27+
sequence.length > 10 -> sequence.take(10) + "..."
2828
else -> sequence
2929
}
3030

backend/src/main/kotlin/org/loculus/backend/controller/SubmissionControllerDescriptions.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package org.loculus.backend.controller
22

3-
import org.loculus.backend.model.HEADER_TO_CONNECT_METADATA_AND_SEQUENCES
3+
import org.loculus.backend.model.FASTA_IDS_HEADER
4+
import org.loculus.backend.model.FASTA_IDS_SEPARATOR
5+
import org.loculus.backend.model.METADATA_ID_HEADER
46

57
const val SUBMIT_RESPONSE_DESCRIPTION = """
68
Returns a list of accession, version and submissionId of the submitted sequence entries.
7-
The submissionId is the (locally unique) '$HEADER_TO_CONNECT_METADATA_AND_SEQUENCES' provided by the submitter in the metadata file.
9+
The submissionId is the (locally unique) '$METADATA_ID_HEADER' provided by the submitter in the metadata file.
810
The version will be 1 for every sequence.
911
The accession is the (globally unique) id that the system assigned to the sequence entry.
10-
You can use this response to associate the user provided $HEADER_TO_CONNECT_METADATA_AND_SEQUENCES with the system assigned accession.
12+
You can use this response to associate the user provided $METADATA_ID_HEADER with the system assigned accession.
1113
"""
1214

1315
const val SUBMIT_ERROR_RESPONSE = """
@@ -18,16 +20,18 @@ const val METADATA_FILE_DESCRIPTION = """
1820
A TSV (tab separated values) file containing the metadata of the submitted sequence entries.
1921
The file may be compressed with zstd, xz, zip, gzip, lzma, bzip2 (with common extensions).
2022
It must contain the column names.
21-
The field '$HEADER_TO_CONNECT_METADATA_AND_SEQUENCES' is required and must be unique within the provided dataset.
23+
The field '$METADATA_ID_HEADER' is required and must be unique within the provided dataset.
2224
It is used to associate metadata to the sequences in the sequences fasta file.
2325
"""
26+
2427
const val SEQUENCE_FILE_DESCRIPTION = """
2528
A fasta file containing the unaligned nucleotide sequences of the submitted sequences.
2629
The file may be compressed with zstd, xz, zip, gzip, lzma, bzip2 (with common extensions).
2730
If the underlying organism has a single segment,
28-
the headers of the fasta file must match the '$HEADER_TO_CONNECT_METADATA_AND_SEQUENCES' field in the metadata file.
31+
the headers of the fasta file must match the '$METADATA_ID_HEADER' field in the metadata file.
2932
If the underlying organism has multiple segments,
30-
the headers of the fasta file must be of the form '>[$HEADER_TO_CONNECT_METADATA_AND_SEQUENCES]_[segmentName]'.
33+
the headers of the fasta file must be added in a '$FASTA_IDS_SEPARATOR'-separated list to the '$FASTA_IDS_HEADER'
34+
field in the metadata file.
3135
"""
3236

3337
const val FILE_MAPPING_DESCRIPTION = """
@@ -114,7 +118,7 @@ The version will increase by one in respect to the original accession version.
114118

115119
const val REVISED_METADATA_FILE_DESCRIPTION = """
116120
A TSV (tab separated values) file containing the metadata of the revised data.
117-
The first row must contain the column names. The column '$HEADER_TO_CONNECT_METADATA_AND_SEQUENCES' is required and must be unique within the
121+
The first row must contain the column names. The column '$METADATA_ID_HEADER' is required and must be unique within the
118122
provided dataset. It is used to associate metadata to the sequences in the sequences fasta file.
119123
Additionally, the column 'accession' is required and must match the accession of the original sequence entry.
120124
"""

backend/src/main/kotlin/org/loculus/backend/model/SubmitModel.kt

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ import org.loculus.backend.config.BackendConfig
1414
import org.loculus.backend.controller.BadRequestException
1515
import org.loculus.backend.controller.DuplicateKeyException
1616
import org.loculus.backend.controller.UnprocessableEntityException
17-
import org.loculus.backend.service.datauseterms.DataUseTermsPreconditionValidator
1817
import org.loculus.backend.service.files.FilesDatabaseService
19-
import org.loculus.backend.service.files.S3Service
20-
import org.loculus.backend.service.groupmanagement.GroupManagementPreconditionValidator
2118
import org.loculus.backend.service.submission.CompressionAlgorithm
2219
import org.loculus.backend.service.submission.SubmissionIdFilesMappingPreconditionValidator
2320
import org.loculus.backend.service.submission.UploadDatabaseService
@@ -31,13 +28,16 @@ import java.io.BufferedInputStream
3128
import java.io.File
3229
import java.io.InputStream
3330

34-
const val HEADER_TO_CONNECT_METADATA_AND_SEQUENCES = "id"
35-
const val HEADER_TO_CONNECT_METADATA_AND_SEQUENCES_ALTERNATE_FOR_BACKCOMPAT = "submissionId"
31+
const val METADATA_ID_HEADER = "id"
32+
const val METADATA_ID_HEADER_ALTERNATE_FOR_BACKCOMPAT = "submissionId"
33+
const val FASTA_IDS_HEADER = "fastaIds"
34+
const val FASTA_IDS_SEPARATOR = " "
3635

3736
const val ACCESSION_HEADER = "accession"
3837
private val log = KotlinLogging.logger { }
3938

4039
typealias SubmissionId = String
40+
typealias FastaId = String
4141
typealias SegmentName = String
4242

4343
const val UNIQUE_CONSTRAINT_VIOLATION_SQL_STATE = "23505"
@@ -85,7 +85,6 @@ class SubmitModel(
8585
private val submissionIdFilesMappingPreconditionValidator: SubmissionIdFilesMappingPreconditionValidator,
8686
private val dateProvider: DateProvider,
8787
private val backendConfig: BackendConfig,
88-
private val s3Service: S3Service,
8988
) {
9089

9190
companion object AcceptedFileTypes {
@@ -126,8 +125,13 @@ class SubmitModel(
126125
val metadataSubmissionIds = uploadDatabaseService.getMetadataUploadSubmissionIds(uploadId).toSet()
127126
if (requiresConsensusSequenceFile(submissionParams.organism)) {
128127
log.debug { "Validating submission with uploadId $uploadId" }
129-
val sequenceSubmissionIds = uploadDatabaseService.getSequenceUploadSubmissionIds(uploadId).toSet()
130-
validateSubmissionIdSetsForConsensusSequences(metadataSubmissionIds, sequenceSubmissionIds)
128+
val metadataFastaIds = uploadDatabaseService.getFastaIdsForMetadata(uploadId).flatten()
129+
val metadataFastaIdsSet = metadataFastaIds.toSet()
130+
if (metadataFastaIdsSet.size < metadataFastaIds.size) {
131+
throw UnprocessableEntityException("Metadata file contains duplicate fastaIds.")
132+
}
133+
val sequenceFastaIds = uploadDatabaseService.getSequenceUploadSubmissionIds(uploadId).toSet()
134+
validateSubmissionIdSetsForConsensusSequences(metadataFastaIdsSet, sequenceFastaIds)
131135
}
132136

133137
if (submissionParams is SubmissionParams.RevisionSubmissionParams) {
@@ -167,6 +171,7 @@ class SubmitModel(
167171
metadataFileTypes,
168172
metadataTempFileToDelete,
169173
)
174+
val requireConsensusSequence = requiresConsensusSequenceFile(submissionParams.organism)
170175
try {
171176
uploadMetadata(uploadId, submissionParams, metadataStream, batchSize)
172177
} finally {
@@ -175,30 +180,30 @@ class SubmitModel(
175180

176181
val sequenceFile = submissionParams.sequenceFile
177182
if (sequenceFile == null) {
178-
if (requiresConsensusSequenceFile(submissionParams.organism)) {
183+
if (requireConsensusSequence) {
179184
throw BadRequestException(
180185
"Submissions for organism ${submissionParams.organism.name} require a sequence file.",
181186
)
182187
}
183-
} else {
184-
if (!requiresConsensusSequenceFile(submissionParams.organism)) {
185-
throw BadRequestException(
186-
"Sequence uploads are not allowed for organism ${submissionParams.organism.name}.",
187-
)
188-
}
188+
return
189+
}
190+
if (!requireConsensusSequence) {
191+
throw BadRequestException(
192+
"Sequence uploads are not allowed for organism ${submissionParams.organism.name}.",
193+
)
194+
}
189195

190-
val sequenceTempFileToDelete = MaybeFile()
191-
try {
192-
val sequenceStream = getStreamFromFile(
193-
sequenceFile,
194-
uploadId,
195-
sequenceFileTypes,
196-
sequenceTempFileToDelete,
197-
)
198-
uploadSequences(uploadId, sequenceStream, batchSize, submissionParams.organism)
199-
} finally {
200-
sequenceTempFileToDelete.delete()
201-
}
196+
val sequenceTempFileToDelete = MaybeFile()
197+
try {
198+
val sequenceStream = getStreamFromFile(
199+
sequenceFile,
200+
uploadId,
201+
sequenceFileTypes,
202+
sequenceTempFileToDelete,
203+
)
204+
uploadSequences(uploadId, sequenceStream, batchSize, submissionParams.organism)
205+
} finally {
206+
sequenceTempFileToDelete.delete()
202207
}
203208
}
204209

@@ -250,10 +255,15 @@ class SubmitModel(
250255
"from $submissionParams.submitter with UploadId $uploadId"
251256
}
252257
val now = dateProvider.getCurrentDateTime()
258+
val maxSequencesPerEntry = backendConfig.getInstanceConfig(submissionParams.organism)
259+
.schema
260+
.submissionDataTypes
261+
.maxSequencesPerEntry
262+
253263
try {
254264
when (submissionParams) {
255265
is SubmissionParams.OriginalSubmissionParams -> {
256-
metadataEntryStreamAsSequence(metadataStream)
266+
metadataEntryStreamAsSequence(metadataStream, maxSequencesPerEntry)
257267
.chunked(batchSize)
258268
.forEach { batch ->
259269
uploadDatabaseService.batchInsertMetadataInAuxTable(
@@ -269,7 +279,7 @@ class SubmitModel(
269279
}
270280

271281
is SubmissionParams.RevisionSubmissionParams -> {
272-
revisionEntryStreamAsSequence(metadataStream)
282+
revisionEntryStreamAsSequence(metadataStream, maxSequencesPerEntry)
273283
.chunked(batchSize)
274284
.forEach { batch ->
275285
uploadDatabaseService.batchInsertRevisedMetadataInAuxTable(
@@ -344,14 +354,17 @@ class SubmitModel(
344354

345355
if (metadataKeysNotInSequences.isNotEmpty() || sequenceKeysNotInMetadata.isNotEmpty()) {
346356
val metadataNotPresentErrorText = if (metadataKeysNotInSequences.isNotEmpty()) {
347-
"Metadata file contains ${metadataKeysNotInSequences.size} ids that are not present " +
348-
"in the sequence file: " + metadataKeysNotInSequences.toList().joinToString(limit = 10) + "; "
357+
"Metadata file contains ${metadataKeysNotInSequences.size} FASTA ids that are not present " +
358+
"in the sequence file: " + metadataKeysNotInSequences.toList().joinToString(limit = 10) {
359+
"'$it'"
360+
} + ". "
349361
} else {
350362
""
351363
}
352364
val sequenceNotPresentErrorText = if (sequenceKeysNotInMetadata.isNotEmpty()) {
353-
"Sequence file contains ${sequenceKeysNotInMetadata.size} ids that are not present " +
354-
"in the metadata file: " + sequenceKeysNotInMetadata.toList().joinToString(limit = 10)
365+
"Sequence file contains ${sequenceKeysNotInMetadata.size} FASTA ids that are not present " +
366+
"in the metadata file: " +
367+
sequenceKeysNotInMetadata.toList().joinToString(limit = 10) { "'$it'" }
355368
} else {
356369
""
357370
}
@@ -364,7 +377,7 @@ class SubmitModel(
364377
if (filesKeysNotInMetadata.isNotEmpty()) {
365378
throw UnprocessableEntityException(
366379
"File upload contains ${filesKeysNotInMetadata.size} submissionIds that are not present in the " +
367-
"metadata file: " + filesKeysNotInMetadata.toList().joinToString(limit = 10),
380+
"metadata file: " + filesKeysNotInMetadata.toList().joinToString(limit = 10) { "'$it'" },
368381
)
369382
}
370383
}

backend/src/main/kotlin/org/loculus/backend/service/submission/CompressionService.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ class CompressionService(private val compressionDictService: CompressionDictServ
102102
}
103103
},
104104
processedData.aminoAcidInsertions,
105+
processedData.sequenceNameToFastaId,
105106
processedData.files,
106107
)
107108

@@ -128,6 +129,7 @@ class CompressionService(private val compressionDictService: CompressionDictServ
128129
}
129130
},
130131
processedData.aminoAcidInsertions,
132+
processedData.sequenceNameToFastaId,
131133
processedData.files,
132134
)
133135

backend/src/main/kotlin/org/loculus/backend/service/submission/EmptyProcessedDataProvider.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class EmptyProcessedDataProvider(private val backendConfig: BackendConfig) {
2020
alignedAminoAcidSequences = referenceGenome.genes.map { it.name }.associateWith { null },
2121
nucleotideInsertions = referenceGenome.nucleotideSequences.map { it.name }.associateWith { emptyList() },
2222
aminoAcidInsertions = referenceGenome.genes.map { it.name }.associateWith { emptyList() },
23+
sequenceNameToFastaId = referenceGenome.nucleotideSequences.map { it.name }.associateWith { "" },
2324
files = null,
2425
)
2526
}

0 commit comments

Comments
 (0)