Did anyone come around a solution for filtering data ( CoreData ) by a day, using NSPredicateEditor ? The idea is to make it most convenient to the user. The standard solution would be to define 2 criteria for date :
One EditorRowTemplate should simply look like:
left expression = aDate (property of a Core Data entity )
rightexpression = Dates
Then, the app should convert the predicate to somewhat like:
"aDate >= '3.5.20210 00:00:00' AND aDate <= '3.5.20210 23:59:59'".
Of course, it should take the value from the date which the user has entered in the row template.
I thought, closures can be a way. So to say, creating the NSPredicate programmatically. But how to use it in NSExpression and grabbing the date from the input ?
The desired row template should look like this :
The row template can convert the predicate in predicate(withSubpredicates:)
, no other overrides required. In IB the right expressions are Dates.
override func predicate(withSubpredicates subpredicates: [NSPredicate]?) -> NSPredicate {
// call super to get the predicate, for example aDate == '3.5.20210 14:03:53'
let predicate = super.predicate(withSubpredicates: subpredicates)
// convert the predicate to aDate >= '3.5.2021 00:00:00' AND aDate < '4.5.2021 00:00:00'
var newPredicate = predicate
if let comparisonPredicate = predicate as? NSComparisonPredicate,
let predicateDate = comparisonPredicate.rightExpression.constantValue as? Date {
let keyPath = comparisonPredicate.leftExpression.keyPath
var components = Calendar.current.dateComponents([.year, .month, .day], from: predicateDate)
components.hour = 0
components.minute = 0
components.second = 0
components.calendar = NSCalendar.current
switch comparisonPredicate.predicateOperatorType {
case .lessThan:
// aDate < '3.5.2021 00:00:00'
let date = components.date! as NSDate
newPredicate = NSPredicate(format: "%K < %@", keyPath,date)
case .lessThanOrEqualTo:
// aDate < '4.5.2021 00:00:00'
components.day = components.day! + 1
let date = components.date! as NSDate
newPredicate = NSPredicate(format: "%K < %@", keyPath,date)
case .greaterThan:
// aDate >= '4.5.2021 00:00:00'
components.day = components.day! + 1
let date = components.date! as NSDate
newPredicate = NSPredicate(format: "%K >= %@", keyPath,date)
case .greaterThanOrEqualTo:
// aDate >= '3.5.2021 00:00:00'
let date = components.date! as NSDate
newPredicate = NSPredicate(format: "%K >= %@", keyPath,date)
case .equalTo:
// aDate >= '3.5.2021 00:00:00' AND aDate < '4.5.2021 00:00:00'
let startDate = components.date! as NSDate
components.day = components.day! + 1
let endDate = components.date! as NSDate
newPredicate = NSPredicate(format: "%K >= %@ AND %K < %@", keyPath, startDate, keyPath, endDate)
case .notEqualTo:
// NOT (aDate >= '3.5.2021 00:00:00' AND aDate < '4.5.2021 00:00:00')
let startDate = components.date! as NSDate
components.day = components.day! + 1
let endDate = components.date! as NSDate
newPredicate = NSPredicate(format: "NOT (%K >= %@ AND %K < %@)", keyPath, startDate, keyPath, endDate)
default:
newPredicate = predicate
}
}
return newPredicate
}