Skip to content

Commit 2235c9e

Browse files
authored
Compute statement hashability from underlying query fragment (#245)
* Compute statement hashability from underlying query fragment We currently depend directly on the hashability of `Statement` in the various fetch property wrappers, but this conformance has been found to be problematic and so we should remove it. We can make this change today, though, before removing it, by computing the hashability of a statement from its query fragment data. * wip * wip
1 parent 8df0449 commit 2235c9e

File tree

4 files changed

+42
-41
lines changed

4 files changed

+42
-41
lines changed

Examples/CaseStudies/ObservableModelDemo.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import SwiftUI
33

44
struct ObservableModelDemo: SwiftUICaseStudy {
55
let readMe = """
6-
This demonstrates how to use the `@FetchAll` and `@FetchOne` tools in an @Observable model. \
6+
This demonstrates how to use the `@FetchAll` and `@FetchOne` tools in an `@Observable` model. \
77
In SwiftUI, the `@Query` macro only works when installed directly in a SwiftUI view, and \
88
cannot be used outside of views.
99

Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Examples/Reminders/SearchReminders.swift

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ class SearchRemindersModel {
6666
withErrorReporting {
6767
try database.write { db in
6868
try Reminder
69-
.where { $0.isCompleted && $0.id.in(baseQuery.select { $1.id }) }
69+
.where {
70+
$0.isCompleted && $0.id.in(
71+
baseQuery(searchText: searchText, searchTokens: searchTokens).select { $1.id }
72+
)
73+
}
7074
.where {
7175
if let monthsAgo {
7276
#sql("\($0.dueDate) < date('now', '-\(raw: monthsAgo) months')")
@@ -78,29 +82,6 @@ class SearchRemindersModel {
7882
}
7983
}
8084

81-
private var baseQuery: SelectOf<ReminderText, Reminder> {
82-
let searchText = searchText.quoted()
83-
84-
return
85-
ReminderText
86-
.where {
87-
if !searchText.isEmpty {
88-
$0.match(searchText)
89-
}
90-
}
91-
.where {
92-
for token in searchTokens {
93-
switch token.kind {
94-
case .near:
95-
$0.match("NEAR(\(token.rawValue.quoted()))")
96-
case .tag:
97-
$0.tags.match(token.rawValue)
98-
}
99-
}
100-
}
101-
.join(Reminder.all) { $0.rowid.eq($1.rowid) }
102-
}
103-
10485
private func updateQuery(debounce: Bool = true) async throws {
10586
if debounce {
10687
try await clock.sleep(for: .seconds(0.3))
@@ -120,7 +101,8 @@ class SearchRemindersModel {
120101
} else {
121102
try await $searchResults.load(
122103
SearchRequest(
123-
baseQuery: baseQuery,
104+
searchText: searchText,
105+
searchTokens: searchTokens,
124106
showCompletedInSearchResults: showCompletedInSearchResults
125107
),
126108
animation: .default
@@ -145,10 +127,12 @@ class SearchRemindersModel {
145127
var completedCount = 0
146128
var rows: [Row] = []
147129
}
148-
let baseQuery: SelectOf<ReminderText, Reminder>
130+
let searchText: String
131+
let searchTokens: [Token]
149132
let showCompletedInSearchResults: Bool
150133
func fetch(_ db: Database) throws -> Value {
151-
try Value(
134+
let baseQuery = baseQuery(searchText: searchText, searchTokens: searchTokens)
135+
return try Value(
152136
completedCount:
153137
baseQuery
154138
.where { $1.isCompleted }
@@ -280,6 +264,32 @@ struct SearchRemindersView: View {
280264
}
281265
}
282266

267+
fileprivate func baseQuery(
268+
searchText: String,
269+
searchTokens: [SearchRemindersModel.Token]
270+
) -> SelectOf<ReminderText, Reminder> {
271+
let searchText = searchText.quoted()
272+
273+
return
274+
ReminderText
275+
.where {
276+
if !searchText.isEmpty {
277+
$0.match(searchText)
278+
}
279+
}
280+
.where {
281+
for token in searchTokens {
282+
switch token.kind {
283+
case .near:
284+
$0.match("NEAR(\(token.rawValue.quoted()))")
285+
case .tag:
286+
$0.tags.match(token.rawValue)
287+
}
288+
}
289+
}
290+
.join(Reminder.all) { $0.rowid.eq($1.rowid) }
291+
}
292+
283293
extension String {
284294
fileprivate func quoted() -> String {
285295
split(separator: " ")

Sources/SQLiteData/Internal/StatementKey.swift

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,10 @@ protocol StatementKeyRequest<QueryValue>: FetchKeyRequest {
55

66
extension StatementKeyRequest {
77
static func == (lhs: Self, rhs: Self) -> Bool {
8-
// NB: A Swift 6.1 regression prevents this from compiling:
9-
// https://github.com/swiftlang/swift/issues/79623
10-
// return AnyHashable(lhs.statement) == AnyHashable(rhs.statement)
11-
let lhs = lhs.statement
12-
let rhs = rhs.statement
13-
return AnyHashable(lhs) == AnyHashable(rhs)
8+
lhs.statement.query == rhs.statement.query
149
}
1510

1611
func hash(into hasher: inout Hasher) {
17-
// NB: A Swift 6.1 regression prevents this from compiling:
18-
// https://github.com/swiftlang/swift/issues/79623
19-
// hasher.combine(statement)
20-
let statement = statement
21-
hasher.combine(statement)
12+
hasher.combine(statement.query)
2213
}
2314
}

0 commit comments

Comments
 (0)