Skip to content

Commit b064000

Browse files
authored
Append instead of replace when using query (#155)
* Append instead of replace when using query select, exclude, include, and fields * Use set instead of array
1 parent 685f07a commit b064000

File tree

5 files changed

+160
-32
lines changed

5 files changed

+160
-32
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.0...main)
55
* _Contributing to this repo? Add info about your change here to be included in the next release_
66

7+
__Improvements__
8+
- Append instead of replace when using query select, exclude, include, and fields ([#155](https://github.com/parse-community/Parse-Swift/pull/155)), thanks to [Corey Baker](https://github.com/cbaker6).
9+
710
### 1.8.0
811
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.7.2...1.8.0)
912

Sources/ParseSwift/LiveQuery/Messages.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct StandardMessage: LiveQueryable, Codable {
3838
struct SubscribeQuery: Encodable {
3939
let className: String
4040
let `where`: QueryWhere
41-
let fields: [String]?
41+
let fields: Set<String>?
4242
}
4343

4444
struct SubscribeMessage<T: ParseObject>: LiveQueryable, Encodable {

Sources/ParseSwift/Types/Query.swift

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -633,20 +633,20 @@ public struct Query<T>: Encodable, Equatable where T: ParseObject {
633633
private let method: String = "GET"
634634
internal var limit: Int = 100
635635
internal var skip: Int = 0
636-
internal var keys: [String]?
637-
internal var include: [String]?
636+
internal var keys: Set<String>?
637+
internal var include: Set<String>?
638638
internal var order: [Order]?
639639
internal var isCount: Bool?
640640
internal var explain: Bool?
641641
internal var hint: AnyEncodable?
642642
internal var `where` = QueryWhere()
643-
internal var excludeKeys: [String]?
643+
internal var excludeKeys: Set<String>?
644644
internal var readPreference: String?
645645
internal var includeReadPreference: String?
646646
internal var subqueryReadPreference: String?
647647
internal var distinct: String?
648648
internal var pipeline: [[String: AnyEncodable]]?
649-
internal var fields: [String]?
649+
internal var fields: Set<String>?
650650

651651
/**
652652
An enum that determines the order to sort the results based on a given key.
@@ -768,21 +768,31 @@ public struct Query<T>: Encodable, Equatable where T: ParseObject {
768768

769769
/**
770770
Make the query include `ParseObject`s that have a reference stored at the provided keys.
771+
If this is called multiple times, then all of the keys specified in each of the calls will be included.
771772
- parameter keys: A variadic list of keys to load child `ParseObject`s for.
772773
*/
773774
public func include(_ keys: String...) -> Query<T> {
774775
var mutableQuery = self
775-
mutableQuery.include = keys
776+
if mutableQuery.include != nil {
777+
mutableQuery.include = mutableQuery.include?.union(keys)
778+
} else {
779+
mutableQuery.include = Set(keys)
780+
}
776781
return mutableQuery
777782
}
778783

779784
/**
780785
Make the query include `ParseObject`s that have a reference stored at the provided keys.
786+
If this is called multiple times, then all of the keys specified in each of the calls will be included.
781787
- parameter keys: An array of keys to load child `ParseObject`s for.
782788
*/
783789
public func include(_ keys: [String]) -> Query<T> {
784790
var mutableQuery = self
785-
mutableQuery.include = keys
791+
if mutableQuery.include != nil {
792+
mutableQuery.include = mutableQuery.include?.union(keys)
793+
} else {
794+
mutableQuery.include = Set(keys)
795+
}
786796
return mutableQuery
787797
}
788798

@@ -797,24 +807,34 @@ public struct Query<T>: Encodable, Equatable where T: ParseObject {
797807
}
798808

799809
/**
800-
Exclude specific keys for a `ParseObject`. Default is to nil.
810+
Exclude specific keys for a `ParseObject`.
811+
If this is called multiple times, then all of the keys specified in each of the calls will be excluded.
801812
- parameter keys: A variadic list of keys include in the result.
802813
- warning: Requires Parse Server > 4.5.0.
803814
*/
804815
public func exclude(_ keys: String...) -> Query<T> {
805816
var mutableQuery = self
806-
mutableQuery.excludeKeys = keys
817+
if mutableQuery.excludeKeys != nil {
818+
mutableQuery.excludeKeys = mutableQuery.excludeKeys?.union(keys)
819+
} else {
820+
mutableQuery.excludeKeys = Set(keys)
821+
}
807822
return mutableQuery
808823
}
809824

810825
/**
811-
Exclude specific keys for a `ParseObject`. Default is to nil.
812-
- parameter keys: An array of keys to exclude.
826+
Exclude specific keys for a `ParseObject`.
827+
If this is called multiple times, then all of the keys specified in each of the calls will be excluded.
828+
- parameter keys: An array of keys to exclude in the result.
813829
- warning: Requires Parse Server > 4.5.0.
814830
*/
815831
public func exclude(_ keys: [String]) -> Query<T> {
816832
var mutableQuery = self
817-
mutableQuery.excludeKeys = keys
833+
if mutableQuery.excludeKeys != nil {
834+
mutableQuery.excludeKeys = mutableQuery.excludeKeys?.union(keys)
835+
} else {
836+
mutableQuery.excludeKeys = Set(keys)
837+
}
818838
return mutableQuery
819839
}
820840

@@ -826,7 +846,11 @@ public struct Query<T>: Encodable, Equatable where T: ParseObject {
826846
*/
827847
public func select(_ keys: String...) -> Query<T> {
828848
var mutableQuery = self
829-
mutableQuery.keys = keys
849+
if mutableQuery.keys != nil {
850+
mutableQuery.keys = mutableQuery.keys?.union(keys)
851+
} else {
852+
mutableQuery.keys = Set(keys)
853+
}
830854
return mutableQuery
831855
}
832856

@@ -838,7 +862,11 @@ public struct Query<T>: Encodable, Equatable where T: ParseObject {
838862
*/
839863
public func select(_ keys: [String]) -> Query<T> {
840864
var mutableQuery = self
841-
mutableQuery.keys = keys
865+
if mutableQuery.keys != nil {
866+
mutableQuery.keys = mutableQuery.keys?.union(keys)
867+
} else {
868+
mutableQuery.keys = Set(keys)
869+
}
842870
return mutableQuery
843871
}
844872

@@ -859,13 +887,18 @@ public struct Query<T>: Encodable, Equatable where T: ParseObject {
859887
If you are only interested in the change of the name field, you can set `query.fields` to "name".
860888
In this situation, when the change of a Player `ParseObject` fulfills the subscription, only the
861889
name field will be sent to the clients instead of the full Player `ParseObject`.
890+
If this is called multiple times, then all of the keys specified in each of the calls will be received.
862891
- warning: This is only for `ParseLiveQuery`.
863892
- parameter keys: A variadic list of fields to receive back instead of the whole `ParseObject`.
864893
*/
865894
@available(macOS 10.15, iOS 13.0, macCatalyst 13.0, watchOS 6.0, tvOS 13.0, *)
866895
public func fields(_ keys: String...) -> Query<T> {
867896
var mutableQuery = self
868-
mutableQuery.fields = keys
897+
if mutableQuery.fields != nil {
898+
mutableQuery.fields = mutableQuery.fields?.union(keys)
899+
} else {
900+
mutableQuery.fields = Set(keys)
901+
}
869902
return mutableQuery
870903
}
871904

@@ -876,13 +909,18 @@ public struct Query<T>: Encodable, Equatable where T: ParseObject {
876909
If you are only interested in the change of the name field, you can set `query.fields` to "name".
877910
In this situation, when the change of a Player `ParseObject` fulfills the subscription, only the
878911
name field will be sent to the clients instead of the full Player `ParseObject`.
912+
If this is called multiple times, then all of the keys specified in each of the calls will be received.
879913
- warning: This is only for `ParseLiveQuery`.
880914
- parameter keys: An array of fields to receive back instead of the whole `ParseObject`.
881915
*/
882916
@available(macOS 10.15, iOS 13.0, macCatalyst 13.0, watchOS 6.0, tvOS 13.0, *)
883917
public func fields(_ keys: [String]) -> Query<T> {
884918
var mutableQuery = self
885-
mutableQuery.fields = keys
919+
if mutableQuery.fields != nil {
920+
mutableQuery.fields = mutableQuery.fields?.union(keys)
921+
} else {
922+
mutableQuery.fields = Set(keys)
923+
}
886924
return mutableQuery
887925
}
888926

Tests/ParseSwiftTests/ParseLiveQueryTests.swift

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ class ParseLiveQueryTests: XCTestCase {
193193
// swiftlint:disable:next line_length
194194
let expected = "{\"op\":\"subscribe\",\"requestId\":1,\"query\":{\"className\":\"GameScore\",\"where\":{\"score\":{\"$gt\":9}},\"fields\":[\"score\"]}}"
195195
let query = GameScore.query("score" > 9)
196-
.fields("score")
196+
.fields(["score"])
197197
let message = SubscribeMessage(operation: .subscribe,
198198
requestId: RequestId(value: 1),
199199
query: query,
@@ -204,6 +204,32 @@ class ParseLiveQueryTests: XCTestCase {
204204
XCTAssertEqual(decoded, expected)
205205
}
206206

207+
func testFieldKeys() throws {
208+
let query = GameScore.query()
209+
XCTAssertNil(query.keys)
210+
211+
var query2 = GameScore.query().fields(["yolo"])
212+
XCTAssertEqual(query2.fields?.count, 1)
213+
XCTAssertEqual(query2.fields?.first, "yolo")
214+
215+
query2 = query2.fields(["hello", "wow"])
216+
XCTAssertEqual(query2.fields?.count, 3)
217+
XCTAssertEqual(query2.fields, ["yolo", "hello", "wow"])
218+
}
219+
220+
func testFieldKeysVariadic() throws {
221+
let query = GameScore.query()
222+
XCTAssertNil(query.keys)
223+
224+
var query2 = GameScore.query().fields("yolo")
225+
XCTAssertEqual(query2.fields?.count, 1)
226+
XCTAssertEqual(query2.fields?.first, "yolo")
227+
228+
query2 = query2.fields("hello", "wow")
229+
XCTAssertEqual(query2.fields?.count, 3)
230+
XCTAssertEqual(query2.fields, ["yolo", "hello", "wow"])
231+
}
232+
207233
func testRedirectResponseDecoding() throws {
208234
guard let url = URL(string: "http://parse.org") else {
209235
XCTFail("Should have url")

Tests/ParseSwiftTests/ParseQueryTests.swift

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,23 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
157157
func testIncludeKeys() {
158158
let query = GameScore.query()
159159
XCTAssertNil(query.include)
160-
var query2 = GameScore.query().include("yolo")
160+
var query2 = GameScore.query().include(["yolo"])
161161
XCTAssertEqual(query2.include?.count, 1)
162162
XCTAssertEqual(query2.include?.first, "yolo")
163-
query2 = query2.include("yolo", "wow")
164-
XCTAssertEqual(query2.include?.count, 2)
165-
XCTAssertEqual(query2.include, ["yolo", "wow"])
166-
query2 = query2.include(["yolo"])
163+
query2 = query2.include(["hello", "wow"])
164+
XCTAssertEqual(query2.include?.count, 3)
165+
XCTAssertEqual(query2.include, Set(["yolo", "hello", "wow"]))
166+
}
167+
168+
func testIncludeKeysVariadic() {
169+
let query = GameScore.query()
170+
XCTAssertNil(query.include)
171+
var query2 = GameScore.query().include("yolo")
167172
XCTAssertEqual(query2.include?.count, 1)
168-
XCTAssertEqual(query2.include, ["yolo"])
173+
XCTAssertEqual(query2.include?.first, "yolo")
174+
query2 = query2.include("hello", "wow")
175+
XCTAssertEqual(query2.include?.count, 3)
176+
XCTAssertEqual(query2.include, Set(["yolo", "hello", "wow"]))
169177
}
170178

171179
func testIncludeAllKeys() {
@@ -179,8 +187,33 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
179187
func testExcludeKeys() throws {
180188
let query = GameScore.query()
181189
XCTAssertNil(query.excludeKeys)
182-
var query2 = GameScore.query().exclude("yolo")
190+
var query2 = GameScore.query().exclude(["yolo"])
183191
XCTAssertEqual(query2.excludeKeys, ["yolo"])
192+
let encoded = try ParseCoding.jsonEncoder().encode(query2)
193+
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
194+
guard let decodedKeys = decodedDictionary["excludeKeys"],
195+
let decodedValues = decodedKeys.value as? [String] else {
196+
XCTFail("Should have casted")
197+
return
198+
}
199+
XCTAssertEqual(decodedValues, ["yolo"])
200+
201+
query2 = query2.exclude(["hello", "wow"])
202+
XCTAssertEqual(query2.excludeKeys, ["yolo", "hello", "wow"])
203+
let encoded2 = try ParseCoding.jsonEncoder().encode(query2)
204+
let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)
205+
guard let decodedKeys2 = decodedDictionary2["excludeKeys"],
206+
let decodedValues2 = decodedKeys2.value as? [String] else {
207+
XCTFail("Should have casted")
208+
return
209+
}
210+
XCTAssertEqual(Set(decodedValues2), Set(["yolo", "hello", "wow"]))
211+
}
212+
213+
func testExcludeKeysVariadic() throws {
214+
let query = GameScore.query()
215+
XCTAssertNil(query.excludeKeys)
216+
var query2 = GameScore.query().exclude("yolo")
184217
XCTAssertEqual(query2.excludeKeys, ["yolo"])
185218
let encoded = try ParseCoding.jsonEncoder().encode(query2)
186219
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
@@ -191,23 +224,51 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
191224
}
192225
XCTAssertEqual(decodedValues, ["yolo"])
193226

194-
query2 = GameScore.query().exclude(["yolo", "wow"])
195-
XCTAssertEqual(query2.excludeKeys, ["yolo", "wow"])
196-
XCTAssertEqual(query2.excludeKeys, ["yolo", "wow"])
227+
query2 = query2.exclude("hello", "wow")
228+
XCTAssertEqual(query2.excludeKeys, ["yolo", "hello", "wow"])
197229
let encoded2 = try ParseCoding.jsonEncoder().encode(query2)
198230
let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)
199231
guard let decodedKeys2 = decodedDictionary2["excludeKeys"],
200232
let decodedValues2 = decodedKeys2.value as? [String] else {
201233
XCTFail("Should have casted")
202234
return
203235
}
204-
XCTAssertEqual(decodedValues2, ["yolo", "wow"])
236+
XCTAssertEqual(Set(decodedValues2), Set(["yolo", "hello", "wow"]))
205237
}
206238

207239
func testSelectKeys() throws {
208240
let query = GameScore.query()
209241
XCTAssertNil(query.keys)
210242

243+
var query2 = GameScore.query().select(["yolo"])
244+
XCTAssertEqual(query2.keys?.count, 1)
245+
XCTAssertEqual(query2.keys?.first, "yolo")
246+
let encoded = try ParseCoding.jsonEncoder().encode(query2)
247+
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
248+
guard let decodedKeys = decodedDictionary["keys"],
249+
let decodedValues = decodedKeys.value as? [String] else {
250+
XCTFail("Should have casted")
251+
return
252+
}
253+
XCTAssertEqual(decodedValues, ["yolo"])
254+
255+
query2 = query2.select(["hello", "wow"])
256+
XCTAssertEqual(query2.keys?.count, 3)
257+
XCTAssertEqual(query2.keys, ["yolo", "hello", "wow"])
258+
let encoded2 = try ParseCoding.jsonEncoder().encode(query2)
259+
let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)
260+
guard let decodedKeys2 = decodedDictionary2["keys"],
261+
let decodedValues2 = decodedKeys2.value as? [String] else {
262+
XCTFail("Should have casted")
263+
return
264+
}
265+
XCTAssertEqual(Set(decodedValues2), Set(["yolo", "hello", "wow"]))
266+
}
267+
268+
func testSelectKeysVariadic() throws {
269+
let query = GameScore.query()
270+
XCTAssertNil(query.keys)
271+
211272
var query2 = GameScore.query().select("yolo")
212273
XCTAssertEqual(query2.keys?.count, 1)
213274
XCTAssertEqual(query2.keys?.first, "yolo")
@@ -220,17 +281,17 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
220281
}
221282
XCTAssertEqual(decodedValues, ["yolo"])
222283

223-
query2 = query2.select(["yolo", "wow"])
224-
XCTAssertEqual(query2.keys?.count, 2)
225-
XCTAssertEqual(query2.keys, ["yolo", "wow"])
284+
query2 = query2.select("hello", "wow")
285+
XCTAssertEqual(query2.keys?.count, 3)
286+
XCTAssertEqual(query2.keys, ["yolo", "hello", "wow"])
226287
let encoded2 = try ParseCoding.jsonEncoder().encode(query2)
227288
let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)
228289
guard let decodedKeys2 = decodedDictionary2["keys"],
229290
let decodedValues2 = decodedKeys2.value as? [String] else {
230291
XCTFail("Should have casted")
231292
return
232293
}
233-
XCTAssertEqual(decodedValues2, ["yolo", "wow"])
294+
XCTAssertEqual(Set(decodedValues2), Set(["yolo", "hello", "wow"]))
234295
}
235296

236297
func testAddingConstraints() {

0 commit comments

Comments
 (0)