Skip to content

Commit 6350a6d

Browse files
committed
fix(filters): quotation mark escaping for textual values
1 parent 7437aa6 commit 6350a6d

File tree

3 files changed

+13
-3
lines changed

3 files changed

+13
-3
lines changed

client/src/commonMain/kotlin/com/algolia/search/model/filter/internal/Filter.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import com.algolia.search.model.Attribute
44
import com.algolia.search.model.filter.Filter
55
import com.algolia.search.model.filter.NumericOperator
66

7-
internal fun String.escape() = "\"$this\""
7+
internal fun String.escape() = "\"${this.escapeQuotation()}\""
8+
internal fun String.escapeQuotation() = this.replace("\"", "\\\"")
89

910
internal fun Attribute.escape() = raw.escape()
1011

@@ -93,7 +94,7 @@ internal fun Filter.Numeric.toLegacy(escape: Boolean): List<String> {
9394

9495
internal fun Filter.Facet.Value.toLegacy(isNegated: Boolean, escape: Boolean): String {
9596
val value = when (this) {
96-
is Filter.Facet.Value.String -> if (escape) raw.escape() else raw
97+
is Filter.Facet.Value.String -> if (escape) raw.escape() else raw.escapeQuotation()
9798
is Filter.Facet.Value.Number -> raw.toString()
9899
is Filter.Facet.Value.Boolean -> raw.toString()
99100
}
@@ -109,7 +110,7 @@ internal fun Filter.Facet.toLegacy(escape: Boolean): List<String> {
109110
}
110111

111112
internal fun Filter.Tag.toLegacy(escape: Boolean): List<String> {
112-
val raw = if (escape) value.escape() else value
113+
val raw = if (escape) value.escape() else value.escapeQuotation()
113114
val value = if (isNegated) "-$raw" else raw
114115

115116
return listOf(value)

client/src/commonTest/kotlin/model/filter/TestFilterFacetString.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ internal class TestFilterFacetString {
1212
private val filterNegate = !Filter.Facet(attributeA, "valueA")
1313
private val filterSpace = Filter.Facet(attributeA, "value with space")
1414
private val filterScore = Filter.Facet(attributeA, "valueA", 1)
15+
private val filterQuotation = Filter.Facet(attributeA, "45\"-50\" tv\'s")
1516

1617
@Test
1718
fun sql() {
1819
FilterConverter.SQL(filter) shouldEqual "\"attributeA\":\"valueA\""
1920
FilterConverter.SQL(filterNegate) shouldEqual "NOT \"attributeA\":\"valueA\""
2021
FilterConverter.SQL(filterSpace) shouldEqual "\"attributeA\":\"value with space\""
2122
FilterConverter.SQL(filterScore) shouldEqual "\"attributeA\":\"valueA\"<score=1>"
23+
FilterConverter.SQL(filterQuotation) shouldEqual "\"attributeA\":\"45\\\"-50\\\" tv's\""
2224
}
2325

2426
@Test
@@ -27,6 +29,7 @@ internal class TestFilterFacetString {
2729
FilterConverter.Legacy(filterNegate) shouldEqual listOf("\"attributeA\":-\"valueA\"")
2830
FilterConverter.Legacy(filterSpace) shouldEqual listOf("\"attributeA\":\"value with space\"")
2931
FilterConverter.Legacy(filterScore) shouldEqual listOf("\"attributeA\":\"valueA\"<score=1>")
32+
FilterConverter.Legacy(filterQuotation) shouldEqual listOf("\"attributeA\":\"45\\\"-50\\\" tv's\"")
3033
}
3134

3235
@Test
@@ -35,5 +38,6 @@ internal class TestFilterFacetString {
3538
FilterConverter.Legacy.Unquoted(filterNegate) shouldEqual listOf("attributeA:-valueA")
3639
FilterConverter.Legacy.Unquoted(filterSpace) shouldEqual listOf("attributeA:value with space")
3740
FilterConverter.Legacy.Unquoted(filterScore) shouldEqual listOf("attributeA:valueA<score=1>")
41+
FilterConverter.Legacy.Unquoted(filterQuotation) shouldEqual listOf("attributeA:45\\\"-50\\\" tv's")
3842
}
3943
}

client/src/commonTest/kotlin/model/filter/TestFilterTag.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@ import kotlin.test.Test
88
internal class TestFilterTag {
99

1010
private val filter = Filter.Tag("valueA")
11+
private val filterQuotation = Filter.Tag("45\"-50\" tv\'s")
1112

1213
@Test
1314
fun sql() {
1415
FilterConverter.SQL(filter) shouldEqual "_tags:\"valueA\""
1516
FilterConverter.SQL(!filter) shouldEqual "NOT _tags:\"valueA\""
17+
FilterConverter.SQL(filterQuotation) shouldEqual "_tags:\"45\\\"-50\\\" tv\'s\""
1618
}
1719

1820
@Test
1921
fun legacy() {
2022
FilterConverter.Legacy(filter) shouldEqual listOf("\"valueA\"")
2123
FilterConverter.Legacy(!filter) shouldEqual listOf("-\"valueA\"")
24+
FilterConverter.Legacy(!filter) shouldEqual listOf("-\"valueA\"")
25+
FilterConverter.Legacy(filterQuotation) shouldEqual listOf("\"45\\\"-50\\\" tv\'s\"")
2226
}
2327

2428
@Test
2529
fun legacyUnquoted() {
2630
FilterConverter.Legacy.Unquoted(filter) shouldEqual listOf("valueA")
2731
FilterConverter.Legacy.Unquoted(!filter) shouldEqual listOf("-valueA")
32+
FilterConverter.Legacy.Unquoted(filterQuotation) shouldEqual listOf("45\\\"-50\\\" tv\'s")
2833
}
2934
}

0 commit comments

Comments
 (0)