Swift 5 support. WIP: Support type-safe predicate expressions

This commit is contained in:
John Estropia
2019-02-01 18:32:22 +09:00
parent 41902fee2e
commit db4426e6b9
15 changed files with 715 additions and 73 deletions

View File

@@ -30,9 +30,10 @@ import CoreStore
#if os(macOS)
typealias Color = NSColor
#else
typealias Color = UIColor
#endif
class Animal: CoreStoreObject {
@@ -134,9 +135,11 @@ class DynamicModelTests: BaseTestDataTestCase {
let k1 = String(keyPath: \Animal.species)
XCTAssertEqual(k1, "species")
#if swift(<5.0)
let k2 = String(keyPath: \Dog.species)
XCTAssertEqual(k2, "species")
#endif
let k3 = String(keyPath: \Dog.nickname)
XCTAssertEqual(k3, "nickname")
@@ -272,11 +275,11 @@ class DynamicModelTests: BaseTestDataTestCase {
_ = try transaction.fetchAll(
From<Dog>()
.where(\Animal.species == "Dog" && \.age == 10)
.where(\Animal.species == "Dog" && \Dog.age == 10)
)
_ = try transaction.fetchAll(
From<Dog>()
.where(\.age == 10 && \Animal.species == "Dog")
.where(\Dog.age == 10 && \Animal.species == "Dog")
.orderBy(.ascending({ $0.species }))
)
_ = try transaction.fetchAll(
@@ -317,7 +320,9 @@ class DynamicModelTests: BaseTestDataTestCase {
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
XCTAssertEqual(String(keyPath: \Animal.species), "species")
#if swift(<5.0)
XCTAssertEqual(String(keyPath: \Dog.species), "species")
#endif
}
@nonobjc

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11759" systemVersion="16C67" minimumToolsVersion="Xcode 4.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14460.32" systemVersion="17G2307" minimumToolsVersion="Xcode 4.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
<entity name="TestEntity1AAA" representedClassName="CoreStoreTests.TestEntity1" syncable="YES">
<attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
@@ -9,6 +9,8 @@
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="testNumber" optional="YES" attributeType="Integer 32" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="testToManyUnordered" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="TestEntity1AAA" inverseName="testToOne" inverseEntity="TestEntity1AAA" syncable="YES"/>
<relationship name="testToOne" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TestEntity1AAA" inverseName="testToManyUnordered" inverseEntity="TestEntity1AAA" syncable="YES"/>
</entity>
<entity name="TestEntity2" representedClassName="CoreStoreTests.TestEntity2" syncable="YES">
<attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
@@ -19,6 +21,8 @@
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="testNumber" optional="YES" attributeType="Integer 32" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="testToManyOrdered" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TestEntity2" inverseName="testToOne" inverseEntity="TestEntity2" syncable="YES"/>
<relationship name="testToOne" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TestEntity2" inverseName="testToManyOrdered" inverseEntity="TestEntity2" syncable="YES"/>
</entity>
<configuration name="Config1">
<memberEntity name="TestEntity1AAA"/>
@@ -27,7 +31,7 @@
<memberEntity name="TestEntity2"/>
</configuration>
<elements>
<element name="TestEntity1AAA" positionX="-63" positionY="-18" width="128" height="165"/>
<element name="TestEntity2" positionX="-63" positionY="9" width="128" height="165"/>
<element name="TestEntity1AAA" positionX="-63" positionY="-18" width="128" height="195"/>
<element name="TestEntity2" positionX="-63" positionY="9" width="128" height="195"/>
</elements>
</model>

View File

@@ -330,7 +330,14 @@ class SetupTests: BaseTestDataTestCase {
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
try! stack.addStorageAndWait(sqliteStore)
try! stack.addStorageAndWait(
SQLiteStore.legacy(
fileName: sqliteStore.fileURL.lastPathComponent,
configuration: sqliteStore.configuration,
migrationMappingProviders: sqliteStore.migrationMappingProviders,
localStorageOptions: .recreateStoreOnModelMismatch
)
)
self.prepareTestDataForStack(stack)
}
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))

View File

@@ -36,4 +36,6 @@ class TestEntity1: NSManagedObject {
@NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: Data?
@NSManaged var testNil: String?
@NSManaged var testToOne: TestEntity1?
@NSManaged var testToManyUnordered: NSSet?
}

View File

@@ -36,4 +36,6 @@ class TestEntity2: NSManagedObject {
@NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: Data?
@NSManaged var testNil: String?
@NSManaged var testToOne: TestEntity2?
@NSManaged var testToManyOrdered: NSOrderedSet?
}

View File

@@ -56,6 +56,163 @@ final class WhereTests: XCTestCase {
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
XCTAssertEqual(String(keyPath: \TestEntity1.testEntityID), "testEntityID")
XCTAssertEqual(String(keyPath: \Animal.color), "color")
}
@objc
dynamic func test_ThatExpressions_HaveCorrectKeyPaths() {
do {
XCTAssertEqual(
#keyPath(TestEntity1.testToOne.testEntityID),
String(keyPath: \TestEntity1.testToOne ~ \.testEntityID)
)
XCTAssertEqual(
#keyPath(TestEntity1.testToOne.testToOne.testToManyUnordered),
String(keyPath: \TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered)
)
XCTAssertEqual(
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
String(keyPath: \TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered)
)
}
do {
XCTAssertEqual(
"master.pets",
String(keyPath: \Animal.master ~ \.pets)
)
XCTAssertEqual(
"master.pets.species",
String(keyPath: \Animal.master ~ \.pets ~ \.species)
)
XCTAssertEqual(
"master.pets.master",
String(keyPath: \Animal.master ~ \.pets ~ \.master)
)
}
do {
XCTAssertEqual(
#keyPath(TestEntity1.testToOne.testToManyUnordered) + ".@count",
(\TestEntity1.testToOne ~ \.testToManyUnordered).count().description
)
XCTAssertEqual(
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered) + ".@count",
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count().description
)
}
do {
XCTAssertEqual(
"master.pets.@count",
(\Animal.master ~ \.pets).count().description
)
}
do {
XCTAssertEqual(
"ANY " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToManyUnordered).any().description
)
XCTAssertEqual(
"ANY " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any().description
)
}
do {
XCTAssertEqual(
"ANY master.pets",
(\Animal.master ~ \.pets).any().description
)
XCTAssertEqual(
"ANY master.pets.species",
(\Animal.master ~ \.pets ~ \.species).any().description
)
}
do {
XCTAssertEqual(
"ALL " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToManyUnordered).all().description
)
XCTAssertEqual(
"ALL " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all().description
)
}
do {
XCTAssertEqual(
"ALL master.pets",
(\Animal.master ~ \.pets).all().description
)
XCTAssertEqual(
"ALL master.pets.species",
(\Animal.master ~ \.pets ~ \.species).all().description
)
}
do {
XCTAssertEqual(
"NONE " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToManyUnordered).none().description
)
XCTAssertEqual(
"NONE " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none().description
)
}
do {
XCTAssertEqual(
"NONE master.pets",
(\Animal.master ~ \.pets).none().description
)
XCTAssertEqual(
"NONE master.pets.species",
(\Animal.master ~ \.pets ~ \.species).none().description
)
}
}
@objc
dynamic func test_ThatWhereClauses_CanBeCreatedFromExpressionsCorrectly() {
do {
let dummy = "dummy"
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testString) == dummy
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testString)) == %@", dummy)
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
XCTAssertEqual(whereClause.predicate, predicate)
}
do {
let dummy = "dummy"
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToOne ~ \.testString) == dummy
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testToOne.testString)) == %@", dummy)
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
XCTAssertEqual(whereClause.predicate, predicate)
}
do {
let count = 3
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered).count() == count
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testToManyUnordered)).@count == %d", count)
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
XCTAssertEqual(whereClause.predicate, predicate)
}
do {
let dummy = "dummy"
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered ~ \TestEntity1.testString).any() == dummy
let predicate = NSPredicate(format: "ANY \(#keyPath(TestEntity1.testToOne.testToManyUnordered)).\(#keyPath(TestEntity1.testString)) == %@", dummy)
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
XCTAssertEqual(whereClause.predicate, predicate)
}
}
@objc