NSPredicate Внутри SUBQUERY
Я пытаюсь написать SUBQUERY для NSPredicate. Моя проблема в том, что у меня нет под рукой запроса для предикатной части SUBQUERY. Есть ли способ вкладывать NSP-предикат в SUBQUERY?
Например, вот что я пробовал:
let ordersPredicate = NSPredicate()//some predicate passed in
//how do I use the ordersPredicate inside the subquery??
let subQueryPredicate = NSPredicate(format: "SUBQUERY(orders, $x,'%@').@count > 0", ordersPredicate.predicateFormat)
Обновление: мне пришлось пока сделать грязный обходной путь, выполнив первый предикат и выполнив ЛЮБОЙ запрос IN. Это хромает:(потому что я выполняю ordersPredicate в других местах, а позже в процессе разработки..
let fetchRequest = NSFetchRequest()//blah
fetchRequest.predicate = orderPredicate
let orders = //execute fetch
let subQueryPredicate = NSPredicate(format: "SUBQUERY(orders, $x, ANY $x in %@).@count > 0", orders)
1 ответ
Благодаря некоторым указателям из @Willeke я смог найти решение.
public extension NSPredicate{
public func stringForSubQuery(prefix:String) -> String{
var predicateString = ""
if let predicate = self as? NSCompoundPredicate{
for (index, subPredicate) in predicate.subpredicates.enumerate(){
if let subPredicate = subPredicate as? NSComparisonPredicate{
predicateString = "\(predicateString) \(prefix)\(subPredicate.predicateFormat)"
}
else if let subPredicate = subPredicate as? NSCompoundPredicate{
predicateString = "\(predicateString) (\(subPredicate.stringForSubQuery(prefix)))"
}
//if its not the last predicate then append the operator string
if index < predicate.subpredicates.count - 1 {
predicateString = "\(predicateString) \(getPredicateOperatorString(predicate.compoundPredicateType))"
}
}
}
return predicateString
}
private func getPredicateOperatorString(predicateType: NSCompoundPredicateType) -> String{
switch(predicateType){
case .NotPredicateType: return "!"
case .AndPredicateType: return "&&"
case .OrPredicateType: return "||"
}
}
}
А вот и использование
let ordersPredicate = NSPredicate()//some predicate passed in
let ordersPredicateFormat = orderPredicate.stringForSubQuery("$x.")
let subQueryPredicate = NSPredicate(format: "SUBQUERY(orders, $x, \(ordersPredicateFormat)).@count > 0")
Для тех, кто столкнется с этим в будущем, вам не нужно создавать строку предиката самостоятельно, просто используйте predicateFormat
прямо в строке подзапроса. Он уже правильно экранирован, поэтому используйте интерполяцию строк.
let ordersPredicate = NSPredicate()
// Add it to the query with string interpolation
let subQueryPredicate = NSPredicate(format: "SUBQUERY(orders, $x, \(ordersPredicate.predicateFormat)).@count > 0")
Если вы попытаетесь передать его в качестве аргумента, он снова попытается экранировать строку, что, вероятно, не сработает.
// Don't do this!
let subQueryPredicate = NSPredicate(format: "SUBQUERY(orders, $x, %@).@count > 0", ordersPredicate.predicateFormat)