Skip to content

Fix query select and exclude #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 8, 2021
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
__New features__
- Add modifiers to containsString, hasPrefix, hasSuffix ([#85](https://github.com/parse-community/Parse-Swift/pull/85)), thanks to [Corey Baker](https://github.com/cbaker6).

__Improvements__
- Can use a variadic version of exclude. Added examples of select and exclude query in playgrounds ([#88](https://github.com/parse-community/Parse-Swift/pull/88)), thanks to [Corey Baker](https://github.com/cbaker6).

### 1.1.6
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.5...1.1.6)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,22 @@ struct GameScore: ParseObject {
var ACL: ParseACL?

var score: Int?
var oldScore: Int?
}

var score = GameScore()
score.score = 200
try score.save()
score.oldScore = 10
do {
try score.save()
} catch {
print(error)
}

let afterDate = Date().addingTimeInterval(-300)
var query = GameScore.query("score" > 100, "createdAt" > afterDate)
var query = GameScore.query("score" > 50,
"createdAt" > afterDate)
.order([.descending("score")])

// Query asynchronously (preferred way) - Performs work on background
// queue and returns to designated on designated callbackQueue.
Expand Down Expand Up @@ -68,6 +76,36 @@ query.first { results in
}
}

let querySelect = query.select("score")
querySelect.first { results in
switch results {
case .success(let score):

guard score.objectId != nil,
let createdAt = score.createdAt else { fatalError() }
assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, "date should be ok")
print("Found score using select: \(score)")

case .failure(let error):
assertionFailure("Error querying: \(error)")
}
}

let queryExclude = query.exclude("score")
queryExclude.first { results in
switch results {
case .success(let score):

guard score.objectId != nil,
let createdAt = score.createdAt else { fatalError() }
assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, "date should be ok")
print("Found score using exclude: \(score)")

case .failure(let error):
assertionFailure("Error querying: \(error)")
}
}

PlaygroundPage.current.finishExecution()

//: [Next](@next)
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ User.login(username: "hello", password: "world") { results in
User.current?.fetch(includeKeys: ["score"]) { result in
switch result {
case .success:
print("Successfully fetched user with score key: \(User.current)")
print("Successfully fetched user with score key: \(String(describing: User.current))")
case .failure(let error):
print("Error fetching score: \(error)")
}
Expand All @@ -111,7 +111,7 @@ User.current?.fetch(includeKeys: ["score"]) { result in
User.current?.fetch(includeKeys: ["*"]) { result in
switch result {
case .success:
print("Successfully fetched user with all keys: \(User.current)")
print("Successfully fetched user with all keys: \(String(describing: User.current))")
case .failure(let error):
print("Error fetching score: \(error)")
}
Expand Down
3 changes: 1 addition & 2 deletions Sources/ParseSwift/API/API+Commands.swift
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,7 @@ internal extension API.Command {

var params: [String: String]?
if let includeParams = include {
let joined = includeParams.joined(separator: ",")
params = ["include": joined]
params = ["include": "\(includeParams)"]
}

return API.Command<T, T>(
Expand Down
3 changes: 1 addition & 2 deletions Sources/ParseSwift/Objects/ParseInstallation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,7 @@ extension ParseInstallation {

var params: [String: String]?
if let includeParams = include {
let joined = includeParams.joined(separator: ",")
params = ["include": joined]
params = ["include": "\(includeParams)"]
}

return API.Command(method: .GET,
Expand Down
3 changes: 1 addition & 2 deletions Sources/ParseSwift/Objects/ParseUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -724,8 +724,7 @@ extension ParseUser {

var params: [String: String]?
if let includeParams = include {
let joined = includeParams.joined(separator: ",")
params = ["include": joined]
params = ["include": "\(includeParams)"]
}

return API.Command(method: .GET,
Expand Down
30 changes: 22 additions & 8 deletions Sources/ParseSwift/Types/Query.swift
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,21 @@ public struct Query<T>: Encodable, Equatable where T: ParseObject {

/**
Exclude specific keys for a `ParseObject`. Default is to nil.
- parameter keys: An arrays of keys to exclude.
- parameter keys: A variadic list of keys include in the result.
- warning: Requires Parse Server > 4.5.0
*/
public func exclude(_ keys: String...) -> Query<T> {
var mutableQuery = self
mutableQuery.excludeKeys = keys
return mutableQuery
}

/**
Exclude specific keys for a `ParseObject`. Default is to nil.
- parameter keys: An array of keys to exclude.
- warning: Requires Parse Server > 4.5.0
*/
public func exclude(_ keys: [String]?) -> Query<T> {
public func exclude(_ keys: [String]) -> Query<T> {
var mutableQuery = self
mutableQuery.excludeKeys = keys
return mutableQuery
Expand All @@ -709,6 +721,7 @@ public struct Query<T>: Encodable, Equatable where T: ParseObject {
Make the query restrict the fields of the returned `ParseObject`s to include only the provided keys.
If this is called multiple times, then all of the keys specified in each of the calls will be included.
- parameter keys: A variadic list of keys include in the result.
- warning: Requires Parse Server > 4.5.0
*/
public func select(_ keys: String...) -> Query<T> {
var mutableQuery = self
Expand All @@ -720,6 +733,7 @@ public struct Query<T>: Encodable, Equatable where T: ParseObject {
Make the query restrict the fields of the returned `ParseObject`s to include only the provided keys.
If this is called multiple times, then all of the keys specified in each of the calls will be included.
- parameter keys: An array of keys to include in the result.
- warning: Requires Parse Server > 4.5.0
*/
public func select(_ keys: [String]) -> Query<T> {
var mutableQuery = self
Expand Down Expand Up @@ -1100,15 +1114,15 @@ extension Query {

func findCommand() -> API.NonParseBodyCommand<Query<ResultType>, [ResultType]> {
let query = self
return API.NonParseBodyCommand(method: .POST, path: endpoint, body: query) {
return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) {
try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).results
}
}

func firstCommand() -> API.NonParseBodyCommand<Query<ResultType>, ResultType?> {
var query = self
query.limit = 1
return API.NonParseBodyCommand(method: .POST, path: endpoint, body: query) {
return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) {
try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).results.first
}
}
Expand All @@ -1117,7 +1131,7 @@ extension Query {
var query = self
query.limit = 1
query.isCount = true
return API.NonParseBodyCommand(method: .POST, path: endpoint, body: query) {
return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) {
try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).count ?? 0
}
}
Expand All @@ -1126,7 +1140,7 @@ extension Query {
var query = self
query.explain = explain
query.hint = hint
return API.NonParseBodyCommand(method: .POST, path: endpoint, body: query) {
return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) {
if let results = try JSONDecoder().decode(AnyResultsResponse.self, from: $0).results {
return results
}
Expand All @@ -1139,7 +1153,7 @@ extension Query {
query.limit = 1
query.explain = explain
query.hint = hint
return API.NonParseBodyCommand(method: .POST, path: endpoint, body: query) {
return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) {
if let results = try JSONDecoder().decode(AnyResultsResponse.self, from: $0).results {
return results
}
Expand All @@ -1153,7 +1167,7 @@ extension Query {
query.isCount = true
query.explain = explain
query.hint = hint
return API.NonParseBodyCommand(method: .POST, path: endpoint, body: query) {
return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) {
if let results = try JSONDecoder().decode(AnyResultsResponse.self, from: $0).results {
return results
}
Expand Down
5 changes: 3 additions & 2 deletions Tests/ParseSwiftTests/ParseInstallationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l
var installation = Installation()
let objectId = "yarr"
installation.objectId = objectId
let includeExpected = ["include": "yolo,test"]
let includeExpected = ["include": "[\"yolo\", \"test\"]"]
do {
let command = try installation.fetchCommand(include: ["yolo", "test"])
XCTAssertNotNil(command)
Expand All @@ -477,7 +477,8 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l
XCTAssertEqual(command.params, includeExpected)
XCTAssertNil(command.body)

guard let urlExpected = URL(string: "http://localhost:1337/1/installations/yarr?include=yolo,test") else {
// swiftlint:disable:next line_length
guard let urlExpected = URL(string: "http://localhost:1337/1/installations/yarr?include=%5B%22yolo%22,%20%22test%22%5D") else {
XCTFail("Should have unwrapped")
return
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/ParseSwiftTests/ParseObjectTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length
let className = score.className
let objectId = "yarr"
score.objectId = objectId
let includeExpected = ["include": "yolo,test"]
let includeExpected = ["include": "[\"yolo\", \"test\"]"]
do {
let command = try score.fetchCommand(include: ["yolo", "test"])
XCTAssertNotNil(command)
Expand All @@ -255,7 +255,7 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length
XCTAssertNil(command.data)

// swiftlint:disable:next line_length
guard let urlExpected = URL(string: "http://localhost:1337/1/classes/GameScore/yarr?include=yolo,test") else {
guard let urlExpected = URL(string: "http://localhost:1337/1/classes/GameScore/yarr?include=%5B%22yolo%22,%20%22test%22%5D") else {
XCTFail("Should have unwrapped")
return
}
Expand Down
49 changes: 42 additions & 7 deletions Tests/ParseSwiftTests/ParseQueryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,26 +162,61 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
XCTAssertEqual(query2.include, ["*"])
}

func testExcludeKeys() {
func testExcludeKeys() throws {
let query = GameScore.query()
XCTAssertNil(query.excludeKeys)
let query2 = GameScore.query().exclude(["yolo"])
var query2 = GameScore.query().exclude("yolo")
XCTAssertEqual(query2.excludeKeys, ["yolo"])
XCTAssertEqual(query2.excludeKeys, ["yolo"])
let encoded = try ParseCoding.jsonEncoder().encode(query2)
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
guard let decodedKeys = decodedDictionary["excludeKeys"],
let decodedValues = decodedKeys.value as? [String] else {
XCTFail("Should have casted")
return
}
XCTAssertEqual(decodedValues, ["yolo"])

query2 = GameScore.query().exclude(["yolo", "wow"])
XCTAssertEqual(query2.excludeKeys, ["yolo", "wow"])
XCTAssertEqual(query2.excludeKeys, ["yolo", "wow"])
let encoded2 = try ParseCoding.jsonEncoder().encode(query2)
let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)
guard let decodedKeys2 = decodedDictionary2["excludeKeys"],
let decodedValues2 = decodedKeys2.value as? [String] else {
XCTFail("Should have casted")
return
}
XCTAssertEqual(decodedValues2, ["yolo", "wow"])
}

func testSelectKeys() {
func testSelectKeys() throws {
let query = GameScore.query()
XCTAssertNil(query.keys)

var query2 = GameScore.query().select("yolo")
XCTAssertEqual(query2.keys?.count, 1)
XCTAssertEqual(query2.keys?.first, "yolo")
query2 = query2.select("yolo", "wow")
let encoded = try ParseCoding.jsonEncoder().encode(query2)
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
guard let decodedKeys = decodedDictionary["keys"],
let decodedValues = decodedKeys.value as? [String] else {
XCTFail("Should have casted")
return
}
XCTAssertEqual(decodedValues, ["yolo"])

query2 = query2.select(["yolo", "wow"])
XCTAssertEqual(query2.keys?.count, 2)
XCTAssertEqual(query2.keys, ["yolo", "wow"])
query2 = query2.select(["yolo"])
XCTAssertEqual(query2.keys?.count, 1)
XCTAssertEqual(query2.keys, ["yolo"])
let encoded2 = try ParseCoding.jsonEncoder().encode(query2)
let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)
guard let decodedKeys2 = decodedDictionary2["keys"],
let decodedValues2 = decodedKeys2.value as? [String] else {
XCTFail("Should have casted")
return
}
XCTAssertEqual(decodedValues2, ["yolo", "wow"])
}

func testAddingConstraints() {
Expand Down
5 changes: 3 additions & 2 deletions Tests/ParseSwiftTests/ParseUserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length
var user = User()
let objectId = "yarr"
user.objectId = objectId
let includeExpected = ["include": "yolo,test"]
let includeExpected = ["include": "[\"yolo\", \"test\"]"]
do {
let command = try user.fetchCommand(include: ["yolo", "test"])
XCTAssertNotNil(command)
Expand All @@ -119,7 +119,8 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length
XCTAssertNil(command.body)
XCTAssertNil(command.data)

guard let urlExpected = URL(string: "http://localhost:1337/1/users/yarr?include=yolo,test") else {
// swiftlint:disable:next line_length
guard let urlExpected = URL(string: "http://localhost:1337/1/users/yarr?include=%5B%22yolo%22,%20%22test%22%5D") else {
XCTFail("Should have unwrapped")
return
}
Expand Down