Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ Choose the right one depending ton the configuration you need for you app.

```ruby
pod "SugarRecord/CoreData"
pod "SugarRecord/CoreData+iCloud"
```

### [Carthage](https://github.com/carthage)
Expand Down Expand Up @@ -71,21 +70,6 @@ func coreDataStorage() -> CoreDataDefaultStorage {
}
```

##### Creating an iCloud Storage

SugarRecord supports the integration of CoreData with iCloud. It's very easy to setup since it's implemented in its own storage that you can use from your app, `CoreDataiCloudStorage`:

```swift
// Initializes the CoreDataiCloudStorage
func icloudStorage() -> CoreDataiCloudStorage {
let bundle = Bundle(for: self.classForCoder)
let model = CoreDataObjectModel.merged([bundle])
let icloudConfig = CoreDataiCloudConfig(ubiquitousContentName: "MyDb", ubiquitousContentURL: "Path/", ubiquitousContainerIdentifier: "com.company.MyApp.anothercontainer")
let icloudStorage = try! CoreDataiCloudStorage(model: model, iCloud: icloudConfig)
return icloudStorage
}
```

#### Contexts
Storages offer multiple kind of contexts that are the entry points to the database. For curious developers, in case of CoreData a context is a wrapper around `NSManagedObjectContext`. The available contexts are:

Expand Down Expand Up @@ -209,7 +193,6 @@ class Presenter {
- [Nimble](https://github.com/quick/nimble)
- [CoreData and threads with GCD](http://www.cimgf.com/2011/05/04/core-data-and-threads-without-the-headache/)
- [Jazzy](https://github.com/realm/jazzy)
- [iCloud + CoreData (objc.io)](http://www.objc.io/issue-10/icloud-core-data.html)

## Contributors

Expand Down
14 changes: 2 additions & 12 deletions SugarRecord.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ Pod::Spec.new do |s|
s.social_media_url = 'https://twitter.com/carambalabs'
s.requires_arc = true

s.ios.deployment_target = "8.0"
s.ios.deployment_target = "9.0"
s.osx.deployment_target = "10.10"

coredata_dependencies = lambda do |spec|
spec.frameworks = ['CoreData']
end

foundation_dependencies = lambda do |spec|
spec.dependency "Result", "~> 3.0"
spec.dependency "Result", "~> 5.0"
end

all_platforms = lambda do |spec|
Expand All @@ -27,22 +27,12 @@ Pod::Spec.new do |s|
spec.tvos.deployment_target = '9.0'
end

excluded_icloud_files = ['SugarRecord/Source/CoreData/Entities/iCloudConfig.swift', 'SugarRecord/Source/CoreData/Storages/CoreDataiCloudStorage.swift']

s.subspec "CoreData" do |spec|
source_files = ['SugarRecord/Source/Foundation/**/*.{swift}', 'SugarRecord/Source/CoreData/**/*.{swift}']
spec.source_files = source_files
spec.exclude_files = excluded_icloud_files
coredata_dependencies.call(spec)
foundation_dependencies.call(spec)
all_platforms.call(spec)
end

s.subspec "CoreData+iCloud" do |spec|
source_files = ['SugarRecord/Source/Foundation/**/*.{swift}', 'SugarRecord/Source/CoreData/**/*.{swift}']
spec.source_files = source_files
coredata_dependencies.call(spec)
foundation_dependencies.call(spec)
end

end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation
import CoreData

@available(OSX 10.12, *)
public class CoreDataObservable<T: NSManagedObject>: RequestObservable<T>, NSFetchedResultsControllerDelegate where T:Equatable {
public class CoreDataObservable<T: NSManagedObject>: RequestObservable<T>, NSFetchedResultsControllerDelegate {

// MARK: - Attributes

Expand Down
30 changes: 0 additions & 30 deletions SugarRecord/Source/CoreData/Entities/CoreDataiCloudConfig.swift

This file was deleted.

147 changes: 147 additions & 0 deletions SugarRecord/Source/CoreData/Extensions/NSManagedObjectContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,115 @@ extension NSManagedObjectContext: Context {
return typedResults
}

public func fetchOne<T: Entity>(_ request: FetchRequest<T>) throws -> T? {
guard let entity = T.self as? NSManagedObject.Type else { throw StorageError.invalidType }
let fetchRequest: NSFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity.entityName)
fetchRequest.predicate = request.predicate
fetchRequest.sortDescriptors = request.sortDescriptor.map {[$0]}
fetchRequest.fetchOffset = request.fetchOffset
fetchRequest.fetchLimit = 1

if let results = try? self.fetch(fetchRequest), results.count > 0, let item = results.first as? T {
return item
}

return nil
}

public func query<T: Entity>(_ request: FetchRequest<T>, attributes: [String]) throws -> [[String: Any]] {
guard let entity = T.self as? NSManagedObject.Type else { throw StorageError.invalidType }
let fetchRequest: NSFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity.entityName)
fetchRequest.predicate = request.predicate
fetchRequest.sortDescriptors = request.sortDescriptor.map {[$0]}
fetchRequest.fetchOffset = request.fetchOffset
fetchRequest.fetchLimit = request.fetchLimit

fetchRequest.propertiesToFetch = attributes
fetchRequest.resultType = .dictionaryResultType

let results = try self.fetch(fetchRequest)
let typedResults = results.compactMap { $0 as? [String: Any] }
return typedResults
}

public func query<T: Entity>(_ request: FetchRequest<T>, attribute: String) throws -> [String]? {
guard let entity = T.self as? NSManagedObject.Type else { throw StorageError.invalidType }
let fetchRequest: NSFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity.entityName)
fetchRequest.predicate = request.predicate
fetchRequest.sortDescriptors = request.sortDescriptor.map {[$0]}
fetchRequest.fetchOffset = request.fetchOffset
fetchRequest.fetchLimit = request.fetchLimit

fetchRequest.propertiesToFetch = [attribute]
fetchRequest.resultType = .dictionaryResultType

let results = try self.fetch(fetchRequest)

var elements = [String]()
results.compactMap { $0 as? [String: Any] }.forEach {
if let value = $0[attribute] as? String {
elements.append(value)
}
}

return elements
}

public func querySet<T: Entity>(_ request: FetchRequest<T>, attribute: String) throws -> Set<String>? {
guard let entity = T.self as? NSManagedObject.Type else { throw StorageError.invalidType }
let fetchRequest: NSFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity.entityName)
fetchRequest.predicate = request.predicate
fetchRequest.sortDescriptors = request.sortDescriptor.map {[$0]}
fetchRequest.fetchOffset = request.fetchOffset
fetchRequest.fetchLimit = request.fetchLimit

fetchRequest.propertiesToFetch = [attribute]
fetchRequest.resultType = .dictionaryResultType

let results = try self.fetch(fetchRequest)

var ids = Set<String>()

if let currentResults = results as? [[String: Any]] {
for item in currentResults {
if let id = item[attribute] as? String {
ids.insert(id)
}
}
}

return ids
}

public func queryOne<T: Entity>(_ request: FetchRequest<T>, attributes: [String]) throws -> [String: Any]? {
guard let entity = T.self as? NSManagedObject.Type else { throw StorageError.invalidType }
let fetchRequest: NSFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity.entityName)
fetchRequest.predicate = request.predicate
fetchRequest.sortDescriptors = request.sortDescriptor.map {[$0]}
fetchRequest.fetchOffset = request.fetchOffset
fetchRequest.fetchLimit = 1

fetchRequest.propertiesToFetch = attributes
fetchRequest.resultType = .dictionaryResultType

let results = try self.fetch(fetchRequest)
let typedResults = results.compactMap { $0 as? [String: Any] }
return typedResults.first
}

public func count<T: Entity>(_ request: FetchRequest<T>) -> Int {
guard let entity = T.self as? NSManagedObject.Type else { return 0 }
let fetchRequest: NSFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity.entityName)
fetchRequest.predicate = request.predicate

if let count = try? self.count(for: fetchRequest) {
return count
}

return 0
}


public func insert<T: Entity>(_ entity: T) throws {}

public func new<T: Entity>() throws -> T {
Expand All @@ -42,6 +151,44 @@ extension NSManagedObjectContext: Context {
throw StorageError.invalidOperation("-removeAll not available in NSManagedObjectContext. Remove the store instead")
}

public func saveToPersistentStore(_ completion: ((Swift.Result<Any?, Error>) -> Void)? = nil) {

self.performAndWait {
do {
try self.save()

if let parentContext = self.parent {
parentContext.saveToPersistentStore(completion)
} else {
DispatchQueue.main.async {
completion?(.success(nil))
}
}
} catch {
DispatchQueue.main.async {
completion?(.failure(error))
}
}
}
}

// MARK: - Batch Actions
public func batchUpdate(entityName: String, propertiesToUpdate: [AnyHashable : Any]?, predicate: NSPredicate?) {
let request = NSBatchUpdateRequest(entityName: entityName)
request.propertiesToUpdate = propertiesToUpdate
request.resultType = .updatedObjectsCountResultType
request.predicate = predicate

_ = try? self.execute(request)
}

public func batchDelete(entityName: String, predicate: NSPredicate?) {
let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
fetch.predicate = predicate
let request = NSBatchDeleteRequest(fetchRequest: fetch)

_ = try? self.execute(request)
}
}


Expand Down
15 changes: 3 additions & 12 deletions SugarRecord/Source/CoreData/Storages/CoreDataDefaultStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public class CoreDataDefaultStorage: Storage {
}
}

public var type: StorageType = .coreData
public var mainContext: Context!
private var _saveContext: Context!
public var saveContext: Context! {
Expand Down Expand Up @@ -110,28 +109,20 @@ public class CoreDataDefaultStorage: Storage {


// MARK: - Init

public convenience init(store: CoreDataStore, model: CoreDataObjectModel, migrate: Bool = true) throws {
try self.init(store: store, model: model, migrate: migrate, versionController: VersionController())
}

internal init(store: CoreDataStore, model: CoreDataObjectModel, migrate: Bool = true, versionController: VersionController) throws {
self.store = store
public init(store: CoreDataStore, model: CoreDataObjectModel, migrate: Bool = true) throws {
self.store = store
self.objectModel = model.model()!
self.persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: objectModel)
self.persistentStore = try cdInitializeStore(store: store, storeCoordinator: persistentStoreCoordinator, migrate: migrate)
self.rootSavingContext = cdContext(withParent: .coordinator(self.persistentStoreCoordinator), concurrencyType: .privateQueueConcurrencyType, inMemory: false)
self.mainContext = cdContext(withParent: .context(self.rootSavingContext), concurrencyType: .mainQueueConcurrencyType, inMemory: false)
#if DEBUG
versionController.check()
#endif
}


// MARK: - Public

@available(OSX 10.12, *)
public func observable<T: NSManagedObject>(request: FetchRequest<T>) -> RequestObservable<T> where T:Equatable {
public func observable<T: NSManagedObject>(request: FetchRequest<T>) -> RequestObservable<T> {
return CoreDataObservable(request: request, context: self.mainContext as! NSManagedObjectContext)
}

Expand Down
Loading