{"id":17448321,"url":"https://github.com/mesqueeb/swiftdatasugar","last_synced_at":"2025-04-19T14:50:53.883Z","repository":{"id":227594316,"uuid":"769782556","full_name":"mesqueeb/SwiftDataSugar","owner":"mesqueeb","description":"🌯 A collection of utilities that make it easier to work with SwiftData in a SwiftUI environment","archived":false,"fork":false,"pushed_at":"2025-02-02T23:07:54.000Z","size":337,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-16T06:13:13.462Z","etag":null,"topics":["crud-sample","swift-data","swift-data-crud","swift-data-migrations","swift-data-utils","swift-ui","swiftdata"],"latest_commit_sha":null,"homepage":"https://swiftpackageindex.com/mesqueeb/SwiftDataSugar/documentation","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mesqueeb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"mesqueeb","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2024-03-10T03:26:06.000Z","updated_at":"2025-02-02T23:07:58.000Z","dependencies_parsed_at":"2024-08-07T02:17:47.721Z","dependency_job_id":"c4e0fefa-8dee-4305-bdb0-a9fe7879cc47","html_url":"https://github.com/mesqueeb/SwiftDataSugar","commit_stats":null,"previous_names":["mesqueeb/swiftdatatodolist"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mesqueeb%2FSwiftDataSugar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mesqueeb%2FSwiftDataSugar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mesqueeb%2FSwiftDataSugar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mesqueeb%2FSwiftDataSugar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mesqueeb","download_url":"https://codeload.github.com/mesqueeb/SwiftDataSugar/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240395709,"owners_count":19794571,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crud-sample","swift-data","swift-data-crud","swift-data-migrations","swift-data-utils","swift-ui","swiftdata"],"created_at":"2024-10-17T20:06:59.667Z","updated_at":"2025-03-02T01:32:42.463Z","avatar_url":"https://github.com/mesqueeb.png","language":"Swift","funding_links":["https://github.com/sponsors/mesqueeb"],"categories":[],"sub_categories":[],"readme":"# SwiftDataSugar 🌯\n\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fmesqueeb%2FSwiftDataSugar%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/mesqueeb/SwiftDataSugar)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fmesqueeb%2FSwiftDataSugar%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/mesqueeb/SwiftDataSugar)\n\n```\n.package(url: \"https://github.com/mesqueeb/SwiftDataSugar\", from: \"0.1.0\")\n```\n\nA collection of utilities that make it easier to work with SwiftData in a SwiftUI environment.\n\n- `DbCollection` is an actor made for doing CRUD on SwiftData from a background thread (and avoids pitfalls that prevent UI reactivity)\n- `DbQuery` is a swiftUI view which uses `@Query` but makes it easier to use with dynamic predicate/sortby\n- `MigrationStep` is a protocol to keep your migration logic organised for migration testing purposes\n- `initModelContainer` wraps `ModelContainer` initialisation to more easily write migration unit tests\n\nThe rendered documentation can be found here: [swiftpackageindex.com/mesqueeb/SwiftDataSugar/documentation](https://swiftpackageindex.com/mesqueeb/SwiftDataSugar/documentation)\n\n## Sample Project: SwiftDataTodoList\n\nA point of reference on how to implement CRUD via SwiftData on all Apple platforms.\n\nFeatures of this proof of concept:\n\n1. Writing uses a background thread (uses the `@ModelActor` macro)\n2. Reading uses MainActor thread (uses SwiftUI's `@Query` macro)\n3. Migration setup with unit testing\n4. Full Multi-platform support\n\n### 1. Writing data\n\n- Writing data to the SwiftData models is done on a background thread\n- An `actor` that conforms to `ModelActor` has been set up with CRUD-like methods to easily write data to the model\n- This actor is called `DbCollection`\n- Instantiating `DbCollection` must be done on `@MainActor` to prevent an issue where writing data isn't reactive in SwiftUI. (see detailed explanation at [A New Issue: The View Does Not Refresh After Data Update](https://fatbobman.com/en/posts/practical-swiftdata-building-swiftui-applications-with-modern-approaches/#a-new-issue-the-view-does-not-refresh-after-data-update), an issue I've reported to Fatbobman and prompted him to write an article on)\n- `DbCollection` can be used for multiple models\n- in this app the usage of `DbCollection` is showcased for a `Todo` model\n\n```swift\n// example instantiating multiple collections in the `@main` swift file\n@MainActor public let dbTodos = DbCollection\u003cTodoItem\u003e(modelContainer: modelContainer)\n@MainActor public let dbUsers = DbCollection\u003cUser\u003e(modelContainer: modelContainer)\n```\n\n### 2. Reading data\n\n- Reading data from the SwiftData models is done on the MainActor thread\n- SwiftUI's `@Query` can be used for simple views that need to query data without dynamic requirements\n- The usage of `@Query` is wrapped in new view called `DbQuery` where you can pass a dynamic _predicate_ and _sortBy_ instances that queries data\n- in this app the usage of `DbQuery` is showcased for a list that can be filtered and sorted dynamically\n\n```swift\nDbQuery(predicate: activePredicate, sortBy: activeSort) { items in\n  ForEach(items, id: \\.id) { item in\n    TodoListItemView(item: item)\n      .id(item.id) // Use ID for List reordering and animations\n    }\n  }\n}\n```\n\n### 3. Migration setup with unit testing\n\n- Custom Migrations in SwiftData, which are hard to get right, are showcased in this app with 3 versions and 2 migrations\n- The latest schema has all of its structs and models type aliased for easier use throughout the codebase\n- Only data crucial to migrations is scoped inside of the versioned schema, other usefull methods and convenience initialisers are extended only on the latest schema\n- Actual migration logic neatly organised per-version: it bundles just the logic to upgrade to the relevant version in the same file as that version's schema\n- The final combined migration plan combines each migration step per version\n- Full unit testing in place of each migration phase (with modern Swift Testing) to give confidence a latest migration will not crash your user's apps on launch\n- The unit testing showcases exaclty _how_ to test migrations in SwiftData\n\n### 4. Multi-Platform Support\n\n- All code used in this proof of concept is compatible with all Apple platforms\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmesqueeb%2Fswiftdatasugar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmesqueeb%2Fswiftdatasugar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmesqueeb%2Fswiftdatasugar/lists"}