Skip to content

Commit 3bb2639

Browse files
authored
🐛 Fix a crash caused by UUID properties (#26)
1 parent 1dbb2c5 commit 3bb2639

5 files changed

Lines changed: 78 additions & 2 deletions

File tree

PredicateKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
Pod::Spec.new do |spec|
1717
spec.name = "PredicateKit"
18-
spec.version = "1.7.0"
18+
spec.version = "1.8.0"
1919
spec.summary = "Write expressive and type-safe predicates for CoreData using key-paths, comparisons and logical operators, literal values, and functions."
2020
spec.description = <<-DESC
2121
PredicateKit allows Swift developers to write expressive and type-safe predicates for CoreData using key-paths, comparisons and logical operators, literal values, and functions.

PredicateKit/Predicate.swift

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ public struct ComparisonOptions: OptionSet {
349349
public static let caseInsensitive = ComparisonOptions(rawValue: 1 << 0)
350350
public static let diacriticInsensitive = ComparisonOptions(rawValue: 1 << 1)
351351
public static let normalized = ComparisonOptions(rawValue: 1 << 2)
352+
public static let none = ComparisonOptions(rawValue: 1 << 3)
352353

353354
public init(rawValue: Int) {
354355
self.rawValue = rawValue
@@ -718,11 +719,22 @@ extension Optional: ComparableCollection where Wrapped: ComparableCollection {
718719
// MARK: - Private Initializers
719720

720721
extension Comparison {
722+
fileprivate init<E: Expression, P: Primitive>(
723+
_ expression: E,
724+
_ `operator`: ComparisonOperator,
725+
_ value: P
726+
) {
727+
self.expression = AnyExpression(expression)
728+
self.operator = `operator`
729+
self.value = value
730+
self.options = P.defaultComparisonOptions
731+
}
732+
721733
fileprivate init<E: Expression>(
722734
_ expression: E,
723735
_ `operator`: ComparisonOperator,
724736
_ value: Primitive,
725-
_ options: ComparisonOptions = .caseInsensitive
737+
_ options: ComparisonOptions
726738
) {
727739
self.expression = AnyExpression(expression)
728740
self.operator = `operator`
@@ -759,3 +771,17 @@ extension ArrayElementKeyPath {
759771
}
760772
}
761773
}
774+
775+
extension Primitive {
776+
static var defaultComparisonOptions: ComparisonOptions {
777+
switch type {
778+
case .uuid:
779+
return .none
780+
781+
// TODO: Add proper defaults for the other types.
782+
// For now, .caseInsensitive does not seem to hurt?
783+
default:
784+
return .caseInsensitive
785+
}
786+
}
787+
}

PredicateKit/Primitive.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,10 @@ extension Optional: Comparable where Wrapped: Comparable {
160160
}
161161
}
162162
}
163+
164+
@available(iOS 13.0, watchOS 6.0, tvOS 13.0, *)
165+
extension Optional: Identifiable where Wrapped: Identifiable {
166+
public var id: Wrapped.ID? {
167+
self?.id
168+
}
169+
}

PredicateKitTests/CoreDataTests/NSFetchRequestBuilderTests.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,27 @@ final class NSFetchRequestBuilderTests: XCTestCase {
109109
XCTAssertEqual(comparison.comparisonPredicateModifier, .direct)
110110
}
111111

112+
@available(iOS 13.0, watchOS 6.0, tvOS 13.0, *)
113+
func testEqualityWithOptionalIdentifiable() throws {
114+
guard let identifiable = makeIdentifiable() else {
115+
XCTFail("could not initialize IdentifiableData")
116+
return
117+
}
118+
119+
identifiable.id = "42"
120+
121+
let request = makeRequest(\Data.optionalIdentifiable == identifiable)
122+
let builder = makeRequestBuilder()
123+
124+
let result: NSFetchRequest<Data> = builder.makeRequest(from: request)
125+
126+
let comparison = try XCTUnwrap(result.predicate as? NSComparisonPredicate)
127+
XCTAssertEqual(comparison.leftExpression, NSExpression(forKeyPath: "optionalIdentifiable.id"))
128+
XCTAssertEqual(comparison.rightExpression, NSExpression(forConstantValue: "42"))
129+
XCTAssertEqual(comparison.predicateOperatorType, .equalTo)
130+
XCTAssertEqual(comparison.comparisonPredicateModifier, .direct)
131+
}
132+
112133
func testArrayElementEqualPredicate() throws {
113134
let request = makeRequest((\Data.relationships).last(\.count) == 42)
114135
let builder = makeRequestBuilder()
@@ -1134,6 +1155,7 @@ private class Data: NSManagedObject {
11341155
@NSManaged var optionalRelationship: Relationship?
11351156
@NSManaged var optionalRelationships: [Relationship]?
11361157
@NSManaged var identifiable: IdentifiableData
1158+
@NSManaged var optionalIdentifiable: IdentifiableData?
11371159
}
11381160

11391161
private class Relationship: NSManagedObject {

PredicateKitTests/PrimitiveTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,25 @@ final class PrimitiveTests: XCTestCase {
158158
XCTAssertFalse(nil < rhs)
159159
XCTAssertFalse(lhs < nil)
160160
}
161+
162+
func testDefaultComparisonOptions() {
163+
XCTAssertEqual(UUID.defaultComparisonOptions, .none)
164+
XCTAssertEqual(Bool.defaultComparisonOptions, .caseInsensitive)
165+
XCTAssertEqual(Int.defaultComparisonOptions, .caseInsensitive)
166+
XCTAssertEqual(Int8.defaultComparisonOptions, .caseInsensitive)
167+
XCTAssertEqual(Int16.defaultComparisonOptions, .caseInsensitive)
168+
XCTAssertEqual(Int32.defaultComparisonOptions, .caseInsensitive)
169+
XCTAssertEqual(Int64.defaultComparisonOptions, .caseInsensitive)
170+
XCTAssertEqual(UInt.defaultComparisonOptions, .caseInsensitive)
171+
XCTAssertEqual(UInt8.defaultComparisonOptions, .caseInsensitive)
172+
XCTAssertEqual(UInt16.defaultComparisonOptions, .caseInsensitive)
173+
XCTAssertEqual(UInt32.defaultComparisonOptions, .caseInsensitive)
174+
XCTAssertEqual(UInt64.defaultComparisonOptions, .caseInsensitive)
175+
XCTAssertEqual(Double.defaultComparisonOptions, .caseInsensitive)
176+
XCTAssertEqual(Float.defaultComparisonOptions, .caseInsensitive)
177+
XCTAssertEqual(String.defaultComparisonOptions, .caseInsensitive)
178+
XCTAssertEqual(Date.defaultComparisonOptions, .caseInsensitive)
179+
XCTAssertEqual(URL.defaultComparisonOptions, .caseInsensitive)
180+
XCTAssertEqual(Data.defaultComparisonOptions, .caseInsensitive)
181+
}
161182
}

0 commit comments

Comments
 (0)