Compare commits

...

18 Commits

Author SHA1 Message Date
John Estropia
edd8ba55d8 fix rare duplication of uniqueID values during import when an import candidate is added by a previous insertion block 2021-01-23 16:51:45 +09:00
John Estropia
18aac84335 fix compiler error 2021-01-02 10:36:33 +09:00
John Estropia
c6be892cb0 added .where(combinedByAnd:) and .where(combinedByOr:) to help compiler with long && and || chains 2021-01-02 10:00:23 +09:00
John Estropia
2cd8101987 Implement ObjectRepresentation on ObjectMonitor, ObjectPublisher, and ObjectSnapshot for future APIs 2021-01-02 09:59:15 +09:00
John Estropia
e1aed37da0 avoid using default queue qos 2020-12-26 23:45:11 +09:00
John Estropia
5de5ecee06 give opportunity for faster equating of ObjectSnapshot 2020-12-26 23:44:35 +09:00
John Estropia
9406901b28 WIP: SwiftUI utils 2020-12-26 19:21:46 +09:00
John Estropia
477f478d85 Add missing Where operators (fixes #410) 2020-12-26 14:02:20 +09:00
John Estropia
668b5ad606 Update playground samples to use Field properties instead of old syntax 2020-12-07 14:08:05 +09:00
John Estropia
f985828f3b cleanup 2020-11-17 18:14:23 +09:00
John Estropia
bb3bc940c2 Remove the dataStack SwiftUI environment key since it's prone to initialization issues 2020-11-11 16:56:20 +09:00
John Estropia
2d5bc77219 Merge branch 'master' into minIOS11
# Conflicts:
#	Sources/ListSnapshot.swift
2020-11-11 13:44:58 +09:00
John Estropia
a40df37192 version bump 2020-11-11 13:29:02 +09:00
John Estropia
63b3d25d78 clear warnings 2020-11-11 13:18:11 +09:00
John Estropia
74721b5c12 allow ObjectSnapshot and ObjectPublisher as parameter to Where clauses 2020-10-10 16:55:35 +09:00
John Estropia
f136549b46 prevent creation of ObjectSnapshot if object is already deleted 2020-10-09 20:14:04 +09:00
John Estropia
4ec2b2e311 Optimize ListSnapshot collection implementation 2020-10-05 23:12:17 +09:00
John Estropia
3d82ee18c7 reinclude LegacyDemo in workspace 2020-10-03 14:36:57 +09:00
40 changed files with 878 additions and 276 deletions

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "7.3.0"
s.version = "7.3.1"
s.swift_version = "5.3"
s.license = "MIT"
s.homepage = "https://github.com/JohnEstropia/CoreStore"

View File

@@ -362,6 +362,10 @@
B52FD3AB1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
B52FD3AC1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
B52FD3AD1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
B52FEC742596DBE100368BFB /* ObjectReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FEC732596DBE000368BFB /* ObjectReader.swift */; };
B52FEC752596DBE100368BFB /* ObjectReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FEC732596DBE000368BFB /* ObjectReader.swift */; };
B52FEC762596DBE100368BFB /* ObjectReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FEC732596DBE000368BFB /* ObjectReader.swift */; };
B52FEC772596DBE100368BFB /* ObjectReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FEC732596DBE000368BFB /* ObjectReader.swift */; };
B533C4DB1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
B533C4DC1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
B533C4DD1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
@@ -1064,6 +1068,7 @@
B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XcodeDataModelSchema.swift; sourceTree = "<group>"; };
B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreSchema.swift; sourceTree = "<group>"; };
B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Logging.swift"; sourceTree = "<group>"; };
B52FEC732596DBE000368BFB /* ObjectReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectReader.swift; sourceTree = "<group>"; };
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+CoreStore.swift"; sourceTree = "<group>"; };
B538BA701D15B3E30003A766 /* CoreStoreBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoreStoreBridge.m; sourceTree = "<group>"; };
B53B275E1EE3B92E00E9B352 /* CoreStoreManagedObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreManagedObject.swift; sourceTree = "<group>"; };
@@ -1535,6 +1540,14 @@
name = "Dynamic Schema";
sourceTree = "<group>";
};
B52FEC722596DB6400368BFB /* SwiftUI */ = {
isa = PBXGroup;
children = (
B52FEC732596DBE000368BFB /* ObjectReader.swift */,
);
name = SwiftUI;
sourceTree = "<group>";
};
B53FBA101CAB607000F0D40A /* Convenience */ = {
isa = PBXGroup;
children = (
@@ -1697,6 +1710,7 @@
B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */,
B549F6721E56A92800FBAB2D /* CoreDataNativeType.swift */,
B5D339F01E94AF5800C880DE /* CoreStoreStrings.swift */,
B52FEC722596DB6400368BFB /* SwiftUI */,
B5E84EDA1AFF84500064E85B /* Setup */,
B51B5C2922D43854009FA3BA /* KeyPaths */,
B5E84EE21AFF84610064E85B /* Logging */,
@@ -2165,7 +2179,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 1020;
LastUpgradeCheck = 1200;
ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = {
2F03A52F19C5C6DA005002A5 = {
@@ -2441,6 +2455,7 @@
B559CD491CAA8C6D00E4D58B /* CSStorageInterface.swift in Sources */,
B5ECDC2F1CA81CDC00C7F112 /* CSCoreStore+Transaction.swift in Sources */,
B5E84F311AFF849C0064E85B /* Internals.WeakObject.swift in Sources */,
B52FEC742596DBE100368BFB /* ObjectReader.swift in Sources */,
B5E84F101AFF847B0064E85B /* GroupBy.swift in Sources */,
B5E84F201AFF84860064E85B /* DataStack+Observing.swift in Sources */,
B501FDDD1CA8D05000BE22EF /* CSSectionBy.swift in Sources */,
@@ -2693,6 +2708,7 @@
B501FDDF1CA8D05000BE22EF /* CSSectionBy.swift in Sources */,
B5BF7FAE234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
B538BA781D15B3E30003A766 /* CoreStoreBridge.m in Sources */,
B52FEC752596DBE100368BFB /* ObjectReader.swift in Sources */,
B51260801E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */,
82BA18D31C4BBD7100A0916E /* NSManagedObjectContext+CoreStore.swift in Sources */,
82BA18AD1C4BBD3100A0916E /* UnsafeDataTransaction.swift in Sources */,
@@ -2945,6 +2961,7 @@
B5220E181D130711009BC71E /* ObjectObserver.swift in Sources */,
B5220E251D13088E009BC71E /* ListObserver.swift in Sources */,
B538BA7A1D15B3E30003A766 /* CoreStoreBridge.m in Sources */,
B52FEC772596DBE100368BFB /* ObjectReader.swift in Sources */,
B5BF7FB0234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
B51260821E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */,
B52DD1A01BE1F92C00949AFE /* UnsafeDataTransaction.swift in Sources */,
@@ -3197,6 +3214,7 @@
B501FDE01CA8D05000BE22EF /* CSSectionBy.swift in Sources */,
B5BF7FAF234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
B538BA791D15B3E30003A766 /* CoreStoreBridge.m in Sources */,
B52FEC762596DBE100368BFB /* ObjectReader.swift in Sources */,
B51260811E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */,
B56321B11BD6521C006C9394 /* NSManagedObjectContext+CoreStore.swift in Sources */,
B563218D1BD65216006C9394 /* CoreStore+Transaction.swift in Sources */,
@@ -3292,6 +3310,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -3363,6 +3382,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -3413,7 +3433,7 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 7.3.0;
MARKETING_VERSION = 7.3.1;
OTHER_LDFLAGS = (
"-weak_framework",
Combine,
@@ -3436,7 +3456,7 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 7.3.0;
MARKETING_VERSION = 7.3.1;
OTHER_LDFLAGS = (
"-weak_framework",
Combine,
@@ -3496,7 +3516,7 @@
GCC_NO_COMMON_BLOCKS = YES;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 7.3.0;
MARKETING_VERSION = 7.3.1;
OTHER_LDFLAGS = (
"-weak_framework",
Combine,
@@ -3522,7 +3542,7 @@
GCC_NO_COMMON_BLOCKS = YES;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 7.3.0;
MARKETING_VERSION = 7.3.1;
OTHER_LDFLAGS = (
"-weak_framework",
Combine,
@@ -3587,7 +3607,7 @@
GCC_NO_COMMON_BLOCKS = YES;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 7.3.0;
MARKETING_VERSION = 7.3.1;
OTHER_LDFLAGS = (
"-weak_framework",
Combine,
@@ -3616,7 +3636,7 @@
GCC_NO_COMMON_BLOCKS = YES;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 7.3.0;
MARKETING_VERSION = 7.3.1;
OTHER_LDFLAGS = (
"-weak_framework",
Combine,
@@ -3682,7 +3702,7 @@
GCC_NO_COMMON_BLOCKS = YES;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 7.3.0;
MARKETING_VERSION = 7.3.1;
OTHER_LDFLAGS = (
"-weak_framework",
Combine,
@@ -3710,7 +3730,7 @@
GCC_NO_COMMON_BLOCKS = YES;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 7.3.0;
MARKETING_VERSION = 7.3.1;
OTHER_LDFLAGS = (
"-weak_framework",
Combine,

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@@ -8,6 +8,6 @@
location = "group:CoreStore.xcodeproj">
</FileRef>
<FileRef
location = "group:/Users/JohnEstropia/Documents/XCodeProjects/CoreStore/LegacyDemo/LegacyDemo.xcodeproj">
location = "group:LegacyDemo/LegacyDemo.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -290,19 +290,6 @@ class DynamicModelTests: BaseTestDataTestCase {
}
}
// #if swift(>=5.1)
//
// let dogKeyPathBuilder = Dog.keyPathBuilder()
// XCTAssertEqual(dogKeyPathBuilder.species.keyPathString, "SELF.species")
// XCTAssertEqual(dogKeyPathBuilder.master.title.keyPathString, "SELF.master.title")
// let a = dogKeyPathBuilder.master
// let b = dogKeyPathBuilder.master.spouse
// let c = dogKeyPathBuilder.master.spouse.pets
// let d = dogKeyPathBuilder.master.spouse.pets.color
// XCTAssertEqual(dogKeyPathBuilder.master.spouse.pets.color.keyPathString, "SELF.master.spouse.pets.color")
//
// #endif
let didSetObserver = dog.observe(\.$species, options: [.new, .old]) { (object, change) in
XCTAssertEqual(object, dog)

View File

@@ -77,17 +77,10 @@ final class WhereTests: XCTestCase {
do {
// let keyPathBuilder = TestEntity1.keyPathBuilder()
// let kp = \TestEntity1.testToOne
// print(keyPathBuilder.testString)
// print(keyPathBuilder.testToOne)
// print(keyPathBuilder.testToOne.testEntityID)
XCTAssertAllEqual(
#keyPath(TestEntity1.testToOne.testEntityID),
(\TestEntity1.testToOne ~ \.testEntityID).description,
String(keyPath: \TestEntity1.testToOne ~ \.testEntityID)
// keyPathBuilder.testToOne.testEntityID.keyPathString
)
XCTAssertAllEqual(
#keyPath(TestEntity1.testToOne.testToOne.testToManyUnordered),

View File

@@ -622,7 +622,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1160;
LastUpgradeCheck = 1160;
LastUpgradeCheck = 1200;
TargetAttributes = {
B5A3911824E5429200E7E8BD = {
CreatedOnToolsVersion = 11.6;
@@ -769,6 +769,33 @@
B5A3911324E5424E00E7E8BD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
};
name = Debug;
@@ -776,6 +803,32 @@
B5A3911424E5424E00E7E8BD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
};
name = Release;

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1160"
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@@ -5,6 +5,7 @@
import CoreStore
import SwiftUI
// MARK: - Modern.ColorsDemo.SwiftUI
extension Modern.ColorsDemo.SwiftUI {
@@ -39,7 +40,7 @@ extension Modern.ColorsDemo.SwiftUI {
.listRowInsets(.init())
}
.onDelete { itemIndices in
self.deleteColors(at: itemIndices, in: sectionID)
}
}

View File

@@ -295,7 +295,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0930;
LastUpgradeCheck = 1200;
ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = {
B54AAD481AF4D26E00848AE0 = {
@@ -422,6 +422,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -479,6 +480,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;

View File

@@ -6,14 +6,24 @@ PlaygroundPage.current.needsIndefiniteExecution = true
/// Model Declaration =====
class Animal: CoreStoreObject {
let species = Value.Required<String>("species", initial: "Swift")
let master = Relationship.ToOne<Person>("master")
let color = Transformable.Optional<UIColor>("color", initial: .orange)
@Field.Stored("species")
var species: String = "Swift"
@Field.Coded("color", coder: FieldCoders.NSCoding.self)
var color: UIColor = .orange
@Field.Relationship("master")
var master: Person?
}
class Person: CoreStoreObject {
let name = Value.Optional<String>("name")
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
@Field.Stored("name")
var name: String?
@Field.Relationship("pets", inverse: \.$master)
var pets: Set<Animal>
}
/// =======================
@@ -24,6 +34,10 @@ let dataStack = DataStack(
entities: [
Entity<Animal>("Animal"),
Entity<Person>("Person")
],
versionLock: [
"Animal": [0x4a201cc685d53c0a, 0x16e6c3b561577875, 0xb032e2da61c792a0, 0xa133b801051acee4],
"Person": [0xca938eea1af4bd56, 0xbca30994506356ad, 0x7a7cc655898816ef, 0x1a4551ffedc9b214]
]
)
)
@@ -42,12 +56,12 @@ dataStack.addStorage(
asynchronous: { transaction in
let animal = transaction.create(Into<Animal>())
animal.species .= "Sparrow"
animal.color .= .yellow
animal.species = "Sparrow"
animal.color = .yellow
let person = transaction.create(Into<Person>())
person.name .= "John"
person.pets.value.insert(animal)
person.name = "John"
person.pets.insert(animal)
},
completion: { result in
@@ -58,13 +72,16 @@ dataStack.addStorage(
case .success:
/// Accessing Objects =====
let bird = try! dataStack.fetchOne(From<Animal>().where(\.species == "Sparrow"))!
print(bird.species.value)
print(bird.color.value as Any)
let bird = try! dataStack.fetchOne(
From<Animal>()
.where(\.$species == "Sparrow")
)!
print(bird.species)
print(bird.color as Any)
print(bird)
let owner = bird.master.value!
print(owner.name.value as Any)
let owner = bird.master!
print(owner.name as Any)
print(owner.pets.count)
print(owner)
/// =======================

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='ios' executeOnSourceChanges='false'>
<playground version='5.0' target-platform='ios' buildActiveScheme='true'>
<timeline fileName='timeline.xctimeline'/>
</playground>

View File

@@ -6,14 +6,24 @@ PlaygroundPage.current.needsIndefiniteExecution = true
/// Model Declaration =====
class Animal: CoreStoreObject {
let species = Value.Required<String>("species", initial: "Swift")
let master = Relationship.ToOne<Person>("master")
let color = Transformable.Optional<NSColor>("color", initial: .orange)
@Field.Stored("species")
var species: String = "Swift"
@Field.Coded("color", coder: FieldCoders.NSCoding.self)
var color: NSColor = .orange
@Field.Relationship("master")
var master: Person?
}
class Person: CoreStoreObject {
let name = Value.Optional<String>("name")
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
@Field.Stored("name")
var name: String?
@Field.Relationship("pets", inverse: \.$master)
var pets: Set<Animal>
}
/// =======================
@@ -24,6 +34,10 @@ let dataStack = DataStack(
entities: [
Entity<Animal>("Animal"),
Entity<Person>("Person")
],
versionLock: [
"Animal": [0x4a201cc685d53c0a, 0x16e6c3b561577875, 0xb032e2da61c792a0, 0xa133b801051acee4],
"Person": [0xca938eea1af4bd56, 0xbca30994506356ad, 0x7a7cc655898816ef, 0x1a4551ffedc9b214]
]
)
)
@@ -42,12 +56,12 @@ dataStack.addStorage(
asynchronous: { transaction in
let animal = transaction.create(Into<Animal>())
animal.species .= "Sparrow"
animal.color .= .yellow
animal.species = "Sparrow"
animal.color = .yellow
let person = transaction.create(Into<Person>())
person.name .= "John"
person.pets.value.insert(animal)
person.name = "John"
person.pets.insert(animal)
},
completion: { result in
@@ -58,13 +72,16 @@ dataStack.addStorage(
case .success:
/// Accessing Objects =====
let bird = try! dataStack.fetchOne(From<Animal>().where(\.species == "Sparrow"))!
print(bird.species.value)
print(bird.color.value as Any)
let bird = try! dataStack.fetchOne(
From<Animal>()
.where(\.$species == "Sparrow")
)!
print(bird.species)
print(bird.color as Any)
print(bird)
let owner = bird.master.value!
print(owner.name.value as Any)
let owner = bird.master!
print(owner.name as Any)
print(owner.pets.count)
print(owner)
/// =======================

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos' executeOnSourceChanges='false'>
<playground version='5.0' target-platform='macos' buildActiveScheme='true'>
<timeline fileName='timeline.xctimeline'/>
</playground>

View File

@@ -2095,7 +2095,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
#### Install with Swift Package Manager:
```swift
dependencies: [
.package(url: "https://github.com/JohnEstropia/CoreStore.git", from: "7.3.0"))
.package(url: "https://github.com/JohnEstropia/CoreStore.git", from: "7.3.1"))
]
```
Declare `import CoreStore` in your swift file to use the library.

View File

@@ -230,7 +230,10 @@ extension BaseDataTransaction {
}
try autoreleasepool {
if let object = existingObjectsByID[objectID] {
if let object = existingObjectsByID[objectID]
?? self.context.insertedObjects
.compactMap({ O.cs_matches(object: $0) ? O.cs_fromRaw(object: $0) : nil })
.first(where: { $0.uniqueIDValue == objectID }) {
guard entityType.shouldUpdate(from: source, in: self) else {

View File

@@ -429,7 +429,7 @@ public /*abstract*/ class BaseDataTransaction {
internal let context: NSManagedObjectContext
internal let transactionQueue: DispatchQueue
internal let childTransactionQueue = DispatchQueue.serial("com.corestore.datastack.childTransactionQueue")
internal let childTransactionQueue = DispatchQueue.serial("com.corestore.datastack.childTransactionQueue", qos: .utility)
internal let supportsUndo: Bool
internal let bypassesQueueing: Bool
internal var isCommitted = false

View File

@@ -1189,7 +1189,6 @@ extension NSAttributeDescription: CoreStoreDebugStringConvertible {
("versionHash", self.versionHash),
("versionHashModifier", self.versionHashModifier as Any),
("isIndexedBySpotlight", self.isIndexedBySpotlight),
("isStoredInExternalRecord", self.isStoredInExternalRecord),
("renamingIdentifier", self.renamingIdentifier as Any)
)
}
@@ -1363,11 +1362,9 @@ extension NSRelationshipDescription: CoreStoreDebugStringConvertible {
("isOptional", self.isOptional),
("isTransient", self.isTransient),
("userInfo", self.userInfo as Any),
("isIndexed", self.isIndexed),
("versionHash", self.versionHash),
("versionHashModifier", self.versionHashModifier as Any),
("isIndexedBySpotlight", self.isIndexedBySpotlight),
("isStoredInExternalRecord", self.isStoredInExternalRecord),
("renamingIdentifier", self.renamingIdentifier as Any)
)
}

View File

@@ -29,4 +29,4 @@
FOUNDATION_EXPORT double CoreStoreVersionNumber;
FOUNDATION_EXPORT const unsigned char CoreStoreVersionString[];
#import "CoreStoreBridge.h"
#import <CoreStore/CoreStoreBridge.h>

View File

@@ -69,7 +69,7 @@ public enum CoreStoreDefaults {
// MARK: Private
private static let defaultStackBarrierQueue = DispatchQueue.concurrent("com.coreStore.defaultStackBarrierQueue")
private static let defaultStackBarrierQueue = DispatchQueue.concurrent("com.coreStore.defaultStackBarrierQueue", qos: .userInteractive)
private static var defaultStackInstance: DataStack?
}

View File

@@ -48,6 +48,6 @@ import Foundation
private enum Static {
static let queue = DispatchQueue.concurrent("com.coreStore.coreStoreManagerObjectBarrierQueue")
static let queue = DispatchQueue.concurrent("com.coreStore.coreStoreManagerObjectBarrierQueue", qos: .userInteractive)
static var cache: [ObjectIdentifier: [KeyPathString: Set<KeyPathString>]] = [:]
}

View File

@@ -254,7 +254,7 @@ public final class CoreStoreSchema: DynamicSchema {
// MARK: Private
private static let barrierQueue = DispatchQueue.concurrent("com.coreStore.coreStoreDataModelBarrierQueue")
private static let barrierQueue = DispatchQueue.concurrent("com.coreStore.coreStoreDataModelBarrierQueue", qos: .userInteractive)
private let allEntities: Set<DynamicEntity>

View File

@@ -440,8 +440,8 @@ public final class DataStack: Equatable {
internal let rootSavingContext: NSManagedObjectContext
internal let mainContext: NSManagedObjectContext
internal let schemaHistory: SchemaHistory
internal let childTransactionQueue = DispatchQueue.serial("com.coreStore.dataStack.childTransactionQueue")
internal let storeMetadataUpdateQueue = DispatchQueue.concurrent("com.coreStore.persistentStoreBarrierQueue")
internal let childTransactionQueue = DispatchQueue.serial("com.coreStore.dataStack.childTransactionQueue", qos: .utility)
internal let storeMetadataUpdateQueue = DispatchQueue.concurrent("com.coreStore.persistentStoreBarrierQueue", qos: .userInteractive)
internal let migrationQueue: OperationQueue = Internals.with {
let migrationQueue = OperationQueue()

View File

@@ -63,7 +63,7 @@ extension DiffableDataSource {
*/
open class TableViewAdapter<O: DynamicObject>: BaseAdapter<O, DefaultTableViewTarget<UITableView>>, UITableViewDataSource {
// MARK: Publi
// MARK: Public
/**
Initializes the `DiffableDataSource.TableViewAdapter`. This instance needs to be held on (retained) for as long as the `UITableView`'s lifecycle.

View File

@@ -31,7 +31,7 @@ import Foundation
extension DispatchQueue {
@nonobjc @inline(__always)
internal static func serial(_ label: String, qos: DispatchQoS = .default) -> DispatchQueue {
internal static func serial(_ label: String, qos: DispatchQoS) -> DispatchQueue {
return DispatchQueue(
label: label,
@@ -43,7 +43,7 @@ extension DispatchQueue {
}
@nonobjc @inline(__always)
internal static func concurrent(_ label: String, qos: DispatchQoS = .default) -> DispatchQueue {
internal static func concurrent(_ label: String, qos: DispatchQoS) -> DispatchQueue {
return DispatchQueue(
label: label,

View File

@@ -217,7 +217,8 @@ extension CoreStoreObject {
guard
let object = context.fetchExisting(id) as CoreStoreObject?,
let rawObject = object.rawObject
let rawObject = object.rawObject,
!rawObject.isDeleted
else {
return nil

View File

@@ -42,6 +42,28 @@ extension From {
return self.fetchChain(appending: clause)
}
/**
Creates a `FetchChainBuilder` that `AND`s the specified `Where` clauses. Use this overload if the compiler cannot infer the types when chaining multiple `&&` operators.
- parameter clauses: the `Where` clauses to create a `FetchChainBuilder` with
- returns: a `FetchChainBuilder` that `AND`s the specified `Where` clauses
*/
public func `where`(combineByAnd clauses: Where<O>...) -> FetchChainBuilder<O> {
return self.fetchChain(appending: clauses.combinedByAnd())
}
/**
Creates a `FetchChainBuilder` that `OR`s the specified `Where` clauses. Use this overload if the compiler cannot infer the types when chaining multiple `||` operators.
- parameter clauses: the `Where` clauses to create a `FetchChainBuilder` with
- returns: a `FetchChainBuilder` that `OR`s the specified `Where` clauses
*/
public func `where`(combineByOr clauses: Where<O>...) -> FetchChainBuilder<O> {
return self.fetchChain(appending: clauses.combinedByOr())
}
/**
Creates a `FetchChainBuilder` with a predicate using the specified string format and arguments
@@ -295,11 +317,6 @@ extension From where O: CoreStoreObject {
return self.fetchChain(appending: clause(O.meta))
}
public func `where`(combinedByAnd clause: Where<O>, _ others: Where<O>...) -> FetchChainBuilder<O> {
return self.fetchChain(appending: ([clause] + others).combinedByAnd())
}
/**
Creates a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
@@ -544,6 +561,28 @@ extension FetchChainBuilder {
return self.fetchChain(appending: clause)
}
/**
Creates a `FetchChainBuilder` that `AND`s the specified `Where` clauses. Use this overload if the compiler cannot infer the types when chaining multiple `&&` operators.
- parameter clauses: the `Where` clauses to create a `FetchChainBuilder` with
- returns: a `FetchChainBuilder` that `AND`s the specified `Where` clauses
*/
public func `where`(combineByAnd clauses: Where<O>...) -> FetchChainBuilder<O> {
return self.fetchChain(appending: clauses.combinedByAnd())
}
/**
Creates a `FetchChainBuilder` that `OR`s the specified `Where` clauses. Use this overload if the compiler cannot infer the types when chaining multiple `||` operators.
- parameter clauses: the `Where` clauses to create a `FetchChainBuilder` with
- returns: a `FetchChainBuilder` that `OR`s the specified `Where` clauses
*/
public func `where`(combineByOr clauses: Where<O>...) -> FetchChainBuilder<O> {
return self.fetchChain(appending: clauses.combinedByOr())
}
/**
Adds a `Where` clause to the `FetchChainBuilder`
@@ -682,6 +721,28 @@ extension QueryChainBuilder {
return self.queryChain(appending: clause)
}
/**
Creates a `FetchChainBuilder` that `AND`s the specified `Where` clauses. Use this overload if the compiler cannot infer the types when chaining multiple `&&` operators.
- parameter clauses: the `Where` clauses to create a `FetchChainBuilder` with
- returns: a `FetchChainBuilder` that `AND`s the specified `Where` clauses
*/
public func `where`(combineByAnd clauses: Where<O>...) -> QueryChainBuilder<O, R> {
return self.queryChain(appending: clauses.combinedByAnd())
}
/**
Creates a `FetchChainBuilder` that `OR`s the specified `Where` clauses. Use this overload if the compiler cannot infer the types when chaining multiple `||` operators.
- parameter clauses: the `Where` clauses to create a `FetchChainBuilder` with
- returns: a `FetchChainBuilder` that `OR`s the specified `Where` clauses
*/
public func `where`(combineByOr clauses: Where<O>...) -> QueryChainBuilder<O, R> {
return self.queryChain(appending: clauses.combinedByOr())
}
/**
Adds a `Where` clause to the `QueryChainBuilder`
@@ -957,6 +1018,28 @@ extension SectionMonitorChainBuilder {
return self.sectionMonitorChain(appending: clause)
}
/**
Creates a `FetchChainBuilder` that `AND`s the specified `Where` clauses. Use this overload if the compiler cannot infer the types when chaining multiple `&&` operators.
- parameter clauses: the `Where` clauses to create a `FetchChainBuilder` with
- returns: a `FetchChainBuilder` that `AND`s the specified `Where` clauses
*/
public func `where`(combineByAnd clauses: Where<O>...) -> SectionMonitorChainBuilder<O> {
return self.sectionMonitorChain(appending: clauses.combinedByAnd())
}
/**
Creates a `FetchChainBuilder` that `OR`s the specified `Where` clauses. Use this overload if the compiler cannot infer the types when chaining multiple `||` operators.
- parameter clauses: the `Where` clauses to create a `FetchChainBuilder` with
- returns: a `FetchChainBuilder` that `OR`s the specified `Where` clauses
*/
public func `where`(combineByOr clauses: Where<O>...) -> SectionMonitorChainBuilder<O> {
return self.sectionMonitorChain(appending: clauses.combinedByOr())
}
/**
Adds a `Where` clause to the `SectionMonitorChainBuilder`

View File

@@ -53,7 +53,7 @@ import CoreData
)
```
*/
public protocol ImportableUniqueObject: ImportableObject {
public protocol ImportableUniqueObject: ImportableObject, Hashable {
/**
The data type for the entity's unique ID attribute

View File

@@ -78,7 +78,7 @@ extension Internals {
var numberOfItems: Int {
return self.structure.allItemIDs.count
return self.structure.allItemsCount
}
var numberOfSections: Int {
@@ -106,6 +106,59 @@ extension Internals {
return self.itemIdentifiers(inSection: identifier).count
}
func itemIdentifier(atAllItemsIndex index: Int) -> NSManagedObjectID? {
guard index >= 0 else {
return nil
}
var remainingIndex = index
for section in self.structure.sections {
let elements = section.elements
let sectionCount = elements.count
if remainingIndex < sectionCount {
return elements[remainingIndex].differenceIdentifier
}
remainingIndex -= sectionCount
}
return nil
}
func itemIdentifiers(atAllItemsBounds bounds: Range<Int>) -> [NSManagedObjectID] {
var remainingIndex = bounds.lowerBound
var itemIdentifiers: [NSManagedObjectID] = []
for section in self.structure.sections {
let elements = section.elements
let sectionCount = elements.count
if remainingIndex < sectionCount {
itemIdentifiers.append(
contentsOf: elements[remainingIndex..<min(sectionCount, bounds.count)]
.map({ $0.differenceIdentifier })
)
}
else if !itemIdentifiers.isEmpty {
itemIdentifiers.append(
contentsOf: elements.prefix(bounds.count - itemIdentifiers.count)
.map({ $0.differenceIdentifier })
)
}
if itemIdentifiers.count >= bounds.count {
return itemIdentifiers
}
remainingIndex -= sectionCount
}
return itemIdentifiers
}
func itemIdentifiers(inSection identifier: String) -> [NSManagedObjectID] {
return self.structure.items(in: identifier)
@@ -332,6 +385,14 @@ extension Internals {
return self.sections.map({ $0.differenceIdentifier })
}
var allItemsCount: Int {
return self.sections.reduce(into: 0) { (result, section) in
result += section.elements.count
}
}
var allItemIDs: [NSManagedObjectID] {
return self.sections.lazy.flatMap({ $0.elements }).map({ $0.differenceIdentifier })

View File

@@ -267,6 +267,17 @@ public func == <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, D>
return Where<O>(keyPath._kvcKeyPathString!, isEqualTo: objectID)
}
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let dog = dataStack.fetchOne(From<Dog>().where(\.master == john))
```
*/
public func == <O: ObjectRepresentation, D: NSManagedObject>(_ keyPath: KeyPath<O, D>, _ object: O) -> Where<O> where O.ObjectType: NSManagedObject {
return Where<O>(keyPath._kvcKeyPathString!, isEqualTo: object.cs_id())
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
@@ -278,6 +289,17 @@ public func != <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, D>
return !Where<O>(keyPath._kvcKeyPathString!, isEqualTo: objectID)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let dog = dataStack.fetchOne(From<Dog>().where(\.master != john))
```
*/
public func != <O: ObjectRepresentation, D: NSManagedObject>(_ keyPath: KeyPath<O, D>, _ object: O) -> Where<O> where O.ObjectType: NSManagedObject {
return !Where<O>(keyPath._kvcKeyPathString!, isEqualTo: object.cs_id())
}
/**
Creates a `Where` clause by checking if a sequence contains a value of a property
```
@@ -303,6 +325,17 @@ public func == <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, Op
return Where<O>(keyPath._kvcKeyPathString!, isEqualTo: object)
}
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let dog = dataStack.fetchOne(From<Dog>().where(\.master == john))
```
*/
public func == <O: ObjectRepresentation, D: NSManagedObject>(_ keyPath: KeyPath<O, Optional<D>>, _ object: O?) -> Where<O> where O.ObjectType: NSManagedObject {
return Where<O>(keyPath._kvcKeyPathString!, isEqualTo: object?.cs_toRaw())
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
@@ -314,6 +347,17 @@ public func != <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, Op
return !Where<O>(keyPath._kvcKeyPathString!, isEqualTo: object)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let dog = dataStack.fetchOne(From<Dog>().where(\.master != john))
```
*/
public func != <O: ObjectRepresentation, D: NSManagedObject>(_ keyPath: KeyPath<O, Optional<D>>, _ object: O?) -> Where<O> where O.ObjectType: NSManagedObject {
return !Where<O>(keyPath._kvcKeyPathString!, isEqualTo: object?.cs_toRaw())
}
/**
Creates a `Where` clause by checking if a sequence contains a value of a property
```
@@ -395,6 +439,155 @@ public func ~= <O, V, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, FieldCon
}
// MARK: - KeyPath where Root: CoreStoreObject, Value: FieldContainer<Root>.Stored<QueryableAttributeType & Comparable>
/**
Creates a `Where` clause by comparing if a property is less than a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age < 20))
```
*/
public func < <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is less than a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age < 20))
```
*/
public func < <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is greater than a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age > 20))
```
*/
public func > <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is greater than a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age > 20))
```
*/
public func > <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is less than or equal to a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age <= 20))
```
*/
public func <= <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is less than or equal to a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age <= 20))
```
*/
public func <= <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is greater than or equal to a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age >= 20))
```
*/
public func >= <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
return Where<O>("%K >= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is greater than or equal to a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age >= 20))
```
*/
public func >= <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
return Where<O>("%K >= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
// MARK: - KeyPath where Root: CoreStoreObject, Value: FieldContainer<Root>.Relationship<CoreStoreObject>
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let dog = dataStack.fetchOne(From<Dog>().where(\.$master == john))
```
*/
public func == <O, D: FieldRelationshipToOneType>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>, _ object: D.DestinationObjectType?) -> Where<O> {
return Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
}
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let dog = dataStack.fetchOne(From<Dog>().where(\.master == john))
```
*/
public func == <O, D: FieldRelationshipToOneType, R: ObjectRepresentation>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>, _ object: R?) -> Where<O> where D.DestinationObjectType == R.ObjectType {
return Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object?.objectID())
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let dog = dataStack.fetchOne(From<Dog>().where(\.$master != john))
```
*/
public func != <O, D: FieldRelationshipToOneType>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>, _ object: D.DestinationObjectType?) -> Where<O> {
return !Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let dog = dataStack.fetchOne(From<Dog>().where(\.master != john))
```
*/
public func != <O, D: FieldRelationshipToOneType, R: ObjectRepresentation>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>, _ object: R?) -> Where<O> where D.DestinationObjectType == R.ObjectType {
return !Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object?.objectID())
}
/**
Creates a `Where` clause by checking if a sequence contains a value of a property
```
let dog = dataStack.fetchOne(From<Dog>().where([john, bob, joe] ~= \.$master))
```
*/
public func ~= <O, D: FieldRelationshipToOneType, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>) -> Where<O> where S.Iterator.Element == D.DestinationObjectType {
return Where<O>(O.meta[keyPath: keyPath].keyPath, isMemberOf: sequence)
}
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Required<QueryableAttributeType & Equatable>
/**
@@ -469,17 +662,6 @@ public func ~= <O, V, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, ValueCon
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Required<QueryableAttributeType & Comparable>
/**
Creates a `Where` clause by comparing if a property is less than a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age < 20))
```
*/
public func < <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is less than a value
```
@@ -491,17 +673,6 @@ public func < <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Require
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value.cs_toQueryableNativeType())
}
/**
Creates a `Where` clause by comparing if a property is greater than a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age > 20))
```
*/
public func > <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is greater than a value
```
@@ -513,17 +684,6 @@ public func > <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Require
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value.cs_toQueryableNativeType())
}
/**
Creates a `Where` clause by comparing if a property is less than or equal to a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age <= 20))
```
*/
public func <= <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is less than or equal to a value
```
@@ -535,17 +695,6 @@ public func <= <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Requir
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toQueryableNativeType())
}
/**
Creates a `Where` clause by comparing if a property is greater than or equal to a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age >= 20))
```
*/
public func >= <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
return Where<O>("%K >= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is greater than or equal to a value
```
@@ -560,17 +709,6 @@ public func >= <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Requir
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Optional<QueryableAttributeType & Comparable>
/**
Creates a `Where` clause by comparing if a property is less than a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age < 20))
```
*/
public func < <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is less than a value
```
@@ -589,17 +727,6 @@ public func < <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ val
}
}
/**
Creates a `Where` clause by comparing if a property is greater than a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age > 20))
```
*/
public func > <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is greater than a value
```
@@ -618,17 +745,6 @@ public func > <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ val
}
}
/**
Creates a `Where` clause by comparing if a property is less than or equal to a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age <= 20))
```
*/
public func <= <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is less than or equal to a value
```
@@ -647,17 +763,6 @@ public func <= <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ va
}
}
/**
Creates a `Where` clause by comparing if a property is greater than or equal to a value
```
let person = dataStack.fetchOne(From<Person>().where(\.$age >= 20))
```
*/
public func >= <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
return Where<O>("%K >= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
}
/**
Creates a `Where` clause by comparing if a property is greater than or equal to a value
```
@@ -679,17 +784,6 @@ public func >= <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ va
// MARK: - KeyPath where Root: CoreStoreObject, Value: RelationshipContainer<Root>.ToOne<CoreStoreObject>
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let dog = dataStack.fetchOne(From<Dog>().where(\.$master == john))
```
*/
public func == <O, D: FieldRelationshipToOneType>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>, _ object: D.DestinationObjectType?) -> Where<O> {
return Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
}
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
@@ -712,17 +806,6 @@ public func == <O, D>(_ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>,
return Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let dog = dataStack.fetchOne(From<Dog>().where(\.$master != john))
```
*/
public func != <O, D: FieldRelationshipToOneType>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>, _ object: D.DestinationObjectType?) -> Where<O> {
return !Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
@@ -745,17 +828,6 @@ public func != <O, D>(_ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>,
return !Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
}
/**
Creates a `Where` clause by checking if a sequence contains a value of a property
```
let dog = dataStack.fetchOne(From<Dog>().where([john, bob, joe] ~= \.$master))
```
*/
public func ~= <O, D: FieldRelationshipToOneType, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>) -> Where<O> where S.Iterator.Element == D.DestinationObjectType {
return Where<O>(O.meta[keyPath: keyPath].keyPath, isMemberOf: sequence)
}
/**
Creates a `Where` clause by checking if a sequence contains a value of a property
```

View File

@@ -71,7 +71,7 @@ public struct ListSnapshot<O: DynamicObject>: RandomAccessCollection, Hashable {
public subscript(index: Index) -> ObjectPublisher<O> {
let context = self.context!
let itemID = self.diffableSnapshot.itemIdentifiers[index]
let itemID = self.diffableSnapshot.itemIdentifier(atAllItemsIndex: index)!
return context.objectPublisher(objectID: itemID)
}
@@ -83,16 +83,13 @@ public struct ListSnapshot<O: DynamicObject>: RandomAccessCollection, Hashable {
*/
public subscript(safeIndex index: Index) -> ObjectPublisher<O>? {
guard let context = self.context else {
guard
let context = self.context,
let itemID = self.diffableSnapshot.itemIdentifier(atAllItemsIndex: index)
else {
return nil
}
let itemIDs = self.diffableSnapshot.itemIdentifiers
guard itemIDs.indices.contains(index) else {
return nil
}
let itemID = itemIDs[index]
return context.objectPublisher(objectID: itemID)
}
@@ -597,20 +594,74 @@ public struct ListSnapshot<O: DynamicObject>: RandomAccessCollection, Hashable {
self.diffableSnapshot.reloadSections(sectionIDs)
}
// MARK: RandomAccessCollection
public var startIndex: Index {
return self.diffableSnapshot.itemIdentifiers.startIndex
return 0
}
public var endIndex: Index {
return self.diffableSnapshot.itemIdentifiers.endIndex
return self.diffableSnapshot.numberOfItems
}
public func index(after i: Index) -> Index {
return i + 1
}
public func formIndex(after i: inout Index) {
return i += 1
}
public func index(before i: Index) -> Index {
return i - 1
}
public func formIndex(before i: inout Index) {
return i -= 1
}
// MARK: BidirectionalCollection
public func index(_ i: Index, offsetBy distance: Int) -> Index {
return i + distance
}
public func index(_ i: Index, offsetBy distance: Int, limitedBy limit: Int) -> Index? {
let length = limit - i
if distance > 0
? length >= 0 && length < distance
: length <= 0 && length > distance {
return nil
}
return i + distance
}
public func distance(from start: Index, to end: Index) -> Int {
return end - start
}
public subscript(bounds: Range<Index>) -> ArraySlice<Element> {
guard let context = self.context else {
return .init()
}
let itemIDs = self.diffableSnapshot.itemIdentifiers(atAllItemsBounds: bounds)
return ArraySlice(itemIDs.map(context.objectPublisher(objectID:)))
}
// MARK: Sequence

View File

@@ -40,12 +40,7 @@ import CoreData
Observers registered via `addObserver(_:)` are not retained. `ObjectMonitor` only keeps a `weak` reference to all observers, thus keeping itself free from retain-cycles.
*/
@available(macOS 10.12, *)
public final class ObjectMonitor<O: DynamicObject>: Equatable {
/**
The object type represented by this `ObjectMonitor`
*/
public typealias ObjectType = O
public final class ObjectMonitor<O: DynamicObject>: Hashable, ObjectRepresentation {
/**
Returns the `DynamicObject` instance being observed, or `nil` if the object was already deleted.
@@ -156,6 +151,51 @@ public final class ObjectMonitor<O: DynamicObject>: Equatable {
}
// MARK: AnyObjectRepresentation
public func objectID() -> O.ObjectID {
return self.id
}
public func cs_dataStack() -> DataStack? {
return self.context.parentStack
}
// MARK: ObjectRepresentation
public typealias ObjectType = O
public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<O> {
return dataStack.unsafeContext().objectPublisher(objectID: self.id)
}
public func asReadOnly(in dataStack: DataStack) -> O? {
return dataStack.unsafeContext().fetchExisting(self.id)
}
public func asEditable(in transaction: BaseDataTransaction) -> O? {
return transaction.unsafeContext().fetchExisting(self.id)
}
public func asSnapshot(in dataStack: DataStack) -> ObjectSnapshot<O>? {
let context = dataStack.unsafeContext()
return ObjectSnapshot<O>(objectID: self.id, context: context)
}
public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot<O>? {
let context = transaction.unsafeContext()
return ObjectSnapshot<O>(objectID: self.id, context: context)
}
// MARK: Internal
internal init(objectID: O.ObjectID, context: NSManagedObjectContext) {

View File

@@ -125,15 +125,23 @@ public final class ObjectPublisher<O: DynamicObject>: ObjectRepresentation, Hash
}
// MARK: ObjectRepresentation
public typealias ObjectType = O
// MARK: AnyObjectRepresentation
public func objectID() -> O.ObjectID {
return self.id
}
public func cs_dataStack() -> DataStack? {
return self.context.parentStack
}
// MARK: ObjectRepresentation
public typealias ObjectType = O
public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<O> {
let context = dataStack.unsafeContext()
@@ -449,20 +457,18 @@ extension ObjectPublisher where O: NSManagedObject {
/**
Returns the value for the property identified by a given key.
*/
@available(*, unavailable, message: "KeyPaths accessed from @dynamicMemberLookup types can't generate KVC keys yet (https://bugs.swift.org/browse/SR-11351)")
public subscript<V: AllowedObjectiveCKeyPathValue>(dynamicMember member: KeyPath<O, V>) -> V {
public subscript<V: AllowedObjectiveCKeyPathValue>(dynamicMember member: KeyPath<O, V>) -> V! {
fatalError()
// return self.snapshot[dynamicMember: member]
return self.snapshot?[dynamicMember: member]
}
/**
Returns the value for the property identified by a given key.
*/
// MARK: Deprecated
@available(*, deprecated, message: "Accessing the property directly now works")
public func value<V: AllowedObjectiveCKeyPathValue>(forKeyPath keyPath: KeyPath<O, V>) -> V! {
let key = String(keyPath: keyPath)
return self.snapshot?.dictionaryForValues()[key] as! V?
return self[dynamicMember: keyPath]
}
}

100
Sources/ObjectReader.swift Normal file
View File

@@ -0,0 +1,100 @@
//
// ListState.swift
// CoreStore
//
// Created by John Rommel Estropia on 2020/12/26.
// Copyright © 2020 John Rommel Estropia. All rights reserved.
//
#if canImport(Combine) && canImport(SwiftUI)
import Combine
import SwiftUI
// MARK: - ObjectReader
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
public struct ObjectReader<Object: DynamicObject, Content: View, Placeholder: View>: View {
// MARK: Internal
public init(
_ objectPublisher: ObjectPublisher<Object>?,
@ViewBuilder content: @escaping (ObjectSnapshot<Object>) -> Content,
@ViewBuilder placeholder: @escaping () -> Placeholder
) {
self.objectPublisher = .init(
objectPublisher.flatMap {
guard let dataStack = $0.cs_dataStack() else {
return nil
}
return $0.asPublisher(in: dataStack)
}
)
self.content = content
self.placeholder = placeholder
}
public init(
_ objectPublisher: ObjectPublisher<Object>?,
@ViewBuilder content: @escaping (ObjectSnapshot<Object>) -> Content
) where Placeholder == EmptyView {
self.init(
objectPublisher,
content: content,
placeholder: EmptyView.init
)
}
// MARK: View
public var body: some View {
if let snapshot = self.objectPublisher.wrappedValue?.snapshot {
self.content(snapshot)
}
else {
self.placeholder()
}
}
// MARK: Private
@ObservedObject
private var objectPublisher: OptionalObservedObject<ObjectPublisher<Object>>
private let content: (ObjectSnapshot<Object>) -> Content
private let placeholder: () -> Placeholder
// MARK: - OptionalObservedObject
fileprivate final class OptionalObservedObject<T: ObservableObject>: ObservableObject where ObservableObjectPublisher == T.ObjectWillChangePublisher {
// MARK: Internal
let wrappedValue: T?
init(_ wrappedValue: T?) {
self.wrappedValue = wrappedValue
self.objectWillChange = wrappedValue.map(\.objectWillChange) ?? .init()
}
// MARK: ObservableObject
let objectWillChange: ObservableObjectPublisher
}
}
#endif

View File

@@ -26,23 +26,37 @@
import CoreData
// MARK: - AnyObjectRepresentation
/**
Used internally by CoreStore. Do not conform to directly.
*/
public protocol AnyObjectRepresentation {
/**
The internal ID for the object.
*/
func objectID() -> NSManagedObjectID
/**
Used internally by CoreStore. Do not call directly.
*/
func cs_dataStack() -> DataStack?
}
// MARK - ObjectRepresentation
/**
An object that acts as interfaces for `CoreStoreObject`s or `NSManagedObject`s
*/
public protocol ObjectRepresentation {
public protocol ObjectRepresentation: AnyObjectRepresentation {
/**
The object type represented by this protocol
*/
associatedtype ObjectType: DynamicObject
/**
The internal ID for the object.
*/
func objectID() -> ObjectType.ObjectID
/**
An instance that may be observed for object changes.
*/
@@ -96,14 +110,22 @@ extension DynamicObject where Self: ObjectRepresentation {
.managedObjectContext
.flatMap({ ObjectSnapshot<Self>(objectID: self.cs_id(), context: $0) })
}
// MARK: ObjectRepresentation
// MARK: AnyObjectRepresentation
public func objectID() -> Self.ObjectID {
return self.cs_id()
}
public func cs_dataStack() -> DataStack? {
return self.cs_toRaw().managedObjectContext?.parentStack
}
// MARK: ObjectRepresentation
public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<Self> {

View File

@@ -48,17 +48,25 @@ public struct ObjectSnapshot<O: DynamicObject>: ObjectRepresentation, Hashable {
return self.values
}
// MARK: ObjectRepresentation
public typealias ObjectType = O
// MARK: AnyObjectRepresentation
public func objectID() -> O.ObjectID {
return self.id
}
public func cs_dataStack() -> DataStack? {
return self.context.parentStack
}
// MARK: ObjectRepresentation
public typealias ObjectType = O
public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<O> {
let context = dataStack.unsafeContext()
@@ -93,7 +101,7 @@ public struct ObjectSnapshot<O: DynamicObject>: ObjectRepresentation, Hashable {
public static func == (_ lhs: Self, _ rhs: Self) -> Bool {
return lhs.id == rhs.id
&& lhs.valuesRef == rhs.valuesRef
&& (lhs.generation == rhs.generation || lhs.valuesRef == rhs.valuesRef)
}
@@ -117,18 +125,27 @@ public struct ObjectSnapshot<O: DynamicObject>: ObjectRepresentation, Hashable {
self.id = objectID
self.context = context
self.values = values
self.generation = .init()
}
// MARK: FilePrivate
fileprivate var values: [String: Any]
fileprivate var values: [String: Any] {
didSet {
self.generation = .init()
}
}
// MARK: Private
private let id: O.ObjectID
private let context: NSManagedObjectContext
private var generation: UUID
private var valuesRef: NSDictionary {
@@ -144,29 +161,33 @@ extension ObjectSnapshot where O: NSManagedObject {
/**
Returns the value for the property identified by a given key.
*/
@available(*, unavailable, message: "KeyPaths accessed from @dynamicMemberLookup types can't generate KVC keys yet (https://bugs.swift.org/browse/SR-11351)")
public subscript<V: AllowedObjectiveCKeyPathValue>(dynamicMember member: KeyPath<O, V>) -> V {
public subscript<V: AllowedObjectiveCKeyPathValue>(dynamicMember member: KeyPath<O, V>) -> V! {
let key = String(keyPath: member)
return self.values[key] as! V
get {
let key = String(keyPath: member)
return self.values[key] as! V?
}
set {
let key = String(keyPath: member)
self.values[key] = newValue
}
}
/**
Returns the value for the property identified by a given key.
*/
// MARK: Deprecated
@available(*, deprecated, message: "Accessing the property directly now works")
public func value<V: AllowedObjectiveCKeyPathValue>(forKeyPath keyPath: KeyPath<O, V>) -> V! {
let key = String(keyPath: keyPath)
return self.values[key] as! V?
return self[dynamicMember: keyPath]
}
/**
Mutates the value for the property identified by a given key.
*/
@available(*, deprecated, message: "Mutating the property directly now works")
public mutating func setValue<V: AllowedObjectiveCKeyPathValue>(_ value: V!, forKeyPath keyPath: KeyPath<O, V>) {
let key = String(keyPath: keyPath)
self.values[key] = value
self[dynamicMember: keyPath] = value
}
}

View File

@@ -469,7 +469,7 @@ extension Where where O: CoreStoreObject {
- parameter keyPath: the keyPath to compare with
- parameter null: the arguments for the `==` operator
*/
public init<V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, isEqualTo null: Void?) {
public init<V>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, isEqualTo null: Void?) {
self.init(O.meta[keyPath: keyPath].keyPath, isEqualTo: null)
}
@@ -480,11 +480,44 @@ extension Where where O: CoreStoreObject {
- parameter keyPath: the keyPath to compare with
- parameter null: the arguments for the `==` operator
*/
public init<D>(_ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>, isEqualTo null: Void?) {
public init<V: FieldRelationshipToOneType>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<V>>, isEqualTo null: Void?) {
self.init(O.meta[keyPath: keyPath].keyPath, isEqualTo: null)
}
/**
Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<V, S: Sequence>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, isMemberOf list: S) where S.Iterator.Element == V {
self.init(O.meta[keyPath: keyPath].keyPath, isMemberOf: list)
}
/**
Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<V: FieldRelationshipToOneType, S: Sequence>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<V>>, isMemberOf list: S) where S.Iterator.Element == V.DestinationObjectType {
self.init(O.meta[keyPath: keyPath].keyPath, isMemberOf: list)
}
/**
Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<V: FieldRelationshipToOneType, S: Sequence>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<V>>, isMemberOf list: S) where S.Iterator.Element: NSManagedObjectID {
self.init(O.meta[keyPath: keyPath].keyPath, isMemberOf: list)
}
/**
Initializes a `Where` clause that compares equality
@@ -507,6 +540,28 @@ extension Where where O: CoreStoreObject {
self.init(O.meta[keyPath: keyPath].keyPath, isEqualTo: value)
}
/**
Initializes a `Where` clause that compares equality to `nil`
- parameter keyPath: the keyPath to compare with
- parameter null: the arguments for the `==` operator
*/
public init<V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, isEqualTo null: Void?) {
self.init(O.meta[keyPath: keyPath].keyPath, isEqualTo: null)
}
/**
Initializes a `Where` clause that compares equality to `nil`
- parameter keyPath: the keyPath to compare with
- parameter null: the arguments for the `==` operator
*/
public init<D>(_ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>, isEqualTo null: Void?) {
self.init(O.meta[keyPath: keyPath].keyPath, isEqualTo: null)
}
/**
Initializes a `Where` clause that compares equality