Skip to content

Instantly share code, notes, and snippets.

@hhanesand
Last active September 30, 2020 02:47
Show Gist options
  • Save hhanesand/456e5b8ad17656e1ba095c43531dae33 to your computer and use it in GitHub Desktop.
Save hhanesand/456e5b8ad17656e1ba095c43531dae33 to your computer and use it in GitHub Desktop.
// MARK: - typed predicate types
public protocol PredicateProtocol: NSPredicate {}
public protocol TypedPredicateProtocol: PredicateProtocol { associatedtype Root }
public final class CompoundPredicate<Root>: NSCompoundPredicate, TypedPredicateProtocol {}
public final class ComparisonPredicate<Root>: NSComparisonPredicate, TypedPredicateProtocol {}
// MARK: - compound operators
public func && <TP1: TypedPredicateProtocol, TP2: TypedPredicateProtocol>(p1: TP1, p2: TP2) -> CompoundPredicate<TP1.Root> where TP1.Root == TP2.Root {
CompoundPredicate(type: .and, subpredicates: [p1, p2])
}
public func || <TP1: TypedPredicateProtocol, TP2: TypedPredicateProtocol>(p1: TP1, p2: TP2) -> CompoundPredicate<TP1.Root> where TP1.Root == TP2.Root {
CompoundPredicate(type: .or, subpredicates: [p1, p2])
}
public prefix func ! <TP: TypedPredicateProtocol>(p: TP) -> CompoundPredicate<TP.Root> {
CompoundPredicate(type: .not, subpredicates: [p])
}
// MARK: - comparison operators
public func == <E: Equatable, R, K: KeyPath<R, E>>(kp: K, value: E) -> ComparisonPredicate<R> {
ComparisonPredicate(kp, .equalTo, value)
}
public func != <E: Equatable, R, K: KeyPath<R, E>>(kp: K, value: E) -> ComparisonPredicate<R> {
ComparisonPredicate(kp, .notEqualTo, value)
}
public func > <C: Comparable, R, K: KeyPath<R, C>>(kp: K, value: C) -> ComparisonPredicate<R> {
ComparisonPredicate(kp, .greaterThan, value)
}
public func < <C: Comparable, R, K: KeyPath<R, C>>(kp: K, value: C) -> ComparisonPredicate<R> {
ComparisonPredicate(kp, .lessThan, value)
}
public func <= <C: Comparable, R, K: KeyPath<R, C>>(kp: K, value: C) -> ComparisonPredicate<R> {
ComparisonPredicate(kp, .lessThanOrEqualTo, value)
}
public func >= <C: Comparable, R, K: KeyPath<R, C>>(kp: K, value: C) -> ComparisonPredicate<R> {
ComparisonPredicate(kp, .greaterThanOrEqualTo, value)
}
public func === <S: Sequence, R, K: KeyPath<R, S.Element>>(kp: K, values: S) -> ComparisonPredicate<R> where S.Element: Equatable {
ComparisonPredicate(kp, .in, values)
}
// MARK: - internal
extension ComparisonPredicate {
convenience init<VAL>(_ kp: KeyPath<Root, VAL>, _ op: NSComparisonPredicate.Operator, _ value: Any?) {
let ex1 = \Root.self == kp ? NSExpression.expressionForEvaluatedObject() : NSExpression(forKeyPath: kp)
let ex2 = NSExpression(forConstantValue: value)
self.init(leftExpression: ex1, rightExpression: ex2, modifier: .direct, type: op)
}
}
struct FetchRequest<T: NSFetchRequestResult> {
let wrapped: NSFetchRequest<T>
static func request<T: NSFetchRequestResult>(for type: T.Type = T.self) -> FetchRequest<T> {
return FetchRequest<T>(wrapped: NSFetchRequest<T>(entityName: String(describing: T.self)))
}
static func request<
T: NSFetchRequestResult, P: TypedPredicateProtocol
>(for type: T.Type = T.self, predicate: P) -> FetchRequest<T> where P.Root == T {
let request = NSFetchRequest<T>(entityName: String(describing: T.self))
request.predicate = predicate
return FetchRequest<T>(wrapped: request)
}
static func request<
T: NSFetchRequestResult, P: TypedPredicateProtocol, S
>(for type: T.Type = T.self,
predicate: P,
ascending: Bool,
sort: KeyPath<T, S>) -> FetchRequest<T> where P.Root == T {
let request = NSFetchRequest<T>(entityName: String(describing: T.self))
request.predicate = predicate
request.sortDescriptors = [NSSortDescriptor(keyPath: sort, ascending: ascending)]
return FetchRequest<T>(wrapped: request)
}
static func request<
T: NSFetchRequestResult, S
>(for type: T.Type = T.self,
ascending: Bool,
sort: KeyPath<T, S>) -> FetchRequest<T> {
let request = NSFetchRequest<T>(entityName: String(describing: T.self))
request.sortDescriptors = [NSSortDescriptor(keyPath: sort, ascending: ascending)]
return FetchRequest<T>(wrapped: request)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment