Support the predicate expressions CoreData can represent - #35
Merged
Merged
Conversation
Code Coverage OverviewLanguages: Swift Swift / code-coverage/llvm-covThe overall coverage in commit 5b11022 in the Show a code coverage summary of the most impacted files.
|
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.
Follow-up to #34 (which merged the base
Foundation.Predicateconversion), extending both the predicate model and the in-memory evaluator to cover the expressions CoreData can represent.Arithmetic
FetchRequest.Predicate.ArithmeticExpression(add/subtract/multiply/divide/modulus) as anExpressioncase, withCodablesupport. Its raw values are the correspondingNSExpressionfunction names, soCoreDataModelbridges them directly viaNSExpression(forFunction:)./andNSExpression'sdivide:by:both do (7 / 2is3); division or remainder by zero, overflowing division, floating-point remainder, and non-numeric operands resolve to no match rather than trapping.#Predicateconverts+,-,*,/,%, and unary minus (lowered to* -1, asNSExpressionhas no negation function).Collections, aggregates and ranges
allSatisfy { ... }andcontains(where:) { ... }convert toALL/ANYmodifier comparisons. Those nodes bind their own element variable, so conversions now thread a context mapping each predicate variable to its key path.min()/max()convert to@min/@maxkey path operators.18..<30) convert alongside closed ones, lowered to comparisons sinceBETWEENisn't evaluatable.Regex
contains(regex)converts to aMATCHEScomparison. The macro wraps regexes inPredicateExpressions.PredicateRegex, which retains the source pattern, so regex literals,Regex(String), and RegexBuilder regexes all convert. The pattern is padded with.*becauseMATCHESmatches the whole value rather than a substring, matching Foundation's own conversion. Requires macOS 15 / iOS 18, where those types are available.Relationship key path traversal (bug fix)
Key paths that traverse a relationship (
events.name) previously resolved to nothing in the in-memory evaluator, so everyALL/ANYpredicate silently matched zero objects while the identical predicate returned the correct rows through CoreData. The evaluator now resolves to-one and to-many relationships against an object index:FetchRequest.evaluate(_:)builds the index from the objects it is given, andInMemoryStoragesupplies every entity's objects so relationships resolve.Tests
ArithmeticExpressionTests: construction, description,Codableround-trip, evaluation semantics, fetch request evaluation.FoundationPredicateTests: every supported expression 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 CoreData fetches for arithmetic,ALL/ANY, and regex predicates 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.161 tests pass, including the Embedded WebAssembly build (the object index is built without dynamic casting, which Embedded Swift forbids).