Skip to content

Commit 1e30fde

Browse files
committed
Decode and re-encode and/or queries to fix double escaping
1 parent 9799984 commit 1e30fde

File tree

11 files changed

+106
-71
lines changed

11 files changed

+106
-71
lines changed

templates/android/library/src/main/java/io/appwrite/Query.kt.twig

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,9 @@ class Query(
5151

5252
fun contains(attribute: String, value: Any) = Query("contains", attribute, parseValue(value)).toJson()
5353

54-
fun or(queries: List<String>): String {
55-
val queryObjects = mutableListOf<Query>()
56-
for(query in queries) {
57-
queryObjects.add(query.fromJson())
58-
}
59-
return Query("or", null, queryObjects).toJson()
60-
}
54+
fun or(queries: List<String>) = Query("or", null, queries.map { it.fromJson<Query>() }).toJson()
6155

62-
fun and(queries: List<String>): String {
63-
val queryObjects = mutableListOf<Query>()
64-
for(query in queries) {
65-
queryObjects.add(query.fromJson())
66-
}
67-
return Query("and", null, queryObjects).toJson()
68-
}
56+
fun and(queries: List<String>) = Query("and", null, queries.map { it.fromJson<Query>() }).toJson()
6957

7058
private fun parseValue(value: Any): List<Any> {
7159
return when (value) {

templates/dart/lib/query.dart.twig

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,16 @@ class Query {
7878
static string endsWith(String attribute, String value) =>
7979
Query._('endsWith', attribute, value).toJson();
8080

81-
/// Filter resouorces where [attribute] contains [value]
81+
/// Filter resources where [attribute] contains [value]
8282
/// [value] can be a single value or a list.
8383
static string contains(String attribute, dynamic value) =>
8484
Query._('contains', attribute, value).toJson();
8585

86-
static string or(List<Query> queries) => Query._('or', null, queries).toJson();
86+
static string or(List<string> queries) =>
87+
Query._('and', null, queries.map((query) => jsonDecode(query)).toList()).toJson();
8788

88-
static string and(List<Query> queries) => Query._('and', null, queries).toJson();
89+
static string and(List<string> queries) =>
90+
Query._('and', null, queries.map((query) => jsonDecode(query)).toList()).toJson();
8991

9092
/// Specify which attributes should be returned by the API call.
9193
static string select(List<String> attributes) =>

templates/deno/src/query.ts.twig

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,17 @@ export class Query {
9494
static contains = (attribute: string, value: string | string[]): string =>
9595
new Query("contains", attribute, value).toString();
9696

97-
static or = (...queries: Query[]) => {
98-
return new Query(
99-
"or",
100-
undefined,
101-
queries
102-
).toString();
103-
};
104-
105-
static and = (...queries: Query[]) => {
106-
return new Query(
107-
"and",
108-
undefined,
109-
queries
110-
).toString();
111-
};
97+
static or = (...queries: string[]) =>
98+
new Query(
99+
"or",
100+
undefined,
101+
queries.map((query) => JSON.parse(query))
102+
).toString();
103+
104+
static and = (...queries: string[]) =>
105+
new Query(
106+
"and",
107+
undefined,
108+
queries.map((query) => JSON.parse(query))
109+
).toString();
112110
}

templates/dotnet/src/Appwrite/Query.cs.twig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,12 @@ namespace Appwrite
134134
return new Query("contains", attribute, value).ToString();
135135
}
136136

137-
public static string Or(List<Query> queries) {
138-
return new Query("or", null, queries).ToString();
137+
public static string Or(List<string> queries) {
138+
return new Query("or", null, queries.Select(q => JsonConvert.DeserializeObject<Query>(q)).ToList()).ToString();
139139
}
140140

141-
public static string And(List<Query> queries) {
142-
return new Query("and", null, queries).ToString();
141+
public static string And(List<string> queries) {
142+
return new Query("and", null, queries.Select(q => JsonConvert.DeserializeObject<Query>(q)).ToList()).ToString();
143143
}
144144
}
145145
}

templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package {{ sdk.namespace | caseDot }}
22

33
import {{ sdk.namespace | caseDot }}.extensions.toJson
4+
import {{ sdk.namespace | caseDot }}.extensions.fromJson
45

56
class Query(
67
val method: String,
@@ -12,15 +13,15 @@ class Query(
1213
companion object {
1314
fun equal(attribute: String, value: Any) = Query("equal", attribute, parseValue(value)).toJson()
1415

15-
fun notEqual(attribute: String, value: Any) = Query("notEqual", attribute, listOf(value)).toJson()
16+
fun notEqual(attribute: String, value: Any) = Query("notEqual", attribute, parseValue(value)).toJson()
1617

17-
fun lessThan(attribute: String, value: Any) = Query("lessThan", attribute, listOf(value)).toJson()
18+
fun lessThan(attribute: String, value: Any) = Query("lessThan", attribute, parseValue(value)).toJson()
1819

19-
fun lessThanEqual(attribute: String, value: Any) = Query("lessThanEqual", attribute, listOf(value)).toJson()
20+
fun lessThanEqual(attribute: String, value: Any) = Query("lessThanEqual", attribute, parseValue(value)).toJson()
2021

21-
fun greaterThan(attribute: String, value: Any) = Query("greaterThan", attribute, listOf(value)).toJson()
22+
fun greaterThan(attribute: String, value: Any) = Query("greaterThan", attribute, parseValue(value)).toJson()
2223

23-
fun greaterThanEqual(attribute: String, value: Any) = Query("greaterThanEqual", attribute, listOf(value)).toJson()
24+
fun greaterThanEqual(attribute: String, value: Any) = Query("greaterThanEqual", attribute, parseValue(value)).toJson()
2425

2526
fun search(attribute: String, value: String) = Query("search", attribute, listOf(value)).toJson()
2627

@@ -50,9 +51,9 @@ class Query(
5051

5152
fun contains(attribute: String, value: Any) = Query("contains", attribute, parseValue(value)).toJson()
5253

53-
fun or(queries: List<Query>) = Query("or", null, queries).toJson()
54+
fun or(queries: List<String>) = Query("or", null, queries.map { it.fromJson<Query>() }).toJson()
5455

55-
fun and(queries: List<Query>) = Query("and", null, queries).toJson()
56+
fun and(queries: List<String>) = Query("and", null, queries.map { it.fromJson<Query>() }).toJson()
5657

5758
private fun parseValue(value: Any): List<Any> {
5859
return when (value) {

templates/node/lib/query.js.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ class Query {
7373
new Query("contains", attribute, value).toString()
7474

7575
static or = (...queries) =>
76-
new Query("or", undefined, queries).toString()
76+
new Query("or", undefined, queries.map((query) => JSON.parse(query))).toString()
7777

7878
static and = (...queries) =>
79-
new Query("and", undefined, queries).toString();
79+
new Query("and", undefined, queries.map((query) => JSON.parse(query))).toString();
8080
}
8181

8282
Query.prototype.toString = function () {

templates/php/src/Query.php.twig

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,22 +270,28 @@ class Query implements \JsonSerializable
270270
/**
271271
* Or
272272
*
273-
* @param array<Query> $queries
273+
* @param array<string> $queries
274274
* @return string
275275
*/
276276
public static function or(array $queries): string
277277
{
278+
foreach (&$queries as &$query) {
279+
$query = \json_decode($query, true);
280+
}
278281
return new Query('or', null, $queries).__toString();
279282
}
280283
281284
/**
282285
* And
283286
*
284-
* @param array<Query> $queries
287+
* @param array<string> $queries
285288
* @return string
286289
*/
287290
public static function and(array $queries): string
288291
{
292+
foreach ($queries as &$query) {
293+
$query = \json_decode($query, true);
294+
}
289295
return new Query('and', null, $queries).__toString();
290296
}
291297
}

templates/python/package/query.py.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ class Query():
101101

102102
@staticmethod
103103
def or_queries(queries):
104-
return str(Query("or", None, queries))
104+
return str(Query("or", None, [json.loads(query) for query in queries]))
105105

106106
@staticmethod
107107
def and_queries(queries):
108-
return str(Query("and", None, queries))
108+
return str(Query("and", None, [json.loads(query) for query in queries]))

templates/ruby/lib/container/query.rb.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ module {{spec.title | caseUcfirst}}
109109
end
110110

111111
def or(queries)
112-
return Query.new("or", nil, queries).to_s
112+
return Query.new("or", nil, queries.map { |query| JSON.parse(query) }).to_s
113113
end
114114

115115
def and(queries)
116-
return Query.new("and", nil, queries).to_s
116+
return Query.new("and", nil, queries.map { |query| JSON.parse(query) }).to_s
117117
end
118118
end
119119
end

templates/swift/Sources/Query.swift.twig

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
import Foundation
22

3-
enum QueryValue: Encodable {
3+
enum QueryValue: Codable {
44
case string(String)
55
case int(Int)
66
case double(Double)
77
case bool(Bool)
88
case query(Query)
99

10+
init(from decoder: Decoder) throws {
11+
let container = try decoder.singleValueContainer()
12+
// Attempt to decode each type
13+
if let stringValue = try? container.decode(String.self) {
14+
self = .string(stringValue)
15+
} else if let intValue = try? container.decode(Int.self) {
16+
self = .int(intValue)
17+
} else if let doubleValue = try? container.decode(Double.self) {
18+
self = .double(doubleValue)
19+
} else if let boolValue = try? container.decode(Bool.self) {
20+
self = .bool(boolValue)
21+
} else if let queryValue = try? container.decode(Query.self) {
22+
self = .query(queryValue)
23+
} else {
24+
throw DecodingError.dataCorruptedError(in: container, debugDescription: "QueryValue cannot be decoded")
25+
}
26+
}
27+
1028
func encode(to encoder: Encoder) throws {
1129
var container = encoder.singleValueContainer()
1230
switch self {
@@ -24,7 +42,7 @@ enum QueryValue: Encodable {
2442
}
2543
}
2644

27-
public struct Query : Encodable, CustomStringConvertible {
45+
public struct Query : Codable, CustomStringConvertible {
2846
var method: String
2947
var attribute: String?
3048
var values: [QueryValue]?
@@ -35,6 +53,14 @@ public struct Query : Encodable, CustomStringConvertible {
3553
self.values = Query.convertToQueryValueArray(values)
3654
}
3755

56+
init(from decoder: Decoder) throws {
57+
let container = try decoder.container(keyedBy: CodingKeys.self)
58+
59+
self.method = try container.decode(String.self, forKey: .method)
60+
self.attribute = try container.decodeIfPresent(String.self, forKey: .attribute)
61+
self.values = try container.decodeIfPresent([QueryValue].self, forKey: .values)
62+
}
63+
3864
private static func convertToQueryValueArray(_ values: Any?) -> [QueryValue]? {
3965
switch values {
4066
case let valueArray as [QueryValue]:
@@ -84,13 +110,11 @@ public struct Query : Encodable, CustomStringConvertible {
84110
}
85111

86112
public var description: String {
87-
do {
88-
let data = try JSONEncoder().encode(self)
89-
90-
return String(data: data, encoding: .utf8) ?? ""
91-
} catch {
113+
guard let data = try? JSONEncoder().encode(self) else {
92114
return ""
93115
}
116+
117+
return String(data: data, encoding: .utf8) ?? ""
94118
}
95119

96120
public static func equal(_ attribute: String, value: Any) -> String {
@@ -225,17 +249,17 @@ public struct Query : Encodable, CustomStringConvertible {
225249
}
226250

227251
public static func cursorBefore(_ id: String) -> String {
228-
return Query(
252+
return Query(
229253
method: "cursorBefore",
230254
values: [id]
231255
).description
232256
}
233257

234258
public static func cursorAfter(_ id: String) -> String {
235-
return Query(
236-
method: "cursorAfter",
237-
values: [id]
238-
).description
259+
return Query(
260+
method: "cursorAfter",
261+
values: [id]
262+
).description
239263
}
240264

241265
public static func limit(_ limit: Int) -> String {
@@ -260,17 +284,33 @@ public struct Query : Encodable, CustomStringConvertible {
260284
).description
261285
}
262286

263-
public static func or(_ queries: [Query]) -> String {
264-
return Query(
287+
public static func or(_ queries: [String]) -> String {
288+
let decoder = JSONDecoder()
289+
let decodedQueries = queries.compactMap { queryStr -> Query? in
290+
guard let data = queryStr.data(using: .utf8) else {
291+
return nil
292+
}
293+
return try? decoder.decode(Query.self, from: data)
294+
}
295+
296+
return Query(
265297
method: "or",
266-
values: queries
298+
values: decodedQueries
267299
).description
268300
}
269301

270-
public static func and(_ queries: [Query]) -> String {
271-
return Query(
302+
public static func and(_ queries: [String]) -> String {
303+
let decoder = JSONDecoder()
304+
let decodedQueries = queries.compactMap { queryStr -> Query? in
305+
guard let data = queryStr.data(using: .utf8) else {
306+
return nil
307+
}
308+
return try? decoder.decode(Query.self, from: data)
309+
}
310+
311+
return Query(
272312
method: "and",
273-
values: queries
313+
values: decodedQueries
274314
).description
275315
}
276316
}

0 commit comments

Comments
 (0)