Compiling never finishes when a query sorts by a field held inside an
optional @Selection enum column group whose case payload is a struct.
Open SQLiteDataIssue.xcodeproj and build. Queries.swift never finishes
compiling. Commenting out the marked .order line in workoutRows(_:)
makes the file compile in a few seconds.
The CasePaths and LazyInitializableByDefault traits are enabled on the
swift-structured-queries dependency.
healthRecords is a shared header table for every kind of record, so it
carries several @Selection enum column groups. time is one of them —
an interval or a calendar day, and optional, because some records have no
time at all. Each case payload holds several fields, so the cases are
structs rather than single values:
@Selection
enum RecordTime: Hashable, Sendable {
case interval(Interval)
case calendar(Day)
@Selection
struct Interval: Codable, Hashable, Sendable {
var startDate: Date
var endDate: Date?
var timeSemantics: TimeSemantics
var durationStatus: DurationStatus
var timeZoneIdentifier: String?
var timeZoneSecondsFromGMT: Int?
}
@Selection
struct Day: Codable, Hashable, Sendable { … }
}
@Table
struct HealthRecord: Identifiable {
let id: UUID
var type: RecordType // @Selection enum, 7 cases
var time: RecordTime? // @Selection enum, optional
var representation: Representation? // @Selection enum, optional
var origin: RecordOrigin // @Selection enum, 6 cases
…
}The query:
WorkoutRecord
.join(HealthRecord.all) { $0.id.eq($1.id) }
.order { _, header in header.time.interval.startDate.desc() }
.select { workout, header in … }In a smaller SwiftPM package with the same RecordTime enum but a
four-column HealthRecord and no join, the same .order expression
compiles in about 20 seconds. Growing the table to the shape above and
building it as an app target is what stops it finishing.
Filtering on a field inside a case is rejected rather than slow:
// error: no exact matches in reference to instance method 'eq'
.where { $0.time.interval.timeSemantics.eq(TimeSemantics.session) }
// error: instance method 'gt' requires the types 'Date??' and 'Date'
// be equivalent
.where { $0.time.interval.startDate.gt(someDate) }
// compiles — the double optional is matched on both sides
.where { $0.time.interval.timeSemantics.eq(TimeSemantics?.some(.session)) }Ordering by the case itself is rejected, since the payload is a struct rather than a single value:
// error: referencing instance method 'desc(nulls:)' on 'Optional'
// requires that 'RecordTime.Interval' conform to 'QueryBindable'
.order { $0.time.interval.desc() }Coalescing the double optional before sorting also never finishes:
.order { _, header in
(header.time.interval.startDate ?? Date.distantPast).desc()
}Pointing the same project at json-each-availability-group-updates
(StructuredQueriesSQLite, same traits, same sources) fails fast instead
of hanging, but it fails on the schema rather than the query, so the
.order line is never reached:
Type 'HealthRecord.RecordTime.Interval' does not conform to
protocol 'QueryRepresentable'
reported in the macro expansion for RecordTime's @Selection.
HealthRecord then stops conforming to Table, so .all, .order and
the return type all error too.
The same project on 0.34.0 hangs, so this is a difference on the branch rather than in how the project is set up.
- Xcode 27.0 (27A5228h), Swift 6.4
- swift-structured-queries 0.34.0 (
StructuredQueriesSQLite), traitsCasePathsandLazyInitializableByDefault - No sqlite-data dependency: the hang is in type checking, so nothing is executed and no database is needed