-
-
Save azamsharpschool/d66674a274e9a80825e5189c263ef235 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // ContentView.swift | |
| // CustomDataStore | |
| // | |
| // Created by Mohammad Azam on 5/24/26. | |
| // | |
| import SwiftUI | |
| import SwiftData | |
| import Foundation | |
| @Model | |
| class Book { | |
| var name: String | |
| var author: String | |
| init(name: String, author: String) { | |
| self.name = name | |
| self.author = author | |
| } | |
| } | |
| @Model | |
| class Review { | |
| var subject: String | |
| var desc: String | |
| var book: Book? | |
| init(subject: String, desc: String) { | |
| self.subject = subject | |
| self.desc = desc | |
| } | |
| } | |
| final class JSONStoreConfiguration: DataStoreConfiguration { | |
| typealias Store = JSONStore | |
| var name: String | |
| var schema: Schema? | |
| var fileURL: URL | |
| init(name: String, schema: Schema? = nil, fileURL: URL) { | |
| self.name = name | |
| self.schema = schema | |
| self.fileURL = fileURL | |
| } | |
| static func == ( | |
| lhs: JSONStoreConfiguration, | |
| rhs: JSONStoreConfiguration | |
| ) -> Bool { | |
| lhs.name == rhs.name | |
| } | |
| func hash(into hasher: inout Hasher) { | |
| hasher.combine(name) | |
| } | |
| } | |
| final class JSONStore: DataStore { | |
| typealias Configuration = JSONStoreConfiguration | |
| typealias Snapshot = DefaultSnapshot | |
| var configuration: JSONStoreConfiguration | |
| var name: String | |
| var schema: Schema | |
| var identifier: String | |
| init( | |
| _ configuration: JSONStoreConfiguration, | |
| migrationPlan: (any SchemaMigrationPlan.Type)? | |
| ) throws { | |
| self.configuration = configuration | |
| self.name = configuration.name | |
| self.schema = configuration.schema! | |
| self.identifier = configuration.fileURL.lastPathComponent | |
| } | |
| } | |
| extension JSONStore { | |
| private func getSnapshots() throws -> [PersistentIdentifier: DefaultSnapshot] { | |
| let fileURL = configuration.fileURL | |
| guard FileManager.default.fileExists(atPath: fileURL.path(percentEncoded: false)) else { return [: ] } | |
| let data = try Data(contentsOf: fileURL) | |
| // get already stored snapshots from the database | |
| let snapshots = try JSONDecoder().decode([DefaultSnapshot].self, from: data) | |
| var result: [PersistentIdentifier: DefaultSnapshot] = [: ] | |
| for snapshot in snapshots { | |
| result[snapshot.persistentIdentifier] = snapshot | |
| } | |
| return result | |
| } | |
| private func persistSnapshots(_ snapshots: [PersistentIdentifier: DefaultSnapshot]) throws { | |
| let encoder = JSONEncoder() | |
| encoder.dateEncodingStrategy = .iso8601 | |
| encoder.outputFormatting = [ | |
| .prettyPrinted, | |
| .sortedKeys | |
| ] | |
| let data = try encoder.encode(Array(snapshots.values)) | |
| try data.write(to: configuration.fileURL, options: .atomic) | |
| } | |
| func save(_ request: DataStoreSaveChangesRequest<DefaultSnapshot>) throws -> DataStoreSaveChangesResult<DefaultSnapshot> { | |
| print("save fired") | |
| var storedSnapshots = try getSnapshots() | |
| var remappedIdentifiers: [ | |
| PersistentIdentifier: PersistentIdentifier | |
| ] = [:] | |
| for snapshot in request.inserted { | |
| let permanentIdentifier = try PersistentIdentifier.identifier(for: identifier, entityName: snapshot.persistentIdentifier.entityName, primaryKey: UUID()) | |
| let permanentSnapshot = snapshot.copy(persistentIdentifier: permanentIdentifier, remappedIdentifiers: remappedIdentifiers) | |
| storedSnapshots[permanentIdentifier] = permanentSnapshot | |
| remappedIdentifiers[snapshot.persistentIdentifier] = permanentIdentifier | |
| } | |
| for snapshot in request.deleted { | |
| storedSnapshots[snapshot.persistentIdentifier] = nil | |
| } | |
| for snapshot in request.updated { | |
| storedSnapshots[snapshot.persistentIdentifier] = snapshot | |
| } | |
| // write snapshots | |
| try persistSnapshots(storedSnapshots) | |
| return DataStoreSaveChangesResult(for: identifier, remappedIdentifiers: remappedIdentifiers) | |
| } | |
| func fetch<T>(_ request: DataStoreFetchRequest<T>) throws -> DataStoreFetchResult<T, DefaultSnapshot> where T : PersistentModel { | |
| print("fetch fired") | |
| let snapshots = try getSnapshots() | |
| let fetchedSnapshots = snapshots.values.filter { | |
| $0.persistentIdentifier.entityName == "\(T.self)" | |
| } | |
| return DataStoreFetchResult(descriptor: request.descriptor, fetchedSnapshots: fetchedSnapshots) | |
| } | |
| } | |
| struct ContentView: View { | |
| @Query private var books: [Book] | |
| @Environment(\.modelContext) private var context | |
| var body: some View { | |
| List { | |
| Button("Save") { | |
| let book = Book(name: "Book 2", author: "Azam") | |
| context.insert(book) | |
| let review = Review(subject: "Subject 1", desc: "Description") | |
| // book.reviews.append(review) | |
| } | |
| ForEach(books) { book in | |
| Text(book.name) | |
| /* | |
| Text("Review count: \(book.reviews.count)") | |
| ForEach(book.reviews) { review in | |
| VStack { | |
| Text(review.subject) | |
| Text(review.desc) | |
| } | |
| }*/ | |
| } | |
| } | |
| } | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // CustomDataStoreApp.swift | |
| // CustomDataStore | |
| // | |
| // Created by Mohammad Azam on 5/24/26. | |
| // | |
| import SwiftUI | |
| import SwiftData | |
| @main | |
| struct CustomDataStoreApp: App { | |
| let container: ModelContainer | |
| init() { | |
| do { | |
| let fileURL = URL.documentsDirectory.appending( | |
| path: "books.json", | |
| directoryHint: .notDirectory | |
| ) | |
| print(fileURL) | |
| let configuration = JSONStoreConfiguration( | |
| name: "JSONStore", | |
| fileURL: fileURL | |
| ) | |
| self.container = try ModelContainer( | |
| for: Book.self, | |
| configurations: configuration | |
| ) | |
| } catch { | |
| fatalError("Unable to create model container: \(error.localizedDescription)") | |
| } | |
| } | |
| var body: some Scene { | |
| WindowGroup { | |
| ContentView() | |
| .modelContainer(container) | |
| } | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment