Skip to content

Commit

Permalink
working on more code changes
Browse files Browse the repository at this point in the history
  • Loading branch information
leogdion committed Oct 11, 2024
1 parent 078e4ec commit 392117e
Show file tree
Hide file tree
Showing 29 changed files with 275 additions and 221 deletions.
2 changes: 1 addition & 1 deletion .swift-format
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
]
},
"prioritizeKeepingFunctionOutputTogether" : false,
"respectsExistingLineBreaks" : false,
"respectsExistingLineBreaks" : true,
"rules" : {
"AllPublicDeclarationsHaveDocumentation" : false,
"AlwaysUseLiteralForEmptyCollectionInit" : false,
Expand Down
2 changes: 1 addition & 1 deletion Example/Sources/ContentObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ internal class ContentObject {
self.error = error
items = []
}
assert(items.count == selectedItemsID.count)
// assert(items.count == selectedItemsID.count)
return items
}

Expand Down
32 changes: 18 additions & 14 deletions Example/Sources/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ import DataThespian
import SwiftData
import SwiftUI

struct ContentView: View {
@State var object = ContentObject()
@Environment(\.database) var database
@Environment(\.databaseChangePublicist) var databaseChangePublisher
internal struct ContentView: View {
@State private var object = ContentObject()
@Environment(\.database) private var database
@Environment(\.databaseChangePublicist) private var databaseChangePublisher

var body: some View {
internal var body: some View {
NavigationSplitView {
List(selection: self.$object.selectedItemsID) {
ForEach(object.items) { item in
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
}
.onDelete(perform: object.deleteItems)
}
.navigationSplitViewColumnWidth(min: 180, ideal: 200)
.navigationSplitViewColumnWidth(min: 200, ideal: 220)
.toolbar {
ToolbarItem {
Button(action: addItem) {
Expand All @@ -47,7 +47,9 @@ struct ContentView: View {
}
}.onAppear {
self.object.initialize(
withDatabase: database, databaseChangePublisher: databaseChangePublisher)
withDatabase: database,
databaseChangePublisher: databaseChangePublisher
)
}
}

Expand All @@ -60,16 +62,18 @@ struct ContentView: View {
}

#Preview {
let databaseChangePublicist = DatabaseChangePublicist(dbWatcher: DataMonitor.shared)
let config = ModelConfiguration(isStoredInMemoryOnly: true)
// swiftlint:disable:next force_try
let modelContainer = try! ModelContainer(for: Item.self, configurations: config)

let backgroundDatabase = BackgroundDatabase(modelContainer: modelContainer) {
let context = ModelContext($0)
context.autosaveEnabled = true
return context
}

ContentView()
.environment(
\.databaseChangePublicist,
DatabaseChangePublicist(
dbWatcher: DataMonitor.shared
)
)
.database(BackgroundDatabase(modelContainer: modelContainer))
.environment( \.databaseChangePublicist, databaseChangePublicist )
.database(backgroundDatabase)
}
14 changes: 9 additions & 5 deletions Example/Sources/DataThespianExampleApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ import SwiftUI
@main
internal struct DataThespianExampleApp: App {
private static let databaseChangePublicist = DatabaseChangePublicist( dbWatcher: DataMonitor.shared)
// swiftlint:disable:next force_try
private static let database = try! BackgroundDatabase(
modelContainer: .init(for: Item.self),
autosaveEnabled: true
)

private static let database = BackgroundDatabase {
// swiftlint:disable:next force_try
try! ModelActorDatabase(modelContainer: ModelContainer(for: Item.self)) {
let context = ModelContext($0)
context.autosaveEnabled = true
return context
}
}

internal var body: some Scene {
WindowGroup {
Expand Down
6 changes: 3 additions & 3 deletions Example/Sources/Item.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import Foundation
import SwiftData

@Model
final class Item {
var timestamp: Date
internal final class Item {
internal private(set) var timestamp: Date

init(timestamp: Date) {
internal init(timestamp: Date) {
self.timestamp = timestamp
}
}
8 changes: 4 additions & 4 deletions Example/Sources/ItemModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import DataThespian
import Foundation
import SwiftData

struct ItemModel: Identifiable {
let model: Model<Item>
let timestamp: Date
internal struct ItemModel: Identifiable {
internal let model: Model<Item>
internal let timestamp: Date

var id: PersistentIdentifier {
internal var id: PersistentIdentifier {
model.persistentIdentifier
}

Expand Down
81 changes: 81 additions & 0 deletions Example/Sources/ModelActorDatabase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//
// ModelActorDatabase.swift
// DataThespian
//
// Created by Leo Dion.
// Copyright © 2024 BrightDigit.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//

public import DataThespian
public import SwiftData

// @ModelActor
// public actor ModelActorDatabase: Database {}

extension BackgroundDatabase {
convenience init (modelContainer: ModelContainer, modelContext closure: (@Sendable (ModelContainer) -> ModelContext)? = nil) {
let closure = closure ?? ModelContext.init
self.init(database: ModelActorDatabase(modelContainer: modelContainer, modelContext: closure))
}
}

extension DefaultSerialModelExecutor {
static func create(from closure: @Sendable @escaping (ModelContainer) -> ModelContext) -> @Sendable (ModelContainer) -> any ModelExecutor {
{
DefaultSerialModelExecutor(modelContext: closure($0))
}
}
}

public actor ModelActorDatabase: Database, ModelActor {
private init(modelExecutor: any ModelExecutor, modelContainer: ModelContainer) {
self.modelExecutor = modelExecutor
self.modelContainer = modelContainer
}

public init(modelContainer: SwiftData.ModelContainer) {
self.init(
modelContainer: modelContainer,
modelContext: ModelContext.init
)
}

public init(modelContainer: SwiftData.ModelContainer, modelContext closure: @Sendable @escaping (ModelContainer) -> ModelContext) {
self.init(
modelContainer: modelContainer,
modelExecutor: DefaultSerialModelExecutor.create(from: closure)
)
}

public init(modelContainer: SwiftData.ModelContainer, modelExecutor closure: @Sendable @escaping (ModelContainer) -> any ModelExecutor) {
self.init(
modelExecutor: closure(modelContainer),
modelContainer: modelContainer
)
}

public nonisolated let modelExecutor: any SwiftData.ModelExecutor

public nonisolated let modelContainer: SwiftData.ModelContainer
}
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ let package = Package(
platforms: [.iOS(.v17), .macCatalyst(.v17), .macOS(.v14), .tvOS(.v17), .visionOS(.v1), .watchOS(.v10)],
products: [
.library(
name: "DataThespian",
targets: ["DataThespian"]
name: "DataThespian",
targets: ["DataThespian"]
)
],
dependencies: [
Expand Down
33 changes: 19 additions & 14 deletions Sources/DataThespian/BackgroundDatabase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,11 @@
//

#if canImport(SwiftData)

public import Foundation

import Foundation
public import SwiftData
import SwiftUI

public final class BackgroundDatabase: Database {
public func withModelContext<T>(_ closure: @Sendable @escaping (ModelContext) throws -> T)
async rethrows -> T
{ try await self.database.withModelContext(closure) }

private actor DatabaseContainer {
private let factory: @Sendable () -> any Database
private var wrappedTask: Task<any Database, Never>?
Expand All @@ -49,7 +43,9 @@
// swiftlint:disable:next strict_fileprivate
fileprivate var database: any Database {
get async {
if let wrappedTask { return await wrappedTask.value }
if let wrappedTask {
return await wrappedTask.value
}
let task = Task { factory() }
self.wrappedTask = task
return await task.value
Expand All @@ -61,15 +57,24 @@

private var database: any Database { get async { await container.database } }

public convenience init(modelContainer: ModelContainer, autosaveEnabled: Bool = false) {
self.init {
assert(isMainThread: false)
return ModelActorDatabase(modelContainer: modelContainer, autosaveEnabled: autosaveEnabled)
}
// @available(*, deprecated, message: "Use your own `ModelActorDatabase`.")
// public convenience init(modelContainer: ModelContainer, autosaveEnabled: Bool = false) {
// self.init {
// assert(isMainThread: false)
// return ModelActorDatabase(modelContainer: modelContainer, autosaveEnabled: autosaveEnabled)
// }
// }

public convenience init(database: @Sendable @escaping @autoclosure () -> any Database) {
self.init(database)
}

internal init(_ factory: @Sendable @escaping () -> any Database) {
public init(_ factory: @Sendable @escaping () -> any Database) {
self.container = .init(factory: factory)
}

public func withModelContext<T>(_ closure: @Sendable @escaping (ModelContext) throws -> T)
async rethrows -> T
{ try await self.database.withModelContext(closure) }
}
#endif
25 changes: 16 additions & 9 deletions Sources/DataThespian/DataMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,16 @@

public static let shared = DataMonitor()

var object: (any NSObjectProtocol)?
var registrations = RegistrationCollection()
private var object: (any NSObjectProtocol)?
private var registrations = RegistrationCollection()

private init() { Self.logger.debug("Creating DatabaseMonitor") }

public nonisolated func register(_ registration: any AgentRegister, force: Bool) {
Task { await self.addRegistration(registration, force: force) }
}

func addRegistration(_ registration: any AgentRegister, force: Bool) {
private func addRegistration(_ registration: any AgentRegister, force: Bool) {
registrations.add(withID: registration.id, force: force, agent: registration.agent)
}

Expand All @@ -61,18 +61,25 @@
}
}

func addObserver() {
guard object == nil else { return }
private func addObserver() {
guard object == nil else {
return
}
object = NotificationCenter.default.addObserver(
forName: .NSManagedObjectContextDidSave, object: nil, queue: nil,
forName: .NSManagedObjectContextDidSave,
object: nil,
queue: nil,
using: { notification in
let update = NotificationDataUpdate(notification)
Task { await self.notifyRegisration(update) }
})
}
)
}

func notifyRegisration(_ update: any DatabaseChangeSet) {
guard !update.isEmpty else { return }
private func notifyRegisration(_ update: any DatabaseChangeSet) {
guard !update.isEmpty else {
return
}
Self.logger.debug("Notifying of Update")

registrations.notify(update)
Expand Down
18 changes: 12 additions & 6 deletions Sources/DataThespian/Database+Extras.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ extension Database {
try await self.get(for: id.persistentIdentifier) { (model: PersistentModelType?) -> U in
guard let model else {
throw Model<PersistentModelType>.NotFoundError(
persistentIdentifier: id.persistentIdentifier)
persistentIdentifier: id.persistentIdentifier
)
}
return try closure(model)
}
Expand All @@ -66,7 +67,8 @@ extension Database {
}

public func first<T: PersistentModel, U: Sendable>(
fetchWith selectPredicate: Predicate<T>, otherwiseInsertBy insert: @Sendable @escaping () -> T,
fetchWith selectPredicate: Predicate<T>,
otherwiseInsertBy insert: @Sendable @escaping () -> T,
with closure: @escaping @Sendable (T) throws -> U
) async throws -> U {
let value = try await self.fetch {
Expand All @@ -75,7 +77,9 @@ extension Database {
try models.first.map(closure)
}

if let value { return value }
if let value {
return value
}

let inserted: Model = await self.insert(insert)

Expand Down Expand Up @@ -110,11 +114,12 @@ extension Database {
public func fetch<T: PersistentModel>(
_: T.Type, _ selectDescriptor: @escaping @Sendable () -> FetchDescriptor<T>
) async throws -> [Model<T>] {
try await self.fetch(selectDescriptor) { models in models.map(Model.init) }
await self.fetch(selectDescriptor) { models in models.map(Model.init) }
}

public func fetch<T, U: Sendable>(
of _: T.Type, for objectIDs: [PersistentIdentifier],
of _: T.Type,
for objectIDs: [PersistentIdentifier],
with closure: @escaping @Sendable (T) throws -> U
) async throws -> [U] where T: PersistentModel {
try await withThrowingTaskGroup(of: U?.self, returning: [U].self) { group in
Expand All @@ -129,7 +134,8 @@ extension Database {
}

public func get<T, U: Sendable>(
of _: T.Type, for objectID: PersistentIdentifier,
of _: T.Type,
for objectID: PersistentIdentifier,
with closure: @escaping @Sendable (T?) throws -> U
) async throws -> U where T: PersistentModel {
try await self.get(for: objectID) { model in try closure(model) }
Expand Down
Loading

0 comments on commit 392117e

Please sign in to comment.