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

Fix a crash caused by UUID properties #26

Merged
merged 3 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all 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 PredicateKit.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

Pod::Spec.new do |spec|
spec.name = "PredicateKit"
spec.version = "1.7.0"
spec.version = "1.8.0"
spec.summary = "Write expressive and type-safe predicates for CoreData using key-paths, comparisons and logical operators, literal values, and functions."
spec.description = <<-DESC
PredicateKit allows Swift developers to write expressive and type-safe predicates for CoreData using key-paths, comparisons and logical operators, literal values, and functions.
Expand Down
28 changes: 27 additions & 1 deletion PredicateKit/Predicate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ public struct ComparisonOptions: OptionSet {
public static let caseInsensitive = ComparisonOptions(rawValue: 1 << 0)
public static let diacriticInsensitive = ComparisonOptions(rawValue: 1 << 1)
public static let normalized = ComparisonOptions(rawValue: 1 << 2)
public static let none = ComparisonOptions(rawValue: 1 << 3)

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

extension Comparison {
fileprivate init<E: Expression, P: Primitive>(
_ expression: E,
_ `operator`: ComparisonOperator,
_ value: P
) {
self.expression = AnyExpression(expression)
self.operator = `operator`
self.value = value
self.options = P.defaultComparisonOptions
}

fileprivate init<E: Expression>(
_ expression: E,
_ `operator`: ComparisonOperator,
_ value: Primitive,
_ options: ComparisonOptions = .caseInsensitive
_ options: ComparisonOptions
) {
self.expression = AnyExpression(expression)
self.operator = `operator`
Expand Down Expand Up @@ -759,3 +771,17 @@ extension ArrayElementKeyPath {
}
}
}

extension Primitive {
static var defaultComparisonOptions: ComparisonOptions {
switch type {
case .uuid:
return .none

// TODO: Add proper defaults for the other types.
// For now, .caseInsensitive does not seem to hurt?
default:
return .caseInsensitive
}
}
}
7 changes: 7 additions & 0 deletions PredicateKit/Primitive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,10 @@ extension Optional: Comparable where Wrapped: Comparable {
}
}
}

@available(iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension Optional: Identifiable where Wrapped: Identifiable {
public var id: Wrapped.ID? {
self?.id
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,27 @@ final class NSFetchRequestBuilderTests: XCTestCase {
XCTAssertEqual(comparison.comparisonPredicateModifier, .direct)
}

@available(iOS 13.0, watchOS 6.0, tvOS 13.0, *)
func testEqualityWithOptionalIdentifiable() throws {
guard let identifiable = makeIdentifiable() else {
XCTFail("could not initialize IdentifiableData")
return
}

identifiable.id = "42"

let request = makeRequest(\Data.optionalIdentifiable == identifiable)
let builder = makeRequestBuilder()

let result: NSFetchRequest<Data> = builder.makeRequest(from: request)

let comparison = try XCTUnwrap(result.predicate as? NSComparisonPredicate)
XCTAssertEqual(comparison.leftExpression, NSExpression(forKeyPath: "optionalIdentifiable.id"))
XCTAssertEqual(comparison.rightExpression, NSExpression(forConstantValue: "42"))
XCTAssertEqual(comparison.predicateOperatorType, .equalTo)
XCTAssertEqual(comparison.comparisonPredicateModifier, .direct)
}

func testArrayElementEqualPredicate() throws {
let request = makeRequest((\Data.relationships).last(\.count) == 42)
let builder = makeRequestBuilder()
Expand Down Expand Up @@ -1134,6 +1155,7 @@ private class Data: NSManagedObject {
@NSManaged var optionalRelationship: Relationship?
@NSManaged var optionalRelationships: [Relationship]?
@NSManaged var identifiable: IdentifiableData
@NSManaged var optionalIdentifiable: IdentifiableData?
}

private class Relationship: NSManagedObject {
Expand Down
21 changes: 21 additions & 0 deletions PredicateKitTests/PrimitiveTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,25 @@ final class PrimitiveTests: XCTestCase {
XCTAssertFalse(nil < rhs)
XCTAssertFalse(lhs < nil)
}

func testDefaultComparisonOptions() {
XCTAssertEqual(UUID.defaultComparisonOptions, .none)
XCTAssertEqual(Bool.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(Int.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(Int8.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(Int16.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(Int32.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(Int64.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(UInt.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(UInt8.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(UInt16.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(UInt32.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(UInt64.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(Double.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(Float.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(String.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(Date.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(URL.defaultComparisonOptions, .caseInsensitive)
XCTAssertEqual(Data.defaultComparisonOptions, .caseInsensitive)
}
}
Loading