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

Add modifiers to containsString, hasPrefix, hasSuffix #85

Merged
merged 5 commits into from
Feb 23, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ coverage:
status:
patch:
default:
target: 49
target: auto
changes: false
project:
default:
Expand Down
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.6...main)
* _Contributing to this repo? Add info about your change here to be included in next release_

__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).

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

__Fixes__
- Send correct SDK version number to Parse Server ([#82](https://github.com/parse-community/Parse-Swift/pull/82)), thanks to [Corey Baker](https://github.com/cbaker6).
- Send correct SDK version number to Parse Server ([#84](https://github.com/parse-community/Parse-Swift/pull/84)), thanks to [Corey Baker](https://github.com/cbaker6).

### 1.1.5
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.4...1.1.5)
Expand Down
51 changes: 27 additions & 24 deletions Sources/ParseSwift/Types/Query.swift
Original file line number Diff line number Diff line change
Expand Up @@ -410,28 +410,22 @@ public func matchesText(key: String, text: String) -> QueryConstraint {
- warning: This may be slow for large datasets.
- parameter key: The key that the string to match is stored in.
- parameter regex: The regular expression pattern to match.
- returns: The same instance of `Query` as the receiver.
*/
public func matchesRegex(key: String, regex: String) -> QueryConstraint {
.init(key: key, value: regex, comparator: .regex)
}

/**
Add a regular expression constraint for finding string values that match the provided regular expression.
- warning: This may be slow for large datasets.
- parameter key: The key that the string to match is stored in.
- parameter regex: The regular expression pattern to match.
- parameter modifiers: Any of the following supported PCRE modifiers:
- parameter modifiers: Any of the following supported PCRE modifiers (defaults to nil):
- `i` - Case insensitive search
- `m` - Search across multiple lines of input
- returns: The same instance of `Query` as the receiver.
*/
public func matchesRegex(key: String, regex: String, modifiers: String) -> QueryConstraint {
let dictionary = [
QueryConstraint.Comparator.regex.rawValue: regex,
QueryConstraint.Comparator.regexOptions.rawValue: modifiers
]
return .init(key: key, value: dictionary)
public func matchesRegex(key: String, regex: String, modifiers: String? = nil) -> QueryConstraint {

if let modifiers = modifiers {
let dictionary = [
QueryConstraint.Comparator.regex.rawValue: regex,
QueryConstraint.Comparator.regexOptions.rawValue: modifiers
]
return .init(key: key, value: dictionary)
} else {
return .init(key: key, value: regex, comparator: .regex)
}
}

private func regexStringForString(_ inputString: String) -> String {
Expand All @@ -444,35 +438,44 @@ private func regexStringForString(_ inputString: String) -> String {
- warning: This will be slow for large datasets.
- parameter key: The key that the string to match is stored in.
- parameter substring: The substring that the value must contain.
- parameter modifiers: Any of the following supported PCRE modifiers (defaults to nil):
- `i` - Case insensitive search
- `m` - Search across multiple lines of input
- returns: The same instance of `Query` as the receiver.
*/
public func containsString(key: String, substring: String) -> QueryConstraint {
public func containsString(key: String, substring: String, modifiers: String? = nil) -> QueryConstraint {
let regex = regexStringForString(substring)
return matchesRegex(key: key, regex: regex)
return matchesRegex(key: key, regex: regex, modifiers: modifiers)
}

/**
Add a constraint for finding string values that start with a provided prefix.
This will use smart indexing, so it will be fast for large datasets.
- parameter key: The key that the string to match is stored in.
- parameter prefix: The substring that the value must start with.
- parameter modifiers: Any of the following supported PCRE modifiers (defaults to nil):
- `i` - Case insensitive search
- `m` - Search across multiple lines of input
- returns: The same instance of `Query` as the receiver.
*/
public func hasPrefix(key: String, prefix: String) -> QueryConstraint {
public func hasPrefix(key: String, prefix: String, modifiers: String? = nil) -> QueryConstraint {
let regex = "^\(regexStringForString(prefix))"
return matchesRegex(key: key, regex: regex)
return matchesRegex(key: key, regex: regex, modifiers: modifiers)
}

/**
Add a constraint for finding string values that end with a provided suffix.
- warning: This will be slow for large datasets.
- parameter key: The key that the string to match is stored in.
- parameter suffix: The substring that the value must end with.
- parameter modifiers: Any of the following supported PCRE modifiers (defaults to nil):
- `i` - Case insensitive search
- `m` - Search across multiple lines of input
- returns: The same instance of `Query` as the receiver.
*/
public func hasSuffix(key: String, suffix: String) -> QueryConstraint {
public func hasSuffix(key: String, suffix: String, modifiers: String? = nil) -> QueryConstraint {
let regex = "\(regexStringForString(suffix))$"
return matchesRegex(key: key, regex: regex)
return matchesRegex(key: key, regex: regex, modifiers: modifiers)
}

/**
Expand Down
81 changes: 81 additions & 0 deletions Tests/ParseSwiftTests/ParseQueryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,33 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
}
}

func testWhereKeyContainsStringModifier() {
let expected: [String: AnyCodable] = [
"yolo": ["$regex": "\\Qyarr\\E",
"$options": "i"]
]
let constraint = containsString(key: "yolo", substring: "yarr", modifiers: "i")
let query = GameScore.query(constraint)
let queryWhere = query.`where`

do {
let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
XCTAssertEqual(expected.keys, decodedDictionary.keys)

guard let expectedValues = expected.values.first?.value as? [String: String],
let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {
XCTFail("Should have casted")
return
}
XCTAssertEqual(expectedValues, decodedValues)

} catch {
XCTFail(error.localizedDescription)
return
}
}

func testWhereKeyHasPrefix() {
let expected: [String: AnyCodable] = [
"yolo": ["$regex": "^\\Qyarr\\E"]
Expand All @@ -921,6 +948,33 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
}
}

func testWhereKeyHasPrefixModifier() {
let expected: [String: AnyCodable] = [
"yolo": ["$regex": "^\\Qyarr\\E",
"$options": "i"]
]
let constraint = hasPrefix(key: "yolo", prefix: "yarr", modifiers: "i")
let query = GameScore.query(constraint)
let queryWhere = query.`where`

do {
let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
XCTAssertEqual(expected.keys, decodedDictionary.keys)

guard let expectedValues = expected.values.first?.value as? [String: String],
let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {
XCTFail("Should have casted")
return
}
XCTAssertEqual(expectedValues, decodedValues)

} catch {
XCTFail(error.localizedDescription)
return
}
}

func testWhereKeyHasSuffix() {
let expected: [String: AnyCodable] = [
"yolo": ["$regex": "\\Qyarr\\E$"]
Expand All @@ -947,6 +1001,33 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
}
}

func testWhereKeyHasSuffixModifier() {
let expected: [String: AnyCodable] = [
"yolo": ["$regex": "\\Qyarr\\E$",
"$options": "i"]
]
let constraint = hasSuffix(key: "yolo", suffix: "yarr", modifiers: "i")
let query = GameScore.query(constraint)
let queryWhere = query.`where`

do {
let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
XCTAssertEqual(expected.keys, decodedDictionary.keys)

guard let expectedValues = expected.values.first?.value as? [String: String],
let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {
XCTFail("Should have casted")
return
}
XCTAssertEqual(expectedValues, decodedValues)

} catch {
XCTFail(error.localizedDescription)
return
}
}

func testOrQuery() {
let expected: [String: AnyCodable] = [
"$or": [
Expand Down