keyPath utilities for Select queries

This commit is contained in:
John Rommel Estropia
2017-09-21 07:56:02 +09:00
parent 3e082d5ed4
commit 1bfb7451c3
12 changed files with 938 additions and 261 deletions

View File

@@ -354,7 +354,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) -> U? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -373,7 +373,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) -> U? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -402,7 +402,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -421,7 +421,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),

View File

@@ -35,7 +35,7 @@ import CoreData
- SeeAlso: `SelectTerm`
*/
@objc
public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
public final class CSSelectTerm: NSObject {
/**
Provides a `CSSelectTerm` to a `CSSelect` clause for querying an entity attribute.
@@ -175,11 +175,11 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
// MARK: CoreStoreObjectiveCType
public let bridgeToSwift: SelectTerm
public let bridgeToSwift: SelectTerm<NSManagedObject>
public init(_ swiftValue: SelectTerm) {
public init<D: NSManagedObject>(_ swiftValue: SelectTerm<D>) {
self.bridgeToSwift = swiftValue
self.bridgeToSwift = swiftValue.downcast()
super.init()
}
}
@@ -187,7 +187,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
// MARK: - SelectTerm
extension SelectTerm: CoreStoreSwiftType {
extension SelectTerm where D: NSManagedObject {
// MARK: CoreStoreSwiftType
@@ -195,6 +195,24 @@ extension SelectTerm: CoreStoreSwiftType {
return CSSelectTerm(self)
}
// MARK: FilePrivate
fileprivate func downcast() -> SelectTerm<NSManagedObject> {
switch self {
case ._attribute(let keyPath):
return SelectTerm<NSManagedObject>._attribute(keyPath)
case ._aggregate(let function, let keyPath, let alias, let nativeType):
return SelectTerm<NSManagedObject>._aggregate(function: function, keyPath: keyPath, alias: alias, nativeType: nativeType)
case ._identity(let alias, let nativeType):
return SelectTerm<NSManagedObject>._identity(alias: alias, nativeType: nativeType)
}
}
}
@@ -221,7 +239,7 @@ public final class CSSelect: NSObject {
@objc
public convenience init(numberTerm: CSSelectTerm) {
self.init(Select<NSNumber>(numberTerm.bridgeToSwift))
self.init(Select<NSManagedObject, NSNumber>(numberTerm.bridgeToSwift))
}
/**
@@ -237,7 +255,7 @@ public final class CSSelect: NSObject {
@objc
public convenience init(decimalTerm: CSSelectTerm) {
self.init(Select<NSDecimalNumber>(decimalTerm.bridgeToSwift))
self.init(Select<NSManagedObject, NSDecimalNumber>(decimalTerm.bridgeToSwift))
}
/**
@@ -253,7 +271,7 @@ public final class CSSelect: NSObject {
@objc
public convenience init(stringTerm: CSSelectTerm) {
self.init(Select<NSString>(stringTerm.bridgeToSwift))
self.init(Select<NSManagedObject, NSString>(stringTerm.bridgeToSwift))
}
/**
@@ -269,7 +287,7 @@ public final class CSSelect: NSObject {
@objc
public convenience init(dateTerm: CSSelectTerm) {
self.init(Select<Date>(dateTerm.bridgeToSwift))
self.init(Select<NSManagedObject, Date>(dateTerm.bridgeToSwift))
}
/**
@@ -285,7 +303,7 @@ public final class CSSelect: NSObject {
@objc
public convenience init(dataTerm: CSSelectTerm) {
self.init(Select<Data>(dataTerm.bridgeToSwift))
self.init(Select<NSManagedObject, Data>(dataTerm.bridgeToSwift))
}
/**
@@ -300,7 +318,7 @@ public final class CSSelect: NSObject {
@objc
public convenience init(objectIDTerm: ()) {
self.init(Select<NSManagedObjectID>(.objectID()))
self.init(Select<NSManagedObject, NSManagedObjectID>(.objectID()))
}
/**
@@ -316,7 +334,7 @@ public final class CSSelect: NSObject {
@objc
public static func dictionaryForTerm(_ term: CSSelectTerm) -> CSSelect {
return self.init(Select<NSDictionary>(term.bridgeToSwift))
return self.init(Select<NSManagedObject, NSDictionary>(term.bridgeToSwift))
}
/**
@@ -335,7 +353,7 @@ public final class CSSelect: NSObject {
@objc
public static func dictionaryForTerms(_ terms: [CSSelectTerm]) -> CSSelect {
return self.init(Select<NSDictionary>(terms.map { $0.bridgeToSwift }))
return self.init(Select<NSManagedObject, NSDictionary>(terms.map { $0.bridgeToSwift }))
}
@@ -365,18 +383,18 @@ public final class CSSelect: NSObject {
// MARK: CoreStoreObjectiveCType
public init<T: QueryableAttributeType>(_ swiftValue: Select<T>) {
public init<D: NSManagedObject, T: QueryableAttributeType>(_ swiftValue: Select<D, T>) {
self.attributeType = T.cs_rawAttributeType
self.selectTerms = swiftValue.selectTerms
self.selectTerms = swiftValue.selectTerms.map({ $0.downcast() })
self.bridgeToSwift = swiftValue
super.init()
}
public init<T>(_ swiftValue: Select<T>) {
public init<D: NSManagedObject, T>(_ swiftValue: Select<D, T>) {
self.attributeType = .undefinedAttributeType
self.selectTerms = swiftValue.selectTerms
self.selectTerms = swiftValue.selectTerms.map({ $0.downcast() })
self.bridgeToSwift = swiftValue
super.init()
}
@@ -385,7 +403,95 @@ public final class CSSelect: NSObject {
// MARK: Internal
internal let attributeType: NSAttributeType
internal let selectTerms: [SelectTerm]
internal let selectTerms: [SelectTerm<NSManagedObject>]
// MARK: Internal
internal func applyToFetchRequest(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) {
fetchRequest.includesPendingChanges = false
fetchRequest.resultType = .dictionaryResultType
func attributeDescription(for keyPath: String, in entity: NSEntityDescription) -> NSAttributeDescription? {
let components = keyPath.components(separatedBy: ".")
switch components.count {
case 0:
return nil
case 1:
return entity.attributesByName[components[0]]
default:
guard let relationship = entity.relationshipsByName[components[0]],
let destinationEntity = relationship.destinationEntity else {
return nil
}
return attributeDescription(
for: components.dropFirst().joined(separator: "."),
in: destinationEntity
)
}
}
var propertiesToFetch = [Any]()
for term in self.selectTerms {
switch term {
case ._attribute(let keyPath):
propertiesToFetch.append(keyPath)
case ._aggregate(let function, let keyPath, let alias, let nativeType):
let entityDescription = fetchRequest.entity!
if let attributeDescription = attributeDescription(for: keyPath, in: entityDescription) {
let expressionDescription = NSExpressionDescription()
expressionDescription.name = alias
if nativeType == .undefinedAttributeType {
expressionDescription.expressionResultType = attributeDescription.attributeType
}
else {
expressionDescription.expressionResultType = nativeType
}
expressionDescription.expression = NSExpression(
forFunction: function,
arguments: [NSExpression(forKeyPath: keyPath)]
)
propertiesToFetch.append(expressionDescription)
}
else {
CoreStore.log(
.warning,
message: "The key path \"\(keyPath)\" could not be resolved in entity \(cs_typeName(entityDescription.managedObjectClassName)) as an attribute and will be ignored by \(cs_typeName(self)) query clause."
)
}
case ._identity(let alias, let nativeType):
let expressionDescription = NSExpressionDescription()
expressionDescription.name = alias
if nativeType == .undefinedAttributeType {
expressionDescription.expressionResultType = .objectIDAttributeType
}
else {
expressionDescription.expressionResultType = nativeType
}
expressionDescription.expression = NSExpression.expressionForEvaluatedObject()
propertiesToFetch.append(expressionDescription)
}
}
fetchRequest.propertiesToFetch = propertiesToFetch
}
// MARK: Private
@@ -396,7 +502,7 @@ public final class CSSelect: NSObject {
// MARK: - Select
extension Select: CoreStoreSwiftType {
extension Select where D: NSManagedObject {
// MARK: CoreStoreSwiftType
@@ -404,4 +510,12 @@ extension Select: CoreStoreSwiftType {
return CSSelect(self)
}
// MARK: FilePrivate
fileprivate func downcast() -> Select<NSManagedObject, T> {
return Select<NSManagedObject, T>(self.selectTerms.map({ $0.downcast() }))
}
}

View File

@@ -41,7 +41,7 @@ public protocol QueryChainableBuilderType {
associatedtype ResultType: SelectResultType
var from: From<ObjectType> { get set }
var select: Select<ResultType> { get set }
var select: Select<ObjectType, ResultType> { get set }
var queryClauses: [QueryClause] { get set }
}
@@ -79,7 +79,7 @@ public struct QueryChainBuilder<D: DynamicObject, R: SelectResultType>: QueryCha
public typealias ResultType = R
public var from: From<D>
public var select: Select<R>
public var select: Select<D, R>
public var queryClauses: [QueryClause] = []
}
@@ -101,12 +101,12 @@ public struct SectionMonitorChainBuilder<D: DynamicObject>: SectionMonitorBuilde
public extension From {
public func select<R>(_ resultType: R.Type, _ selectTerm: SelectTerm, _ selectTerms: SelectTerm...) -> QueryChainBuilder<D, R> {
public func select<R>(_ resultType: R.Type, _ selectTerm: SelectTerm<D>, _ selectTerms: SelectTerm<D>...) -> QueryChainBuilder<D, R> {
return self.select(resultType, [selectTerm] + selectTerms)
}
public func select<R>(_ resultType: R.Type, _ selectTerms: [SelectTerm]) -> QueryChainBuilder<D, R> {
public func select<R>(_ resultType: R.Type, _ selectTerms: [SelectTerm<D>]) -> QueryChainBuilder<D, R> {
return .init(
from: self,
@@ -170,6 +170,97 @@ public extension From {
}
}
public extension From where D: NSManagedObject {
public func select<R>(_ keyPath: KeyPath<D, R>) -> QueryChainBuilder<D, R> {
return self.select(R.self, [SelectTerm<D>.attribute(keyPath)])
}
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, T>) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(sectionKeyPath._kvcKeyPathString!, { $0 })
}
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, T>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(sectionKeyPath._kvcKeyPathString!, sectionIndexTransformer)
}
}
public extension From where D: CoreStoreObject {
public func select<R>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<R>>) -> QueryChainBuilder<D, R> {
return self.select(R.self, [SelectTerm<D>.attribute(keyPath)])
}
public func select<R>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<R>>) -> QueryChainBuilder<D, R> {
return self.select(R.self, [SelectTerm<D>.attribute(keyPath)])
}
public func select<R>(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<R>>) -> QueryChainBuilder<D, R> {
return self.select(R.self, [SelectTerm<D>.attribute(keyPath)])
}
public func select<R>(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<R>>) -> QueryChainBuilder<D, R> {
return self.select(R.self, [SelectTerm<D>.attribute(keyPath)])
}
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Required<T>>) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 })
}
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Optional<T>>) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 })
}
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Required<T>>) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 })
}
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 })
}
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Required<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Optional<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Required<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
}
public extension FetchChainBuilder {
public func `where`(_ clause: Where<D>) -> FetchChainBuilder<D> {
@@ -274,6 +365,37 @@ public extension QueryChainBuilder {
}
}
public extension QueryChainBuilder where D: NSManagedObject {
public func groupBy<T>(_ keyPath: KeyPath<D, T>) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>(keyPath))
}
}
public extension QueryChainBuilder where D: CoreStoreObject {
public func groupBy<T>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<T>>) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>(keyPath))
}
public func groupBy<T>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<T>>) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>(keyPath))
}
public func groupBy<T>(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<T>>) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>(keyPath))
}
public func groupBy<T>(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>(keyPath))
}
}
@available(OSX 10.12, *)
public extension SectionMonitorChainBuilder {

View File

@@ -235,7 +235,7 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public static func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
public static func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) -> U? {
return self.defaultStack.queryValue(from, selectClause, queryClauses)
}
@@ -250,7 +250,7 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public static func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
public static func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) -> U? {
return self.defaultStack.queryValue(from, selectClause, queryClauses)
}
@@ -271,7 +271,7 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public static func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
public static func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
}
@@ -286,7 +286,7 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public static func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
public static func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
}

View File

@@ -300,7 +300,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) -> U? {
CoreStore.assert(
Thread.isMainThread,
@@ -319,7 +319,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) -> U? {
CoreStore.assert(
Thread.isMainThread,
@@ -348,7 +348,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
CoreStore.assert(
Thread.isMainThread,
@@ -367,7 +367,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
CoreStore.assert(
Thread.isMainThread,

View File

@@ -103,6 +103,37 @@ public struct GroupBy<D: DynamicObject>: GroupByClause, QueryClause, Hashable {
}
}
public extension GroupBy where D: NSManagedObject {
public init<T>(_ keyPath: KeyPath<D, T>) {
self.init([keyPath._kvcKeyPathString!])
}
}
public extension GroupBy where D: CoreStoreObject {
public init<T>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<T>>) {
self.init([D.meta[keyPath: keyPath].keyPath])
}
public init<T>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<T>>) {
self.init([D.meta[keyPath: keyPath].keyPath])
}
public init<T>(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<T>>) {
self.init([D.meta[keyPath: keyPath].keyPath])
}
public init<T>(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>) {
self.init([D.meta[keyPath: keyPath].keyPath])
}
}
// MARK: - GroupByClause

View File

@@ -142,15 +142,14 @@ internal extension NSManagedObjectContext {
fetchRequest.fetchLimit = 0
let selectTerms = selectClause.selectTerms
selectTerms.applyToFetchRequest(fetchRequest, owner: selectClause)
selectClause.applyToFetchRequest(fetchRequest)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.queryValue(selectTerms, fetchRequest: fetchRequest.dynamicCast())
return self.queryValue(selectClause.selectTerms, fetchRequest: fetchRequest.dynamicCast())
}
@nonobjc
@@ -161,7 +160,7 @@ internal extension NSManagedObjectContext {
fetchRequest.fetchLimit = 0
selectClause.selectTerms.applyToFetchRequest(fetchRequest, owner: selectClause)
selectClause.applyToFetchRequest(fetchRequest)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {

View File

@@ -279,51 +279,50 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
// MARK: QueryableSource
@nonobjc
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) -> U? {
return self.queryValue(from, selectClause, queryClauses)
}
@nonobjc
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) -> U? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
let selectTerms = selectClause.selectTerms
selectTerms.applyToFetchRequest(fetchRequest, owner: selectClause)
selectClause.applyToFetchRequest(fetchRequest)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.queryValue(selectTerms, fetchRequest: fetchRequest)
return self.queryValue(selectClause.selectTerms, fetchRequest: fetchRequest)
}
@nonobjc
public func queryValue<B>(_ clauseChain: B) -> B.ResultType? where B : QueryChainableBuilderType, B.ResultType : QueryableAttributeType {
public func queryValue<B>(_ clauseChain: B) -> B.ResultType? where B: QueryChainableBuilderType, B.ResultType: QueryableAttributeType {
return self.queryValue(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
}
@nonobjc
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
return self.queryAttributes(from, selectClause, queryClauses)
}
@nonobjc
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
selectClause.selectTerms.applyToFetchRequest(fetchRequest, owner: selectClause)
selectClause.applyToFetchRequest(fetchRequest)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
@@ -498,7 +497,7 @@ internal extension NSManagedObjectContext {
// MARK: Querying
@nonobjc
internal func queryValue<U: QueryableAttributeType>(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> U? {
internal func queryValue<D, U: QueryableAttributeType>(_ selectTerms: [SelectTerm<D>], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> U? {
var fetchResults: [Any]?
var fetchError: Error?
@@ -516,9 +515,9 @@ internal extension NSManagedObjectContext {
if let fetchResults = fetchResults {
if let rawResult = fetchResults.first as? NSDictionary,
let rawObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] as? U.QueryableNativeType {
let rawObject = rawResult[selectTerms.first!.keyPathString] as? U.QueryableNativeType {
return Select<U>.ReturnType.cs_fromQueryableNativeType(rawObject)
return Select<D, U>.ReturnType.cs_fromQueryableNativeType(rawObject)
}
return nil
}
@@ -531,7 +530,7 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal func queryValue(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Any? {
internal func queryValue<D>(_ selectTerms: [SelectTerm<D>], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Any? {
var fetchResults: [Any]?
var fetchError: Error?
@@ -549,7 +548,7 @@ internal extension NSManagedObjectContext {
if let fetchResults = fetchResults {
if let rawResult = fetchResults.first as? NSDictionary,
let rawObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] {
let rawObject = rawResult[selectTerms.first!.keyPathString] {
return rawObject
}
@@ -581,7 +580,7 @@ internal extension NSManagedObjectContext {
}
if let fetchResults = fetchResults {
return Select<NSDictionary>.ReturnType.cs_fromQueryResultsNativeType(fetchResults)
return NSDictionary.cs_fromQueryResultsNativeType(fetchResults)
}
CoreStore.log(

View File

@@ -44,7 +44,7 @@ public protocol QueryableSource: class {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U?
func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) -> U?
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -56,7 +56,7 @@ public protocol QueryableSource: class {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U?
func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) -> U?
// TODO: docs
func queryValue<B: QueryChainableBuilderType>(_ clauseChain: B) -> B.ResultType? where B.ResultType: QueryableAttributeType
@@ -71,7 +71,7 @@ public protocol QueryableSource: class {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]?
func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]?
/**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -83,7 +83,7 @@ public protocol QueryableSource: class {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]?
func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]?
// TODO: docs
func queryAttributes<B: QueryChainableBuilderType>(_ clauseChain: B) -> [[String: Any]]? where B.ResultType == NSDictionary

View File

@@ -52,7 +52,7 @@ public protocol SelectAttributesResultType: SelectResultType {
/**
The `SelectTerm` is passed to the `Select` clause to indicate the attributes/aggregate keys to be queried.
*/
public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
public enum SelectTerm<D: DynamicObject>: ExpressibleByStringLiteral, Hashable {
/**
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute. A shorter way to do the same is to assign from the string keypath directly:
@@ -74,7 +74,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- parameter keyPath: the attribute name
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
*/
public static func attribute(_ keyPath: KeyPathString) -> SelectTerm {
public static func attribute(_ keyPath: KeyPathString) -> SelectTerm<D> {
return ._attribute(keyPath)
}
@@ -91,7 +91,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
*/
public static func average(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm {
public static func average(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._aggregate(
function: "average:",
@@ -113,7 +113,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for a count query
*/
public static func count(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm {
public static func count(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._aggregate(
function: "count:",
@@ -135,7 +135,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
*/
public static func maximum(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm {
public static func maximum(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._aggregate(
function: "max:",
@@ -157,7 +157,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
*/
public static func minimum(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm {
public static func minimum(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._aggregate(
function: "min:",
@@ -179,7 +179,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/
public static func sum(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm {
public static func sum(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._aggregate(
function: "sum:",
@@ -202,7 +202,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "objecID" is used
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/
public static func objectID(as alias: KeyPathString? = nil) -> SelectTerm {
public static func objectID(as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._identity(
alias: alias ?? "objectID",
@@ -231,7 +231,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
// MARK: Equatable
public static func == (lhs: SelectTerm, rhs: SelectTerm) -> Bool {
public static func == (lhs: SelectTerm<D>, rhs: SelectTerm<D>) -> Bool {
switch (lhs, rhs) {
@@ -248,7 +248,9 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
case (._identity(let alias1, let nativeType1), ._identity(let alias2, let nativeType2)):
return alias1 == alias2 && nativeType1 == nativeType2
default:
case (._attribute, _),
(._aggregate, _),
(._identity, _):
return false
}
}
@@ -277,6 +279,355 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
case _attribute(KeyPathString)
case _aggregate(function: String, keyPath: KeyPathString, alias: String, nativeType: NSAttributeType)
case _identity(alias: String, nativeType: NSAttributeType)
internal var keyPathString: String {
switch self {
case ._attribute(let keyPath): return keyPath
case ._aggregate(_, _, let alias, _): return alias
case ._identity(let alias, _): return alias
}
}
}
extension SelectTerm where D: NSManagedObject {
/**
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute.
- parameter keyPath: the attribute name
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
*/
public static func attribute<V>(_ keyPath: KeyPath<D, V>) -> SelectTerm<D> {
return self.attribute(keyPath._kvcKeyPathString!)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the average value of an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
*/
public static func average<V>(_ keyPath: KeyPath<D, V>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.average(keyPath._kvcKeyPathString!, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for a count query.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for a count query
*/
public static func count<V>(_ keyPath: KeyPath<D, V>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.count(keyPath._kvcKeyPathString!, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
*/
public static func maximum<V>(_ keyPath: KeyPath<D, V>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.maximum(keyPath._kvcKeyPathString!, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
*/
public static func minimum<V>(_ keyPath: KeyPath<D, V>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.minimum(keyPath._kvcKeyPathString!, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the sum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/
public static func sum<V>(_ keyPath: KeyPath<D, V>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.sum(keyPath._kvcKeyPathString!, as: alias)
}
}
extension SelectTerm where D: CoreStoreObject {
/**
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute.
- parameter keyPath: the attribute name
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
*/
public static func attribute<V>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<V>>) -> SelectTerm<D> {
return self.attribute(D.meta[keyPath: keyPath].keyPath)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute.
- parameter keyPath: the attribute name
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
*/
public static func attribute<V>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<V>>) -> SelectTerm<D> {
return self.attribute(D.meta[keyPath: keyPath].keyPath)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute.
- parameter keyPath: the attribute name
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
*/
public static func attribute<V>(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<V>>) -> SelectTerm<D> {
return self.attribute(D.meta[keyPath: keyPath].keyPath)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute.
- parameter keyPath: the attribute name
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
*/
public static func attribute<V>(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<V>>) -> SelectTerm<D> {
return self.attribute(D.meta[keyPath: keyPath].keyPath)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the average value of an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
*/
public static func average<V>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.average(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the average value of an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
*/
public static func average<V>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.average(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the average value of an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
*/
public static func average<V>(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.average(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the average value of an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
*/
public static func average<V>(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.average(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for a count query.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for a count query
*/
public static func count<V>(_ keyPath: KeyPath<D,
ValueContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.count(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for a count query.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for a count query
*/
public static func count<V>(_ keyPath: KeyPath<D,
ValueContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.count(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for a count query.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for a count query
*/
public static func count<V>(_ keyPath: KeyPath<D,
TransformableContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.count(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for a count query.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for a count query
*/
public static func count<V>(_ keyPath: KeyPath<D,
TransformableContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.count(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
*/
public static func maximum<V>(_ keyPath: KeyPath<D,
ValueContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.maximum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
*/
public static func maximum<V>(_ keyPath: KeyPath<D,
ValueContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.maximum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
*/
public static func maximum<V>(_ keyPath: KeyPath<D,
TransformableContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.maximum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
*/
public static func maximum<V>(_ keyPath: KeyPath<D,
TransformableContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.maximum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
*/
public static func minimum<V>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.minimum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
*/
public static func minimum<V>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.minimum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
*/
public static func minimum<V>(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.minimum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
*/
public static func minimum<V>(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.minimum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the sum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/
public static func sum<V>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.sum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the sum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/
public static func sum<V>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.sum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the sum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/
public static func sum<V>(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.sum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the sum value for an attribute.
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/
public static func sum<V>(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.sum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
}
@@ -308,12 +659,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- parameter sortDescriptors: a series of `NSSortDescriptor`s
*/
public struct Select<T: SelectResultType>: Hashable {
/**
The `SelectResultType` type for the query's return value
*/
public typealias ReturnType = T
public struct Select<D: DynamicObject, T: SelectResultType>: SelectClause, Hashable {
/**
Initializes a `Select` clause with a list of `SelectTerm`s
@@ -321,7 +667,7 @@ public struct Select<T: SelectResultType>: Hashable {
- parameter selectTerm: a `SelectTerm`
- parameter selectTerms: a series of `SelectTerm`s
*/
public init(_ selectTerm: SelectTerm, _ selectTerms: SelectTerm...) {
public init(_ selectTerm: SelectTerm<D>, _ selectTerms: SelectTerm<D>...) {
self.selectTerms = [selectTerm] + selectTerms
}
@@ -331,7 +677,7 @@ public struct Select<T: SelectResultType>: Hashable {
- parameter selectTerms: a series of `SelectTerm`s
*/
public init(_ selectTerms: [SelectTerm]) {
public init(_ selectTerms: [SelectTerm<D>]) {
self.selectTerms = selectTerms
}
@@ -339,12 +685,20 @@ public struct Select<T: SelectResultType>: Hashable {
// MARK: Equatable
public static func == <T, U>(lhs: Select<T>, rhs: Select<U>) -> Bool {
public static func == <T, U>(lhs: Select<D, T>, rhs: Select<D, U>) -> Bool {
return lhs.selectTerms == rhs.selectTerms
}
// MARK: SelectClause
public typealias ObjectType = D
public typealias ReturnType = T
public let selectTerms: [SelectTerm<D>]
// MARK: Hashable
public var hashValue: Int {
@@ -355,36 +709,7 @@ public struct Select<T: SelectResultType>: Hashable {
// MARK: Internal
internal let selectTerms: [SelectTerm]
}
public extension Select where T: NSManagedObjectID {
public init() {
self.init(.objectID())
}
}
// MARK: - NSDictionary: SelectAttributesResultType
extension NSDictionary: SelectAttributesResultType {
// MARK: SelectAttributesResultType
public static func cs_fromQueryResultsNativeType(_ result: [Any]) -> [[String : Any]] {
return result as! [[String: Any]]
}
}
// MARK: - Internal
internal extension Collection where Iterator.Element == SelectTerm {
internal func applyToFetchRequest<T>(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>, owner: T) {
internal func applyToFetchRequest(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) {
fetchRequest.includesPendingChanges = false
fetchRequest.resultType = .dictionaryResultType
@@ -414,7 +739,7 @@ internal extension Collection where Iterator.Element == SelectTerm {
}
var propertiesToFetch = [Any]()
for term in self {
for term in self.selectTerms {
switch term {
@@ -445,7 +770,7 @@ internal extension Collection where Iterator.Element == SelectTerm {
CoreStore.log(
.warning,
message: "The key path \"\(keyPath)\" could not be resolved in entity \(cs_typeName(entityDescription.managedObjectClassName)) as an attribute and will be ignored by \(cs_typeName(owner)) query clause."
message: "The key path \"\(keyPath)\" could not be resolved in entity \(cs_typeName(entityDescription.managedObjectClassName)) as an attribute and will be ignored by \(cs_typeName(self)) query clause."
)
}
@@ -468,19 +793,106 @@ internal extension Collection where Iterator.Element == SelectTerm {
fetchRequest.propertiesToFetch = propertiesToFetch
}
}
public extension Select where T: NSManagedObjectID {
internal func keyPathForFirstSelectTerm() -> KeyPathString {
/**
Initializes a `Select` that queries for `NSManagedObjectID` results
*/
public init() {
switch self.first! {
case ._attribute(let keyPath):
return keyPath
case ._aggregate(_, _, let alias, _):
return alias
case ._identity(let alias, _):
return alias
}
self.init(.objectID())
}
}
public extension Select where D: NSManagedObject {
/**
Initializes a `Select` that queries the value of an attribute pertained by a keyPath
- parameter keyPath: the keyPath for the attribute
*/
public init(_ keyPath: KeyPath<D, T>) {
self.init(.attribute(keyPath))
}
}
public extension Select where D: CoreStoreObject, T: ImportableAttributeType {
/**
Initializes a `Select` that queries the value of an attribute pertained by a keyPath
- parameter keyPath: the keyPath for the attribute
*/
public init(_ keyPath: KeyPath<D, ValueContainer<D>.Required<T>>) {
self.init(.attribute(keyPath))
}
/**
Initializes a `Select` that queries the value of an attribute pertained by a keyPath
- parameter keyPath: the keyPath for the attribute
*/
public init(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<T>>) {
self.init(.attribute(keyPath))
}
}
public extension Select where D: CoreStoreObject, T: ImportableAttributeType & NSCoding & NSCopying {
/**
Initializes a `Select` that queries the value of an attribute pertained by a keyPath
- parameter keyPath: the keyPath for the attribute
*/
public init(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<T>>) {
self.init(.attribute(keyPath))
}
/**
Initializes a `Select` that queries the value of an attribute pertained by a keyPath
- parameter keyPath: the keyPath for the attribute
*/
public init(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>) {
self.init(.attribute(keyPath))
}
}
// MARK: - SelectClause
/**
Abstracts the `Select` clause for protocol utilities.
*/
public protocol SelectClause {
/**
The `DynamicObject` type associated with the clause
*/
associatedtype ObjectType: DynamicObject
/**
The `SelectResultType` type associated with the clause
*/
associatedtype ReturnType: SelectResultType
/**
The `SelectTerm`s for the query
*/
var selectTerms: [SelectTerm<ObjectType>] { get }
}
// MARK: - NSDictionary: SelectAttributesResultType
extension NSDictionary: SelectAttributesResultType {
// MARK: SelectAttributesResultType
public static func cs_fromQueryResultsNativeType(_ result: [Any]) -> [[String : Any]] {
return result as! [[String: Any]]
}
}