diff --git a/CoreStoreTests/QueryTests.swift b/CoreStoreTests/QueryTests.swift index a82b963..a848c46 100644 --- a/CoreStoreTests/QueryTests.swift +++ b/CoreStoreTests/QueryTests.swift @@ -49,7 +49,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testBoolean)), + Select(#keyPath(TestEntity1.testBoolean)), queryClauses ) XCTAssertNotNil(value) @@ -59,7 +59,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testNumber)), + Select(#keyPath(TestEntity1.testNumber)), queryClauses ) XCTAssertNotNil(value) @@ -69,7 +69,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testNumber)), + Select(#keyPath(TestEntity1.testNumber)), queryClauses ) XCTAssertNotNil(value) @@ -79,7 +79,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testNumber)), + Select(#keyPath(TestEntity1.testNumber)), queryClauses ) XCTAssertNotNil(value) @@ -89,7 +89,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testNumber)), + Select(#keyPath(TestEntity1.testNumber)), queryClauses ) XCTAssertNotNil(value) @@ -99,7 +99,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testNumber)), + Select(#keyPath(TestEntity1.testNumber)), queryClauses ) XCTAssertNotNil(value) @@ -109,7 +109,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testNumber)), + Select(#keyPath(TestEntity1.testNumber)), queryClauses ) XCTAssertNotNil(value) @@ -119,7 +119,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testNumber)), + Select(#keyPath(TestEntity1.testNumber)), queryClauses ) XCTAssertNotNil(value) @@ -129,7 +129,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testNumber)), + Select(#keyPath(TestEntity1.testNumber)), queryClauses ) XCTAssertNotNil(value) @@ -139,7 +139,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testDecimal)), + Select(#keyPath(TestEntity1.testDecimal)), queryClauses ) XCTAssertNotNil(value) @@ -149,7 +149,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testString)), + Select(#keyPath(TestEntity1.testString)), queryClauses ) XCTAssertNotNil(value) @@ -159,7 +159,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testString)), + Select(#keyPath(TestEntity1.testString)), queryClauses ) XCTAssertNotNil(value) @@ -169,7 +169,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testData)), + Select(#keyPath(TestEntity1.testData)), queryClauses ) XCTAssertNotNil(value) @@ -179,7 +179,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testData)), + Select(#keyPath(TestEntity1.testData)), queryClauses ) XCTAssertNotNil(value) @@ -189,7 +189,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testDate)), + Select(#keyPath(TestEntity1.testDate)), queryClauses ) XCTAssertNotNil(value) @@ -199,7 +199,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testDate)), + Select(#keyPath(TestEntity1.testDate)), queryClauses ) XCTAssertNotNil(value) @@ -209,7 +209,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testDate)), + Select(#keyPath(TestEntity1.testDate)), queryClauses ) XCTAssertNil(value) @@ -234,7 +234,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testBoolean))), + Select(.average(#keyPath(TestEntity1.testBoolean))), queryClauses ) XCTAssertNotNil(value) @@ -244,7 +244,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testNumber))), + Select(.average(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -254,7 +254,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testNumber))), + Select(.average(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -264,7 +264,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testNumber))), + Select(.average(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -274,7 +274,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testNumber))), + Select(.average(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -284,7 +284,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testNumber))), + Select(.average(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -294,7 +294,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testNumber))), + Select(.average(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -304,7 +304,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testNumber))), + Select(.average(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -314,7 +314,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testNumber))), + Select(.average(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -324,7 +324,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testDecimal))), + Select(.average(#keyPath(TestEntity1.testDecimal))), queryClauses ) XCTAssertNotNil(value) @@ -334,7 +334,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testString))), + Select(.average(#keyPath(TestEntity1.testString))), queryClauses ) XCTAssertNil(value) @@ -343,7 +343,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testString))), + Select(.average(#keyPath(TestEntity1.testString))), queryClauses ) XCTAssertNil(value) @@ -352,7 +352,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testData))), + Select(.average(#keyPath(TestEntity1.testData))), queryClauses ) XCTAssertNil(value) @@ -361,7 +361,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testData))), + Select(.average(#keyPath(TestEntity1.testData))), queryClauses ) XCTAssertNil(value) @@ -370,7 +370,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testDate))), + Select(.average(#keyPath(TestEntity1.testDate))), queryClauses ) XCTAssertNil(value) @@ -379,7 +379,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.average(#keyPath(TestEntity1.testDate))), + Select(.average(#keyPath(TestEntity1.testDate))), queryClauses ) XCTAssertNil(value) @@ -388,7 +388,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(#keyPath(TestEntity1.testEntityID)), + Select(#keyPath(TestEntity1.testEntityID)), queryClauses ) XCTAssertNil(value) @@ -412,7 +412,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testBoolean))), + Select(.count(#keyPath(TestEntity1.testBoolean))), queryClauses ) XCTAssertNotNil(value) @@ -422,7 +422,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testNumber))), + Select(.count(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -432,7 +432,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testNumber))), + Select(.count(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -442,7 +442,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testNumber))), + Select(.count(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -452,7 +452,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testNumber))), + Select(.count(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -462,7 +462,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testNumber))), + Select(.count(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -472,7 +472,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testNumber))), + Select(.count(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -482,7 +482,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testNumber))), + Select(.count(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -492,7 +492,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testNumber))), + Select(.count(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -502,7 +502,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testDecimal))), + Select(.count(#keyPath(TestEntity1.testDecimal))), queryClauses ) XCTAssertNil(value) @@ -511,7 +511,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testString))), + Select(.count(#keyPath(TestEntity1.testString))), queryClauses ) XCTAssertNil(value) @@ -520,7 +520,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testString))), + Select(.count(#keyPath(TestEntity1.testString))), queryClauses ) XCTAssertNil(value) @@ -529,7 +529,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testData))), + Select(.count(#keyPath(TestEntity1.testData))), queryClauses ) XCTAssertNil(value) @@ -538,7 +538,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testData))), + Select(.count(#keyPath(TestEntity1.testData))), queryClauses ) XCTAssertNil(value) @@ -547,7 +547,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testDate))), + Select(.count(#keyPath(TestEntity1.testDate))), queryClauses ) XCTAssertNil(value) @@ -556,7 +556,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testDate))), + Select(.count(#keyPath(TestEntity1.testDate))), queryClauses ) XCTAssertNil(value) @@ -565,7 +565,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.count(#keyPath(TestEntity1.testEntityID))), + Select(.count(#keyPath(TestEntity1.testEntityID))), queryClauses ) XCTAssertNil(value) @@ -589,7 +589,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testBoolean))), + Select(.maximum(#keyPath(TestEntity1.testBoolean))), queryClauses ) XCTAssertNotNil(value) @@ -599,7 +599,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testNumber))), + Select(.maximum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -609,7 +609,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testNumber))), + Select(.maximum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -619,7 +619,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testNumber))), + Select(.maximum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -629,7 +629,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testNumber))), + Select(.maximum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -639,7 +639,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testNumber))), + Select(.maximum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -649,7 +649,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testNumber))), + Select(.maximum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -659,7 +659,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testNumber))), + Select(.maximum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -669,7 +669,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testNumber))), + Select(.maximum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -679,7 +679,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testDecimal))), + Select(.maximum(#keyPath(TestEntity1.testDecimal))), queryClauses ) XCTAssertNotNil(value) @@ -689,7 +689,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testString))), + Select(.maximum(#keyPath(TestEntity1.testString))), queryClauses ) XCTAssertNotNil(value) @@ -699,7 +699,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testString))), + Select(.maximum(#keyPath(TestEntity1.testString))), queryClauses ) XCTAssertNotNil(value) @@ -709,7 +709,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testData))), + Select(.maximum(#keyPath(TestEntity1.testData))), queryClauses ) XCTAssertNotNil(value) @@ -719,7 +719,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testData))), + Select(.maximum(#keyPath(TestEntity1.testData))), queryClauses ) XCTAssertNotNil(value) @@ -729,7 +729,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testDate))), + Select(.maximum(#keyPath(TestEntity1.testDate))), queryClauses ) XCTAssertNotNil(value) @@ -739,7 +739,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testDate))), + Select(.maximum(#keyPath(TestEntity1.testDate))), queryClauses ) XCTAssertNotNil(value) @@ -749,7 +749,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.maximum(#keyPath(TestEntity1.testEntityID))), + Select(.maximum(#keyPath(TestEntity1.testEntityID))), queryClauses ) XCTAssertNil(value) @@ -773,7 +773,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testBoolean))), + Select(.minimum(#keyPath(TestEntity1.testBoolean))), queryClauses ) XCTAssertNotNil(value) @@ -783,7 +783,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testNumber))), + Select(.minimum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -793,7 +793,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testNumber))), + Select(.minimum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -803,7 +803,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testNumber))), + Select(.minimum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -813,7 +813,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testNumber))), + Select(.minimum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -823,7 +823,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testNumber))), + Select(.minimum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -833,7 +833,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testNumber))), + Select(.minimum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -843,7 +843,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testNumber))), + Select(.minimum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -853,7 +853,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testNumber))), + Select(.minimum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -863,7 +863,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testDecimal))), + Select(.minimum(#keyPath(TestEntity1.testDecimal))), queryClauses ) XCTAssertNotNil(value) @@ -873,7 +873,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testString))), + Select(.minimum(#keyPath(TestEntity1.testString))), queryClauses ) XCTAssertNotNil(value) @@ -883,7 +883,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testString))), + Select(.minimum(#keyPath(TestEntity1.testString))), queryClauses ) XCTAssertNotNil(value) @@ -893,7 +893,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testData))), + Select(.minimum(#keyPath(TestEntity1.testData))), queryClauses ) XCTAssertNotNil(value) @@ -903,7 +903,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testData))), + Select(.minimum(#keyPath(TestEntity1.testData))), queryClauses ) XCTAssertNotNil(value) @@ -913,7 +913,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testDate))), + Select(.minimum(#keyPath(TestEntity1.testDate))), queryClauses ) XCTAssertNotNil(value) @@ -923,7 +923,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testDate))), + Select(.minimum(#keyPath(TestEntity1.testDate))), queryClauses ) XCTAssertNotNil(value) @@ -933,7 +933,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.minimum(#keyPath(TestEntity1.testEntityID))), + Select(.minimum(#keyPath(TestEntity1.testEntityID))), queryClauses ) XCTAssertNil(value) @@ -957,7 +957,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testBoolean))), + Select(.sum(#keyPath(TestEntity1.testBoolean))), queryClauses ) XCTAssertNotNil(value) @@ -967,7 +967,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testNumber))), + Select(.sum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -977,7 +977,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testNumber))), + Select(.sum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -987,7 +987,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testNumber))), + Select(.sum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -997,7 +997,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testNumber))), + Select(.sum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -1007,7 +1007,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testNumber))), + Select(.sum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -1017,7 +1017,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testNumber))), + Select(.sum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -1027,7 +1027,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testNumber))), + Select(.sum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -1037,7 +1037,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testNumber))), + Select(.sum(#keyPath(TestEntity1.testNumber))), queryClauses ) XCTAssertNotNil(value) @@ -1047,7 +1047,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testDecimal))), + Select(.sum(#keyPath(TestEntity1.testDecimal))), queryClauses ) XCTAssertNotNil(value) @@ -1057,7 +1057,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testString))), + Select(.sum(#keyPath(TestEntity1.testString))), queryClauses ) XCTAssertNil(value) @@ -1066,7 +1066,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testString))), + Select(.sum(#keyPath(TestEntity1.testString))), queryClauses ) XCTAssertNil(value) @@ -1075,7 +1075,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testData))), + Select(.sum(#keyPath(TestEntity1.testData))), queryClauses ) XCTAssertNil(value) @@ -1084,7 +1084,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testData))), + Select(.sum(#keyPath(TestEntity1.testData))), queryClauses ) XCTAssertNil(value) @@ -1093,7 +1093,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testDate))), + Select(.sum(#keyPath(TestEntity1.testDate))), queryClauses ) XCTAssertNil(value) @@ -1102,7 +1102,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testDate))), + Select(.sum(#keyPath(TestEntity1.testDate))), queryClauses ) XCTAssertNil(value) @@ -1111,7 +1111,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.sum(#keyPath(TestEntity1.testEntityID))), + Select(.sum(#keyPath(TestEntity1.testEntityID))), queryClauses ) XCTAssertNil(value) @@ -1135,7 +1135,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1144,7 +1144,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1153,7 +1153,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1162,7 +1162,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1171,7 +1171,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1180,7 +1180,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1189,7 +1189,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1198,7 +1198,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1207,7 +1207,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1216,7 +1216,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1225,7 +1225,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1234,7 +1234,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1243,7 +1243,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1252,7 +1252,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1261,7 +1261,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1270,7 +1270,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNil(value) @@ -1279,7 +1279,7 @@ class QueryTests: BaseTestDataTestCase { let value = stack.queryValue( from, - Select(.objectID()), + Select(.objectID()), queryClauses ) XCTAssertNotNil(value) @@ -1304,7 +1304,7 @@ class QueryTests: BaseTestDataTestCase { let values = stack.queryAttributes( from, - Select( + Select( #keyPath(TestEntity1.testBoolean), #keyPath(TestEntity1.testNumber), #keyPath(TestEntity1.testDecimal), @@ -1355,7 +1355,7 @@ class QueryTests: BaseTestDataTestCase { let values = stack.queryAttributes( from, - Select( + Select( .sum(#keyPath(TestEntity1.testBoolean)), .count(#keyPath(TestEntity1.testNumber)), .maximum(#keyPath(TestEntity1.testNumber)), diff --git a/CoreStoreTests/SelectTests.swift b/CoreStoreTests/SelectTests.swift index 0c10154..a2067e0 100644 --- a/CoreStoreTests/SelectTests.swift +++ b/CoreStoreTests/SelectTests.swift @@ -38,7 +38,7 @@ final class SelectTests: XCTestCase { do { - let term: SelectTerm = "attribute" + let term: SelectTerm = "attribute" XCTAssertEqual(term, SelectTerm.attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute2")) XCTAssertNotEqual(term, SelectTerm.average("attribute")) @@ -58,7 +58,7 @@ final class SelectTests: XCTestCase { } do { - let term = SelectTerm.attribute("attribute") + let term = SelectTerm.attribute("attribute") XCTAssertNotEqual(term, SelectTerm.attribute("attribute2")) XCTAssertNotEqual(term, SelectTerm.average("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute")) @@ -82,7 +82,7 @@ final class SelectTests: XCTestCase { do { - let term = SelectTerm.average("attribute") + let term = SelectTerm.average("attribute") XCTAssertEqual(term, SelectTerm.average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.average("attribute2")) @@ -106,7 +106,7 @@ final class SelectTests: XCTestCase { } do { - let term = SelectTerm.average("attribute", as: "alias") + let term = SelectTerm.average("attribute", as: "alias") XCTAssertEqual(term, SelectTerm.average("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias2")) XCTAssertNotEqual(term, SelectTerm.average("attribute2")) @@ -135,7 +135,7 @@ final class SelectTests: XCTestCase { do { - let term = SelectTerm.count("attribute") + let term = SelectTerm.count("attribute") XCTAssertEqual(term, SelectTerm.count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.count("attribute2")) @@ -159,7 +159,7 @@ final class SelectTests: XCTestCase { } do { - let term = SelectTerm.count("attribute", as: "alias") + let term = SelectTerm.count("attribute", as: "alias") XCTAssertEqual(term, SelectTerm.count("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias2")) XCTAssertNotEqual(term, SelectTerm.count("attribute2")) @@ -188,7 +188,7 @@ final class SelectTests: XCTestCase { do { - let term = SelectTerm.maximum("attribute") + let term = SelectTerm.maximum("attribute") XCTAssertEqual(term, SelectTerm.maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute2")) @@ -212,7 +212,7 @@ final class SelectTests: XCTestCase { } do { - let term = SelectTerm.maximum("attribute", as: "alias") + let term = SelectTerm.maximum("attribute", as: "alias") XCTAssertEqual(term, SelectTerm.maximum("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias2")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute2")) @@ -241,7 +241,7 @@ final class SelectTests: XCTestCase { do { - let term = SelectTerm.minimum("attribute") + let term = SelectTerm.minimum("attribute") XCTAssertEqual(term, SelectTerm.minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute2")) @@ -265,7 +265,7 @@ final class SelectTests: XCTestCase { } do { - let term = SelectTerm.minimum("attribute", as: "alias") + let term = SelectTerm.minimum("attribute", as: "alias") XCTAssertEqual(term, SelectTerm.minimum("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias2")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute2")) @@ -294,7 +294,7 @@ final class SelectTests: XCTestCase { do { - let term = SelectTerm.sum("attribute") + let term = SelectTerm.sum("attribute") XCTAssertEqual(term, SelectTerm.sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.sum("attribute2")) @@ -318,7 +318,7 @@ final class SelectTests: XCTestCase { } do { - let term = SelectTerm.sum("attribute", as: "alias") + let term = SelectTerm.sum("attribute", as: "alias") XCTAssertEqual(term, SelectTerm.sum("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias2")) XCTAssertNotEqual(term, SelectTerm.sum("attribute2")) @@ -347,7 +347,7 @@ final class SelectTests: XCTestCase { do { - let term = SelectTerm.objectID() + let term = SelectTerm.objectID() XCTAssertEqual(term, SelectTerm.objectID()) XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute")) @@ -368,7 +368,7 @@ final class SelectTests: XCTestCase { } do { - let term = SelectTerm.objectID(as: "alias") + let term = SelectTerm.objectID(as: "alias") XCTAssertEqual(term, SelectTerm.objectID(as: "alias")) XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias2")) XCTAssertNotEqual(term, SelectTerm.objectID()) @@ -393,12 +393,12 @@ final class SelectTests: XCTestCase { @objc dynamic func test_ThatSelectClauses_ConfigureCorrectly() { - let term1 = SelectTerm.attribute("attribute1") - let term2 = SelectTerm.attribute("attribute2") - let term3 = SelectTerm.attribute("attribute3") + let term1 = SelectTerm.attribute("attribute1") + let term2 = SelectTerm.attribute("attribute2") + let term3 = SelectTerm.attribute("attribute3") do { - let select = Select(term1, term2, term3) + let select = Select(term1, term2, term3) XCTAssertEqual(select.selectTerms, [term1, term2, term3]) XCTAssertNotEqual(select.selectTerms, [term1, term3, term2]) XCTAssertNotEqual(select.selectTerms, [term2, term1, term3]) @@ -408,7 +408,7 @@ final class SelectTests: XCTestCase { } do { - let select = Select([term1, term2, term3]) + let select = Select([term1, term2, term3]) XCTAssertEqual(select.selectTerms, [term1, term2, term3]) XCTAssertNotEqual(select.selectTerms, [term1, term3, term2]) XCTAssertNotEqual(select.selectTerms, [term2, term1, term3]) diff --git a/Sources/BaseDataTransaction+Querying.swift b/Sources/BaseDataTransaction+Querying.swift index a5f0b11..0ece0ae 100644 --- a/Sources/BaseDataTransaction+Querying.swift +++ b/Sources/BaseDataTransaction+Querying.swift @@ -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` parameter. */ - public func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> U? { + public func queryValue(_ from: From, _ selectClause: Select, _ 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` parameter. */ - public func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> U? { + public func queryValue(_ from: From, _ selectClause: Select, _ 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` parameter. */ - public func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> [[String: Any]]? { + public func queryAttributes(_ from: From, _ selectClause: Select, _ 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` parameter. */ - public func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[String: Any]]? { + public func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[String: Any]]? { CoreStore.assert( self.isRunningInAllowedQueue(), diff --git a/Sources/CSSelect.swift b/Sources/CSSelect.swift index c06b4f6..7312ff8 100644 --- a/Sources/CSSelect.swift +++ b/Sources/CSSelect.swift @@ -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 - public init(_ swiftValue: SelectTerm) { + public init(_ swiftValue: SelectTerm) { - 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 { + + switch self { + + case ._attribute(let keyPath): + return SelectTerm._attribute(keyPath) + + case ._aggregate(let function, let keyPath, let alias, let nativeType): + return SelectTerm._aggregate(function: function, keyPath: keyPath, alias: alias, nativeType: nativeType) + + case ._identity(let alias, let nativeType): + return SelectTerm._identity(alias: alias, nativeType: nativeType) + } + } } @@ -221,7 +239,7 @@ public final class CSSelect: NSObject { @objc public convenience init(numberTerm: CSSelectTerm) { - self.init(Select(numberTerm.bridgeToSwift)) + self.init(Select(numberTerm.bridgeToSwift)) } /** @@ -237,7 +255,7 @@ public final class CSSelect: NSObject { @objc public convenience init(decimalTerm: CSSelectTerm) { - self.init(Select(decimalTerm.bridgeToSwift)) + self.init(Select(decimalTerm.bridgeToSwift)) } /** @@ -253,7 +271,7 @@ public final class CSSelect: NSObject { @objc public convenience init(stringTerm: CSSelectTerm) { - self.init(Select(stringTerm.bridgeToSwift)) + self.init(Select(stringTerm.bridgeToSwift)) } /** @@ -269,7 +287,7 @@ public final class CSSelect: NSObject { @objc public convenience init(dateTerm: CSSelectTerm) { - self.init(Select(dateTerm.bridgeToSwift)) + self.init(Select(dateTerm.bridgeToSwift)) } /** @@ -285,7 +303,7 @@ public final class CSSelect: NSObject { @objc public convenience init(dataTerm: CSSelectTerm) { - self.init(Select(dataTerm.bridgeToSwift)) + self.init(Select(dataTerm.bridgeToSwift)) } /** @@ -300,7 +318,7 @@ public final class CSSelect: NSObject { @objc public convenience init(objectIDTerm: ()) { - self.init(Select(.objectID())) + self.init(Select(.objectID())) } /** @@ -316,7 +334,7 @@ public final class CSSelect: NSObject { @objc public static func dictionaryForTerm(_ term: CSSelectTerm) -> CSSelect { - return self.init(Select(term.bridgeToSwift)) + return self.init(Select(term.bridgeToSwift)) } /** @@ -335,7 +353,7 @@ public final class CSSelect: NSObject { @objc public static func dictionaryForTerms(_ terms: [CSSelectTerm]) -> CSSelect { - return self.init(Select(terms.map { $0.bridgeToSwift })) + return self.init(Select(terms.map { $0.bridgeToSwift })) } @@ -365,18 +383,18 @@ public final class CSSelect: NSObject { // MARK: CoreStoreObjectiveCType - public init(_ swiftValue: Select) { + public init(_ swiftValue: Select) { self.attributeType = T.cs_rawAttributeType - self.selectTerms = swiftValue.selectTerms + self.selectTerms = swiftValue.selectTerms.map({ $0.downcast() }) self.bridgeToSwift = swiftValue super.init() } - public init(_ swiftValue: Select) { + public init(_ swiftValue: Select) { 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] + + + // MARK: Internal + + internal func applyToFetchRequest(_ fetchRequest: NSFetchRequest) { + + 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 { + + return Select(self.selectTerms.map({ $0.downcast() })) + } } diff --git a/Sources/ChainedClauseBuilder.swift b/Sources/ChainedClauseBuilder.swift index 7974877..7bcaae8 100644 --- a/Sources/ChainedClauseBuilder.swift +++ b/Sources/ChainedClauseBuilder.swift @@ -41,7 +41,7 @@ public protocol QueryChainableBuilderType { associatedtype ResultType: SelectResultType var from: From { get set } - var select: Select { get set } + var select: Select { get set } var queryClauses: [QueryClause] { get set } } @@ -79,7 +79,7 @@ public struct QueryChainBuilder: QueryCha public typealias ResultType = R public var from: From - public var select: Select + public var select: Select public var queryClauses: [QueryClause] = [] } @@ -101,12 +101,12 @@ public struct SectionMonitorChainBuilder: SectionMonitorBuilde public extension From { - public func select(_ resultType: R.Type, _ selectTerm: SelectTerm, _ selectTerms: SelectTerm...) -> QueryChainBuilder { + 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 { + public func select(_ resultType: R.Type, _ selectTerms: [SelectTerm]) -> QueryChainBuilder { return .init( from: self, @@ -170,6 +170,97 @@ public extension From { } } +public extension From where D: NSManagedObject { + + public func select(_ keyPath: KeyPath) -> QueryChainBuilder { + + return self.select(R.self, [SelectTerm.attribute(keyPath)]) + } + + @available(OSX 10.12, *) + public func sectionBy(_ sectionKeyPath: KeyPath) -> SectionMonitorChainBuilder { + + return self.sectionBy(sectionKeyPath._kvcKeyPathString!, { $0 }) + } + + @available(OSX 10.12, *) + public func sectionBy(_ sectionKeyPath: KeyPath, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder { + + return self.sectionBy(sectionKeyPath._kvcKeyPathString!, sectionIndexTransformer) + } +} + +public extension From where D: CoreStoreObject { + + public func select(_ keyPath: KeyPath.Required>) -> QueryChainBuilder { + + return self.select(R.self, [SelectTerm.attribute(keyPath)]) + } + + public func select(_ keyPath: KeyPath.Optional>) -> QueryChainBuilder { + + return self.select(R.self, [SelectTerm.attribute(keyPath)]) + } + + public func select(_ keyPath: KeyPath.Required>) -> QueryChainBuilder { + + return self.select(R.self, [SelectTerm.attribute(keyPath)]) + } + + public func select(_ keyPath: KeyPath.Optional>) -> QueryChainBuilder { + + return self.select(R.self, [SelectTerm.attribute(keyPath)]) + } + + @available(OSX 10.12, *) + public func sectionBy(_ sectionKeyPath: KeyPath.Required>) -> SectionMonitorChainBuilder { + + return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 }) + } + + @available(OSX 10.12, *) + public func sectionBy(_ sectionKeyPath: KeyPath.Optional>) -> SectionMonitorChainBuilder { + + return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 }) + } + + @available(OSX 10.12, *) + public func sectionBy(_ sectionKeyPath: KeyPath.Required>) -> SectionMonitorChainBuilder { + + return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 }) + } + + @available(OSX 10.12, *) + public func sectionBy(_ sectionKeyPath: KeyPath.Optional>) -> SectionMonitorChainBuilder { + + return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 }) + } + + @available(OSX 10.12, *) + public func sectionBy(_ sectionKeyPath: KeyPath.Required>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder { + + return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer) + } + + @available(OSX 10.12, *) + public func sectionBy(_ sectionKeyPath: KeyPath.Optional>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder { + + return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer) + } + + @available(OSX 10.12, *) + public func sectionBy(_ sectionKeyPath: KeyPath.Required>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder { + + return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer) + } + + @available(OSX 10.12, *) + public func sectionBy(_ sectionKeyPath: KeyPath.Optional>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder { + + return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer) + } +} + public extension FetchChainBuilder { public func `where`(_ clause: Where) -> FetchChainBuilder { @@ -274,6 +365,37 @@ public extension QueryChainBuilder { } } +public extension QueryChainBuilder where D: NSManagedObject { + + public func groupBy(_ keyPath: KeyPath) -> QueryChainBuilder { + + return self.groupBy(GroupBy(keyPath)) + } +} + +public extension QueryChainBuilder where D: CoreStoreObject { + + public func groupBy(_ keyPath: KeyPath.Required>) -> QueryChainBuilder { + + return self.groupBy(GroupBy(keyPath)) + } + + public func groupBy(_ keyPath: KeyPath.Optional>) -> QueryChainBuilder { + + return self.groupBy(GroupBy(keyPath)) + } + + public func groupBy(_ keyPath: KeyPath.Required>) -> QueryChainBuilder { + + return self.groupBy(GroupBy(keyPath)) + } + + public func groupBy(_ keyPath: KeyPath.Optional>) -> QueryChainBuilder { + + return self.groupBy(GroupBy(keyPath)) + } +} + @available(OSX 10.12, *) public extension SectionMonitorChainBuilder { diff --git a/Sources/CoreStore+Querying.swift b/Sources/CoreStore+Querying.swift index 9e275bb..4a6e43f 100644 --- a/Sources/CoreStore+Querying.swift +++ b/Sources/CoreStore+Querying.swift @@ -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` parameter. */ - public static func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> U? { + public static func queryValue(_ from: From, _ selectClause: Select, _ 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` parameter. */ - public static func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> U? { + public static func queryValue(_ from: From, _ selectClause: Select, _ 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` parameter. */ - public static func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> [[String: Any]]? { + public static func queryAttributes(_ from: From, _ selectClause: Select, _ 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` parameter. */ - public static func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[String: Any]]? { + public static func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[String: Any]]? { return self.defaultStack.queryAttributes(from, selectClause, queryClauses) } diff --git a/Sources/DataStack+Querying.swift b/Sources/DataStack+Querying.swift index 5f09687..409644e 100644 --- a/Sources/DataStack+Querying.swift +++ b/Sources/DataStack+Querying.swift @@ -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` parameter. */ - public func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> U? { + public func queryValue(_ from: From, _ selectClause: Select, _ 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` parameter. */ - public func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> U? { + public func queryValue(_ from: From, _ selectClause: Select, _ 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` parameter. */ - public func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> [[String: Any]]? { + public func queryAttributes(_ from: From, _ selectClause: Select, _ 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` parameter. */ - public func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[String: Any]]? { + public func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[String: Any]]? { CoreStore.assert( Thread.isMainThread, diff --git a/Sources/GroupBy.swift b/Sources/GroupBy.swift index 1ee748b..467fc62 100644 --- a/Sources/GroupBy.swift +++ b/Sources/GroupBy.swift @@ -103,6 +103,37 @@ public struct GroupBy: GroupByClause, QueryClause, Hashable { } } +public extension GroupBy where D: NSManagedObject { + + public init(_ keyPath: KeyPath) { + + self.init([keyPath._kvcKeyPathString!]) + } +} + +public extension GroupBy where D: CoreStoreObject { + + public init(_ keyPath: KeyPath.Required>) { + + self.init([D.meta[keyPath: keyPath].keyPath]) + } + + public init(_ keyPath: KeyPath.Optional>) { + + self.init([D.meta[keyPath: keyPath].keyPath]) + } + + public init(_ keyPath: KeyPath.Required>) { + + self.init([D.meta[keyPath: keyPath].keyPath]) + } + + public init(_ keyPath: KeyPath.Optional>) { + + self.init([D.meta[keyPath: keyPath].keyPath]) + } +} + // MARK: - GroupByClause diff --git a/Sources/NSManagedObjectContext+ObjectiveC.swift b/Sources/NSManagedObjectContext+ObjectiveC.swift index 91bd888..deef584 100644 --- a/Sources/NSManagedObjectContext+ObjectiveC.swift +++ b/Sources/NSManagedObjectContext+ObjectiveC.swift @@ -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 { diff --git a/Sources/NSManagedObjectContext+Querying.swift b/Sources/NSManagedObjectContext+Querying.swift index 69a268b..51f626b 100644 --- a/Sources/NSManagedObjectContext+Querying.swift +++ b/Sources/NSManagedObjectContext+Querying.swift @@ -279,51 +279,50 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource { // MARK: QueryableSource @nonobjc - public func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> U? { + public func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> U? { return self.queryValue(from, selectClause, queryClauses) } @nonobjc - public func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> U? { + public func queryValue(_ from: From, _ selectClause: Select, _ 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(_ clauseChain: B) -> B.ResultType? where B : QueryChainableBuilderType, B.ResultType : QueryableAttributeType { + public func queryValue(_ clauseChain: B) -> B.ResultType? where B: QueryChainableBuilderType, B.ResultType: QueryableAttributeType { return self.queryValue(clauseChain.from, clauseChain.select, clauseChain.queryClauses) } @nonobjc - public func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> [[String: Any]]? { + public func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> [[String: Any]]? { return self.queryAttributes(from, selectClause, queryClauses) } @nonobjc - public func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[String: Any]]? { + public func queryAttributes(_ from: From, _ selectClause: Select, _ 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(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest) -> U? { + internal func queryValue(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest) -> 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.ReturnType.cs_fromQueryableNativeType(rawObject) + return Select.ReturnType.cs_fromQueryableNativeType(rawObject) } return nil } @@ -531,7 +530,7 @@ internal extension NSManagedObjectContext { } @nonobjc - internal func queryValue(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest) -> Any? { + internal func queryValue(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest) -> 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.ReturnType.cs_fromQueryResultsNativeType(fetchResults) + return NSDictionary.cs_fromQueryResultsNativeType(fetchResults) } CoreStore.log( diff --git a/Sources/QueryableSource.swift b/Sources/QueryableSource.swift index cf3da07..b8fb498 100644 --- a/Sources/QueryableSource.swift +++ b/Sources/QueryableSource.swift @@ -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` parameter. */ - func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> U? + func queryValue(_ from: From, _ selectClause: Select, _ 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` parameter. */ - func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> U? + func queryValue(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> U? // TODO: docs func queryValue(_ 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` parameter. */ - func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> [[String: Any]]? + func queryAttributes(_ from: From, _ selectClause: Select, _ 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` parameter. */ - func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[String: Any]]? + func queryAttributes(_ from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[String: Any]]? // TODO: docs func queryAttributes(_ clauseChain: B) -> [[String: Any]]? where B.ResultType == NSDictionary diff --git a/Sources/Select.swift b/Sources/Select.swift index 1c5bc43..98a9786 100644 --- a/Sources/Select.swift +++ b/Sources/Select.swift @@ -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: 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 { 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()" 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 { 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()" 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 { 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()" 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 { 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()" 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 { 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()" 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 { 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 { 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, rhs: SelectTerm) -> 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(_ keyPath: KeyPath) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute + */ + public static func average(_ keyPath: KeyPath, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for a count query + */ + public static func count(_ keyPath: KeyPath, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute + */ + public static func maximum(_ keyPath: KeyPath, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute + */ + public static func minimum(_ keyPath: KeyPath, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute + */ + public static func sum(_ keyPath: KeyPath, as alias: KeyPathString? = nil) -> SelectTerm { + + 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(_ keyPath: KeyPath.Required>) -> SelectTerm { + + 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(_ keyPath: KeyPath.Optional>) -> SelectTerm { + + 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(_ keyPath: KeyPath.Required>) -> SelectTerm { + + 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(_ keyPath: KeyPath.Optional>) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute + */ + public static func average(_ keyPath: KeyPath.Required>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute + */ + public static func average(_ keyPath: KeyPath.Optional>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute + */ + public static func average(_ keyPath: KeyPath.Required>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute + */ + public static func average(_ keyPath: KeyPath.Optional>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for a count query + */ + public static func count(_ keyPath: KeyPath.Required>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for a count query + */ + public static func count(_ keyPath: KeyPath.Optional>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for a count query + */ + public static func count(_ keyPath: KeyPath.Required>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for a count query + */ + public static func count(_ keyPath: KeyPath.Optional>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute + */ + public static func maximum(_ keyPath: KeyPath.Required>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute + */ + public static func maximum(_ keyPath: KeyPath.Optional>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute + */ + public static func maximum(_ keyPath: KeyPath.Required>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute + */ + public static func maximum(_ keyPath: KeyPath.Optional>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute + */ + public static func minimum(_ keyPath: KeyPath.Required>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute + */ + public static func minimum(_ keyPath: KeyPath.Optional>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute + */ + public static func minimum(_ keyPath: KeyPath.Required>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute + */ + public static func minimum(_ keyPath: KeyPath.Optional>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute + */ + public static func sum(_ keyPath: KeyPath.Required>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute + */ + public static func sum(_ keyPath: KeyPath.Optional>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute + */ + public static func sum(_ keyPath: KeyPath.Required>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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()" is used + - returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute + */ + public static func sum(_ keyPath: KeyPath.Optional>, as alias: KeyPathString? = nil) -> SelectTerm { + + 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: Hashable { - - /** - The `SelectResultType` type for the query's return value - */ - public typealias ReturnType = T +public struct Select: SelectClause, Hashable { /** Initializes a `Select` clause with a list of `SelectTerm`s @@ -321,7 +667,7 @@ public struct Select: Hashable { - parameter selectTerm: a `SelectTerm` - parameter selectTerms: a series of `SelectTerm`s */ - public init(_ selectTerm: SelectTerm, _ selectTerms: SelectTerm...) { + public init(_ selectTerm: SelectTerm, _ selectTerms: SelectTerm...) { self.selectTerms = [selectTerm] + selectTerms } @@ -331,7 +677,7 @@ public struct Select: Hashable { - parameter selectTerms: a series of `SelectTerm`s */ - public init(_ selectTerms: [SelectTerm]) { + public init(_ selectTerms: [SelectTerm]) { self.selectTerms = selectTerms } @@ -339,12 +685,20 @@ public struct Select: Hashable { // MARK: Equatable - public static func == (lhs: Select, rhs: Select) -> Bool { + public static func == (lhs: Select, rhs: Select) -> Bool { return lhs.selectTerms == rhs.selectTerms } + // MARK: SelectClause + + public typealias ObjectType = D + public typealias ReturnType = T + + public let selectTerms: [SelectTerm] + + // MARK: Hashable public var hashValue: Int { @@ -355,36 +709,7 @@ public struct Select: 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(_ fetchRequest: NSFetchRequest, owner: T) { + internal func applyToFetchRequest(_ fetchRequest: NSFetchRequest) { 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) { + + 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.Required>) { + + 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.Optional>) { + + 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.Required>) { + + 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.Optional>) { + + 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] { get } +} + + +// MARK: - NSDictionary: SelectAttributesResultType + +extension NSDictionary: SelectAttributesResultType { + + // MARK: SelectAttributesResultType + + public static func cs_fromQueryResultsNativeType(_ result: [Any]) -> [[String : Any]] { + + return result as! [[String: Any]] } }