I have this code in my init method:
self.monitor = CoreStore.monitorSectionedList(
From<ListEntityType>()
.sectionBy(#keyPath(ListEntityType.muscle.name)) { (sectionName) -> String? in
return "\(String(describing: sectionName)) years old"
}
.orderBy(.ascending(#keyPath(ListEntityType.muscle.name)), .ascending(\.name))
)
I want to somehow add to this monitor .where
condition in runtime.
ListEntityType
is a type alias of an entity called Exercise
. So each Exercise
contains one to one relationship Muscle
(exercise.muscle
).
each entity has unique identifier attribute.
I have array of muscles identifier which I want to use as filter to display object from sectioned list.
How can loop through this identifiers to add then to .where clause to the CoreStore.monitorSectionedList
I probably expect something like this but not 100% sure just assumption:
let predicate = NSPredicate(format: "%K = $ARGUMENT")
var predicates = [NSPredicate]()
if let muscles : [MuscleGroupEntity] = workout?.muscles.toArray() {
for muscle in muscles
{
let myNewPredicate = predicate.withSubstitutionVariables(["ARGUMENT" : muscle.id])
predicates.append(myNewPredicate)
}
}
self.monitor = CoreStore.monitorSectionedList(
From<ListEntityType>()
.sectionBy(#keyPath(ListEntityType.muscle.name)) { (sectionName) -> String? in
return "\(String(describing: sectionName)) years old"
}
.where(format:"%K = %@", argumentArray: predicates)
.orderBy(.ascending(#keyPath(ListEntityType.muscle.name)), .ascending(\.name))
)
this code crashed with error:
-[NSComparisonPredicate rangeOfString:]: unrecognized selector sent to
I guess this is something from predicate I found here, but not sure how to use it correctly in my case
EDITED For MartinM comments:
I have ExerciseEntity with a property Muscle.
If I want to get all exercises using just one muscle id it pretty simple:
.where(format:"%K = %@", #keyPath(ExerciseEntity.muscle.id), "id_12345")
But I want to specify more muscles and define them in runtime. Somehow I need to understand what the format is and what the arguments and how to pass array of identifiers instead just one "id_12345"
If you want to fetch all ExerciseEntity where their muscle.id is contained in a list of muscleIds, you simply use:
let muscleIds = workout?.muscles.compactMap({ $0.id }) ?? []
From....
.where(Where<ExerciseEntity>(#keyPath(ExerciseEntity.muscle.id), isMemberOf: muscleIds))
Thats the equivalent of a predicate with format: %K IN %@, ExerciseEntity.muscle.id, muscleIds
This also works negating -> NOT(%K IN %@), same as you can use a !Where in CoreStore.
Compound predicates need to specify how they are linked. CoreStore supports a shorthand for 2 predicates at a time, using logical operators, for example:
Where<ExerciseEntity>(yourWhereClause) && Where<ExerciseEntity(otherWhereClause)
This is the equivalent to using NSCompoundPredicate like this:
NSCompoundPredicate(type: .and, subpredicates: [left.predicate, right.predicate])
You can also pass that compound predicate as argument to the where clause directly if you need a more complex conjunction. You could then also store that compound predicate somewhere and append another compound predicate that fits your needs.