// // FetchCondition.swift // CoreStore // // Copyright © 2017 John Rommel Estropia // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // import Foundation import CoreData public protocol FetchChainableBuilderType { associatedtype ObjectType: DynamicObject var from: From { get set } var fetchClauses: [FetchClause] { get set } } public protocol QueryChainableBuilderType { associatedtype ObjectType: DynamicObject associatedtype ResultType: SelectResultType var from: From { get set } var select: Select { get set } var groupBy: GroupBy { get set } var queryClauses: [QueryClause] { get set } } public protocol SectionMonitorBuilderType { associatedtype ObjectType: DynamicObject var from: From { get set } var sectionBy: SectionBy { get set } var fetchClauses: [FetchClause] { get set } } // MARK: - FetchChainBuilder public struct FetchChainBuilder: FetchChainableBuilderType { // MARK: FetchChainableBuilderType public typealias ObjectType = D public var from: From public var fetchClauses: [FetchClause] = [] } // MARK: - QueryChainBuilder public struct QueryChainBuilder: QueryChainableBuilderType { // MARK: QueryChainableBuilderType public typealias ObjectType = D public typealias ResultType = R public var from: From public var select: Select public var groupBy: GroupBy public var queryClauses: [QueryClause] = [] } // MARK: - SectionMonitorChainBuilder public struct SectionMonitorChainBuilder: SectionMonitorBuilderType { // MARK: SectionMonitorBuilderType public var from: From public var sectionBy: SectionBy public var fetchClauses: [FetchClause] = [] } // MARK: - From public extension From { public func select(_ resultType: R.Type, _ selectTerm: SelectTerm, _ selectTerms: SelectTerm...) -> QueryChainBuilder { return self.select(resultType, [selectTerm] + selectTerms) } public func select(_ resultType: R.Type, _ selectTerms: [SelectTerm]) -> QueryChainBuilder { return .init( from: self, select: .init(selectTerms), groupBy: .init(), queryClauses: [] ) } public func sectionBy(_ sectionKeyPath: KeyPathString) -> SectionMonitorChainBuilder { return self.sectionBy(sectionKeyPath, { $0 }) } public func sectionBy(_ sectionKeyPath: KeyPathString, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder { return .init( from: self, sectionBy: .init(sectionKeyPath, sectionIndexTransformer), fetchClauses: [] ) } public func `where`(_ clause: Where) -> FetchChainBuilder { return self.fetchChain(appending: clause) } public func `where`(format: String, _ args: Any...) -> FetchChainBuilder { return self.fetchChain(appending: Where(format, argumentArray: args)) } public func `where`(format: String, argumentArray: [Any]?) -> FetchChainBuilder { return self.fetchChain(appending: Where(format, argumentArray: argumentArray)) } public func orderBy(_ sortKey: OrderBy.SortKey, _ sortKeys: OrderBy.SortKey...) -> FetchChainBuilder { return self.fetchChain(appending: OrderBy([sortKey] + sortKeys)) } public func tweak(_ fetchRequest: @escaping (NSFetchRequest) -> Void) -> FetchChainBuilder { return self.fetchChain(appending: Tweak(fetchRequest)) } public func appending(_ clause: FetchClause) -> FetchChainBuilder { return self.fetchChain(appending: clause) } // MARK: Private private func fetchChain(appending clause: FetchClause) -> FetchChainBuilder { return .init(from: self, fetchClauses: [clause]) } } public extension FetchChainBuilder { public func `where`(_ clause: Where) -> FetchChainBuilder { return self.fetchChain(appending: clause) } public func `where`(format: String, _ args: Any...) -> FetchChainBuilder { return self.fetchChain(appending: Where(format, argumentArray: args)) } public func `where`(format: String, argumentArray: [Any]?) -> FetchChainBuilder { return self.fetchChain(appending: Where(format, argumentArray: argumentArray)) } public func orderBy(_ sortKey: OrderBy.SortKey, _ sortKeys: OrderBy.SortKey...) -> FetchChainBuilder { return self.fetchChain(appending: OrderBy([sortKey] + sortKeys)) } public func tweak(_ fetchRequest: @escaping (NSFetchRequest) -> Void) -> FetchChainBuilder { return self.fetchChain(appending: Tweak(fetchRequest)) } public func appending(_ clause: FetchClause) -> FetchChainBuilder { return self.fetchChain(appending: clause) } // MARK: Private private func fetchChain(appending clause: FetchClause) -> FetchChainBuilder { return .init( from: self.from, fetchClauses: self.fetchClauses + [clause] ) } } public extension QueryChainBuilder { public func groupBy(_ keyPath: KeyPathString, _ keyPaths: KeyPathString...) -> QueryChainBuilder { return self.groupBy([keyPath] + keyPaths) } public func groupBy(_ keyPaths: [KeyPathString]) -> QueryChainBuilder { return .init( from: self.from, select: self.select, groupBy: .init(keyPaths), queryClauses: self.queryClauses ) } public func `where`(_ clause: Where) -> QueryChainBuilder { return self.queryChain(appending: clause) } public func `where`(format: String, _ args: Any...) -> QueryChainBuilder { return self.queryChain(appending: Where(format, argumentArray: args)) } public func `where`(format: String, argumentArray: [Any]?) -> QueryChainBuilder { return self.queryChain(appending: Where(format, argumentArray: argumentArray)) } public func orderBy(_ sortKey: OrderBy.SortKey, _ sortKeys: OrderBy.SortKey...) -> QueryChainBuilder { return self.queryChain(appending: OrderBy([sortKey] + sortKeys)) } public func tweak(_ fetchRequest: @escaping (NSFetchRequest) -> Void) -> QueryChainBuilder { return self.queryChain(appending: Tweak(fetchRequest)) } public func appending(_ clause: QueryClause) -> QueryChainBuilder { return self.queryChain(appending: clause) } // MARK: Private private func queryChain(appending clause: QueryClause) -> QueryChainBuilder { return .init( from: self.from, select: self.select, groupBy: self.groupBy, queryClauses: self.queryClauses + [clause] ) } } public extension SectionMonitorChainBuilder { public func `where`(_ clause: Where) -> SectionMonitorChainBuilder { return self.sectionMonitorChain(appending: clause) } public func `where`(format: String, _ args: Any...) -> SectionMonitorChainBuilder { return self.sectionMonitorChain(appending: Where(format, argumentArray: args)) } public func `where`(format: String, argumentArray: [Any]?) -> SectionMonitorChainBuilder { return self.sectionMonitorChain(appending: Where(format, argumentArray: argumentArray)) } public func orderBy(_ sortKey: OrderBy.SortKey, _ sortKeys: OrderBy.SortKey...) -> SectionMonitorChainBuilder { return self.sectionMonitorChain(appending: OrderBy([sortKey] + sortKeys)) } public func tweak(_ fetchRequest: @escaping (NSFetchRequest) -> Void) -> SectionMonitorChainBuilder { return self.sectionMonitorChain(appending: Tweak(fetchRequest)) } public func appending(_ clause: FetchClause) -> SectionMonitorChainBuilder { return self.sectionMonitorChain(appending: clause) } // MARK: Private private func sectionMonitorChain(appending clause: FetchClause) -> SectionMonitorChainBuilder { return .init( from: self.from, sectionBy: self.sectionBy, fetchClauses: self.fetchClauses + [clause] ) } }