Complete Challenge 3

> Modify the predicate string parameter to be an enum such as .beginsWith, then make that enum get resolved to a string inside the initializer.
This commit is contained in:
CypherPoet 2019-11-22 23:23:02 -06:00
parent 241e97cf17
commit b42f48bc19
4 changed files with 101 additions and 22 deletions

View File

@ -33,6 +33,7 @@
F36B22BE2387EFE6000C9E74 /* DynamicFilteringExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36B22BD2387EFE6000C9E74 /* DynamicFilteringExample.swift */; };
F36B22C22387F02D000C9E74 /* GenericFilteredListExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36B22C12387F02D000C9E74 /* GenericFilteredListExample.swift */; };
F36B22C42388010F000C9E74 /* Country+FetchHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36B22C32388010F000C9E74 /* Country+FetchHelpers.swift */; };
F36B22C723880CC0000C9E74 /* NSComparisonPredicate+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36B22C623880CC0000C9E74 /* NSComparisonPredicate+Utils.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -64,6 +65,7 @@
F36B22BD2387EFE6000C9E74 /* DynamicFilteringExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicFilteringExample.swift; sourceTree = "<group>"; };
F36B22C12387F02D000C9E74 /* GenericFilteredListExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenericFilteredListExample.swift; sourceTree = "<group>"; };
F36B22C32388010F000C9E74 /* Country+FetchHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Country+FetchHelpers.swift"; sourceTree = "<group>"; };
F36B22C623880CC0000C9E74 /* NSComparisonPredicate+Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSComparisonPredicate+Utils.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -203,6 +205,7 @@
F36B22A2238783F5000C9E74 /* Reusables */ = {
isa = PBXGroup;
children = (
F36B22C523880C7A000C9E74 /* Predicate Utils */,
F36B22A3238783FB000C9E74 /* Views */,
);
path = Reusables;
@ -247,6 +250,14 @@
path = Candy;
sourceTree = "<group>";
};
F36B22C523880C7A000C9E74 /* Predicate Utils */ = {
isa = PBXGroup;
children = (
F36B22C623880CC0000C9E74 /* NSComparisonPredicate+Utils.swift */,
);
path = "Predicate Utils";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -334,6 +345,7 @@
F36B229223869A44000C9E74 /* DynamicFilteringExampleListView.swift in Sources */,
F36B22B42387E301000C9E74 /* Candy+CoreDataProperties.swift in Sources */,
F36B22AA2387DE7D000C9E74 /* CandyListSection.swift in Sources */,
F36B22C723880CC0000C9E74 /* NSComparisonPredicate+Utils.swift in Sources */,
F316C3E72384994E00741AEC /* SceneDelegate.swift in Sources */,
F316C3EA2384994E00741AEC /* ExploringCoreData.xcdatamodeld in Sources */,
F36B22BE2387EFE6000C9E74 /* DynamicFilteringExample.swift in Sources */,

View File

@ -0,0 +1,82 @@
//
// PredicateComparison.swift
// ExploringCoreData
//
// Created by CypherPoet on 11/22/19.
//
//
import Foundation
extension NSComparisonPredicate {
/// If applicable, makes a string consisting of braces and any characters for operator sensitivity.
///
/// - Parameters:
/// - diacriticSensitive: [Diacritic sensitivity](https://en.wikipedia.org/wiki/Diacritic)
/// refers to any possible glyphs that might be added to
/// a chracter, such as accents or dots.
static func operatorBraces(
caseSensitive: Bool,
diacriticSensitive: Bool
) -> String? {
guard caseSensitive || diacriticSensitive else { return nil }
return "[\(caseSensitive ? "c" : "")\(diacriticSensitive ? "d" : "")]"
}
/// The keyword to use within an NSPredicate expression
public static func keyword(
for predicateOperator: Operator
) -> String {
switch predicateOperator {
case .lessThan:
return "<"
case .lessThanOrEqualTo:
return "<="
case .greaterThan:
return ">"
case .greaterThanOrEqualTo:
return ">="
case .equalTo:
return "="
case .notEqualTo:
return "!="
case .matches:
return "MATCHES"
case .like:
return "LIKE"
case .beginsWith:
return "BEGINSWITH"
case .endsWith:
return "ENDSWITH"
case .in:
return "IN"
case .customSelector:
return "CUSTOMSELECTOR"
case .contains:
return "CONTAINS"
case .between:
return "BETWEEN"
@unknown default:
return ""
}
}
public static func stringValue(
for predicateOperator: Operator,
caseSensitive: Bool = true,
diacriticSensitive: Bool = true
) -> String {
let braces = Self.operatorBraces(
caseSensitive: caseSensitive,
diacriticSensitive: diacriticSensitive
)
return "\(Self.keyword(for: predicateOperator))\(braces ?? "")"
}
}

View File

@ -16,7 +16,7 @@ struct FilteredList<ManagedObject: NSManagedObject, Content: View>: View {
/// The name of the [string comparison](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html)
/// to be used between the `filterKey` and `filterValue`
private var filterComparison: String
private var comparisonOperator: NSComparisonPredicate.Operator
private var sortDescriptors: [NSSortDescriptor]
@ -27,21 +27,22 @@ struct FilteredList<ManagedObject: NSManagedObject, Content: View>: View {
init(
filterKey: String,
filterValue: String,
filterComparison: String = "BEGINSWITH",
filterComparison comparisonOperator: NSComparisonPredicate.Operator = .beginsWith,
sortDescriptors: [NSSortDescriptor] = [],
@ViewBuilder buildListItem: @escaping (ManagedObject) -> Content
) {
self.filterKey = filterKey
self.filterValue = filterValue
self.filterComparison = filterComparison
self.comparisonOperator = comparisonOperator
self.sortDescriptors = sortDescriptors
self.buildListItem = buildListItem
// 🤔 Lots of potential to make this even moar configurable, IMO
let comparisonString = NSComparisonPredicate.stringValue(for: comparisonOperator)
self.fetchRequest = .init(
entity: ManagedObject.entity(),
sortDescriptors: sortDescriptors,
predicate: NSPredicate(format: "%K \(filterComparison) %@", filterKey, filterValue),
predicate: NSPredicate(format: "%K \(comparisonString) %@", filterKey, filterValue),
animation: nil
)
}
@ -61,19 +62,6 @@ extension FilteredList {
}
// MARK: - Computeds
extension FilteredList {
}
// MARK: - View Variables
extension FilteredList {
}
//// MARK: - Preview

View File

@ -29,10 +29,6 @@ extension OneToManyRelationshipsExample {
}
// MARK: - Computeds
extension OneToManyRelationshipsExample {
}
// MARK: - View Variables
extension OneToManyRelationshipsExample {
@ -41,6 +37,7 @@ extension OneToManyRelationshipsExample {
FilteredList(
filterKey: "name",
filterValue: "U",
filterComparison: .beginsWith,
sortDescriptors: [
Country.SortDescriptor.byAbbreviation,
],