Skip to content

Commit 6f9d9f5

Browse files
authored
Feat: Add support for generated columns (#101)
1 parent 5176292 commit 6f9d9f5

File tree

7 files changed

+543
-166
lines changed

7 files changed

+543
-166
lines changed

Sources/StructuredQueries/Macros.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,14 @@ public macro Table(
3434
/// - name: The column's name. Defaults to the property's name, _e.g._ 'id' becomes `"id"`.
3535
/// - representableType: A type that represents the property type in a query expression. For types
3636
/// that don't have a single representation in SQL, like `Date` and `UUID`.
37+
/// - generated: Allows to declare the column as a read-only database computed column, making it
38+
/// available for queries but not for updates.
3739
/// - primaryKey: The column is its table's auto-incrementing primary key.
3840
@attached(peer)
3941
public macro Column(
4042
_ name: String = "",
4143
as representableType: (any QueryRepresentable.Type)? = nil,
44+
generated: GeneratedColumn? = nil,
4245
primaryKey: Bool = false
4346
) =
4447
#externalMacro(

Sources/StructuredQueriesCore/Documentation.docc/Articles/DefiningYourSchema.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ that represent those database definitions.
2525
* [Default representations for dates and UUIDs](#Default-representations-for-dates-and-UUIDs)
2626
* [Primary keyed tables](#Primary-keyed-tables)
2727
* [Ephemeral columns](#Ephemeral-columns)
28+
* [Generated columns](#Generated-columns)
2829
* [Table definition tools](#Table-definition-tools)
2930

3031
### Defining a table
@@ -447,6 +448,31 @@ struct Book {
447448
}
448449
```
449450

451+
### Generated columns
452+
453+
Some databases, including SQLite, support [generated columns](https://www.sqlite.org/gencol.html),
454+
which are columns whose values are computed from other columns in the same row. Since these columns
455+
are read-only from an application's perspective, they should be included in `SELECT` statements but
456+
excluded from `INSERT` or `UPDATE` statements.
457+
458+
You can mark a property as a generated column by using the `generated` parameter of the `@Column`
459+
macro with a value of `.stored` or `.virtual`. This ensures the property is decoded when
460+
fetching data but is not included in the `Draft` type used for creating or updating records.
461+
462+
For example, if your database computes a stored `endAt` timestamp, you can model it like this:
463+
464+
```swift
465+
@Table
466+
struct Event {
467+
let id: UUID
468+
var startAt: Date
469+
var duration: TimeInterval
470+
471+
@Column(generated: .stored)
472+
var endAt: Date
473+
}
474+
```
475+
450476
### Table definition tools
451477

452478
This library does not come with any tools for actually constructing table definition queries,

Sources/StructuredQueriesCore/TableColumn.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,15 @@ where Value.QueryOutput: Sendable {
7777
)
7878
}
7979
}
80+
81+
/// A type that describes how a table column is generated (e.g. SQLite generated columns).
82+
///
83+
/// You provide a value of this type to a `@Column` macro to differentiate between generated columns
84+
/// that are physically stored in the database table and those that are "virtual".
85+
///
86+
/// ```swift
87+
/// @Column(generated: .stored)
88+
/// ```
89+
public enum GeneratedColumn {
90+
case virtual, stored
91+
}

0 commit comments

Comments
 (0)