Skip to content
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