diff --git a/CoreStoreTests/BridgingTests.m b/CoreStoreTests/BridgingTests.m index b62d65c..5ae9800 100644 --- a/CoreStoreTests/BridgingTests.m +++ b/CoreStoreTests/BridgingTests.m @@ -45,12 +45,26 @@ - (void)test_ThatFromClauses_BridgeCorrectly { { - CSFrom *from = From([TestEntity1 class]); + CSFrom *from = CSFromCreate([TestEntity1 class]); XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]); XCTAssertNil(from.configurations); } { - CSFrom *from = From([TestEntity1 class], @[[NSNull null], @"Config2"]); + CSFrom *from = CSFromCreate([TestEntity1 class], [NSNull null]); + XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]); + + NSArray *configurations = @[[NSNull null]]; + XCTAssertEqualObjects(from.configurations, configurations); + } + { + CSFrom *from = CSFromCreate([TestEntity1 class], @"Config1"); + XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]); + + NSArray *configurations = @[@"Config1"]; + XCTAssertEqualObjects(from.configurations, configurations); + } + { + CSFrom *from = CSFromCreate([TestEntity1 class], @[[NSNull null], @"Config2"]); XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]); NSArray *configurations = @[[NSNull null], @"Config2"]; @@ -61,26 +75,63 @@ - (void)test_ThatWhereClauses_BridgeCorrectly { { - CSWhere *where = Where(@"%K == %@", @"key", @"value"); + CSWhere *where = CSWhereFormat(@"%K == %@", @"key", @"value"); NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"]; XCTAssertEqualObjects(where.predicate, predicate); } { - CSWhere *where = Where(YES); + CSWhere *where = CSWhereValue(YES); NSPredicate *predicate = [NSPredicate predicateWithValue:YES]; XCTAssertEqualObjects(where.predicate, predicate); } { - CSWhere *where = Where([NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"]); + CSWhere *where = CSWherePredicate([NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"]); NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"]; XCTAssertEqualObjects(where.predicate, predicate); } } +- (void)test_ThatOrderByClauses_BridgeCorrectly { + + { + CSOrderBy *orderBy = CSOrderBySortKey(CSSortAscending(@"key")); + XCTAssertEqualObjects(orderBy.sortDescriptors, @[[NSSortDescriptor sortDescriptorWithKey:@"key" ascending:YES]]); + } + { + CSOrderBy *orderBy = CSOrderBySortKey(CSSortDescending(@"key")); + XCTAssertEqualObjects(orderBy.sortDescriptors, @[[NSSortDescriptor sortDescriptorWithKey:@"key" ascending:NO]]); + } + { + CSOrderBy *orderBy = CSOrderBySortKeys(CSSortAscending(@"key1"), CSSortDescending(@"key2"), nil); + NSArray *sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"key1" ascending:YES], + [NSSortDescriptor sortDescriptorWithKey:@"key2" ascending:NO]]; + XCTAssertEqualObjects(orderBy.sortDescriptors, sortDescriptors); + } +} + - (void)test_ThatGroupByClauses_BridgeCorrectly { - CSGroupBy *groupBy = GroupBy(@[@"key"]); - XCTAssertEqualObjects(groupBy.keyPaths, @[@"key"]); + { + CSGroupBy *groupBy = CSGroupByKeyPath(@"key"); + XCTAssertEqualObjects(groupBy.keyPaths, @[@"key"]); + } + { + CSGroupBy *groupBy = CSGroupByKeyPaths(@[@"key1", @"key2"]); + + NSArray *keyPaths = @[@"key1", @"key2"]; + XCTAssertEqualObjects(groupBy.keyPaths, keyPaths); + } +} + +- (void)test_ThatTweakClauses_BridgeCorrectly { + + CSTweak *tweak = CSTweakCreate(^(NSFetchRequest * _Nonnull fetchRequest) { + + fetchRequest.fetchLimit = 100; + }); + NSFetchRequest *request = [NSFetchRequest new]; + tweak.block(request); + XCTAssertEqual(request.fetchLimit, 100); } - (void)test_ThatDataStacks_BridgeCorrectly { @@ -93,6 +144,9 @@ [CSCoreStore setDefaultStack:dataStack]; XCTAssertTrue([dataStack isEqual:[CSCoreStore defaultStack]]); +} + +- (void)test_ThatStorages_BridgeCorrectly { NSError *memoryError; CSInMemoryStore *memoryStorage = [CSCoreStore diff --git a/Sources/Fetching and Querying/Concrete Clauses/GroupBy.swift b/Sources/Fetching and Querying/Concrete Clauses/GroupBy.swift index 9afddf3..a18a39b 100644 --- a/Sources/Fetching and Querying/Concrete Clauses/GroupBy.swift +++ b/Sources/Fetching and Querying/Concrete Clauses/GroupBy.swift @@ -47,16 +47,6 @@ public struct GroupBy: QueryClause, Hashable { self.init([]) } - /** - Initializes a `GroupBy` clause with a list of key path strings - - - parameter keyPaths: a list of key path strings to group results with - */ - public init(_ keyPaths: [KeyPath]) { - - self.keyPaths = keyPaths - } - /** Initializes a `GroupBy` clause with a list of key path strings @@ -68,6 +58,16 @@ public struct GroupBy: QueryClause, Hashable { self.init([keyPath] + keyPaths) } + /** + Initializes a `GroupBy` clause with a list of key path strings + + - parameter keyPaths: a list of key path strings to group results with + */ + public init(_ keyPaths: [KeyPath]) { + + self.keyPaths = keyPaths + } + // MARK: QueryClause diff --git a/Sources/Fetching and Querying/Concrete Clauses/OrderBy.swift b/Sources/Fetching and Querying/Concrete Clauses/OrderBy.swift index 5db68a2..f90ee96 100644 --- a/Sources/Fetching and Querying/Concrete Clauses/OrderBy.swift +++ b/Sources/Fetching and Querying/Concrete Clauses/OrderBy.swift @@ -70,14 +70,9 @@ public enum SortKey { public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable { /** - Initializes a `OrderBy` clause with a list of sort descriptors - - - parameter sortDescriptors: a series of `NSSortDescriptor`s + The list of sort descriptors */ - public init(_ sortDescriptors: [NSSortDescriptor]) { - - self.sortDescriptors = sortDescriptors - } + public let sortDescriptors: [NSSortDescriptor] /** Initializes a `OrderBy` clause with an empty list of sort descriptors @@ -97,6 +92,16 @@ public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable { self.init([sortDescriptor]) } + /** + Initializes a `OrderBy` clause with a list of sort descriptors + + - parameter sortDescriptors: a series of `NSSortDescriptor`s + */ + public init(_ sortDescriptors: [NSSortDescriptor]) { + + self.sortDescriptors = sortDescriptors + } + /** Initializes a `OrderBy` clause with a series of `SortKey`s @@ -130,8 +135,6 @@ public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable { self.init([sortKey] + sortKeys) } - public let sortDescriptors: [NSSortDescriptor] - // MARK: FetchClause, QueryClause, DeleteClause diff --git a/Sources/Fetching and Querying/Concrete Clauses/Tweak.swift b/Sources/Fetching and Querying/Concrete Clauses/Tweak.swift index 6427c6f..bf4b870 100644 --- a/Sources/Fetching and Querying/Concrete Clauses/Tweak.swift +++ b/Sources/Fetching and Querying/Concrete Clauses/Tweak.swift @@ -44,15 +44,20 @@ import CoreData */ public struct Tweak: FetchClause, QueryClause, DeleteClause { + /** + The block to customize the `NSFetchRequest` + */ + public let closure: (fetchRequest: NSFetchRequest) -> Void + /** Initializes a `Tweak` clause with a closure where the `NSFetchRequest` may be configured. - Important: `Tweak`'s closure is executed only just before the fetch occurs, so make sure that any values captured by the closure is not prone to race conditions. Also, some utilities (such as `ListMonitor`s) may keep `FetchClause`s in memory and may thus introduce retain cycles if reference captures are not handled properly. - - parameter customization: a list of key path strings to group results with + - parameter closure: the block to customize the `NSFetchRequest` */ - public init(_ customization: (fetchRequest: NSFetchRequest) -> Void) { + public init(_ closure: (fetchRequest: NSFetchRequest) -> Void) { - self.customization = customization + self.closure = closure } @@ -60,11 +65,6 @@ public struct Tweak: FetchClause, QueryClause, DeleteClause { public func applyToFetchRequest(fetchRequest: NSFetchRequest) { - self.customization(fetchRequest: fetchRequest) + self.closure(fetchRequest: fetchRequest) } - - - // MARK: Private - - private let customization: (fetchRequest: NSFetchRequest) -> Void } diff --git a/Sources/ObjectiveC/CSFrom.swift b/Sources/ObjectiveC/CSFrom.swift index 45d7df8..579d592 100644 --- a/Sources/ObjectiveC/CSFrom.swift +++ b/Sources/ObjectiveC/CSFrom.swift @@ -66,38 +66,36 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType { /** Initializes a `CSFrom` clause with the specified entity class. ``` - MyPersonEntity *people = [transaction fetchAllFrom:[CSFrom entityClass:[MyPersonEntity class]]]; + MyPersonEntity *people = [transaction fetchAllFrom:CSFromCreate([MyPersonEntity class])]; ``` - parameter entityClass: the `NSManagedObject` class type to be created - - returns: a `CSFrom` clause with the specified entity class */ @objc - public static func entityClass(entityClass: AnyClass) -> CSFrom { + public convenience init(entityClass: AnyClass) { - return self.init(From(entityClass)) + self.init(From(entityClass)) } /** Initializes a `CSFrom` clause with the specified configurations. ``` - MyPersonEntity *people = [transaction fetchAllFrom:[CSFrom entityClass:[MyPersonEntity class] configuration:@"Configuration1"]]; + MyPersonEntity *people = [transaction fetchAllFrom: + CSFromCreate([MyPersonEntity class], @"Config1")]; ``` - parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration. - - parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter) - - returns: a `CSFrom` clause with the specified configurations */ @objc - public static func entityClass(entityClass: AnyClass, configuration: AnyObject) -> CSFrom { + public convenience init(entityClass: AnyClass, configuration: AnyObject) { switch configuration { case let string as String: - return self.init(From(entityClass, string)) + self.init(From(entityClass, string)) case is NSNull: - return self.init(From(entityClass, nil)) + self.init(From(entityClass, nil)) default: CoreStore.abort("The configuration argument only accepts NSString and NSNull values") @@ -107,15 +105,16 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType { /** Initializes a `CSFrom` clause with the specified configurations. ``` - MyPersonEntity *people = [transaction fetchAllFrom:[CSFrom entityClass:[MyPersonEntity class] configurations:@[[NSNull null], @"Configuration1"]]]; + MyPersonEntity *people = [transaction fetchAllFrom: + CSFromCreate([MyPersonEntity class], + @[[NSNull null], @"Config1"])]; ``` - parameter entity: the associated `NSManagedObject` entity class - - parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration. - - returns: a `CSFrom` clause with the specified configurations + - parameter configurations: an array of the `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration. */ @objc - public static func entityClass(entityClass: AnyClass, configurations: [AnyObject]) -> CSFrom { + public convenience init(entityClass: AnyClass, configurations: [AnyObject]) { var arguments = [String?]() for configuration in configurations { @@ -132,7 +131,7 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType { CoreStore.abort("The configurations argument only accepts NSString and NSNull values") } } - return self.init(From(entityClass, arguments)) + self.init(From(entityClass, arguments)) } diff --git a/Sources/ObjectiveC/CSGroupBy.swift b/Sources/ObjectiveC/CSGroupBy.swift index 48bcb19..4e0c615 100644 --- a/Sources/ObjectiveC/CSGroupBy.swift +++ b/Sources/ObjectiveC/CSGroupBy.swift @@ -40,21 +40,32 @@ public final class CSGroupBy: NSObject, CSQueryClause, CoreStoreObjectiveCType { /** The list of key path strings to group results with */ + @objc public var keyPaths: [KeyPath] { return self.bridgeToSwift.keyPaths } + /** + Initializes a `CSGroupBy` clause with a key path string + + - parameter keyPath: a key path string to group results with + */ + @objc + public convenience init(keyPath: KeyPath) { + + self.init(GroupBy(keyPath)) + } + /** Initializes a `CSGroupBy` clause with a list of key path strings - parameter keyPaths: a list of key path strings to group results with - - returns: a `CSGroupBy` clause with a list of key path strings */ @objc - public static func keyPaths(keyPaths: [KeyPath]) -> CSGroupBy { + public convenience init(keyPaths: [KeyPath]) { - return self.init(GroupBy(keyPaths)) + self.init(GroupBy(keyPaths)) } diff --git a/Sources/ObjectiveC/CSOrderBy.swift b/Sources/ObjectiveC/CSOrderBy.swift index 56658fb..e900559 100644 --- a/Sources/ObjectiveC/CSOrderBy.swift +++ b/Sources/ObjectiveC/CSOrderBy.swift @@ -27,32 +27,6 @@ import Foundation import CoreData -// MARK: - CSSortKey - -/** - The `CSSortKey` is a syntax-sugar class for `NSSortDescriptor` meant to be used with `CSOrderBy`. - - - SeeAlso: `CSOrderBy` - - SeeAlso: `SortKey` - */ -@objc -public final class CSSortKey: NSSortDescriptor { - - /** - Initializes a `CSSortKey` with a the specified key path and sort order - - - parameter keyPath: the property key to use when performing a comparison - - parameter ascending: `YES` if the receiver specifies sorting in ascending order, otherwise `NO` - - returns: a `CSSortKey` with a the specified key path and sort order - */ - @objc - public static func withKeyPath(keyPath: KeyPath, ascending: Bool) -> CSSortKey { - - return self.init(key: keyPath, ascending: ascending) - } -} - - // MARK: - CSOrderBy /** @@ -64,27 +38,44 @@ public final class CSSortKey: NSSortDescriptor { public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteClause, CoreStoreObjectiveCType { /** - Initializes a `CSOrderBy` clause with a list of sort descriptors - - - parameter sortDescriptors: a series of `NSSortDescriptor`s - - returns: a `CSOrderBy` clause with a list of sort descriptors + The list of sort descriptors */ @objc - public static func sortDescriptors(sortDescriptors: [NSSortDescriptor]) -> CSOrderBy { + public var sortDescriptors: [NSSortDescriptor] { - return self.init(OrderBy(sortDescriptors)) + return self.bridgeToSwift.sortDescriptors } /** Initializes a `CSOrderBy` clause with a single sort descriptor + ``` + MyPersonEntity *people = [transaction + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSOrderBySortKey(CSSortAscending(@"fullname"))]]]; + ``` - parameter sortDescriptor: a `NSSortDescriptor` - - returns: a `CSOrderBy` clause with a single sort descriptor */ @objc - public static func sortDescriptor(sortDescriptor: NSSortDescriptor) -> CSOrderBy { + public convenience init(sortDescriptor: NSSortDescriptor) { - return self.init(OrderBy(sortDescriptor)) + self.init(OrderBy(sortDescriptor)) + } + + /** + Initializes a `CSOrderBy` clause with a list of sort descriptors + ``` + MyPersonEntity *people = [transaction + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSOrderBySortKeys(CSSortAscending(@"fullname"), CSSortDescending(@"age"), nil))]]]; + ``` + + - parameter sortDescriptors: an array of `NSSortDescriptor`s + */ + @objc + public convenience init(sortDescriptors: [NSSortDescriptor]) { + + self.init(OrderBy(sortDescriptors)) } diff --git a/Sources/ObjectiveC/CSSelect.swift b/Sources/ObjectiveC/CSSelect.swift index adae8d7..fd6c1c3 100644 --- a/Sources/ObjectiveC/CSSelect.swift +++ b/Sources/ObjectiveC/CSSelect.swift @@ -42,16 +42,16 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType { ``` NSString *fullName = [CSCoreStore queryValueFrom:[CSFrom entityClass:[MyPersonEntity class]] - select:[CSSelect stringForTerm:[CSSelectTerm attribute:@"fullName"]] + select:CSSelectString(CSAttribute(@"fullname")) fetchClauses:@[[CSWhere keyPath:@"employeeID" isEqualTo: @1111]]]; ``` - parameter keyPath: the attribute name - - returns: a `CSSelectTerm` to a `CSSelect` clause for querying an entity attribute */ - public static func attribute(keyPath: KeyPath) -> CSSelectTerm { + @objc + public convenience init(keyPath: KeyPath) { - return self.init(.Attribute(keyPath)) + self.init(.Attribute(keyPath)) } /** @@ -66,6 +66,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType { - parameter `as`: 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()" is used - returns: a `CSSelectTerm` to a `CSSelect` clause for querying the average value of an attribute */ + @objc public static func average(keyPath: KeyPath, `as` alias: KeyPath?) -> CSSelectTerm { return self.init(.Average(keyPath, As: alias)) @@ -83,6 +84,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType { - 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()" is used - returns: a `SelectTerm` to a `Select` clause for a count query */ + @objc public static func count(keyPath: KeyPath, `as` alias: KeyPath?) -> CSSelectTerm { return self.init(.Count(keyPath, As: alias)) @@ -100,6 +102,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType { - 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()" is used - returns: a `CSSelectTerm` to a `CSSelect` clause for querying the maximum value for an attribute */ + @objc public static func maximum(keyPath: KeyPath, `as` alias: KeyPath?) -> CSSelectTerm { return self.init(.Maximum(keyPath, As: alias)) @@ -117,6 +120,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType { - 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()" is used - returns: a `CSSelectTerm` to a `CSSelect` clause for querying the minimum value for an attribute */ + @objc public static func minimum(keyPath: KeyPath, `as` alias: KeyPath?) -> CSSelectTerm { return self.init(.Minimum(keyPath, As: alias)) @@ -134,6 +138,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType { - 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()" is used - returns: a `CSSelectTerm` to a `CSSelect` clause for querying the sum value for an attribute */ + @objc public static func sum(keyPath: KeyPath, `as` alias: KeyPath?) -> CSSelectTerm { return self.init(.Sum(keyPath, As: alias)) @@ -152,16 +157,13 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType { - 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 objectIDAs(alias: KeyPath? = nil) -> SelectTerm { + @objc + public static func objectIDAs(alias: KeyPath? = nil) -> CSSelectTerm { - return ._Identity( - alias: alias ?? "objectID", - nativeType: .ObjectIDAttributeType - ) + return self.init(.ObjectID(As: alias)) } - // MARK: NSObject public override var hash: Int { @@ -214,100 +216,97 @@ public final class CSSelect: NSObject { /** Creates a `CSSelect` clause for querying `NSNumber` values. ``` - NSNumber *maximumAge = [CSCoreStore - queryValueFrom:[CSFrom entityClass:[MyPersonEntity class]] - select:[CSSelect numberForTerm:[CSSelectTerm maximum:@"age" as:nil]]]; + NSNumber *maxAge = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectNumber(CSAggregateMax(@"age")) + // ... ``` - parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - - returns: a `CSSelect` clause for querying an entity attribute */ - public static func numberForTerm(term: CSSelectTerm) -> CSSelect { + public convenience init(numberTerm: CSSelectTerm) { - return self.init(Select(term.bridgeToSwift)) + self.init(Select(numberTerm.bridgeToSwift)) } /** Creates a `CSSelect` clause for querying `NSDecimalNumber` values. ``` - NSNumber *averageAge = [CSCoreStore - queryValueFrom:[CSFrom entityClass:[MyPersonEntity class]] - select:[CSSelect decimalNumberForTerm:[CSSelectTerm average:@"age" as:nil]]]; + NSDecimalNumber *averagePrice = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectDecimal(CSAggregateAverage(@"price")) + // ... ``` - parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - - returns: a `CSSelect` clause for querying an entity attribute */ - public static func decimalNumberForTerm(term: CSSelectTerm) -> CSSelect { + public convenience init(decimalTerm: CSSelectTerm) { - return self.init(Select(term.bridgeToSwift)) + self.init(Select(decimalTerm.bridgeToSwift)) } /** Creates a `CSSelect` clause for querying `NSString` values. ``` - NSString *fullName = [CSCoreStore - queryValueFrom:[CSFrom entityClass:[MyPersonEntity class]] - select:[CSSelect stringForTerm:[CSSelectTerm attribute:@"fullName"]] - fetchClauses:@[[CSWhere keyPath:@"employeeID" isEqualTo: @1111]]]; + NSString *fullname = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectString(CSAttribute(@"fullname")) + // ... ``` - parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - - returns: a `CSSelect` clause for querying an entity attribute */ - public static func stringForTerm(term: CSSelectTerm) -> CSSelect { + public convenience init(stringTerm: CSSelectTerm) { - return self.init(Select(term.bridgeToSwift)) + self.init(Select(stringTerm.bridgeToSwift)) } /** Creates a `CSSelect` clause for querying `NSDate` values. ``` - NSDate *lastUpdatedDate = [CSCoreStore - queryValueFrom:[CSFrom entityClass:[MyPersonEntity class]] - select:[CSSelect dateForTerm:[CSSelectTerm maximum:@"updatedDate" as:nil]]]; + NSDate *lastUpdate = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectDate(CSAggregateMax(@"updatedDate")) + // ... ``` - parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - - returns: a `CSSelect` clause for querying an entity attribute */ - public static func dateForTerm(term: CSSelectTerm) -> CSSelect { + public convenience init(dateTerm: CSSelectTerm) { - return self.init(Select(term.bridgeToSwift)) + self.init(Select(dateTerm.bridgeToSwift)) } /** Creates a `CSSelect` clause for querying `NSData` values. ``` NSData *imageData = [CSCoreStore - queryValueFrom:[CSFrom entityClass:[MyPersonEntity class]] - select:[CSSelect dataForTerm:[CSSelectTerm attribute:@"imageData" as:nil]] - fetchClauses:@[[CSWhere keyPath:@"employeeID" isEqualTo: @1111]]]; + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectData(CSAttribute(@"imageData")) + // ... ``` - parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - - returns: a `CSSelect` clause for querying an entity attribute */ - public static func dataForTerm(term: CSSelectTerm) -> CSSelect { + public convenience init(dataTerm: CSSelectTerm) { - return self.init(Select(term.bridgeToSwift)) + self.init(Select(dataTerm.bridgeToSwift)) } /** Creates a `CSSelect` clause for querying `NSManagedObjectID` values. ``` - NSManagedObjectID *objectIDForOldest = [CSCoreStore - queryValueFrom:[CSFrom entityClass:[MyPersonEntity class]] - select:[CSSelect objectID] - fetchClauses:@[[CSWhere keyPath:@"employeeID" isEqualTo: @1111]]]; + NSManagedObjectID *objectID = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectObjectID() + // ... ``` - parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - - returns: a `CSSelect` clause for querying an entity attribute */ - public static func objectID() -> CSSelect { + public convenience init(objectIDTerm: ()) { - return self.init(Select(.ObjectID())) + self.init(Select(.ObjectID())) } /** diff --git a/Sources/ObjectiveC/CSTweak.swift b/Sources/ObjectiveC/CSTweak.swift index b41640b..5c9864f 100644 --- a/Sources/ObjectiveC/CSTweak.swift +++ b/Sources/ObjectiveC/CSTweak.swift @@ -38,15 +38,24 @@ import CoreData public final class CSTweak: NSObject, CSFetchClause, CSQueryClause, CSDeleteClause, CoreStoreObjectiveCType { /** - Initializes a `CSTweak` clause with a closure where the `NSFetchRequest` may be configured. - - - parameter customization: a list of key path strings to group results with - - returns: a `CSTweak` clause with a closure where the `NSFetchRequest` may be configured + The block to customize the `NSFetchRequest` */ @objc - public static func customization(customization: (fetchRequest: NSFetchRequest) -> Void) -> CSTweak { + public var block: (fetchRequest: NSFetchRequest) -> Void { - return self.init(Tweak(customization)) + return self.bridgeToSwift.closure + } + + /** + Initializes a `CSTweak` clause with a closure where the `NSFetchRequest` may be configured. + + - Important: `CSTweak`'s closure is executed only just before the fetch occurs, so make sure that any values captured by the closure is not prone to race conditions. Also, some utilities (such as `CSListMonitor`s) may keep `CSFetchClause`s in memory and may thus introduce retain cycles if reference captures are not handled properly. + - parameter block: the block to customize the `NSFetchRequest` + */ + @objc + public convenience init(block: (fetchRequest: NSFetchRequest) -> Void) { + + self.init(Tweak(block)) } diff --git a/Sources/ObjectiveC/CSWhere.swift b/Sources/ObjectiveC/CSWhere.swift index 12ffe74..3710187 100644 --- a/Sources/ObjectiveC/CSWhere.swift +++ b/Sources/ObjectiveC/CSWhere.swift @@ -48,27 +48,36 @@ public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau /** Initializes a `CSWhere` clause with a predicate that always evaluates to the specified boolean value + ``` + MyPersonEntity *people = [transaction + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSWhereValue(YES)]]]; + ``` - parameter value: the boolean value for the predicate - - returns: a `CSWhere` clause with a predicate that always evaluates to the specified boolean value */ @objc - public static func value(value: Bool) -> CSWhere { + public convenience init(value: Bool) { - return self.init(Where(value)) + self.init(Where(value)) } /** Initializes a `CSWhere` clause with a predicate using the specified string format and arguments + ``` + NSPredicate *predicate = // ... + MyPersonEntity *people = [transaction + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSWherePredicate(predicate)]]; + ``` - parameter format: the format string for the predicate - parameter argumentArray: the arguments for `format` - - returns: a `CSWhere` clause with a predicate using the specified string format and arguments */ @objc - public static func format(format: String, argumentArray: [NSObject]?) -> CSWhere { + public convenience init(format: String, argumentArray: [NSObject]?) { - return self.init(Where(format, argumentArray: argumentArray)) + self.init(Where(format, argumentArray: argumentArray)) } /** @@ -76,12 +85,11 @@ public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau - parameter keyPath: the keyPath to compare with - parameter value: the arguments for the `==` operator - - returns: a `CSWhere` clause that compares equality */ @objc - public static func keyPath(keyPath: KeyPath, isEqualTo value: NSObject?) -> CSWhere { + public convenience init(keyPath: KeyPath, isEqualTo value: NSObject?) { - return self.init(Where(keyPath, isEqualTo: value)) + self.init(Where(keyPath, isEqualTo: value)) } /** @@ -89,24 +97,22 @@ public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau - parameter keyPath: the keyPath to compare with - parameter list: the array to check membership of - - returns: a `CSWhere` clause that compares membership */ @objc - public static func keyPath(keyPath: KeyPath, isMemberOf list: [NSObject]) -> CSWhere { + public convenience init(keyPath: KeyPath, isMemberOf list: [NSObject]) { - return self.init(Where(keyPath, isMemberOf: list)) + self.init(Where(keyPath, isMemberOf: list)) } /** Initializes a `CSWhere` clause with an `NSPredicate` - parameter predicate: the `NSPredicate` for the fetch or query - - returns: a `CSWhere` clause with an `NSPredicate` */ @objc - public static func predicate(predicate: NSPredicate) -> CSWhere { + public convenience init(predicate: NSPredicate) { - return self.init(Where(predicate)) + self.init(Where(predicate)) } diff --git a/Sources/ObjectiveC/CoreStoreBridge.h b/Sources/ObjectiveC/CoreStoreBridge.h index 6c93e94..e83b75c 100644 --- a/Sources/ObjectiveC/CoreStoreBridge.h +++ b/Sources/ObjectiveC/CoreStoreBridge.h @@ -23,11 +23,12 @@ // SOFTWARE. // -#import - #ifndef CoreStoreBridge_h #define CoreStoreBridge_h +#import +#import + #if !__has_feature(objc_arc) #error CoreStore Objective-C utilities require ARC be enabled #endif @@ -36,9 +37,10 @@ #error CoreStore Objective-C utilities can only be used on platforms that support C function overloading #endif -#define CS_OBJC_EXTERN extern -#define CS_OBJC_OVERLOADABLE __attribute__((__overloadable__)) -#define CS_OBJC_REQUIRES_NIL_TERMINATION(A, B) __attribute__((sentinel(A, B))) +#define CS_OBJC_EXTERN extern +#define CS_OBJC_OVERLOADABLE __attribute__((__overloadable__)) +#define CS_OBJC_REQUIRES_NIL_TERMINATION __attribute__((sentinel(0, 1))) +#define CS_OBJC_RETURNS_RETAINED __attribute__((ns_returns_retained)) // MARK: - From @@ -50,7 +52,8 @@ Initializes a CSFrom clause with the specified entity class. @code - MyPersonEntity *people = [transaction fetchAllFrom:From([MyPersonEntity class])]; + MyPersonEntity *people = [transaction fetchAllFrom: + CSFromCreate([MyPersonEntity class])]; @endcode @param entityClass @@ -60,14 +63,58 @@ a CSFrom clause with the specified entity class */ CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE -CSFrom *_Nonnull From(Class _Nonnull entityClass); +CSFrom *_Nonnull CSFromCreate(Class _Nonnull entityClass) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Initializes a CSFrom clause with the specified configuration. + + @code + MyPersonEntity *people = [transaction fetchAllFrom: + CSFromCreate([MyPersonEntity class], @"Configuration1")]; + @endcode + + @param entityClass + the NSManagedObject class type to be created + + @param configuration + an NSPersistentStore configuration name to associate objects from. This parameter is required if multiple configurations contain the created NSManagedObject's entity type. Set to [NSNull null] to use the default configuration. + + @result + a CSFrom clause with the specified configuration + */ +CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE +CSFrom *_Nonnull CSFromCreate(Class _Nonnull entityClass, NSNull *_Nonnull configuration) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Initializes a CSFrom clause with the specified configuration. + + @code + MyPersonEntity *people = [transaction fetchAllFrom: + CSFromCreate([MyPersonEntity class], @"Configuration1")]; + @endcode + + @param entityClass + the NSManagedObject class type to be created + + @param configuration + an NSPersistentStore configuration name to associate objects from. This parameter is required if multiple configurations contain the created NSManagedObject's entity type. Set to [NSNull null] to use the default configuration. + + @result + a CSFrom clause with the specified configuration + */ +CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE +CSFrom *_Nonnull CSFromCreate(Class _Nonnull entityClass, NSString *_Nonnull configuration) CS_OBJC_RETURNS_RETAINED; /** @abstract Initializes a CSFrom clause with the specified configurations. @code - MyPersonEntity *people = [transaction fetchAllFrom:From([MyPersonEntity class], @[@"Configuration1"])]; + MyPersonEntity *people = [transaction fetchAllFrom: + CSFromCreate([MyPersonEntity class], + @[[NSNull null], @"Configuration1"])]; @endcode @param entityClass @@ -80,9 +127,134 @@ CSFrom *_Nonnull From(Class _Nonnull entityClass); a CSFrom clause with the specified configurations */ CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE -CSFrom *_Nonnull From(Class _Nonnull entityClass, NSArray *_Nonnull configurations); +CSFrom *_Nonnull CSFromCreate(Class _Nonnull entityClass, NSArray *_Nonnull configurations) CS_OBJC_RETURNS_RETAINED; +// MARK: - Select + +@class CSSelect; +@class CSSelectTerm; + +/** + @abstract + Creates a CSSelect clause for querying an NSNumber value + + @code + NSNumber *maxAge = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectNumber(CSAggregateMax(@"age")) + // ... + @endcode + + @param selectTerm + the CSSelectTerm specifying the attribute/aggregate value to query + + @result + a CSSelect clause for querying an NSNumber value + */ +CS_OBJC_EXTERN +CSSelect *_Nonnull CSSelectNumber(CSSelectTerm *_Nonnull selectTerm) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Creates a CSSelect clause for querying an NSDecimalNumber value + + @code + NSDecimalNumber *averagePrice = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectDecimal(CSAggregateAverage(@"price")) + // ... + @endcode + + @param selectTerm + the CSSelectTerm specifying the attribute/aggregate value to query + + @result + a CSSelect clause for querying an NSDecimalNumber value + */ +CS_OBJC_EXTERN +CSSelect *_Nonnull CSSelectDecimal(CSSelectTerm *_Nonnull selectTerm) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Creates a CSSelect clause for querying an NSString value + + @code + NSString *fullname = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectString(CSAttribute(@"fullname")) + // ... + @endcode + + @param selectTerm + the CSSelectTerm specifying the attribute/aggregate value to query + + @result + a CSSelect clause for querying an NSString value + */ +CS_OBJC_EXTERN +CSSelect *_Nonnull CSSelectString(CSSelectTerm *_Nonnull selectTerm) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Creates a CSSelect clause for querying an NSDate value + + @code + NSDate *lastUpdate = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectDate(CSAggregateMax(@"updatedDate")) + // ... + @endcode + + @param selectTerm + the CSSelectTerm specifying the attribute/aggregate value to query + + @result + a CSSelect clause for querying an NSDate value + */ +CS_OBJC_EXTERN +CSSelect *_Nonnull CSSelectDate(CSSelectTerm *_Nonnull selectTerm) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Creates a CSSelect clause for querying an NSData value + + @code + NSData *imageData = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectData(CSAttribute(@"imageData")) + // ... + @endcode + + @param selectTerm + the CSSelectTerm specifying the attribute/aggregate value to query + + @result + a CSSelect clause for querying an NSData value + */ +CS_OBJC_EXTERN +CSSelect *_Nonnull CSSelectData(CSSelectTerm *_Nonnull selectTerm) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Creates a CSSelect clause for querying an NSManagedObjectID value + + @code + NSManagedObjectID *objectID = [CSCoreStore + queryValueFrom:CSFromCreate([MyPersonEntity class]) + select:CSSelectObjectID() + // ... + @endcode + + @param selectTerm + the CSSelectTerm specifying the attribute/aggregate value to query + + @result + a CSSelect clause for querying an NSManagedObjectID value + */ +CS_OBJC_EXTERN +CSSelect *_Nonnull CSSelectObjectID() CS_OBJC_RETURNS_RETAINED; + // MARK: - Where @@ -92,19 +264,31 @@ CSFrom *_Nonnull From(Class _Nonnull entityClass, NSArray *_Nonnull configur @abstract Initializes a CSWhere clause with a predicate that always evaluates to the specified boolean value + @code + MyPersonEntity *people = [transaction + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSWhereValue(YES)]]; + @endcode + @param value the boolean value for the predicate @result a CSWhere clause with a predicate that always evaluates to the specified boolean value */ -CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE -CSWhere *_Nonnull Where(BOOL value); +CS_OBJC_EXTERN +CSWhere *_Nonnull CSWhereValue(BOOL value) CS_OBJC_RETURNS_RETAINED; /** @abstract Initializes a CSWhere clause with a predicate using the specified string format and arguments + @code + MyPersonEntity *people = [transaction + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSWhereFormat(@"%K == %@", @"key", @"value")]]; + @endcode + @param format the format string for the predicate @@ -114,27 +298,160 @@ CSWhere *_Nonnull Where(BOOL value); @result a CSWhere clause with a predicate using the specified string format and arguments */ -CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE -CSWhere *_Nonnull Where(NSString *_Nonnull format, ...); +CS_OBJC_EXTERN +CSWhere *_Nonnull CSWhereFormat(NSString *_Nonnull format, ...) CS_OBJC_RETURNS_RETAINED; /** @abstract Initializes a CSWhere clause with an NSPredicate + @code + NSPredicate *predicate = // ... + MyPersonEntity *people = [transaction + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSWherePredicate(predicate)]]; + @endcode + @param predicate the NSPredicate for the fetch or query @result a CSWhere clause with an NSPredicate */ +CS_OBJC_EXTERN +CSWhere *_Nonnull CSWherePredicate(NSPredicate *_Nonnull predicate) CS_OBJC_RETURNS_RETAINED; + + +// MARK: - OrderBy + +@class CSOrderBy; + +/** + @abstract + Syntax sugar for initializing an ascending NSSortDescriptor for use with CSOrderBy + + @code + MyPersonEntity *people = [CSCoreStore + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSOrderBySortKey(CSSortAscending(@"fullname"))]]]; + @endcode + + @param key + the attribute key to sort with + + @result + an NSSortDescriptor for use with CSOrderBy + */ +CS_OBJC_EXTERN +NSSortDescriptor *_Nonnull CSSortAscending(NSString *_Nonnull key) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Syntax sugar for initializing a descending NSSortDescriptor for use with CSOrderBy + + @code + MyPersonEntity *people = [CSCoreStore + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSOrderBySortKey(CSSortDescending(@"fullname"))]]]; + @endcode + + @param key + the attribute key to sort with + + @result + an NSSortDescriptor for use with CSOrderBy + */ +CS_OBJC_EXTERN +NSSortDescriptor *_Nonnull CSSortDescending(NSString *_Nonnull key) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Initializes a CSOrderBy clause with a single sort descriptor + + @code + MyPersonEntity *people = [transaction + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSOrderBySortKey(CSSortAscending(@"fullname"))]]]; + @endcode + + @param sortDescriptor + an NSSortDescriptor + + @result + a CSOrderBy clause with a single sort descriptor + */ +CS_OBJC_EXTERN +CSOrderBy *_Nonnull CSOrderBySortKey(NSSortDescriptor *_Nonnull sortDescriptor) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Initializes a CSOrderBy clause with a list of sort descriptors + + @code + MyPersonEntity *people = [transaction + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSOrderBySortKeys(CSSortAscending(@"fullname"), CSSortDescending(@"age"), nil))]]]; + @endcode + + @param sortDescriptors + a nil-terminated array of NSSortDescriptors + + @result + a CSOrderBy clause with a list of sort descriptors + */ CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE -CSWhere *_Nonnull Where(NSPredicate *_Nonnull predicate); +CSOrderBy *_Nonnull CSOrderBySortKeys(NSSortDescriptor *_Nonnull sortDescriptor, ...) CS_OBJC_RETURNS_RETAINED CS_OBJC_REQUIRES_NIL_TERMINATION; + +/** + @abstract + Initializes a CSOrderBy clause with a list of sort descriptors + + @code + MyPersonEntity *people = [transaction + fetchAllFrom:CSFromCreate([MyPersonEntity class]) + fetchClauses:@[CSOrderBySortKeys(@[CSSortAscending(@"fullname"), CSSortDescending(@"age")]))]]]; + @endcode + + @param sortDescriptors + an array of NSSortDescriptors + + @result + a CSOrderBy clause with a list of sort descriptors + */ +CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE +CSOrderBy *_Nonnull CSOrderBySortKeys(NSArray *_Nonnull sortDescriptors) CS_OBJC_RETURNS_RETAINED; // MARK: - GroupBy @class CSGroupBy; +/** + @abstract + Initializes a CSGroupBy clause with a key path string + + @param keyPaths + a key path string to group results with + + @result + a CSGroupBy clause with a key path string + */ +CS_OBJC_EXTERN +CSGroupBy *_Nonnull CSGroupByKeyPath(NSString *_Nonnull keyPath) CS_OBJC_RETURNS_RETAINED; + +/** + @abstract + Initializes a CSGroupBy clause with a list of key path strings + + @param keyPaths + a nil-terminated list of key path strings to group results with + + @result + a CSGroupBy clause with a list of key path strings + */ +CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE +CSGroupBy *_Nonnull CSGroupByKeyPaths(NSString *_Nonnull keyPath, ...) CS_OBJC_RETURNS_RETAINED; + /** @abstract Initializes a CSGroupBy clause with a list of key path strings @@ -145,8 +462,29 @@ CSWhere *_Nonnull Where(NSPredicate *_Nonnull predicate); @result a CSGroupBy clause with a list of key path strings */ -CS_OBJC_OVERLOADABLE -CSGroupBy *_Nonnull GroupBy(NSArray *_Nonnull keyPaths); +CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE +CSGroupBy *_Nonnull CSGroupByKeyPaths(NSArray *_Nonnull keyPaths) CS_OBJC_RETURNS_RETAINED; + + +// MARK: - Tweak + +@class CSTweak; + +/** + @abstract + Initializes a CSTweak clause with a block where the NSFetchRequest may be configured. + + @important + CSTweak's closure is executed only just before the fetch occurs, so make sure that any values captured by the closure is not prone to race conditions. Also, some utilities (such as CSListMonitors) may keep CSFetchClauses in memory and may thus introduce retain cycles if reference captures are not handled properly. + + @param block + the block to customize the NSFetchRequest + + @result + a CSTweak clause with the NSFetchRequest configuration block + */ +CS_OBJC_EXTERN CS_OBJC_OVERLOADABLE +CSTweak *_Nonnull CSTweakCreate(void (^_Nonnull block)(NSFetchRequest *_Nonnull fetchRequest)) CS_OBJC_RETURNS_RETAINED; #endif /* CoreStoreBridge_h */ diff --git a/Sources/ObjectiveC/CoreStoreBridge.m b/Sources/ObjectiveC/CoreStoreBridge.m index f71a466..8f25e99 100644 --- a/Sources/ObjectiveC/CoreStoreBridge.m +++ b/Sources/ObjectiveC/CoreStoreBridge.m @@ -28,49 +28,171 @@ CS_OBJC_OVERLOADABLE -CSFrom *_Nonnull From(Class _Nonnull entityClass) { +CSFrom *_Nonnull CSFromCreate(Class _Nonnull entityClass) CS_OBJC_RETURNS_RETAINED { - return [CSFrom entityClass:entityClass]; + return [[CSFrom alloc] initWithEntityClass:entityClass]; } CS_OBJC_OVERLOADABLE -CSFrom *_Nonnull From(Class _Nonnull entityClass, NSArray *_Nonnull configurations) { +CSFrom *_Nonnull CSFromCreate(Class _Nonnull entityClass, NSNull *_Nonnull configuration) CS_OBJC_RETURNS_RETAINED { - return [CSFrom entityClass:entityClass configurations:configurations]; + return [[CSFrom alloc] initWithEntityClass:entityClass configuration:configuration]; } +CS_OBJC_OVERLOADABLE +CSFrom *_Nonnull CSFromCreate(Class _Nonnull entityClass, NSString *_Nonnull configuration) CS_OBJC_RETURNS_RETAINED { + + return [[CSFrom alloc] initWithEntityClass:entityClass configuration:configuration]; +} + +CS_OBJC_OVERLOADABLE +CSFrom *_Nonnull CSFromCreate(Class _Nonnull entityClass, NSArray *_Nonnull configurations) CS_OBJC_RETURNS_RETAINED { + + return [[CSFrom alloc] initWithEntityClass:entityClass configurations:configurations]; +} + + +// MARK: - Select + +//CSSelectTerm *_Nonnull CSAttribute(NSString *_Nonnull keyPath) CS_OBJC_RETURNS_RETAINED { +// +// return [[CSSelectTerm alloc] initWithKeyPath:keyPath]; +//} + +CSSelect *_Nonnull CSSelectNumber(CSSelectTerm *_Nonnull selectTerm) CS_OBJC_RETURNS_RETAINED { + + return [[CSSelect alloc] initWithNumberTerm:selectTerm]; +} + +CSSelect *_Nonnull CSSelectDecimal(CSSelectTerm *_Nonnull selectTerm) CS_OBJC_RETURNS_RETAINED { + + return [[CSSelect alloc] initWithDecimalTerm:selectTerm]; +} + +CSSelect *_Nonnull CSSelectString(CSSelectTerm *_Nonnull selectTerm) CS_OBJC_RETURNS_RETAINED { + + return [[CSSelect alloc] initWithStringTerm:selectTerm]; +} + +CSSelect *_Nonnull CSSelectDate(CSSelectTerm *_Nonnull selectTerm) CS_OBJC_RETURNS_RETAINED { + + return [[CSSelect alloc] initWithDateTerm:selectTerm]; +} + +CSSelect *_Nonnull CSSelectData(CSSelectTerm *_Nonnull selectTerm) CS_OBJC_RETURNS_RETAINED { + + return [[CSSelect alloc] initWithDataTerm:selectTerm]; +} + +CSSelect *_Nonnull CSSelectObjectID() CS_OBJC_RETURNS_RETAINED { + + return [[CSSelect alloc] initWithObjectIDTerm]; +} // MARK: - Where -CS_OBJC_OVERLOADABLE -CSWhere *_Nonnull Where(BOOL value) { +CSWhere *_Nonnull CSWhereValue(BOOL value) CS_OBJC_RETURNS_RETAINED { - return [CSWhere value:value]; + return [[CSWhere alloc] initWithValue:value]; } -CS_OBJC_OVERLOADABLE -CSWhere *_Nonnull Where(NSString *_Nonnull format, ...) { +CSWhere *_Nonnull CSWhereFormat(NSString *_Nonnull format, ...) CS_OBJC_RETURNS_RETAINED { CSWhere *where; va_list args; va_start(args, format); - where = [CSWhere predicate:[NSPredicate predicateWithFormat:format arguments:args]]; + where = [[CSWhere alloc] initWithPredicate:[NSPredicate predicateWithFormat:format arguments:args]]; va_end(args); return where; } -CS_OBJC_OVERLOADABLE -CSWhere *_Nonnull Where(NSPredicate *_Nonnull predicate) { +CSWhere *_Nonnull CSWherePredicate(NSPredicate *_Nonnull predicate) CS_OBJC_RETURNS_RETAINED { - return [CSWhere predicate:predicate]; + return [[CSWhere alloc] initWithPredicate:predicate]; +} + + +// MARK: - OrderBy + +@class CSOrderBy; + +NSSortDescriptor *_Nonnull CSSortAscending(NSString *_Nonnull key) { + + return [[NSSortDescriptor alloc] initWithKey:key ascending:YES]; +} + +NSSortDescriptor *_Nonnull CSSortDescending(NSString *_Nonnull key) { + + return [[NSSortDescriptor alloc] initWithKey:key ascending:NO]; +} + +CSOrderBy *_Nonnull CSOrderBySortKey(NSSortDescriptor *_Nonnull sortDescriptor) CS_OBJC_RETURNS_RETAINED { + + return [[CSOrderBy alloc] initWithSortDescriptor:sortDescriptor]; +} + +CS_OBJC_OVERLOADABLE +CSOrderBy *_Nonnull CSOrderBySortKeys(NSSortDescriptor *_Nonnull sortDescriptor, ...) CS_OBJC_RETURNS_RETAINED { + + va_list args; + va_start(args, sortDescriptor); + + NSMutableArray *sortDescriptors = [NSMutableArray new]; + [sortDescriptors addObject:sortDescriptor]; + + NSSortDescriptor *next; + while ((next = va_arg(args, NSSortDescriptor *)) != nil) { + + [sortDescriptors addObject:next]; + } + va_end(args); + return [[CSOrderBy alloc] initWithSortDescriptors:sortDescriptors]; +} + +CS_OBJC_OVERLOADABLE +CSOrderBy *_Nonnull CSOrderBySortKeys(NSArray *_Nonnull sortDescriptors) CS_OBJC_RETURNS_RETAINED { + + return [[CSOrderBy alloc] initWithSortDescriptors:sortDescriptors]; } // MARK: - GroupBy -CS_OBJC_OVERLOADABLE -CSGroupBy *_Nonnull GroupBy(NSArray *_Nonnull keyPaths) { - - return [CSGroupBy keyPaths:keyPaths]; +CSGroupBy *_Nonnull CSGroupByKeyPath(NSString *_Nonnull keyPath) CS_OBJC_RETURNS_RETAINED { + + return [[CSGroupBy alloc] initWithKeyPath:keyPath]; +} + +CS_OBJC_OVERLOADABLE +CSGroupBy *_Nonnull CSGroupByKeyPaths(NSString *_Nonnull keyPath, ...) CS_OBJC_RETURNS_RETAINED { + + va_list args; + va_start(args, keyPath); + + NSMutableArray *keyPaths = [NSMutableArray new]; + [keyPaths addObject:keyPath]; + + NSString *next; + while ((next = va_arg(args, NSString *)) != nil) { + + [keyPaths addObject:next]; + } + va_end(args); + return [[CSGroupBy alloc] initWithKeyPaths:keyPaths]; +} + +CS_OBJC_OVERLOADABLE +CSGroupBy *_Nonnull CSGroupByKeyPaths(NSArray *_Nonnull keyPaths) CS_OBJC_RETURNS_RETAINED { + + return [[CSGroupBy alloc] initWithKeyPaths:keyPaths]; +} + + +// MARK: - Tweak + +CS_OBJC_OVERLOADABLE +CSTweak *_Nonnull CSTweakCreate(void (^_Nonnull block)(NSFetchRequest *_Nonnull fetchRequest)) CS_OBJC_RETURNS_RETAINED { + + return [[CSTweak alloc] initWithBlock:block]; }