Skip to content

Commit 4327395

Browse files
committed
Initial commit
1 parent d9f153b commit 4327395

File tree

10 files changed

+461
-34
lines changed

10 files changed

+461
-34
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@
33
/Packages
44
xcuserdata/
55
DerivedData/
6-
.swiftpm/configuration/registries.json
7-
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
6+
.swiftpm/
87
.netrc

.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

Lines changed: 0 additions & 8 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Change Log
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](http://keepachangelog.com/)
6+
and this project adheres to [Semantic Versioning](http://semver.org/).
7+
8+
## [1.0.0] - 2023-09-27
9+
10+
Initial release.

Package.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
// swift-tools-version: 5.9
2-
// The swift-tools-version declares the minimum version of Swift required to build this package.
32

43
import PackageDescription
54

65
let package = Package(
76
name: "swiftdata-sectionedquery",
7+
platforms: [
8+
.iOS(.v17),
9+
.macOS(.v14),
10+
.tvOS(.v17),
11+
.watchOS(.v10),
12+
.visionOS(.v1)
13+
],
814
products: [
9-
// Products define the executables and libraries a package produces, making them visible to other packages.
1015
.library(
11-
name: "swiftdata-sectionedquery",
12-
targets: ["swiftdata-sectionedquery"]),
16+
name: "SectionedQuery",
17+
targets: ["SectionedQuery"]),
1318
],
1419
targets: [
15-
// Targets are the basic building blocks of a package, defining a module or a test suite.
16-
// Targets can depend on other targets in this package and products from dependencies.
1720
.target(
18-
name: "swiftdata-sectionedquery"),
19-
.testTarget(
20-
name: "swiftdata-sectionedqueryTests",
21-
dependencies: ["swiftdata-sectionedquery"]),
21+
name: "SectionedQuery")
2222
]
2323
)

README.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# SectionedQuery
2+
3+
A property wrapper that fetches a set of SwiftData models, grouped into
4+
sections, and keeps those models in sync with the underlying data.
5+
6+
## Table of Contents
7+
8+
- [Intent](#intent)
9+
- [Features](#features)
10+
- [Supported Platforms](#supported-platforms)
11+
- [Example Usage](#example-usage)
12+
- [Usage Notes](#usage-notes)
13+
- [License](#license)
14+
15+
## Intent
16+
17+
Originally announced at WWDC 2023, SwiftData makes it easy to persist
18+
data using declarative code. The framework includes a new `@Query` property
19+
wrapper that fetches a set of models, similar to the `@FetchRequest`
20+
property wrapper used with a CoreData stack.
21+
22+
However, SwiftData does not currently include a property wrapper that
23+
fetches models grouped into sections, similar to the `@SectionedFetchRequest`
24+
property wrapper used with a CoreData stack.
25+
26+
This package fills this gap in the SwiftData framework by providing a
27+
`@SectionedQuery` property wrapper and `SectionedResults` type that makes
28+
it easy to write sectioned queries and use the data in your views.
29+
30+
## Features
31+
32+
- **Multiple Initializers**
33+
34+
Initializers for `@SectionedQuery` that match those for `@Query`,
35+
making it easy to build your queries using any mix of predicates, sort
36+
descriptors, animations, and more.
37+
38+
- **Automatic View Updates**
39+
40+
`@SectionedQuery` will automatically trigger an update of the view when the
41+
underlying data changes, so there's no need to trigger a manual refresh.
42+
43+
- **Iterable Result Type**
44+
45+
The `SectionedResults` type conforms to `RandomAccessCollection`, making it
46+
easy to iterate over each section and its elements without any complex code.
47+
48+
## Supported Platforms
49+
50+
The following platforms are supported:
51+
52+
- iOS 17.0+
53+
- macOS 14.0+
54+
- tvOS 13.0+
55+
- watchOS 10.0+
56+
- visionOS 1.0+
57+
58+
## Example Usage
59+
60+
Use `@SectionedQuery` in your SwiftUI views to fetch data, just like you would
61+
with `@Query`. Simply specify the property of your model to section results by
62+
and set the type to `SectionedResults<SectionIdentifier, Result>`.
63+
64+
```swift
65+
import SwiftData
66+
import SectionedQuery
67+
68+
69+
@Model
70+
class Item {
71+
72+
@Attribute(.unique) var name: String
73+
var kind: String
74+
75+
}
76+
77+
78+
struct ContentView: View {
79+
80+
@SectionedQuery(\.kind) private var results: SectionedResults<String, Item>
81+
82+
var body: some View {
83+
List(results) { section in
84+
Section(section.id) {
85+
ForEach(section) { item in
86+
Text(item.name)
87+
}
88+
}
89+
}
90+
}
91+
92+
}
93+
```
94+
95+
If you want to support dynamic sectioned queries, you can set the property from
96+
the view's initializer, passing in any relevant parameters.
97+
98+
```swift
99+
import SwiftData
100+
import SectionedQuery
101+
102+
103+
@Model
104+
class Item {
105+
106+
@Attribute(.unique) var name: String
107+
var kind: String
108+
109+
}
110+
111+
112+
struct DynamicContentView: View {
113+
114+
@SectionedQuery private var results: SectionedResults<String, Item>
115+
116+
var body: some View {
117+
List(results) { section in
118+
Section(section.id) {
119+
ForEach(section) { item in
120+
Text(item.name)
121+
}
122+
}
123+
}
124+
}
125+
126+
init(order: SortOrder) {
127+
_results = SectionedQuery(\.kind, order: order)
128+
}
129+
130+
}
131+
```
132+
133+
## Usage Notes
134+
135+
When using the `@SectionedQuery` property wrapper, there are a few important
136+
things to keep in mind:
137+
138+
- The model property that you section results by must conform to `Hashable`.
139+
140+
- The `SectionedResults<SectionIdentifier, Result>` type must be specialized:
141+
142+
- `SectionIdentifier` must match the type of the model property you section
143+
results by. It must conform to `Hashable`.
144+
145+
- `Result` must match the type of the model you are querying. It must
146+
conform to `PersistentModel`.
147+
148+
Because `SectionedResults` conforms to `RandomAccessCollection`, you can easily
149+
use it with SwiftUI views like `List` and `ForEach`.
150+
151+
## License
152+
153+
This package is distributed under [The MIT License](./LICENSE).
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// File.swift
3+
//
4+
//
5+
// Created by Thomas Magis-Agosta on 9/27/23.
6+
//
7+
8+
import Foundation
9+
10+
internal extension Array where Iterator.Element: Hashable {
11+
12+
func uniqued() -> [Element] {
13+
var seen: Set<Iterator.Element> = []
14+
return filter { seen.insert($0).inserted }
15+
}
16+
17+
}

0 commit comments

Comments
 (0)