Skip to content

Commit

Permalink
cleaning up before merge
Browse files Browse the repository at this point in the history
  • Loading branch information
leogdion committed Oct 16, 2024
1 parent 5685ab3 commit 0663086
Show file tree
Hide file tree
Showing 14 changed files with 263 additions and 59 deletions.
28 changes: 28 additions & 0 deletions Example/Sources/ChildViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// ChildViewModel.swift
// DataThespian
//
// Created by Leo Dion on 10/16/24.
//

import DataThespian
import Foundation
import SwiftData

internal struct ChildViewModel: Sendable, Identifiable {
internal let model: Model<ItemChild>
internal let timestamp: Date

internal var id: PersistentIdentifier {
model.persistentIdentifier
}

private init(model: Model<ItemChild>, timestamp: Date) {
self.model = model
self.timestamp = timestamp
}

internal init(child: ItemChild) {
self.init(model: .init(child), timestamp: child.timestamp)
}
}
62 changes: 39 additions & 23 deletions Example/Sources/ContentObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ internal class ContentObject {
private var databaseChangeCancellable: AnyCancellable?
private var databaseChangeSubscription: AnyCancellable?
private var database: (any Database)?
internal private(set) var items = [ItemModel]()
internal var selectedItemsID: Set<ItemModel.ID> = []
internal private(set) var items = [ItemViewModel]()
internal var selectedItemsID: Set<ItemViewModel.ID> = []
private var newItem: AnyCancellable?
internal var error: (any Error)?

internal var selectedItems: [ItemModel] {
internal var selectedItems: [ItemViewModel] {
let selectedItemsID = self.selectedItemsID
let items: [ItemModel]
let items: [ItemViewModel]
do {
items = try self.items.filter(
#Predicate<ItemModel> {
#Predicate<ItemViewModel> {
selectedItemsID.contains($0.id)
}
)
Expand All @@ -49,17 +49,7 @@ internal class ContentObject {
private static func deleteModels(_ models: [Model<Item>], from database: (any Database))
async throws
{
try await database.withModelContext { modelContext in
let items: [Item] = models.compactMap {
modelContext.model(for: $0.persistentIdentifier) as? Item
}
dump(items.first?.persistentModelID)
assert(items.count == models.count)
for item in items {
modelContext.delete(item)
}
try modelContext.save()
}
try await database.deleteModels(models)
}

private func beginUpdateItems() {
Expand All @@ -76,10 +66,10 @@ internal class ContentObject {
guard let database else {
return
}
self.items = try await database.withModelContext({ modelContext in
self.items = try await database.withModelContext { modelContext in
let items = try modelContext.fetch(FetchDescriptor<Item>())
return items.map(ItemModel.init)
})
return items.map(ItemViewModel.init)
}
}

internal func initialize(
Expand Down Expand Up @@ -114,20 +104,46 @@ internal class ContentObject {
}
Task {
try await Self.deleteModels(models, from: database)
try await database.save()
}
}

internal func addItem(withDate date: Date = .init()) {
internal func addChild(to item: ItemViewModel) {
guard let database else {
return
}
Task {
let timestamp = Date()
let childModel = await database.insert {
ItemChild(timestamp: timestamp)
}

try await database.withModelContext { modelContext in
let newItem = Item(timestamp: date)
modelContext.insert(newItem)
dump(newItem.persistentModelID)
let item = try modelContext.existingModel(for: item.model)
let child = try modelContext.existingModel(for: childModel)
assert(child != nil && item != nil)
child?.parent = item
try modelContext.save()
}
}
}

internal func addItem(withDate date: Date = .init()) {
guard let database else {
return
}
Task {
let insertedModel = await database.insert { Item(timestamp: date) }
print("inserted:", insertedModel.isTemporary)
try await database.save()
let savedModel = try await database.get(
for: .predicate(
#Predicate<Item> {
$0.timestamp == date
}
)
)
print("saved:", savedModel.isTemporary)
}
}
}
2 changes: 1 addition & 1 deletion Example/Sources/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal struct ContentView: View {
if selectedItems.count > 1 {
Text("Multiple Selected")
} else if let item = selectedItems.first {
Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
ItemChildView(object: object, item: item)
} else {
Text("Select an item")
}
Expand Down
1 change: 1 addition & 0 deletions Example/Sources/Item.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal final class Item: Unique {
}

internal private(set) var timestamp: Date
internal private(set) var children: [ItemChild]?

internal init(timestamp: Date) {
self.timestamp = timestamp
Expand Down
19 changes: 19 additions & 0 deletions Example/Sources/ItemChild.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// ItemChild.swift
// DataThespian
//
// Created by Leo Dion on 10/16/24.
//
import Foundation
import SwiftData

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

internal init(parent: Item? = nil, timestamp: Date) {
self.parent = parent
self.timestamp = timestamp
}
}
31 changes: 31 additions & 0 deletions Example/Sources/ItemChildView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// ItemChildView.swift
// DataThespianExample
//
// Created by Leo Dion on 10/16/24.
//

import SwiftUI

internal struct ItemChildView: View {
internal var object: ContentObject
internal let item: ItemViewModel
internal var body: some View {
VStack {
Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
Divider()
Button("Add Child") {
object.addChild(to: item)
}
ForEach(item.children) { child in
Text(
"Child at \(child.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))"
)
}
}
}
}
//
// #Preview {
// ItemChildView()
// }
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,26 @@ import DataThespian
import Foundation
import SwiftData

internal struct ItemModel: Identifiable {
internal struct ItemViewModel: Sendable, Identifiable {
internal let model: Model<Item>
internal let timestamp: Date
internal let children: [ChildViewModel]

internal var id: PersistentIdentifier {
model.persistentIdentifier
}

private init(model: Model<Item>, timestamp: Date) {
private init(model: Model<Item>, timestamp: Date, children: [ChildViewModel]?) {
self.model = model
self.timestamp = timestamp
self.children = children ?? []
}

internal init(item: Item) {
self.init(model: .init(item), timestamp: item.timestamp)
self.init(
model: .init(item),
timestamp: item.timestamp,
children: item.children?.map(ChildViewModel.init)
)
}
}
45 changes: 19 additions & 26 deletions Sources/DataThespian/Databases/Database+Extras.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,6 @@
public import SwiftData

extension Database {
public func insert<PersistentModelType: PersistentModel>(
_ closuer: @Sendable @escaping () -> PersistentModelType
) async -> Model<PersistentModelType> {
let id: PersistentIdentifier = await self.insert(closuer)
return .init(persistentIdentifier: id)
}

public func with<PersistentModelType: PersistentModel, U: Sendable>(
_ id: Model<PersistentModelType>,
_ closure: @escaping @Sendable (PersistentModelType) throws -> U
Expand Down Expand Up @@ -68,25 +61,25 @@
}
}

public func first<T: PersistentModel, U: Sendable>(
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 {
.init(predicate: selectPredicate, fetchLimit: 1)
} with: { models in
try models.first.map(closure)
}

if let value {
return value
}

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

return try await self.with(inserted, closure)
}
// public func first<T: PersistentModel, U: Sendable>(
// 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 {
// .init(predicate: selectPredicate, fetchLimit: 1)
// } with: { models in
// try models.first.map(closure)
// }
//
// if let value {
// return value
// }
//
// let inserted: Model = await self.insert(insert)
//
// return try await self.with(inserted, closure)
// }

public func delete<T: PersistentModel>(model _: T.Type, where predicate: Predicate<T>? = nil)
async throws
Expand Down
6 changes: 3 additions & 3 deletions Sources/DataThespian/Databases/Database+ModelContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
try await self.withModelContext { try $0.delete(where: predicate) }
}

public func insert(_ closuer: @Sendable @escaping () -> some PersistentModel) async
-> PersistentIdentifier
{ await self.withModelContext { $0.insert(closuer) } }
// public func insert(_ closuer: @Sendable @escaping () -> some PersistentModel) async
// -> PersistentIdentifier
// { await self.withModelContext { $0.insert(closuer) } }

public func fetch<T, U: Sendable>(
_ selectDescriptor: @escaping @Sendable () -> FetchDescriptor<T>,
Expand Down
18 changes: 18 additions & 0 deletions Sources/DataThespian/Databases/Queryable+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
public import SwiftData

extension Queryable {
@discardableResult
public func insert<PersistentModelType: PersistentModel>(
_ closuer: @Sendable @escaping () -> PersistentModelType
) async -> Model<PersistentModelType> {
Expand Down Expand Up @@ -115,3 +116,20 @@ extension Queryable {
return try await self.get(for: .model(model), with: closure)
}
}

extension Queryable {
public func deleteModels<PersistentModelType>(_ models: [Model<PersistentModelType>]) async throws
{
try await withThrowingTaskGroup(
of: Void.self,
body: { group in
for model in models {
group.addTask {
try await self.delete(.model(model))
}
}
try await group.waitForAll()
}
)
}
}
2 changes: 1 addition & 1 deletion Sources/DataThespian/Databases/Queryable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

public import SwiftData

public protocol Queryable {
public protocol Queryable: Sendable {
func save() async throws

func insert<PersistentModelType: PersistentModel, U: Sendable>(
Expand Down
4 changes: 4 additions & 0 deletions Sources/DataThespian/Model.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
}

extension Model where T: PersistentModel {
public var isTemporary: Bool {
self.persistentIdentifier.isTemporary ?? false
}

public init(_ model: T) { self.init(persistentIdentifier: model.persistentModelID) }

internal static func ifMap(_ model: T?) -> Model? { model.map(self.init) }
Expand Down
4 changes: 2 additions & 2 deletions Sources/DataThespian/SwiftData/ModelContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@

#if canImport(SwiftData)
import Foundation
import SwiftData
public import SwiftData

extension ModelContext {
internal func existingModel<T>(for model: Model<T>) throws -> T?
public func existingModel<T>(for model: Model<T>) throws -> T?
where T: PersistentModel {
try self.existingModel(for: model.persistentIdentifier)
}
Expand Down
Loading

0 comments on commit 0663086

Please sign in to comment.