Add support for Foundation.Predicate - #34
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves #15
Converts predicates built with the
#Predicatemacro intoFetchRequest.Predicateby walking thePredicateExpressionstree, cross-platform via swift-foundation'sFoundationEssentials— and extends the CoreModel predicate model and in-memory evaluator so everything CoreData can represent converts and evaluates consistently.Foundation.Predicate conversion
FetchRequest.Predicate.init(_: Foundation.Predicate<T>)(macOS 14 / iOS 17 / tvOS 17 / watchOS 10, matchingFoundation.Predicateavailability).==,!=,<,<=,>,>=), compounds (&&/||flattened into single compounds,!),contains,starts(with:),localizedStandardContains(Darwin, mapped toCONTAINS[cd]), boolean properties used directly as predicates, constants, andnilcomparisons.+,-,*,/,%, and unary minus convert to the newArithmeticExpression.allSatisfy { ... }andcontains(where:) { ... }convert toALL/ANYmodifier comparisons via variable-binding contexts (single-comparison tests; compound tests throw).min()/max()convert to@min/@maxkey path operators.18...30lowers to>= lower && <= upper, half-open18..<30to>= lower && < upper(BETWEENisn't evaluatable).debugDescription, so plain Swift structs work on all platforms.contains(regex)converts to aMATCHEScomparison. The macro wraps regexes inPredicateExpressions.PredicateRegex, which retains the source pattern, so literals,Regex(String), and RegexBuilder regexes all convert; the pattern is padded with.*becauseMATCHESmatches the whole value (requires macOS 15 / iOS 18, where those types are available).??, nested closures) throw a descriptiveConversionErrorinstead of silently misconverting.CoreModel predicate model
FetchRequest.Predicate.ArithmeticExpression(add/subtract/multiply/divide/modulus) as a newExpressioncase, withCodablesupport and in-memory evaluation: integer operands stay integral, division is always floating-point (matchingNSExpression'sdivide:by:), division by zero and floating-point remainder resolve to no match.events.namenow resolves through to-one and to-many relationships against an object index, soALL/ANYpredicates produce the same results in memory as they do in CoreData. Previously these silently matched nothing.FetchRequest.evaluate(_:)builds the index from the objects it is given, andInMemoryStoragenow supplies every entity's objects so relationships resolve.CoreDataModel
NSExpression(forFunction:)— theFunctionraw values are theNSExpressionfunction names.Tests
ArithmeticExpressionTests: CoreModel API construction, description, Codable round-trip, evaluation semantics (promotion, division by zero, non-numeric operands), fetch request evaluation.FoundationPredicateTests: every supported#Predicateexpression shape, converted-tree assertions, in-memory filtering, and error paths.KeyPathTraversalTests: to-one and to-many traversal,ALL/ANY, unresolved relationships,InMemoryStoragefetches, and the same traversals built with#Predicate.CoreDataModelTests: end-to-end fetches against a CoreData store using arithmetic andALL/ANYpredicates built both from#Predicateand the CoreModel API, including a check that empty to-manyALLis vacuously true in CoreData and that the in-memory evaluator agrees on the same objects.