@@ -274,6 +274,10 @@ private extension FetchRequest.Predicate.Expression {
274274 return try function . sqlFragment ( for : entity , predicate : predicate )
275275 case . attribute , . relationship :
276276 return SQLFragment ( sql : " ? " , bindings : [ try constantBinding ( predicate : predicate ) ] )
277+ case . arithmetic :
278+ // - TODO: Translate arithmetic expressions to SQL. Until then they are
279+ // rejected so the caller can fall back to in-memory evaluation.
280+ throw SQLiteDatabaseError . invalidPredicate ( predicate )
277281 }
278282 }
279283
@@ -291,7 +295,7 @@ private extension FetchRequest.Predicate.Expression {
291295 case . toMany :
292296 throw SQLiteDatabaseError . invalidPredicate ( predicate )
293297 }
294- case . keyPath , . function :
298+ case . keyPath , . function , . arithmetic :
295299 throw SQLiteDatabaseError . invalidPredicate ( predicate )
296300 }
297301 }
@@ -336,7 +340,10 @@ internal extension EntityDescription {
336340 if property . rawValue == SQLiteDatabase . primaryKeyColumn {
337341 return true
338342 }
339- if attributes . contains ( where : { $0 . id == property } ) {
343+ // Composite attributes are expanded into leaf columns named by dotted path, so an
344+ // element key path such as `address.location.latitude` matches its column directly.
345+ // A composite attribute *as a whole* deliberately does not: it has no single column.
346+ if attributeColumns . contains ( where : { $0 . name == property . rawValue } ) {
340347 return true
341348 }
342349 return relationships . contains ( where : { $0 . id == property && $0 . type == . toOne } )
0 commit comments