diff --git a/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/LapisController.kt b/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/LapisController.kt index 1ed0b94fc..300e3a8d3 100644 --- a/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/LapisController.kt +++ b/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/LapisController.kt @@ -40,6 +40,7 @@ import org.genspectrum.lapis.request.AminoAcidInsertion import org.genspectrum.lapis.request.AminoAcidMutation import org.genspectrum.lapis.request.CommonSequenceFilters import org.genspectrum.lapis.request.Field +import org.genspectrum.lapis.request.GetRequestSequenceFilters import org.genspectrum.lapis.request.MutationProportionsRequest import org.genspectrum.lapis.request.NucleotideInsertion import org.genspectrum.lapis.request.NucleotideMutation @@ -83,7 +84,7 @@ class LapisController( fun aggregated( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @FieldsToAggregateBy @RequestParam fields: List?, @@ -138,7 +139,7 @@ class LapisController( fun getAggregatedAsCsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @FieldsToAggregateBy @RequestParam fields: List?, @@ -191,7 +192,7 @@ class LapisController( fun getAggregatedAsTsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @FieldsToAggregateBy @RequestParam fields: List?, @@ -283,7 +284,7 @@ class LapisController( fun getNucleotideMutations( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @RequestParam(required = false) @NucleotideMutations nucleotideMutations: List?, @@ -338,7 +339,7 @@ class LapisController( fun getNucleotideMutationsAsCsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @RequestParam(required = false) @NucleotideMutations nucleotideMutations: List?, @@ -387,7 +388,7 @@ class LapisController( fun getNucleotideMutationsAsTsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @RequestParam(required = false) @NucleotideMutations nucleotideMutations: List?, @@ -476,7 +477,7 @@ class LapisController( fun getAminoAcidMutations( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @RequestParam(required = false) @NucleotideMutations nucleotideMutations: List?, @@ -527,7 +528,7 @@ class LapisController( fun getAminoAcidMutationsAsCsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @RequestParam(required = false) @NucleotideMutations nucleotideMutations: List?, @@ -576,7 +577,7 @@ class LapisController( fun getAminoAcidMutationsAsTsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @RequestParam(required = false) @NucleotideMutations nucleotideMutations: List?, @@ -681,7 +682,7 @@ class LapisController( fun getDetailsAsJson( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @DetailsFields @RequestParam fields: List?, @@ -734,7 +735,7 @@ class LapisController( fun getDetailsAsCsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @DetailsFields @RequestParam fields: List?, @@ -784,7 +785,7 @@ class LapisController( fun getDetailsAsTsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @DetailsFields @RequestParam fields: List?, @@ -873,7 +874,7 @@ class LapisController( fun getNucleotideInsertions( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @InsertionsOrderByFields @RequestParam orderBy: List?, @@ -925,7 +926,7 @@ class LapisController( fun getNucleotideInsertionsAsCsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @InsertionsOrderByFields @RequestParam orderBy: List?, @@ -976,7 +977,7 @@ class LapisController( fun getNucleotideInsertionsAsTsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @InsertionsOrderByFields @RequestParam orderBy: List?, @@ -1071,7 +1072,7 @@ class LapisController( fun getAminoAcidInsertions( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @InsertionsOrderByFields @RequestParam orderBy: List?, @@ -1123,7 +1124,7 @@ class LapisController( fun getAminoAcidInsertionsAsCsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @InsertionsOrderByFields @RequestParam orderBy: List?, @@ -1174,7 +1175,7 @@ class LapisController( fun getAminoAcidInsertionsAsTsv( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @InsertionsOrderByFields @RequestParam orderBy: List?, @@ -1270,7 +1271,7 @@ class LapisController( @PathVariable(name = "gene", required = true) gene: String, @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @AminoAcidSequencesOrderByFields @RequestParam orderBy: List?, diff --git a/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/MultiSegmentedSequenceController.kt b/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/MultiSegmentedSequenceController.kt index d1243a40c..e887832e3 100644 --- a/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/MultiSegmentedSequenceController.kt +++ b/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/MultiSegmentedSequenceController.kt @@ -17,6 +17,7 @@ import org.genspectrum.lapis.openApi.Offset import org.genspectrum.lapis.openApi.PrimitiveFieldFilters import org.genspectrum.lapis.request.AminoAcidInsertion import org.genspectrum.lapis.request.AminoAcidMutation +import org.genspectrum.lapis.request.GetRequestSequenceFilters import org.genspectrum.lapis.request.NucleotideInsertion import org.genspectrum.lapis.request.NucleotideMutation import org.genspectrum.lapis.request.OrderByField @@ -47,7 +48,7 @@ class MultiSegmentedSequenceController( @PathVariable(name = "segment", required = true) segment: String, @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @NucleotideSequencesOrderByFields @RequestParam orderBy: List?, diff --git a/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/SingleSegmentedSequenceController.kt b/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/SingleSegmentedSequenceController.kt index 368a278db..94d74136a 100644 --- a/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/SingleSegmentedSequenceController.kt +++ b/lapis2/src/main/kotlin/org/genspectrum/lapis/controller/SingleSegmentedSequenceController.kt @@ -18,6 +18,7 @@ import org.genspectrum.lapis.openApi.Offset import org.genspectrum.lapis.openApi.PrimitiveFieldFilters import org.genspectrum.lapis.request.AminoAcidInsertion import org.genspectrum.lapis.request.AminoAcidMutation +import org.genspectrum.lapis.request.GetRequestSequenceFilters import org.genspectrum.lapis.request.NucleotideInsertion import org.genspectrum.lapis.request.NucleotideMutation import org.genspectrum.lapis.request.OrderByField @@ -47,7 +48,7 @@ class SingleSegmentedSequenceController( fun getAlignedNucleotideSequences( @PrimitiveFieldFilters @RequestParam - sequenceFilters: Map?, + sequenceFilters: GetRequestSequenceFilters?, @NucleotideSequencesOrderByFields @RequestParam orderBy: List?, diff --git a/lapis2/src/main/kotlin/org/genspectrum/lapis/model/SiloFilterExpressionMapper.kt b/lapis2/src/main/kotlin/org/genspectrum/lapis/model/SiloFilterExpressionMapper.kt index 63b2bf075..98ea8456f 100644 --- a/lapis2/src/main/kotlin/org/genspectrum/lapis/model/SiloFilterExpressionMapper.kt +++ b/lapis2/src/main/kotlin/org/genspectrum/lapis/model/SiloFilterExpressionMapper.kt @@ -21,6 +21,7 @@ import org.genspectrum.lapis.silo.IntBetween import org.genspectrum.lapis.silo.IntEquals import org.genspectrum.lapis.silo.NucleotideInsertionContains import org.genspectrum.lapis.silo.NucleotideSymbolEquals +import org.genspectrum.lapis.silo.Or import org.genspectrum.lapis.silo.PangoLineageEquals import org.genspectrum.lapis.silo.SiloFilterExpression import org.genspectrum.lapis.silo.StringEquals @@ -30,7 +31,7 @@ import java.time.LocalDate import java.time.format.DateTimeParseException import java.util.Locale -data class SequenceFilterValue(val type: SequenceFilterFieldType, val value: String, val originalKey: String) +data class SequenceFilterValue(val type: SequenceFilterFieldType, val values: List, val originalKey: String) typealias SequenceFilterFieldName = String @@ -46,10 +47,10 @@ class SiloFilterExpressionMapper( val allowedSequenceFiltersWithType = sequenceFilters .sequenceFilters - .map { (key, value) -> + .map { (key, values) -> val nullableField = allowedSequenceFilterFields.fields[key.lowercase(Locale.US)] val (filterExpressionId, type) = mapToFilterExpressionIdentifier(nullableField, key) - filterExpressionId to SequenceFilterValue(type, value, key) + filterExpressionId to SequenceFilterValue(type, values, key) } .groupBy({ it.first }, { it.second }) @@ -62,10 +63,10 @@ class SiloFilterExpressionMapper( val filterExpressions = allowedSequenceFiltersWithType.map { (key, values) -> val (siloColumnName, filter) = key when (filter) { - Filter.StringEquals -> StringEquals(siloColumnName, values[0].value) - Filter.PangoLineage -> mapToPangoLineageFilter(siloColumnName, values[0].value) + Filter.StringEquals -> mapToStringEqualsFilters(siloColumnName, values) + Filter.PangoLineage -> mapToPangoLineageFilter(siloColumnName, values) Filter.DateBetween -> mapToDateBetweenFilter(siloColumnName, values) - Filter.VariantQuery -> mapToVariantQueryFilter(values[0].value) + Filter.VariantQuery -> mapToVariantQueryFilter(values[0].values[0]) Filter.IntEquals -> mapToIntEqualsFilter(siloColumnName, values) Filter.IntBetween -> mapToIntBetweenFilter(siloColumnName, values) Filter.FloatEquals -> mapToFloatEqualsFilter(siloColumnName, values) @@ -161,6 +162,11 @@ class SiloFilterExpressionMapper( } } + private fun mapToStringEqualsFilters( + siloColumnName: SequenceFilterFieldName, + values: List, + ) = Or(values[0].values.map { StringEquals(siloColumnName, it) }) + private fun mapToVariantQueryFilter(variantQuery: String): SiloFilterExpression { if (variantQuery.isBlank()) { throw BadRequestException("variantQuery must not be empty") @@ -208,7 +214,8 @@ class SiloFilterExpressionMapper( } private fun getAsDate(sequenceFilterValue: SequenceFilterValue?): LocalDate? { - val (_, value, originalKey) = sequenceFilterValue ?: return null + val (_, values, originalKey) = sequenceFilterValue ?: return null + val value = extractSingleFilterValue(values, originalKey) try { return LocalDate.parse(value) @@ -219,22 +226,26 @@ class SiloFilterExpressionMapper( private fun mapToPangoLineageFilter( column: String, - value: String, - ) = when { - value.endsWith(".*") -> PangoLineageEquals(column, value.substringBeforeLast(".*"), includeSublineages = true) - value.endsWith('*') -> PangoLineageEquals(column, value.substringBeforeLast('*'), includeSublineages = true) - value.endsWith('.') -> throw BadRequestException( - "Invalid pango lineage: $value must not end with a dot. Did you mean '$value*'?", - ) + value: List, + ) = Or( + value[0].values.map { + when { + it.endsWith(".*") -> PangoLineageEquals(column, it.substringBeforeLast(".*"), includeSublineages = true) + it.endsWith('*') -> PangoLineageEquals(column, it.substringBeforeLast('*'), includeSublineages = true) + it.endsWith('.') -> throw BadRequestException( + "Invalid pango lineage: $it must not end with a dot. Did you mean '$it*'?", + ) - else -> PangoLineageEquals(column, value, includeSublineages = false) - } + else -> PangoLineageEquals(column, it, includeSublineages = false) + } + }, + ) private fun mapToIntEqualsFilter( siloColumnName: SequenceFilterFieldName, values: List, ): SiloFilterExpression { - val value = values[0].value + val value = extractSingleFilterValue(values[0]) try { return IntEquals(siloColumnName, value.toInt()) } catch (exception: NumberFormatException) { @@ -249,7 +260,7 @@ class SiloFilterExpressionMapper( siloColumnName: SequenceFilterFieldName, values: List, ): SiloFilterExpression { - val value = values[0].value + val value = extractSingleFilterValue(values[0]) try { return FloatEquals(siloColumnName, value.toDouble()) } catch (exception: NumberFormatException) { @@ -274,7 +285,8 @@ class SiloFilterExpressionMapper( private inline fun findIntOfFilterType( dateRangeFilters: List, ): Int? { - val (_, value, originalKey) = dateRangeFilters.find { (type, _, _) -> type is T } ?: return null + val (_, values, originalKey) = dateRangeFilters.find { (type, _, _) -> type is T } ?: return null + val value = extractSingleFilterValue(values, originalKey) try { return value.toInt() @@ -300,7 +312,8 @@ class SiloFilterExpressionMapper( private inline fun findFloatOfFilterType( dateRangeFilters: List, ): Double? { - val (_, value, originalKey) = dateRangeFilters.find { (type, _, _) -> type is T } ?: return null + val (_, values, originalKey) = dateRangeFilters.find { (type, _, _) -> type is T } ?: return null + val value = extractSingleFilterValue(values, originalKey) try { return value.toDouble() @@ -356,4 +369,14 @@ class SiloFilterExpressionMapper( } private val variantQueryTypes = listOf(Filter.PangoLineage) + + private fun extractSingleFilterValue(value: SequenceFilterValue) = + extractSingleFilterValue(value.values, value.originalKey) + + private fun extractSingleFilterValue( + values: List, + originalKey: String, + ) = values.singleOrNull() ?: throw BadRequestException( + "Expected exactly one value for '$originalKey' but got ${values.size} values.", + ) } diff --git a/lapis2/src/main/kotlin/org/genspectrum/lapis/openApi/OpenApiDocs.kt b/lapis2/src/main/kotlin/org/genspectrum/lapis/openApi/OpenApiDocs.kt index ba2a9a928..61a321973 100644 --- a/lapis2/src/main/kotlin/org/genspectrum/lapis/openApi/OpenApiDocs.kt +++ b/lapis2/src/main/kotlin/org/genspectrum/lapis/openApi/OpenApiDocs.kt @@ -9,6 +9,7 @@ import org.genspectrum.lapis.config.MetadataType import org.genspectrum.lapis.config.OpennessLevel import org.genspectrum.lapis.config.ReferenceGenome import org.genspectrum.lapis.config.SequenceFilterFieldName +import org.genspectrum.lapis.config.SequenceFilterFieldType import org.genspectrum.lapis.config.SequenceFilterFields import org.genspectrum.lapis.controller.AGGREGATED_GROUP_BY_FIELDS_DESCRIPTION import org.genspectrum.lapis.controller.AMINO_ACID_INSERTIONS_PROPERTY @@ -282,7 +283,20 @@ private fun mapToOpenApiType(type: MetadataType): String = private fun primitiveSequenceFilterFieldSchemas(sequenceFilterFields: SequenceFilterFields) = sequenceFilterFields.fields .values - .associate { (fieldName, field) -> fieldName to Schema().type(field.openApiType) } + .associate { (fieldName, field) -> fieldName to filterFieldSchema(field) } + +private fun filterFieldSchema(fieldType: SequenceFilterFieldType) = + when (fieldType) { + SequenceFilterFieldType.String, SequenceFilterFieldType.PangoLineage -> + Schema().anyOf( + listOf( + Schema().type(fieldType.openApiType), + arraySchema(Schema().type(fieldType.openApiType)), + ), + ) + + else -> Schema().type(fieldType.openApiType) + } private fun requestSchemaForCommonSequenceFilters( requestProperties: Map>, diff --git a/lapis2/src/main/kotlin/org/genspectrum/lapis/request/CommonSequenceFilters.kt b/lapis2/src/main/kotlin/org/genspectrum/lapis/request/CommonSequenceFilters.kt index 7f56bf5c5..cb32e3622 100644 --- a/lapis2/src/main/kotlin/org/genspectrum/lapis/request/CommonSequenceFilters.kt +++ b/lapis2/src/main/kotlin/org/genspectrum/lapis/request/CommonSequenceFilters.kt @@ -13,9 +13,13 @@ import org.genspectrum.lapis.controller.NUCLEOTIDE_MUTATIONS_PROPERTY import org.genspectrum.lapis.controller.OFFSET_PROPERTY import org.genspectrum.lapis.controller.ORDER_BY_PROPERTY import org.genspectrum.lapis.controller.SPECIAL_REQUEST_PROPERTIES +import org.springframework.util.MultiValueMap + +typealias SequenceFilters = Map> +typealias GetRequestSequenceFilters = MultiValueMap interface CommonSequenceFilters { - val sequenceFilters: Map + val sequenceFilters: SequenceFilters val nucleotideMutations: List val aaMutations: List val nucleotideInsertions: List @@ -87,17 +91,19 @@ fun parseCommonFields( else -> throw BadRequestException("offset must be a number or null") } - val sequenceFilters = node.fields().asSequence().filter { isStringOrNumber(it.value) } - .filter { !SPECIAL_REQUEST_PROPERTIES.contains(it.key) }.associate { it.key to it.value.asText() } + val sequenceFilters = node.fields() + .asSequence() + .filter { !SPECIAL_REQUEST_PROPERTIES.contains(it.key) } + .associate { it.key to getValuesList(it.value, it.key) } return ParsedCommonFields( - nucleotideMutations, - aminoAcidMutations, - nucleotideInsertions, - aminoAcidInsertions, - sequenceFilters, - orderByFields, - limit, - offset, + nucleotideMutations = nucleotideMutations, + aminoAcidMutations = aminoAcidMutations, + nucleotideInsertions = nucleotideInsertions, + aminoAcidInsertions = aminoAcidInsertions, + sequenceFilters = sequenceFilters, + orderByFields = orderByFields, + limit = limit, + offset = offset, ) } @@ -106,17 +112,27 @@ data class ParsedCommonFields( val aminoAcidMutations: List, val nucleotideInsertions: List, val aminoAcidInsertions: List, - val sequenceFilters: Map, + val sequenceFilters: SequenceFilters, val orderByFields: List, val limit: Int?, val offset: Int?, ) -private fun isStringOrNumber(jsonNode: JsonNode) = - when (jsonNode.nodeType) { - JsonNodeType.STRING, - JsonNodeType.NUMBER, - -> true - - else -> false +private fun getValuesList( + value: JsonNode, + key: String, +) = when { + value.isValueNode -> listOf(value.asText()) + value.nodeType == JsonNodeType.ARRAY -> value.map { + when { + it.isValueNode -> it.asText() + else -> throw BadRequestException( + "Found unexpected array value $it of type ${it.nodeType} for $key, expected a primitive", + ) + } } + + else -> throw BadRequestException( + "Found unexpected value $value of type ${value.nodeType} for $key, expected primitive or array", + ) +} diff --git a/lapis2/src/main/kotlin/org/genspectrum/lapis/request/MutationProportionsRequest.kt b/lapis2/src/main/kotlin/org/genspectrum/lapis/request/MutationProportionsRequest.kt index 526d7c994..19c317952 100644 --- a/lapis2/src/main/kotlin/org/genspectrum/lapis/request/MutationProportionsRequest.kt +++ b/lapis2/src/main/kotlin/org/genspectrum/lapis/request/MutationProportionsRequest.kt @@ -11,7 +11,7 @@ import org.genspectrum.lapis.controller.MIN_PROPORTION_PROPERTY import org.springframework.boot.jackson.JsonComponent data class MutationProportionsRequest( - override val sequenceFilters: Map, + override val sequenceFilters: SequenceFilters, override val nucleotideMutations: List, override val aaMutations: List, override val nucleotideInsertions: List, diff --git a/lapis2/src/main/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequest.kt b/lapis2/src/main/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequest.kt index ff0c86287..8ee0e8a62 100644 --- a/lapis2/src/main/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequest.kt +++ b/lapis2/src/main/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequest.kt @@ -7,7 +7,7 @@ import com.fasterxml.jackson.databind.JsonNode import org.springframework.boot.jackson.JsonComponent data class SequenceFiltersRequest( - override val sequenceFilters: Map, + override val sequenceFilters: SequenceFilters, override val nucleotideMutations: List, override val aaMutations: List, override val nucleotideInsertions: List, diff --git a/lapis2/src/main/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequestWithFields.kt b/lapis2/src/main/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequestWithFields.kt index 43dbb9f1c..424eda662 100644 --- a/lapis2/src/main/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequestWithFields.kt +++ b/lapis2/src/main/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequestWithFields.kt @@ -10,7 +10,7 @@ import org.genspectrum.lapis.controller.FIELDS_PROPERTY import org.springframework.boot.jackson.JsonComponent data class SequenceFiltersRequestWithFields( - override val sequenceFilters: Map, + override val sequenceFilters: SequenceFilters, override val nucleotideMutations: List, override val aaMutations: List, override val nucleotideInsertions: List, diff --git a/lapis2/src/main/kotlin/org/genspectrum/lapis/silo/SiloQuery.kt b/lapis2/src/main/kotlin/org/genspectrum/lapis/silo/SiloQuery.kt index 5fe05db33..c367597bd 100644 --- a/lapis2/src/main/kotlin/org/genspectrum/lapis/silo/SiloQuery.kt +++ b/lapis2/src/main/kotlin/org/genspectrum/lapis/silo/SiloQuery.kt @@ -190,7 +190,7 @@ data class AminoAcidInsertionContains(val position: Int, val value: String, val "AminoAcidInsertionContains", ) -object True : SiloFilterExpression("True") +data object True : SiloFilterExpression("True") data class And(val children: List) : SiloFilterExpression("And") diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/auth/ProtectedDataAuthorizationTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/auth/ProtectedDataAuthorizationTest.kt index 685faccb2..2e40730f4 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/auth/ProtectedDataAuthorizationTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/auth/ProtectedDataAuthorizationTest.kt @@ -125,7 +125,7 @@ class ProtectedDataAuthorizationTest( @Test fun `given aggregated access key in GET request but filters are too fine-grained, then access is denied`() { mockMvc.perform( - getSample("$validRoute?accessKey=testAggregatedDataAccessKey&gisaid_epi_isl=value"), + getSample("$validRoute?accessKey=testAggregatedDataAccessKey&key=value"), ) .andExpect(status().isForbidden) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) @@ -138,7 +138,7 @@ class ProtectedDataAuthorizationTest( postRequestWithBody( """ { "accessKey": "testAggregatedDataAccessKey", - "gisaid_epi_isl": "some value" + "key": "some value" }""", ), ) @@ -176,7 +176,7 @@ class ProtectedDataAuthorizationTest( private fun sequenceFilterRequest() = SequenceFiltersRequestWithFields( - mapOf("field1" to "value1"), + mapOf("field1" to listOf("value1")), emptyList(), emptyList(), emptyList(), diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/config/DatabaseConfigTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/config/DatabaseConfigTest.kt index ae2159c3a..f38c17869 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/config/DatabaseConfigTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/config/DatabaseConfigTest.kt @@ -15,12 +15,12 @@ class DatabaseConfigTest { @Test fun `load test database config`() { assertThat(underTest.schema.instanceName, `is`("sars_cov-2_minimal_test_config")) - assertThat(underTest.schema.primaryKey, `is`("gisaid_epi_isl")) + assertThat(underTest.schema.primaryKey, `is`("key")) assertThat(underTest.schema.opennessLevel, `is`(OpennessLevel.OPEN)) assertThat( underTest.schema.metadata, containsInAnyOrder( - DatabaseMetadata(name = "gisaid_epi_isl", type = MetadataType.STRING), + DatabaseMetadata(name = "key", type = MetadataType.STRING), DatabaseMetadata(name = "date", type = MetadataType.DATE), DatabaseMetadata(name = "region", type = MetadataType.STRING), DatabaseMetadata(name = "country", type = MetadataType.STRING), @@ -48,11 +48,11 @@ class DatabaseConfigWithoutFeaturesTest { @Test fun `a config without features can be read`() { assertThat(underTest.schema.instanceName, `is`("sars_cov-2_minimal_test_config")) - assertThat(underTest.schema.primaryKey, `is`("gisaid_epi_isl")) + assertThat(underTest.schema.primaryKey, `is`("key")) assertThat( underTest.schema.metadata, containsInAnyOrder( - DatabaseMetadata(name = "gisaid_epi_isl", type = MetadataType.STRING), + DatabaseMetadata(name = "key", type = MetadataType.STRING), DatabaseMetadata(name = "date", type = MetadataType.DATE), DatabaseMetadata(name = "region", type = MetadataType.STRING), DatabaseMetadata(name = "country", type = MetadataType.STRING), diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/Helpers.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/Helpers.kt new file mode 100644 index 000000000..d402c7ccc --- /dev/null +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/Helpers.kt @@ -0,0 +1,55 @@ +package org.genspectrum.lapis.controller + +import org.genspectrum.lapis.request.Field +import org.genspectrum.lapis.request.MutationProportionsRequest +import org.genspectrum.lapis.request.SequenceFiltersRequest +import org.genspectrum.lapis.request.SequenceFiltersRequestWithFields + +fun sequenceFiltersRequest(sequenceFilters: Map) = + SequenceFiltersRequest( + sequenceFilters.mapValues { listOf(it.value) }, + emptyList(), + emptyList(), + emptyList(), + emptyList(), + emptyList(), + ) + +fun mutationProportionsRequest( + sequenceFilters: Map, + minProportion: Double?, +) = MutationProportionsRequest( + sequenceFilters.mapValues { listOf(it.value) }, + emptyList(), + emptyList(), + emptyList(), + emptyList(), + minProportion, + emptyList(), +) + +fun sequenceFiltersRequestWithFields( + sequenceFilters: Map, + fields: List = emptyList(), +) = SequenceFiltersRequestWithFields( + sequenceFilters.mapValues { listOf(it.value) }, + emptyList(), + emptyList(), + emptyList(), + emptyList(), + fields.map { Field(it) }, + emptyList(), +) + +fun sequenceFiltersRequestWithArrayValuedFields( + sequenceFilters: Map>, + fields: List = emptyList(), +) = SequenceFiltersRequestWithFields( + sequenceFilters, + emptyList(), + emptyList(), + emptyList(), + emptyList(), + fields.map { Field(it) }, + emptyList(), +) diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/LapisControllerCsvTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/LapisControllerCsvTest.kt index e7399695b..0b758d880 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/LapisControllerCsvTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/LapisControllerCsvTest.kt @@ -7,9 +7,7 @@ import com.fasterxml.jackson.databind.node.TextNode import com.ninjasquad.springmockk.MockkBean import io.mockk.every import org.genspectrum.lapis.model.SiloQueryModel -import org.genspectrum.lapis.request.Field import org.genspectrum.lapis.request.LapisInfo -import org.genspectrum.lapis.request.SequenceFiltersRequestWithFields import org.genspectrum.lapis.response.AggregationData import org.genspectrum.lapis.response.AminoAcidInsertionResponse import org.genspectrum.lapis.response.AminoAcidMutationResponse @@ -426,17 +424,4 @@ class LapisControllerCsvTest( Arguments.of(AMINO_ACID_INSERTIONS_ROUTE), ) } - - private fun sequenceFiltersRequestWithFields( - sequenceFilters: Map, - fields: List = emptyList(), - ) = SequenceFiltersRequestWithFields( - sequenceFilters, - emptyList(), - emptyList(), - emptyList(), - emptyList(), - fields.map { Field(it) }, - emptyList(), - ) } diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/LapisControllerTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/LapisControllerTest.kt index fef35029e..e8b0d760c 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/LapisControllerTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/LapisControllerTest.kt @@ -6,10 +6,7 @@ import com.fasterxml.jackson.databind.node.TextNode import com.ninjasquad.springmockk.MockkBean import io.mockk.every import org.genspectrum.lapis.model.SiloQueryModel -import org.genspectrum.lapis.request.Field -import org.genspectrum.lapis.request.MutationProportionsRequest import org.genspectrum.lapis.request.NucleotideMutation -import org.genspectrum.lapis.request.SequenceFiltersRequest import org.genspectrum.lapis.request.SequenceFiltersRequestWithFields import org.genspectrum.lapis.response.AggregationData import org.genspectrum.lapis.response.AminoAcidInsertionResponse @@ -120,6 +117,31 @@ class LapisControllerTest( .andExpect(jsonPath("\$.data[0].date").value("a date")) } + @ParameterizedTest(name = "{0} aggregated with multiple values for filter field") + @MethodSource("getRequestsWithMultipleValuesForField") + fun `aggregated with multiple values for filter field`( + testName: String, + request: MockHttpServletRequestBuilder, + ) { + every { + siloQueryModelMock.getAggregated( + sequenceFiltersRequestWithArrayValuedFields( + mapOf("country" to listOf("Switzerland", "Germany")), + ), + ) + } returns listOf( + AggregationData( + 0, + mapOf("country" to TextNode("Switzerland")), + ), + ) + + mockMvc.perform(request) + .andExpect(status().isOk) + .andExpect(jsonPath("\$.data[0].count").value(0)) + .andExpect(jsonPath("\$.data[0].country").value("Switzerland")) + } + @Test fun `GET aggregated with valid mutation`() { every { @@ -368,6 +390,20 @@ class LapisControllerTest( Arguments.of(NUCLEOTIDE_INSERTIONS_ROUTE), Arguments.of(AMINO_ACID_INSERTIONS_ROUTE), ) + + @JvmStatic + val requestsWithMultipleValuesForField = listOf( + Arguments.of( + "GET", + getSample("$AGGREGATED_ROUTE?country=Switzerland&country=Germany"), + ), + Arguments.of( + "POST", + postSample(AGGREGATED_ROUTE) + .content("""{"country": ["Switzerland", "Germany"]}""") + .contentType(MediaType.APPLICATION_JSON), + ), + ) } @Test @@ -440,42 +476,6 @@ class LapisControllerTest( .andExpect(jsonPath("\$.data[0].date").value("a date")) } - private fun sequenceFiltersRequestWithFields( - sequenceFilters: Map, - fields: List = emptyList(), - ) = SequenceFiltersRequestWithFields( - sequenceFilters, - emptyList(), - emptyList(), - emptyList(), - emptyList(), - fields.map { Field(it) }, - emptyList(), - ) - - private fun sequenceFiltersRequest(sequenceFilters: Map) = - SequenceFiltersRequest( - sequenceFilters, - emptyList(), - emptyList(), - emptyList(), - emptyList(), - emptyList(), - ) - - private fun mutationProportionsRequest( - sequenceFilters: Map, - minProportion: Double?, - ) = MutationProportionsRequest( - sequenceFilters, - emptyList(), - emptyList(), - emptyList(), - emptyList(), - minProportion, - emptyList(), - ) - private fun someNucleotideMutationProportion() = NucleotideMutationResponse("the mutation", 42, 0.5) private fun someAminoAcidMutationProportion() = AminoAcidMutationResponse("the mutation", 42, 0.5) diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/MultiSegmentedSequenceControllerTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/MultiSegmentedSequenceControllerTest.kt index ffaa12594..6f397ea33 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/MultiSegmentedSequenceControllerTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/MultiSegmentedSequenceControllerTest.kt @@ -5,7 +5,6 @@ import io.mockk.every import org.genspectrum.lapis.config.REFERENCE_GENOME_GENES_APPLICATION_ARG_PREFIX import org.genspectrum.lapis.config.REFERENCE_GENOME_SEGMENTS_APPLICATION_ARG_PREFIX import org.genspectrum.lapis.model.SiloQueryModel -import org.genspectrum.lapis.request.SequenceFiltersRequest import org.genspectrum.lapis.silo.DataVersion import org.genspectrum.lapis.silo.SequenceType import org.junit.jupiter.api.BeforeEach @@ -151,14 +150,4 @@ class MultiSegmentedSequenceControllerTest( mockMvc.perform(request) .andExpect(status().isNotFound) } - - private fun sequenceFiltersRequest(sequenceFilters: Map) = - SequenceFiltersRequest( - sequenceFilters, - emptyList(), - emptyList(), - emptyList(), - emptyList(), - emptyList(), - ) } diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/SingleSegmentedSequenceControllerTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/SingleSegmentedSequenceControllerTest.kt index a82cb277d..d6cd1fa8b 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/SingleSegmentedSequenceControllerTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/controller/SingleSegmentedSequenceControllerTest.kt @@ -5,7 +5,6 @@ import io.mockk.every import org.genspectrum.lapis.config.REFERENCE_GENOME_GENES_APPLICATION_ARG_PREFIX import org.genspectrum.lapis.config.REFERENCE_GENOME_SEGMENTS_APPLICATION_ARG_PREFIX import org.genspectrum.lapis.model.SiloQueryModel -import org.genspectrum.lapis.request.SequenceFiltersRequest import org.genspectrum.lapis.silo.DataVersion import org.genspectrum.lapis.silo.SequenceType import org.junit.jupiter.api.BeforeEach @@ -151,14 +150,4 @@ class SingleSegmentedSequenceControllerTest( mockMvc.perform(request) .andExpect(status().isNotFound) } - - private fun sequenceFiltersRequest(sequenceFilters: Map) = - SequenceFiltersRequest( - sequenceFilters, - emptyList(), - emptyList(), - emptyList(), - emptyList(), - emptyList(), - ) } diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/logging/RequestContextLoggerTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/logging/RequestContextLoggerTest.kt index 2580ebd99..2cd6c44a7 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/logging/RequestContextLoggerTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/logging/RequestContextLoggerTest.kt @@ -106,25 +106,28 @@ internal class RequestContextLoggerTest { listOf( Arguments.of( SequenceFiltersRequestWithFields( - mapOf("country" to "Germany"), + mapOf("country" to listOf("Germany")), emptyList(), emptyList(), emptyList(), emptyList(), emptyList(), ), - """"country":"Germany"""", + """"country":["Germany"]""", ), Arguments.of( SequenceFiltersRequestWithFields( - mapOf("country" to "Germany", "nucleotideMutation" to "A123T"), + mapOf( + "country" to listOf("Germany"), + "nucleotideMutation" to listOf("A123T"), + ), emptyList(), emptyList(), emptyList(), emptyList(), emptyList(), ), - """"country":"Germany","nucleotideMutation":"A123T"""", + """"country":["Germany"],"nucleotideMutation":["A123T"]""", ), ) } diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/model/SiloFilterExpressionMapperTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/model/SiloFilterExpressionMapperTest.kt index 512bca96d..147eb34ba 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/model/SiloFilterExpressionMapperTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/model/SiloFilterExpressionMapperTest.kt @@ -1,5 +1,6 @@ package org.genspectrum.lapis.model +import org.genspectrum.lapis.DATE_FIELD import org.genspectrum.lapis.FIELD_WITH_UPPERCASE_LETTER import org.genspectrum.lapis.controller.BadRequestException import org.genspectrum.lapis.dummySequenceFilterFields @@ -9,6 +10,7 @@ import org.genspectrum.lapis.request.CommonSequenceFilters import org.genspectrum.lapis.request.NucleotideInsertion import org.genspectrum.lapis.request.NucleotideMutation import org.genspectrum.lapis.request.OrderByField +import org.genspectrum.lapis.request.SequenceFilters import org.genspectrum.lapis.silo.AminoAcidInsertionContains import org.genspectrum.lapis.silo.AminoAcidSymbolEquals import org.genspectrum.lapis.silo.And @@ -21,6 +23,7 @@ import org.genspectrum.lapis.silo.IntBetween import org.genspectrum.lapis.silo.IntEquals import org.genspectrum.lapis.silo.NucleotideInsertionContains import org.genspectrum.lapis.silo.NucleotideSymbolEquals +import org.genspectrum.lapis.silo.Or import org.genspectrum.lapis.silo.PangoLineageEquals import org.genspectrum.lapis.silo.SiloFilterExpression import org.genspectrum.lapis.silo.StringEquals @@ -65,7 +68,7 @@ class SiloFilterExpressionMapperTest { val result = underTest.map(filterParameter) val expected = - And(listOf(PangoLineageEquals(FIELD_WITH_UPPERCASE_LETTER, SOME_VALUE, includeSublineages = false))) + and(or(PangoLineageEquals(FIELD_WITH_UPPERCASE_LETTER, SOME_VALUE, includeSublineages = false))) assertThat(result, equalTo(expected)) } @@ -76,7 +79,7 @@ class SiloFilterExpressionMapperTest { val result = underTest.map(filterParameter) val expected = - And(listOf(PangoLineageEquals(FIELD_WITH_UPPERCASE_LETTER, SOME_VALUE, includeSublineages = false))) + and(or(PangoLineageEquals(FIELD_WITH_UPPERCASE_LETTER, SOME_VALUE, includeSublineages = false))) assertThat(result, equalTo(expected)) } @@ -92,10 +95,10 @@ class SiloFilterExpressionMapperTest { @ParameterizedTest(name = "FilterParameter: {0}, SiloQuery: {1}") @MethodSource("getFilterParametersWithExpectedSiloQuery") fun `given filter parameters then maps to expected FilterExpression`( - filterParameter: Map, + filterParameter: Map>, expectedResult: SiloFilterExpression, ) { - val result = underTest.map(getSequenceFilters(filterParameter)) + val result = underTest.map(DummySequenceFilters(filterParameter)) assertThat(result, equalTo(expectedResult)) } @@ -285,7 +288,7 @@ class SiloFilterExpressionMapperTest { val result = underTest.map(filterParameter) val expected = - And(listOf(NucleotideSymbolEquals(null, 123, "B"), NucleotideSymbolEquals("sequenceName", 999, "A"))) + and(NucleotideSymbolEquals(null, 123, "B"), NucleotideSymbolEquals("sequenceName", 999, "A")) assertThat(result, equalTo(expected)) } @@ -302,7 +305,7 @@ class SiloFilterExpressionMapperTest { val result = underTest.map(filterParameter) val expected = - And(listOf(HasNucleotideMutation(null, 123), HasNucleotideMutation("sequenceName", 999))) + and(HasNucleotideMutation(null, 123), HasNucleotideMutation("sequenceName", 999)) assertThat(result, equalTo(expected)) } @@ -319,7 +322,7 @@ class SiloFilterExpressionMapperTest { val result = underTest.map(filterParameter) val expected = - And(listOf(AminoAcidSymbolEquals("geneName1", 123, "B"), AminoAcidSymbolEquals("geneName2", 999, "A"))) + and(AminoAcidSymbolEquals("geneName1", 123, "B"), AminoAcidSymbolEquals("geneName2", 999, "A")) assertThat(result, equalTo(expected)) } @@ -336,7 +339,7 @@ class SiloFilterExpressionMapperTest { val result = underTest.map(filterParameter) val expected = - And(listOf(HasAminoAcidMutation("geneName1", 123), HasAminoAcidMutation("geneName2", 999))) + and(HasAminoAcidMutation("geneName1", 123), HasAminoAcidMutation("geneName2", 999)) assertThat(result, equalTo(expected)) } @@ -353,7 +356,7 @@ class SiloFilterExpressionMapperTest { val result = underTest.map(filterParameter) val expected = - And(listOf(NucleotideInsertionContains(123, "ABCD"), NucleotideInsertionContains(999, "DEF"))) + and(NucleotideInsertionContains(123, "ABCD"), NucleotideInsertionContains(999, "DEF")) assertThat(result, equalTo(expected)) } @@ -370,7 +373,7 @@ class SiloFilterExpressionMapperTest { val result = underTest.map(filterParameter) val expected = - And(listOf(AminoAcidInsertionContains(123, "ABCD", "gene"), AminoAcidInsertionContains(999, "DEF", "ORF1"))) + and(AminoAcidInsertionContains(123, "ABCD", "gene"), AminoAcidInsertionContains(999, "DEF", "ORF1")) assertThat(result, equalTo(expected)) } @@ -385,7 +388,7 @@ class SiloFilterExpressionMapperTest { @Test fun `given a query with a variantQuery alongside nucleotide mutations then it should throw an error`() { val filterParameter = DummySequenceFilters( - mapOf("variantQuery" to "A123T"), + mapOf("variantQuery" to listOf("A123T")), listOf(NucleotideMutation(null, 123, null)), emptyList(), emptyList(), @@ -402,7 +405,7 @@ class SiloFilterExpressionMapperTest { @Test fun `given a query with a variantQuery alongside amino acid mutations then it should throw an error`() { val filterParameter = DummySequenceFilters( - mapOf("variantQuery" to "A123T"), + mapOf("variantQuery" to listOf("A123T")), emptyList(), listOf(AminoAcidMutation("gene", 123, null)), emptyList(), @@ -432,162 +435,234 @@ class SiloFilterExpressionMapperTest { ) } + @ParameterizedTest + @MethodSource("getFilterParametersWithMultipleValues") + fun `GIVEN multiple value for date field THEN throws an error`( + sequenceFilters: SequenceFilters, + expectedErrorMessage: String, + ) { + val exception = assertThrows { underTest.map(DummySequenceFilters(sequenceFilters)) } + + assertThat( + exception.message, + containsString(expectedErrorMessage), + ) + } + companion object { + @JvmStatic + val filterParametersWithMultipleValues = listOf( + Arguments.of( + mapOf(DATE_FIELD to listOf("2021-06-03", "2021-06-04")), + "Expected exactly one value for '$DATE_FIELD' but got 2 values.", + ), + Arguments.of( + mapOf("dateTo" to listOf("2021-06-03", "2021-06-04")), + "Expected exactly one value for 'dateTo' but got 2 values.", + ), + Arguments.of( + mapOf("dateFrom" to listOf("2021-06-03", "2021-06-04")), + "Expected exactly one value for 'dateFrom' but got 2 values.", + ), + Arguments.of( + mapOf("intField" to listOf("1", "2")), + "Expected exactly one value for 'intField' but got 2 values.", + ), + Arguments.of( + mapOf("intFieldTo" to listOf("1", "2")), + "Expected exactly one value for 'intFieldTo' but got 2 values.", + ), + Arguments.of( + mapOf("intFieldFrom" to listOf("1", "2")), + "Expected exactly one value for 'intFieldFrom' but got 2 values.", + ), + Arguments.of( + mapOf("floatField" to listOf("0.1", "0.2")), + "Expected exactly one value for 'floatField' but got 2 values.", + ), + Arguments.of( + mapOf("floatFieldTo" to listOf("0.1", "0.2")), + "Expected exactly one value for 'floatFieldTo' but got 2 values.", + ), + Arguments.of( + mapOf("floatFieldFrom" to listOf("0.1", "0.2")), + "Expected exactly one value for 'floatFieldFrom' but got 2 values.", + ), + ) + @JvmStatic fun getFilterParametersWithExpectedSiloQuery() = listOf( Arguments.of( mapOf( - "some_metadata" to "ABC", - "other_metadata" to "def", + "some_metadata" to listOf("ABC"), + "other_metadata" to listOf("def"), ), - And( - listOf( - StringEquals("some_metadata", "ABC"), - StringEquals("other_metadata", "def"), - ), + and( + or(StringEquals("some_metadata", "ABC")), + or(StringEquals("other_metadata", "def")), ), ), Arguments.of( - mapOf("pangoLineage" to "A.1.2.3"), - And(listOf(PangoLineageEquals("pangoLineage", "A.1.2.3", includeSublineages = false))), + mapOf("pangoLineage" to listOf("A.1.2.3")), + and(or(PangoLineageEquals("pangoLineage", "A.1.2.3", includeSublineages = false))), ), Arguments.of( - mapOf("pangoLineage" to "A.1.2.3*"), - And(listOf(PangoLineageEquals("pangoLineage", "A.1.2.3", includeSublineages = true))), + mapOf("pangoLineage" to listOf("A.1.2.3*")), + and(or(PangoLineageEquals("pangoLineage", "A.1.2.3", includeSublineages = true))), ), Arguments.of( - mapOf("pangoLineage" to "A.1.2.3.*"), - And(listOf(PangoLineageEquals("pangoLineage", "A.1.2.3", includeSublineages = true))), + mapOf("pangoLineage" to listOf("A.1.2.3.*")), + and(or(PangoLineageEquals("pangoLineage", "A.1.2.3", includeSublineages = true))), ), Arguments.of( mapOf( - "pangoLineage" to "A.1.2.3", - "some_metadata" to "ABC", - "other_metadata" to "DEF", + "pangoLineage" to listOf("A.1.2.3"), + "some_metadata" to listOf("ABC"), + "other_metadata" to listOf("DEF"), ), And( listOf( - PangoLineageEquals("pangoLineage", "A.1.2.3", includeSublineages = false), - StringEquals("some_metadata", "ABC"), - StringEquals("other_metadata", "DEF"), + or(PangoLineageEquals("pangoLineage", "A.1.2.3", includeSublineages = false)), + or(StringEquals("some_metadata", "ABC")), + or(StringEquals("other_metadata", "DEF")), ), ), ), Arguments.of( mapOf( - "date" to "2021-06-03", + "date" to listOf("2021-06-03"), ), - And(listOf(DateBetween("date", from = LocalDate.of(2021, 6, 3), to = LocalDate.of(2021, 6, 3)))), + and(DateBetween("date", from = LocalDate.of(2021, 6, 3), to = LocalDate.of(2021, 6, 3))), ), Arguments.of( mapOf( - "dateTo" to "2021-06-03", + "dateTo" to listOf("2021-06-03"), ), - And(listOf(DateBetween("date", from = null, to = LocalDate.of(2021, 6, 3)))), + and(DateBetween("date", from = null, to = LocalDate.of(2021, 6, 3))), ), Arguments.of( mapOf( - "dateFrom" to "2021-03-28", + "dateFrom" to listOf("2021-03-28"), ), - And(listOf(DateBetween("date", from = LocalDate.of(2021, 3, 28), to = null))), + and(DateBetween("date", from = LocalDate.of(2021, 3, 28), to = null)), ), Arguments.of( mapOf( - "dateFrom" to "2021-03-28", - "dateTo" to "2021-06-03", + "dateFrom" to listOf("2021-03-28"), + "dateTo" to listOf("2021-06-03"), ), - And(listOf(DateBetween("date", from = LocalDate.of(2021, 3, 28), to = LocalDate.of(2021, 6, 3)))), + and(DateBetween("date", from = LocalDate.of(2021, 3, 28), to = LocalDate.of(2021, 6, 3))), ), Arguments.of( mapOf( - "dateTo" to "2021-06-03", - "some_metadata" to "ABC", + "dateTo" to listOf("2021-06-03"), + "some_metadata" to listOf("ABC"), ), - And( - listOf( - DateBetween("date", from = null, to = LocalDate.of(2021, 6, 3)), - StringEquals("some_metadata", "ABC"), - ), + and( + DateBetween("date", from = null, to = LocalDate.of(2021, 6, 3)), + or(StringEquals("some_metadata", "ABC")), ), ), Arguments.of( mapOf( - "variantQuery" to "300G & 400A", + "variantQuery" to listOf("300G & 400A"), ), - And( - listOf( - And( - listOf( - NucleotideSymbolEquals(null, 300, "G"), - NucleotideSymbolEquals(null, 400, "A"), - ), - ), + and( + and( + NucleotideSymbolEquals(null, 300, "G"), + NucleotideSymbolEquals(null, 400, "A"), ), ), ), Arguments.of( mapOf( - "variantQuery" to "300G", - "some_metadata" to "ABC", + "variantQuery" to listOf("300G"), + "some_metadata" to listOf("ABC"), ), - And( - listOf( - NucleotideSymbolEquals(null, 300, "G"), - StringEquals("some_metadata", "ABC"), - ), + and( + NucleotideSymbolEquals(null, 300, "G"), + or(StringEquals("some_metadata", "ABC")), + ), + ), + Arguments.of( + mapOf( + "intField" to listOf("42"), ), + and(IntEquals("intField", 42)), ), Arguments.of( mapOf( - "intField" to "42", + "intFieldFrom" to listOf("42"), ), - And(listOf(IntEquals("intField", 42))), + and(IntBetween("intField", 42, null)), ), Arguments.of( mapOf( - "intFieldFrom" to "42", + "intFieldTo" to listOf("42"), ), - And(listOf(IntBetween("intField", 42, null))), + and(IntBetween("intField", null, 42)), ), Arguments.of( mapOf( - "intFieldTo" to "42", + "floatField" to listOf("42.45"), ), - And(listOf(IntBetween("intField", null, 42))), + and(FloatEquals("floatField", 42.45)), ), Arguments.of( mapOf( - "floatField" to "42.45", + "floatFieldFrom" to listOf("42.45"), ), - And(listOf(FloatEquals("floatField", 42.45))), + and(FloatBetween("floatField", 42.45, null)), ), Arguments.of( mapOf( - "floatFieldFrom" to "42.45", + "floatFieldTo" to listOf("42.45"), ), - And(listOf(FloatBetween("floatField", 42.45, null))), + and(FloatBetween("floatField", null, 42.45)), ), Arguments.of( mapOf( - "floatFieldTo" to "42.45", + "some_metadata" to listOf("value1", "value2"), + ), + and( + or( + StringEquals("some_metadata", "value1"), + StringEquals("some_metadata", "value2"), + ), + ), + ), + Arguments.of( + mapOf( + "pangoLineage" to listOf("A.1.2.3", "B.1.2.3"), + ), + and( + or( + PangoLineageEquals("pangoLineage", "A.1.2.3", includeSublineages = false), + PangoLineageEquals("pangoLineage", "B.1.2.3", includeSublineages = false), + ), ), - And(listOf(FloatBetween("floatField", null, 42.45))), ), ) } private fun getSequenceFilters(sequenceFilters: Map) = - DummySequenceFilters(sequenceFilters, emptyList(), emptyList(), emptyList(), emptyList()) + DummySequenceFilters( + sequenceFilters.mapValues { listOf(it.value) }, + ) data class DummySequenceFilters( - override val sequenceFilters: Map, - override val nucleotideMutations: List, - override val aaMutations: List, - override val nucleotideInsertions: List, - override val aminoAcidInsertions: List, + override val sequenceFilters: SequenceFilters, + override val nucleotideMutations: List = emptyList(), + override val aaMutations: List = emptyList(), + override val nucleotideInsertions: List = emptyList(), + override val aminoAcidInsertions: List = emptyList(), override val orderByFields: List = emptyList(), override val limit: Int? = null, override val offset: Int? = null, ) : CommonSequenceFilters } + +private fun and(vararg expressions: SiloFilterExpression) = And(expressions.toList()) + +private fun or(vararg expressions: SiloFilterExpression) = Or(expressions.toList()) diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/request/MutationProportionsRequestTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/request/MutationProportionsRequestTest.kt index c6247146f..5e3375be3 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/request/MutationProportionsRequestTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/request/MutationProportionsRequestTest.kt @@ -47,12 +47,12 @@ class MutationProportionsRequestTest { listOf( Arguments.of( """ - { - "country": "Switzerland" - } - """, + { + "country": "Switzerland" + } + """, MutationProportionsRequest( - mapOf("country" to "Switzerland"), + mapOf("country" to listOf("Switzerland")), emptyList(), emptyList(), emptyList(), @@ -61,10 +61,24 @@ class MutationProportionsRequestTest { ), Arguments.of( """ - { - "nucleotideMutations": ["T1-", "A23062T"] - } - """, + { + "country": ["Switzerland", "Germany"] + } + """, + MutationProportionsRequest( + mapOf("country" to listOf("Switzerland", "Germany")), + emptyList(), + emptyList(), + emptyList(), + emptyList(), + ), + ), + Arguments.of( + """ + { + "nucleotideMutations": ["T1-", "A23062T"] + } + """, MutationProportionsRequest( emptyMap(), listOf(NucleotideMutation(null, 1, "-"), NucleotideMutation(null, 23062, "T")), @@ -75,10 +89,10 @@ class MutationProportionsRequestTest { ), Arguments.of( """ - { - "aminoAcidMutations": ["S:501Y", "ORF1b:12"] - } - """, + { + "aminoAcidMutations": ["S:501Y", "ORF1b:12"] + } + """, MutationProportionsRequest( emptyMap(), emptyList(), @@ -89,10 +103,10 @@ class MutationProportionsRequestTest { ), Arguments.of( """ - { - "nucleotideInsertions": ["ins_S:501:Y", "ins_12:ABCD"] - } - """, + { + "nucleotideInsertions": ["ins_S:501:Y", "ins_12:ABCD"] + } + """, MutationProportionsRequest( emptyMap(), emptyList(), @@ -106,10 +120,10 @@ class MutationProportionsRequestTest { ), Arguments.of( """ - { - "aminoAcidInsertions": ["ins_S:501:Y", "ins_ORF1:12:ABCD"] - } - """, + { + "aminoAcidInsertions": ["ins_S:501:Y", "ins_ORF1:12:ABCD"] + } + """, MutationProportionsRequest( emptyMap(), emptyList(), @@ -123,25 +137,22 @@ class MutationProportionsRequestTest { ), Arguments.of( """ - { - "minProportion": 0.7 - } - """, + { + "minProportion": 0.7 + } + """, MutationProportionsRequest(emptyMap(), emptyList(), emptyList(), emptyList(), emptyList(), 0.7), ), Arguments.of( """ - { - "accessKey": "some access key" - } - """, + { + "accessKey": "some access key" + } + """, MutationProportionsRequest(emptyMap(), emptyList(), emptyList(), emptyList(), emptyList()), ), Arguments.of( - """ - { - } - """, + "{}", MutationProportionsRequest(emptyMap(), emptyList(), emptyList(), emptyList(), emptyList()), ), ) @@ -151,50 +162,50 @@ class MutationProportionsRequestTest { listOf( Arguments.of( """ - { - "minProportion": "not a number" - } - """, + { + "minProportion": "not a number" + } + """, "minProportion must be a number", ), Arguments.of( """ - { - "minProportion": ["not a number"] - } - """, + { + "minProportion": ["not a number"] + } + """, "minProportion must be a number", ), Arguments.of( """ - { - "nucleotideMutations": "not an array" - } - """, + { + "nucleotideMutations": "not an array" + } + """, "nucleotideMutations must be an array or null", ), Arguments.of( """ - { - "nucleotideInsertions": "not an array" - } - """, + { + "nucleotideInsertions": "not an array" + } + """, "nucleotideInsertions must be an array or null", ), Arguments.of( """ - { - "aminoAcidInsertions": "not an array" - } - """, + { + "aminoAcidInsertions": "not an array" + } + """, "aminoAcidInsertions must be an array or null", ), Arguments.of( """ - { - "aminoAcidMutations": "not an array" - } - """, + { + "aminoAcidMutations": "not an array" + } + """, "aminoAcidMutations must be an array or null", ), ) diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequestWithFieldsTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequestWithFieldsTest.kt index c7faddff0..d7bff3ee4 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequestWithFieldsTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/request/SequenceFiltersRequestWithFieldsTest.kt @@ -55,7 +55,7 @@ class SequenceFiltersRequestWithFieldsTest { } """, SequenceFiltersRequestWithFields( - mapOf("country" to "Switzerland"), + mapOf("country" to listOf("Switzerland")), emptyList(), emptyList(), emptyList(), @@ -63,6 +63,21 @@ class SequenceFiltersRequestWithFieldsTest { listOf(Field("date"), Field("country")), ), ), + Arguments.of( + """ + { + "country": ["Switzerland", "Germany"] + } + """, + SequenceFiltersRequestWithFields( + mapOf("country" to listOf("Switzerland", "Germany")), + emptyList(), + emptyList(), + emptyList(), + emptyList(), + emptyList(), + ), + ), Arguments.of( """ { @@ -170,7 +185,7 @@ class SequenceFiltersRequestWithFieldsTest { } """, SequenceFiltersRequestWithFields( - mapOf("country" to "Switzerland"), + mapOf("country" to listOf("Switzerland")), emptyList(), emptyList(), emptyList(), diff --git a/lapis2/src/test/kotlin/org/genspectrum/lapis/silo/SiloClientTest.kt b/lapis2/src/test/kotlin/org/genspectrum/lapis/silo/SiloClientTest.kt index 834c64385..349f4b12a 100644 --- a/lapis2/src/test/kotlin/org/genspectrum/lapis/silo/SiloClientTest.kt +++ b/lapis2/src/test/kotlin/org/genspectrum/lapis/silo/SiloClientTest.kt @@ -164,11 +164,11 @@ class SiloClientTest { """{ "queryResult": [ { - "gisaid_epi_isl": "key1", + "key": "key1", "someSequenceName": "ABCD" }, { - "gisaid_epi_isl": "key2", + "key": "key2", "someSequenceName": "DEFG" } ] diff --git a/lapis2/src/test/resources/config/protectedDataDatabaseConfig.yaml b/lapis2/src/test/resources/config/protectedDataDatabaseConfig.yaml index 2f102b849..576b82254 100644 --- a/lapis2/src/test/resources/config/protectedDataDatabaseConfig.yaml +++ b/lapis2/src/test/resources/config/protectedDataDatabaseConfig.yaml @@ -2,9 +2,9 @@ schema: instanceName: protectedDataTestConfig opennessLevel: PROTECTED metadata: - - name: gisaid_epi_isl + - name: key type: string valuesAreUnique: true - name: country type: string - primaryKey: gisaid_epi_isl + primaryKey: key diff --git a/lapis2/src/test/resources/config/testDatabaseConfig.yaml b/lapis2/src/test/resources/config/testDatabaseConfig.yaml index aa56983ff..e8e792bdb 100644 --- a/lapis2/src/test/resources/config/testDatabaseConfig.yaml +++ b/lapis2/src/test/resources/config/testDatabaseConfig.yaml @@ -2,7 +2,7 @@ schema: instanceName: sars_cov-2_minimal_test_config opennessLevel: OPEN metadata: - - name: gisaid_epi_isl + - name: key type: string - name: date type: date @@ -18,4 +18,4 @@ schema: type: aaInsertion features: - name: sarsCoV2VariantQuery - primaryKey: gisaid_epi_isl + primaryKey: key diff --git a/lapis2/src/test/resources/config/testDatabaseConfigWithoutFeatures.yaml b/lapis2/src/test/resources/config/testDatabaseConfigWithoutFeatures.yaml index 559315855..1fa92d8c5 100644 --- a/lapis2/src/test/resources/config/testDatabaseConfigWithoutFeatures.yaml +++ b/lapis2/src/test/resources/config/testDatabaseConfigWithoutFeatures.yaml @@ -2,7 +2,7 @@ schema: instanceName: sars_cov-2_minimal_test_config opennessLevel: OPEN metadata: - - name: gisaid_epi_isl + - name: key type: string - name: date type: date @@ -16,4 +16,4 @@ schema: type: insertion - name: aaInsertion type: aaInsertion - primaryKey: gisaid_epi_isl + primaryKey: key diff --git a/siloLapisTests/test/aggregatedQueries/filterByMultipleValuesForTheSameField.json b/siloLapisTests/test/aggregatedQueries/filterByMultipleValuesForTheSameField.json new file mode 100644 index 000000000..0376e716d --- /dev/null +++ b/siloLapisTests/test/aggregatedQueries/filterByMultipleValuesForTheSameField.json @@ -0,0 +1,30 @@ +{ + "testCaseName": "filter by multiple values for the same field", + "lapisRequest": { + "key": [ + "key_1408408", + "key_1749899", + "key_2016901" + ], + "fields": [ + "key" + ], + "orderBy": [ + "key" + ] + }, + "expected": [ + { + "count": 1, + "key": "key_1408408" + }, + { + "count": 1, + "key": "key_1749899" + }, + { + "count": 1, + "key": "key_2016901" + } + ] +} diff --git a/siloLapisTests/test/alignedNucleotideSequence.spec.ts b/siloLapisTests/test/alignedNucleotideSequence.spec.ts index 9efd73597..f58b70adc 100644 --- a/siloLapisTests/test/alignedNucleotideSequence.spec.ts +++ b/siloLapisTests/test/alignedNucleotideSequence.spec.ts @@ -17,7 +17,7 @@ describe('The /alignedNucleotideSequence endpoint', () => { it('should order ascending by specified fields', async () => { const result = await lapisSingleSegmentedSequenceController.postAlignedNucleotideSequence({ - nucleotideSequenceRequest: { orderBy: [{ field: 'gisaid_epi_isl', type: 'ascending' }] }, + nucleotideSequenceRequest: { orderBy: [{ field: 'key', type: 'ascending' }] }, }); const { primaryKeys, sequences } = sequenceData(result); @@ -30,7 +30,7 @@ describe('The /alignedNucleotideSequence endpoint', () => { it('should order descending by specified fields', async () => { const result = await lapisSingleSegmentedSequenceController.postAlignedNucleotideSequence({ - nucleotideSequenceRequest: { orderBy: [{ field: 'gisaid_epi_isl', type: 'descending' }] }, + nucleotideSequenceRequest: { orderBy: [{ field: 'key', type: 'descending' }] }, }); const { primaryKeys, sequences } = sequenceData(result); @@ -44,7 +44,7 @@ describe('The /alignedNucleotideSequence endpoint', () => { it('should apply limit and offset', async () => { const resultWithLimit = await lapisSingleSegmentedSequenceController.postAlignedNucleotideSequence({ nucleotideSequenceRequest: { - orderBy: [{ field: 'gisaid_epi_isl', type: 'ascending' }], + orderBy: [{ field: 'key', type: 'ascending' }], limit: 2, }, }); @@ -60,7 +60,7 @@ describe('The /alignedNucleotideSequence endpoint', () => { const resultWithLimitAndOffset = await lapisSingleSegmentedSequenceController.postAlignedNucleotideSequence({ nucleotideSequenceRequest: { - orderBy: [{ field: 'gisaid_epi_isl', type: 'ascending' }], + orderBy: [{ field: 'key', type: 'ascending' }], limit: 2, offset: 1, }, diff --git a/siloLapisTests/test/aminoAcidSequence.spec.ts b/siloLapisTests/test/aminoAcidSequence.spec.ts index 206dc91aa..b1e66c851 100644 --- a/siloLapisTests/test/aminoAcidSequence.spec.ts +++ b/siloLapisTests/test/aminoAcidSequence.spec.ts @@ -19,7 +19,7 @@ describe('The /alignedAminoAcidSequence endpoint', () => { it('should order ascending by specified fields', async () => { const result = await lapisClient.postAlignedAminoAcidSequence({ gene: 'S', - aminoAcidSequenceRequest: { orderBy: [{ field: 'gisaid_epi_isl', type: 'ascending' }] }, + aminoAcidSequenceRequest: { orderBy: [{ field: 'key', type: 'ascending' }] }, }); const { primaryKeys, sequences } = sequenceData(result); @@ -33,7 +33,7 @@ describe('The /alignedAminoAcidSequence endpoint', () => { it('should order descending by specified fields', async () => { const result = await lapisClient.postAlignedAminoAcidSequence({ gene: 'S', - aminoAcidSequenceRequest: { orderBy: [{ field: 'gisaid_epi_isl', type: 'descending' }] }, + aminoAcidSequenceRequest: { orderBy: [{ field: 'key', type: 'descending' }] }, }); const { primaryKeys, sequences } = sequenceData(result); @@ -48,7 +48,7 @@ describe('The /alignedAminoAcidSequence endpoint', () => { const resultWithLimit = await lapisClient.postAlignedAminoAcidSequence({ gene: 'S', aminoAcidSequenceRequest: { - orderBy: [{ field: 'gisaid_epi_isl', type: 'ascending' }], + orderBy: [{ field: 'key', type: 'ascending' }], limit: 2, }, }); @@ -64,7 +64,7 @@ describe('The /alignedAminoAcidSequence endpoint', () => { const resultWithLimitAndOffset = await lapisClient.postAlignedAminoAcidSequence({ gene: 'S', aminoAcidSequenceRequest: { - orderBy: [{ field: 'gisaid_epi_isl', type: 'ascending' }], + orderBy: [{ field: 'key', type: 'ascending' }], limit: 2, offset: 1, }, diff --git a/siloLapisTests/test/details.spec.ts b/siloLapisTests/test/details.spec.ts index e5581c476..84f37a80f 100644 --- a/siloLapisTests/test/details.spec.ts +++ b/siloLapisTests/test/details.spec.ts @@ -74,8 +74,8 @@ describe('The /details endpoint', () => { it('should apply limit and offset', async () => { const resultWithLimit = await lapisClient.postDetails1({ detailsPostRequest: { - orderBy: [{ field: 'gisaid_epi_isl', type: 'ascending' }], - fields: ['gisaid_epi_isl'], + orderBy: [{ field: 'key', type: 'ascending' }], + fields: ['key'], limit: 2, }, }); @@ -85,8 +85,8 @@ describe('The /details endpoint', () => { const resultWithLimitAndOffset = await lapisClient.postDetails1({ detailsPostRequest: { - orderBy: [{ field: 'gisaid_epi_isl', type: 'ascending' }], - fields: ['gisaid_epi_isl'], + orderBy: [{ field: 'key', type: 'ascending' }], + fields: ['key'], limit: 2, offset: 1, }, @@ -98,8 +98,8 @@ describe('The /details endpoint', () => { it('should return the data as CSV', async () => { const urlParams = new URLSearchParams({ - fields: 'gisaid_epi_isl,pangoLineage,division', - orderBy: 'gisaid_epi_isl', + fields: 'key,pangoLineage,division', + orderBy: 'key', limit: '3', dataFormat: 'csv', }); @@ -108,18 +108,18 @@ describe('The /details endpoint', () => { expect(await result.text()).to.be.equal( String.raw` -division,gisaid_epi_isl,pangoLineage -Vaud,EPI_ISL_1001493,B.1.177.44 -Bern,EPI_ISL_1001920,B.1.177 -Solothurn,EPI_ISL_1002052,B.1 +division,key,pangoLineage +Vaud,key_1001493,B.1.177.44 +Bern,key_1001920,B.1.177 +Solothurn,key_1002052,B.1 `.trim() ); }); it('should return the data as TSV', async () => { const urlParams = new URLSearchParams({ - fields: 'gisaid_epi_isl,pangoLineage,division', - orderBy: 'gisaid_epi_isl', + fields: 'key,pangoLineage,division', + orderBy: 'key', limit: '3', dataFormat: 'tsv', }); @@ -128,10 +128,10 @@ Solothurn,EPI_ISL_1002052,B.1 expect(await result.text()).to.be.equal( String.raw` -division gisaid_epi_isl pangoLineage -Vaud EPI_ISL_1001493 B.1.177.44 -Bern EPI_ISL_1001920 B.1.177 -Solothurn EPI_ISL_1002052 B.1 +division key pangoLineage +Vaud key_1001493 B.1.177.44 +Bern key_1001920 B.1.177 +Solothurn key_1002052 B.1 `.trim() ); }); diff --git a/siloLapisTests/testData/small_metadata_set.tsv b/siloLapisTests/testData/small_metadata_set.tsv index 510847594..680f8597e 100644 --- a/siloLapisTests/testData/small_metadata_set.tsv +++ b/siloLapisTests/testData/small_metadata_set.tsv @@ -1,101 +1,101 @@ -gisaid_epi_isl pangoLineage date region country division unsorted_date age qc_value insertions aaInsertions -EPI_ISL_1408408 B.1.1.7 2021-03-18 Europe Switzerland Basel-Land 4 0.98 S:214:EPE -EPI_ISL_1749899 B.1.1.7 2021-04-13 Europe Switzerland Bern 2020-03-08 5 0.97 -EPI_ISL_2016901 B.1.1.7 2021-04-25 Europe Switzerland Aargau 2021-01-29 6 0.96 -EPI_ISL_1749892 B.1.1.7 2021-04-13 Europe Switzerland Bern 2020-12-24 4 0.95 -EPI_ISL_1597932 B.1.1.7 2021-03-19 Europe Switzerland Solothurn 2021-02-10 54 0.94 S:214:EPE -EPI_ISL_1407962 B.1.1.7 Europe Switzerland Solothurn 2021-01-16 55 0.93 -EPI_ISL_1750503 B.1.258.17 2020-12-24 Europe Switzerland Zürich 2021-02-14 56 0.92 -EPI_ISL_1360935 B.1.1.7 2021-03-08 Europe Switzerland Jura 2021-01-03 57 0.91 -EPI_ISL_2019235 B.1.1.7 2021-04-28 Europe Switzerland Basel-Stadt 2021-01-22 58 0.90 -EPI_ISL_1749960 B.1.1.7 2021-04-15 Europe Switzerland Basel-Land 2021-02-03 59 0.89 -EPI_ISL_1361468 B.1.1.7 2021-03-06 Europe Switzerland Zürich 2021-01-20 50 0.98 -EPI_ISL_1408062 B.1.1.7 2021-03-03 Europe Switzerland Valais 2020-11-24 50 0.97 22204:CAGAA -EPI_ISL_1597890 B.1.1.7 2021-03-21 Switzerland Vaud 2021-01-25 51 0.96 22339:GCTGGT -EPI_ISL_1682849 XA.1 2020-12-17 Europe Switzerland Thurgau 2021-01-21 52 0.95 -EPI_ISL_1408805 B.1.221 2020-11-24 Europe Switzerland Schwyz 2020-12-09 53 0.94 -EPI_ISL_1750868 B.1.1.189 2020-12-15 Europe Switzerland Solothurn 2021-01-20 54 0.93 S:214:EPE -EPI_ISL_2019350 B.1.1.7 2021-04-27 Europe Switzerland Valais 2020-12-21 55 0.92 -EPI_ISL_2017036 B.1.1.7 2021-04-23 Europe Switzerland Solothurn 2021-03-09 56 0.91 -EPI_ISL_1599113 B.1.1.39 2020-12-08 Europe Switzerland Zürich 2021-03-05 57 0.90 -EPI_ISL_2214128 B.1.1.7 2021-05-10 Europe Switzerland Geneva 2020-11-13 58 0.89 -EPI_ISL_2408472 B.1.1.7 2021-05-25 Europe Switzerland Obwalden 2021-03-02 59 0.98 -EPI_ISL_830864 B.1.177 2020-10-08 Europe Switzerland Basel-Stadt 2021-03-03 50 0.97 -EPI_ISL_581968 B.1.160 2020-08-17 Europe Switzerland Basel-Stadt 2021-03-25 50 0.96 S:214:EPE -EPI_ISL_2213804 Q.7 2021-05-08 Europe Switzerland Geneva 2021-04-12 51 25701:CCC -EPI_ISL_2405276 B.1.1.7 2021-05-24 Europe Switzerland Vaud 2021-04-28 52 0.94 -EPI_ISL_2213934 B.1.1.7 2021-05-13 Europe Switzerland Geneva 2021-04-23 53 0.93 -EPI_ISL_2213984 B.1.1.7 2021-05-08 Europe Switzerland Geneva 2021-05-09 54 0.92 25701:CCC -EPI_ISL_2574088 B.1.1.7 2021-06-10 Europe Switzerland Sankt Gallen 2021-05-05 55 0.91 25701:CCC -EPI_ISL_2544226 B.1.1.7 2021-06-05 Europe Switzerland Ticino 2021-05-12 56 0.90 -EPI_ISL_2360326 Q.7 2021-05-23 Europe Switzerland Ticino 2021-03-10 57 0.89 -EPI_ISL_2379651 B.1.1.7 2021-05-11 Europe Switzerland Valais 2021-06-01 58 0.98 -EPI_ISL_1036103 B.1.258 2020-12-09 Europe Switzerland Aargau 2021-06-03 59 0.97 -EPI_ISL_931279 B.1.1 2020-10-28 Europe Switzerland Basel-Stadt 2021-05-11 50 0.96 -EPI_ISL_931031 B.1.177 2020-10-22 Europe Switzerland Basel-Stadt 2021-05-10 50 0.95 -EPI_ISL_1273458 B.1.1.7 2021-01-26 Europe Switzerland Basel-Land 2021-05-18 51 0.94 25701:CCC -EPI_ISL_1273715 B.1.160 2021-01-20 Europe Switzerland Basel-Stadt 2021-05-08 52 0.93 -EPI_ISL_737604 B.1.1 2020-12-14 Europe Switzerland Bern 2021-05-14 53 0.92 -EPI_ISL_1129663 B.1.1.7 2020-12-29 Europe Switzerland Bern 2021-05-07 54 0.91 -EPI_ISL_1003629 B.1.1.39 2021-01-25 Europe Switzerland Aargau 2021-05-18 55 0.90 S:214:EPE -EPI_ISL_737715 B.1.177 2020-12-13 Europe Switzerland Bern 2021-05-16 56 0.89 S:247:SGE -EPI_ISL_1003036 B.1.177 2021-01-16 Europe Switzerland Aargau 2021-07-14 57 0.98 5959:TAT -EPI_ISL_899762 B.1.177 2020-12-25 Europe Switzerland Schwyz 2021-07-19 58 0.97 -EPI_ISL_899725 B.1.177 2021-01-12 Europe Switzerland Solothurn 2021-07-14 59 0.96 S:210:IV -EPI_ISL_1195052 B.1.1.7 2021-02-23 Europe Switzerland Solothurn 2021-07-04 50 0.95 -EPI_ISL_1003519 B.1.160.16 2021-01-22 Europe Switzerland 2021-07-29 50 0.94 -EPI_ISL_1003010 B.1.36.35 2021-01-15 Europe Switzerland Solothurn 2021-07-19 51 0.93 -EPI_ISL_1119584 B.1.1 2020-11-04 Europe Switzerland Solothurn 2021-07-05 52 0.92 -EPI_ISL_1002052 B.1 2021-01-15 Europe Switzerland Solothurn 2021-07-15 53 0.91 -EPI_ISL_466942 B.1 2020-03-08 Europe Switzerland Basel-Stadt 2021-05-12 54 0.90 -EPI_ISL_1003849 B.1.160 2021-01-29 Europe Switzerland Neuchâtel 2021-08-05 55 0.89 -EPI_ISL_768148 GD.1 2020-12-24 Europe Switzerland Sankt Gallen 2020-03-16 56 0.98 25701:CCC -EPI_ISL_1080536 B.1.1.7 2021-02-10 Europe Switzerland Basel-Land 2021-08-04 57 0.97 -EPI_ISL_1002156 B.1.221 2021-01-16 Europe Switzerland Basel-Land 2021-02-03 58 0.96 -EPI_ISL_1119315 B.1.1.7 2021-02-14 Europe Switzerland Graubünden 2021-03-18 59 0.95 -EPI_ISL_1004495 B.1.177.44 2021-01-03 Europe Switzerland 2021-04-13 50 0.94 25701:CCC -EPI_ISL_1001920 B.1.177 2021-01-22 Europe Switzerland Bern 2021-04-25 50 0.93 -EPI_ISL_1131102 B.1.160 2021-02-03 Europe Switzerland Zürich 2021-04-13 51 0.92 -EPI_ISL_1003373 B.1.177 2021-01-20 Europe Switzerland Zürich 2021-03-19 52 0.91 -EPI_ISL_721941 B.1.1.70 2020-11-24 Europe Switzerland Zürich 2021-03-15 53 0.90 -EPI_ISL_1130868 B.1.525 2021-01-25 Europe Switzerland Zürich 2020-12-24 54 0.89 25701:CCC -EPI_ISL_1003425 B.1.177 2021-01-21 Europe Switzerland Uri 2021-03-08 55 0.98 -EPI_ISL_737860 B.1.160 2020-12-09 Europe Switzerland Valais 2021-04-28 56 0.97 -EPI_ISL_1001493 B.1.177.44 2021-01-20 Europe Switzerland Vaud 2021-04-15 57 0.96 -EPI_ISL_1260480 B.1.160 2020-12-21 Europe Switzerland Zürich 2021-03-06 58 0.95 -EPI_ISL_1747885 B.1.1.7 2021-03-09 Europe Switzerland Solothurn 2021-03-03 59 0.94 -EPI_ISL_1747752 B.1.1.7 2021-03-05 Europe Switzerland Basel-Land 2021-03-21 50 0.93 -EPI_ISL_1005148 B.1.221 2020-11-13 Europe Switzerland Solothurn 2020-12-17 50 0.92 25701:CCC -EPI_ISL_1748243 B.1.1.7 2021-03-02 Europe Switzerland Solothurn 2020-11-24 0.91 -EPI_ISL_1748215 B.1.1.7 2021-03-03 Europe Switzerland Solothurn 2020-12-15 52 0.90 -EPI_ISL_1748395 B.1.1.7 2021-03-25 Europe Switzerland Basel-Stadt 2021-04-27 53 0.89 -EPI_ISL_1760534 B.1.1.7 2021-04-12 Europe Switzerland Ticino 2021-04-23 54 0.98 -EPI_ISL_2086867 C.36.3 2021-04-28 Europe Switzerland Zürich 2020-12-08 55 0.97 25701:CCC -EPI_ISL_1840634 Q.7 2021-04-23 Europe Switzerland Ticino 2021-05-10 56 0.96 -EPI_ISL_2180995 B.1.1.7 2021-05-09 Europe Switzerland Basel-Stadt 2021-05-25 57 0.95 -EPI_ISL_2181005 B.1.1.7 2021-05-05 Europe Switzerland Basel-Stadt 2020-10-08 58 0.94 -EPI_ISL_2180023 B.1.1.7 2021-05-12 Europe Switzerland Ticino 2020-08-17 59 0.93 25701:CCC -EPI_ISL_2270139 B.1.1.7 2021-03-10 Europe Switzerland Basel-Stadt 2021-05-08 50 0.92 -EPI_ISL_2544452 B.1.1.7 2021-06-01 Europe Switzerland Schwyz 2021-05-24 50 0.91 -EPI_ISL_2544332 B.1.1.7 2021-06-03 Europe Switzerland Bern 2021-05-13 51 0.90 25701:CCC -EPI_ISL_2307766 B.1.1.7 2021-05-11 Europe Switzerland Bern 2021-05-08 52 0.89 -EPI_ISL_2375490 B.1.1.7 2021-05-10 Europe Switzerland Valais 2021-06-10 53 0.98 -EPI_ISL_2374969 B.1.1.7 2021-05-18 Europe Switzerland Aargau 2021-06-05 54 0.97 25701:CCC -EPI_ISL_2307888 B.1.1.7 2021-05-08 Europe Switzerland Solothurn 2021-05-23 55 0.96 -EPI_ISL_2375247 B.1.1.7 2021-05-14 Europe Switzerland Sankt Gallen 2021-05-11 56 25701:CCC -EPI_ISL_2308054 B.1.1.7 2021-05-07 Europe Switzerland Zürich 2020-12-09 57 0.94 -EPI_ISL_2375165 B.1.1.7 2021-05-18 Europe Switzerland Basel-Land 2020-10-28 58 0.93 -EPI_ISL_2375097 B.1.1.7 2021-05-16 Europe Switzerland Basel-Land 2020-10-22 59 0.92 -EPI_ISL_3128737 AY.9.2 2021-07-14 Europe Switzerland Zürich 2021-01-26 50 0.91 -EPI_ISL_3128811 B.1.617.2 2021-07-19 Europe Switzerland Aargau 2021-01-20 50 0.90 -EPI_ISL_3086369 AY.122 2021-07-14 Europe Switzerland Ticino 2020-12-14 51 0.89 25701:CCC -EPI_ISL_3259931 AY.43 2021-07-04 Europe Switzerland Vaud 2020-12-29 52 0.98 S:143:T,ORF1a:3602:FEP -EPI_ISL_3267832 AY.43 2021-07-29 Europe Switzerland Bern 2021-01-25 53 0.97 -EPI_ISL_3128796 B.1.617.2 2021-07-19 Europe Switzerland Zürich 2020-12-13 54 0.96 25701:CCC -EPI_ISL_3016465 B.1.1.7 2021-07-05 Europe Switzerland Valais 2021-01-16 0.95 -EPI_ISL_3247294 2021-07-15 Europe Switzerland Basel-Stadt 2020-12-25 56 0.94 -EPI_ISL_3578231 P.1 2021-05-12 Europe Switzerland Zürich 2021-01-12 57 0.93 25701:CCC,5959:TAT -EPI_ISL_3465732 AY.43 2021-08-05 Europe Switzerland Vaud 2021-02-23 58 0.92 -EPI_ISL_2367431 B.1 2020-03-16 Europe Switzerland Vaud 2021-01-22 59 0.91 -EPI_ISL_3465556 AY.43 2021-08-04 Europe Switzerland Solothurn 2021-01-15 50 0.90 -EPI_ISL_2359636 B.1.1.189 2021-02-03 Europe Switzerland Vaud 2020-11-04 57 0.89 25701:CCC ORF1a:3602:F +key pangoLineage date region country division unsorted_date age qc_value insertions aaInsertions +key_1408408 B.1.1.7 2021-03-18 Europe Switzerland Basel-Land 4 0.98 S:214:EPE +key_1749899 B.1.1.7 2021-04-13 Europe Switzerland Bern 2020-03-08 5 0.97 +key_2016901 B.1.1.7 2021-04-25 Europe Switzerland Aargau 2021-01-29 6 0.96 +key_1749892 B.1.1.7 2021-04-13 Europe Switzerland Bern 2020-12-24 4 0.95 +key_1597932 B.1.1.7 2021-03-19 Europe Switzerland Solothurn 2021-02-10 54 0.94 S:214:EPE +key_1407962 B.1.1.7 Europe Switzerland Solothurn 2021-01-16 55 0.93 +key_1750503 B.1.258.17 2020-12-24 Europe Switzerland Zürich 2021-02-14 56 0.92 +key_1360935 B.1.1.7 2021-03-08 Europe Switzerland Jura 2021-01-03 57 0.91 +key_2019235 B.1.1.7 2021-04-28 Europe Switzerland Basel-Stadt 2021-01-22 58 0.90 +key_1749960 B.1.1.7 2021-04-15 Europe Switzerland Basel-Land 2021-02-03 59 0.89 +key_1361468 B.1.1.7 2021-03-06 Europe Switzerland Zürich 2021-01-20 50 0.98 +key_1408062 B.1.1.7 2021-03-03 Europe Switzerland Valais 2020-11-24 50 0.97 22204:CAGAA +key_1597890 B.1.1.7 2021-03-21 Switzerland Vaud 2021-01-25 51 0.96 22339:GCTGGT +key_1682849 XA.1 2020-12-17 Europe Switzerland Thurgau 2021-01-21 52 0.95 +key_1408805 B.1.221 2020-11-24 Europe Switzerland Schwyz 2020-12-09 53 0.94 +key_1750868 B.1.1.189 2020-12-15 Europe Switzerland Solothurn 2021-01-20 54 0.93 S:214:EPE +key_2019350 B.1.1.7 2021-04-27 Europe Switzerland Valais 2020-12-21 55 0.92 +key_2017036 B.1.1.7 2021-04-23 Europe Switzerland Solothurn 2021-03-09 56 0.91 +key_1599113 B.1.1.39 2020-12-08 Europe Switzerland Zürich 2021-03-05 57 0.90 +key_2214128 B.1.1.7 2021-05-10 Europe Switzerland Geneva 2020-11-13 58 0.89 +key_2408472 B.1.1.7 2021-05-25 Europe Switzerland Obwalden 2021-03-02 59 0.98 +key_830864 B.1.177 2020-10-08 Europe Switzerland Basel-Stadt 2021-03-03 50 0.97 +key_581968 B.1.160 2020-08-17 Europe Switzerland Basel-Stadt 2021-03-25 50 0.96 S:214:EPE +key_2213804 Q.7 2021-05-08 Europe Switzerland Geneva 2021-04-12 51 25701:CCC +key_2405276 B.1.1.7 2021-05-24 Europe Switzerland Vaud 2021-04-28 52 0.94 +key_2213934 B.1.1.7 2021-05-13 Europe Switzerland Geneva 2021-04-23 53 0.93 +key_2213984 B.1.1.7 2021-05-08 Europe Switzerland Geneva 2021-05-09 54 0.92 25701:CCC +key_2574088 B.1.1.7 2021-06-10 Europe Switzerland Sankt Gallen 2021-05-05 55 0.91 25701:CCC +key_2544226 B.1.1.7 2021-06-05 Europe Switzerland Ticino 2021-05-12 56 0.90 +key_2360326 Q.7 2021-05-23 Europe Switzerland Ticino 2021-03-10 57 0.89 +key_2379651 B.1.1.7 2021-05-11 Europe Switzerland Valais 2021-06-01 58 0.98 +key_1036103 B.1.258 2020-12-09 Europe Switzerland Aargau 2021-06-03 59 0.97 +key_931279 B.1.1 2020-10-28 Europe Switzerland Basel-Stadt 2021-05-11 50 0.96 +key_931031 B.1.177 2020-10-22 Europe Switzerland Basel-Stadt 2021-05-10 50 0.95 +key_1273458 B.1.1.7 2021-01-26 Europe Switzerland Basel-Land 2021-05-18 51 0.94 25701:CCC +key_1273715 B.1.160 2021-01-20 Europe Switzerland Basel-Stadt 2021-05-08 52 0.93 +key_737604 B.1.1 2020-12-14 Europe Switzerland Bern 2021-05-14 53 0.92 +key_1129663 B.1.1.7 2020-12-29 Europe Switzerland Bern 2021-05-07 54 0.91 +key_1003629 B.1.1.39 2021-01-25 Europe Switzerland Aargau 2021-05-18 55 0.90 S:214:EPE +key_737715 B.1.177 2020-12-13 Europe Switzerland Bern 2021-05-16 56 0.89 S:247:SGE +key_1003036 B.1.177 2021-01-16 Europe Switzerland Aargau 2021-07-14 57 0.98 5959:TAT +key_899762 B.1.177 2020-12-25 Europe Switzerland Schwyz 2021-07-19 58 0.97 +key_899725 B.1.177 2021-01-12 Europe Switzerland Solothurn 2021-07-14 59 0.96 S:210:IV +key_1195052 B.1.1.7 2021-02-23 Europe Switzerland Solothurn 2021-07-04 50 0.95 +key_1003519 B.1.160.16 2021-01-22 Europe Switzerland 2021-07-29 50 0.94 +key_1003010 B.1.36.35 2021-01-15 Europe Switzerland Solothurn 2021-07-19 51 0.93 +key_1119584 B.1.1 2020-11-04 Europe Switzerland Solothurn 2021-07-05 52 0.92 +key_1002052 B.1 2021-01-15 Europe Switzerland Solothurn 2021-07-15 53 0.91 +key_466942 B.1 2020-03-08 Europe Switzerland Basel-Stadt 2021-05-12 54 0.90 +key_1003849 B.1.160 2021-01-29 Europe Switzerland Neuchâtel 2021-08-05 55 0.89 +key_768148 GD.1 2020-12-24 Europe Switzerland Sankt Gallen 2020-03-16 56 0.98 25701:CCC +key_1080536 B.1.1.7 2021-02-10 Europe Switzerland Basel-Land 2021-08-04 57 0.97 +key_1002156 B.1.221 2021-01-16 Europe Switzerland Basel-Land 2021-02-03 58 0.96 +key_1119315 B.1.1.7 2021-02-14 Europe Switzerland Graubünden 2021-03-18 59 0.95 +key_1004495 B.1.177.44 2021-01-03 Europe Switzerland 2021-04-13 50 0.94 25701:CCC +key_1001920 B.1.177 2021-01-22 Europe Switzerland Bern 2021-04-25 50 0.93 +key_1131102 B.1.160 2021-02-03 Europe Switzerland Zürich 2021-04-13 51 0.92 +key_1003373 B.1.177 2021-01-20 Europe Switzerland Zürich 2021-03-19 52 0.91 +key_721941 B.1.1.70 2020-11-24 Europe Switzerland Zürich 2021-03-15 53 0.90 +key_1130868 B.1.525 2021-01-25 Europe Switzerland Zürich 2020-12-24 54 0.89 25701:CCC +key_1003425 B.1.177 2021-01-21 Europe Switzerland Uri 2021-03-08 55 0.98 +key_737860 B.1.160 2020-12-09 Europe Switzerland Valais 2021-04-28 56 0.97 +key_1001493 B.1.177.44 2021-01-20 Europe Switzerland Vaud 2021-04-15 57 0.96 +key_1260480 B.1.160 2020-12-21 Europe Switzerland Zürich 2021-03-06 58 0.95 +key_1747885 B.1.1.7 2021-03-09 Europe Switzerland Solothurn 2021-03-03 59 0.94 +key_1747752 B.1.1.7 2021-03-05 Europe Switzerland Basel-Land 2021-03-21 50 0.93 +key_1005148 B.1.221 2020-11-13 Europe Switzerland Solothurn 2020-12-17 50 0.92 25701:CCC +key_1748243 B.1.1.7 2021-03-02 Europe Switzerland Solothurn 2020-11-24 0.91 +key_1748215 B.1.1.7 2021-03-03 Europe Switzerland Solothurn 2020-12-15 52 0.90 +key_1748395 B.1.1.7 2021-03-25 Europe Switzerland Basel-Stadt 2021-04-27 53 0.89 +key_1760534 B.1.1.7 2021-04-12 Europe Switzerland Ticino 2021-04-23 54 0.98 +key_2086867 C.36.3 2021-04-28 Europe Switzerland Zürich 2020-12-08 55 0.97 25701:CCC +key_1840634 Q.7 2021-04-23 Europe Switzerland Ticino 2021-05-10 56 0.96 +key_2180995 B.1.1.7 2021-05-09 Europe Switzerland Basel-Stadt 2021-05-25 57 0.95 +key_2181005 B.1.1.7 2021-05-05 Europe Switzerland Basel-Stadt 2020-10-08 58 0.94 +key_2180023 B.1.1.7 2021-05-12 Europe Switzerland Ticino 2020-08-17 59 0.93 25701:CCC +key_2270139 B.1.1.7 2021-03-10 Europe Switzerland Basel-Stadt 2021-05-08 50 0.92 +key_2544452 B.1.1.7 2021-06-01 Europe Switzerland Schwyz 2021-05-24 50 0.91 +key_2544332 B.1.1.7 2021-06-03 Europe Switzerland Bern 2021-05-13 51 0.90 25701:CCC +key_2307766 B.1.1.7 2021-05-11 Europe Switzerland Bern 2021-05-08 52 0.89 +key_2375490 B.1.1.7 2021-05-10 Europe Switzerland Valais 2021-06-10 53 0.98 +key_2374969 B.1.1.7 2021-05-18 Europe Switzerland Aargau 2021-06-05 54 0.97 25701:CCC +key_2307888 B.1.1.7 2021-05-08 Europe Switzerland Solothurn 2021-05-23 55 0.96 +key_2375247 B.1.1.7 2021-05-14 Europe Switzerland Sankt Gallen 2021-05-11 56 25701:CCC +key_2308054 B.1.1.7 2021-05-07 Europe Switzerland Zürich 2020-12-09 57 0.94 +key_2375165 B.1.1.7 2021-05-18 Europe Switzerland Basel-Land 2020-10-28 58 0.93 +key_2375097 B.1.1.7 2021-05-16 Europe Switzerland Basel-Land 2020-10-22 59 0.92 +key_3128737 AY.9.2 2021-07-14 Europe Switzerland Zürich 2021-01-26 50 0.91 +key_3128811 B.1.617.2 2021-07-19 Europe Switzerland Aargau 2021-01-20 50 0.90 +key_3086369 AY.122 2021-07-14 Europe Switzerland Ticino 2020-12-14 51 0.89 25701:CCC +key_3259931 AY.43 2021-07-04 Europe Switzerland Vaud 2020-12-29 52 0.98 S:143:T,ORF1a:3602:FEP +key_3267832 AY.43 2021-07-29 Europe Switzerland Bern 2021-01-25 53 0.97 +key_3128796 B.1.617.2 2021-07-19 Europe Switzerland Zürich 2020-12-13 54 0.96 25701:CCC +key_3016465 B.1.1.7 2021-07-05 Europe Switzerland Valais 2021-01-16 0.95 +key_3247294 2021-07-15 Europe Switzerland Basel-Stadt 2020-12-25 56 0.94 +key_3578231 P.1 2021-05-12 Europe Switzerland Zürich 2021-01-12 57 0.93 25701:CCC,5959:TAT +key_3465732 AY.43 2021-08-05 Europe Switzerland Vaud 2021-02-23 58 0.92 +key_2367431 B.1 2020-03-16 Europe Switzerland Vaud 2021-01-22 59 0.91 +key_3465556 AY.43 2021-08-04 Europe Switzerland Solothurn 2021-01-15 50 0.90 +key_2359636 B.1.1.189 2021-02-03 Europe Switzerland Vaud 2020-11-04 57 0.89 25701:CCC ORF1a:3602:F diff --git a/siloLapisTests/testData/testDatabaseConfig.yaml b/siloLapisTests/testData/testDatabaseConfig.yaml index 3bd20d6d4..33119b810 100644 --- a/siloLapisTests/testData/testDatabaseConfig.yaml +++ b/siloLapisTests/testData/testDatabaseConfig.yaml @@ -2,7 +2,7 @@ schema: instanceName: sars_cov-2_minimal_test_config opennessLevel: OPEN metadata: - - name: gisaid_epi_isl + - name: key type: string - name: date type: date @@ -27,6 +27,6 @@ schema: type: aaInsertion features: - name: sarsCoV2VariantQuery - primaryKey: gisaid_epi_isl + primaryKey: key dateToSortBy: date partitionBy: pangoLineage