Skip to content

Commit 4772c44

Browse files
committed
Update docs
1 parent 7b8e8f1 commit 4772c44

File tree

16 files changed

+235
-251
lines changed

16 files changed

+235
-251
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ struct Reminder {
3131
var title = ""
3232
var isCompleted = false
3333
var priority: Int?
34-
@Column(as: Date.ISO8601Representation?.self)
3534
var dueDate: Date?
3635
}
3736
```

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

Lines changed: 77 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -152,113 +152,6 @@ with your table's columns, instead. For these data types you must either define
152152
The library comes with several `QueryRepresentable` conformances to aid in representing dates,
153153
UUIDs, and JSON, and you can define your own conformances for your own custom data types.
154154
155-
#### Dates
156-
157-
While some relational databases, like MySQL and Postgres, have native support for dates, SQLite
158-
does _not_. Instead, it has 3 different ways to represent dates:
159-
160-
* Text column interpreted as ISO-8601-formatted string.
161-
* Int column interpreted as number of seconds since Unix epoch.
162-
* Double column interpreted as a Julian day (number of days since November 24, 4713 BC).
163-
164-
Because of this ambiguity, the `@Table` macro does not know what you intend when you define a data
165-
type like this:
166-
167-
```swift
168-
@Table struct Reminder {
169-
let id: Int
170-
var date: Date // 🛑 'Date' column requires a query representation
171-
}
172-
```
173-
174-
In order to make it explicit how you expect to turn a `Date` into a type that SQLite understands
175-
(_i.e._ text, integer, or double) you can use the `@Column` macro with the `as:` argument. The
176-
library comes with 3 strategies out the box to help, ``Foundation/Date/ISO8601Representation`` for
177-
storing the date as a string, ``Foundation/Date/UnixTimeRepresentation`` for storing the date as an
178-
integer, and ``Foundation/Date/JulianDayRepresentation`` for storing the date as a floating point
179-
number.
180-
181-
Any of these representations can be used like so:
182-
183-
```swift
184-
@Table struct Reminder {
185-
let id: Int
186-
@Column(as: Date.ISO8601Representation.self)
187-
var date: Date
188-
}
189-
```
190-
191-
And StructuredQueries will take care of formatting the value for the database:
192-
193-
@Row {
194-
@Column {
195-
```swift
196-
Reminder.insert(
197-
Reminder.Draft(date: Date())
198-
)
199-
```
200-
}
201-
@Column {
202-
```sql
203-
INSERT INTO "reminders"
204-
("date")
205-
VALUES
206-
('2018-01-29 00:08:00.000')
207-
```
208-
}
209-
}
210-
211-
When querying against a date column with a Swift date, you will need to explicitly bundle up the
212-
Swift date into the appropriate representation to use various query helpers. This can be done using
213-
the `#bind` macro:
214-
215-
```swift
216-
Reminder.where { $0.created > #bind(startDate) }
217-
```
218-
219-
#### UUID
220-
221-
SQLite also does not have native support for UUIDs. If you try to use a UUID in your tables you
222-
will get an error:
223-
224-
```swift
225-
@Table struct Reminder {
226-
let id: UUID // 🛑 'UUID' column requires a query representation
227-
var title = ""
228-
}
229-
```
230-
231-
To use such identifiers in your table you can store the column as a data blob, and then you can
232-
use the ``Foundation/UUID/BytesRepresentation`` column representation:
233-
234-
```swift
235-
@Table struct Reminder {
236-
@Column(as: UUID.BytesRepresentation.self)
237-
let id: UUID
238-
var title = ""
239-
}
240-
```
241-
242-
Alternatively you can store the column as text and use either
243-
``Foundation/UUID/LowercasedRepresentation`` or ``Foundation/UUID/UppercasedRepresentation`` to
244-
translate the UUID to text:
245-
246-
```swift
247-
@Table struct Reminder {
248-
@Column(as: UUID.LowercasedRepresentation.self)
249-
let id: UUID
250-
var title = ""
251-
}
252-
```
253-
254-
When querying against a UUID column with a Swift UUID, you will need to explicitly bundle up the
255-
Swift UUID into the appropriate representation to use various query helpers. This can be done using
256-
the `#bind` macro:
257-
258-
```swift
259-
Reminder.where { $0.id != #bind(reminder.id) }
260-
```
261-
262155
#### RawRepresentable
263156
264157
Simple data types, in particular ones conforming to `RawRepresentable` whose `RawValue` is a string
@@ -353,6 +246,83 @@ With that you can insert reminders with notes like so:
353246
}
354247
}
355248
249+
#### SQLite dates and UUIDs
250+
251+
While some relational databases, like MySQL and Postgres, have native types for dates and UUIDs,
252+
SQLite does _not_, and instead can represent them in a variety of ways. Dates, for example, have 3
253+
different representations:
254+
255+
* Text column interpreted as ISO-8601-formatted string.
256+
* Int column interpreted as number of seconds since Unix epoch.
257+
* Double column interpreted as a Julian day (number of days since November 24, 4713 BC).
258+
259+
By default, StructuredQueries will bind and decode dates as ISO-8601 text. If you want to the
260+
library to use a different representation (_i.e._ integer or double), you can provide an explicit
261+
query representation to the `@Column` macro's `as:` argument.
262+
``Foundation/Date/UnixTimeRepresentation`` will store the date as an integer, and
263+
``Foundation/Date/JulianDayRepresentation`` will store the date as a floating point number.
264+
265+
For example:
266+
267+
```swift
268+
@Table struct Reminder {
269+
let id: Int
270+
@Column(as: Date.UnixTimeRepresentation.self)
271+
var date: Date
272+
}
273+
```
274+
275+
And StructuredQueries will take care of formatting the value for the database:
276+
277+
@Row {
278+
@Column {
279+
```swift
280+
Reminder.insert(
281+
Reminder.Draft(date: Date())
282+
)
283+
```
284+
}
285+
@Column {
286+
```sql
287+
INSERT INTO "reminders"
288+
("date")
289+
VALUES
290+
(1517184480)
291+
```
292+
}
293+
}
294+
295+
When querying against a date column with a Swift date, you will need to explicitly bundle up the
296+
Swift date into the appropriate representation to use various query helpers. This can be done using
297+
the `#bind` macro:
298+
299+
```swift
300+
Reminder.where { $0.created > #bind(startDate) }
301+
```
302+
303+
SQLite also does not have type-level support for UUIDs. By default, the library will bind and decode
304+
UUIDs as lowercased, hexadecimal text, but it also provides custom representations. This includes
305+
``Foundation/UUID/UppercasedRepresentation`` for uppercased text, as well as
306+
``Foundation/UUID/BytesRepresentation`` for raw bytes.
307+
308+
To use such custom representations, you can provide it to the `@Column` macro's `as:` parameter:
309+
310+
```swift
311+
@Table struct Reminder {
312+
@Column(as: UUID.BytesRepresentation.self)
313+
let id: UUID
314+
var title = ""
315+
}
316+
```
317+
318+
When querying against a UUID column with a Swift UUID, you will need to explicitly bundle up the
319+
Swift UUID into the appropriate representation to use various query helpers. This can be done using
320+
the `#bind` macro:
321+
322+
```swift
323+
Reminder.where { $0.id != #bind(reminder.id) }
324+
```
325+
356326
### Primary keyed tables
357327
358328
It is possible to tell let the `@Table` macro know which property of your data type is the primary

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,14 @@ could be restored for a certain amount of time. These tables can be represented
2626
struct RemindersList: Identifiable {
2727
let id: Int
2828
var title = ""
29-
@Column(as: Date.ISO8601Representation?.self)
3029
var deletedAt: Date?
3130
}
3231
@Table
3332
struct Reminder: Identifiable {
3433
let id: Int
3534
var title = ""
3635
var isCompleted = false
37-
@Column(as: Date.ISO8601Representation?.self)
3836
var dueAt: Date?
39-
@Column(as: Date.ISO8601Representation?.self)
4037
var deletedAt: Date?
4138
var remindersListID: RemindersList.ID
4239
}
@@ -207,7 +204,6 @@ struct Reminder {
207204
let id: Int
208205
var title = ""
209206
var isCompleted = false
210-
@Column(as: Date.ISO8601Representation?.self)
211207
var deletedAt: Date?
212208

213209
static let all = Self.where { $0.isDeleted.isNot(nil) }

Sources/StructuredQueriesCore/Documentation.docc/Extensions/QueryRepresentable.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@
1010

1111
### Conformances
1212

13-
- ``Foundation/Date/ISO8601Representation``
13+
- ``Swift/Decodable/JSONRepresentation``
1414
- ``Foundation/Date/JulianDayRepresentation``
1515
- ``Foundation/Date/UnixTimeRepresentation``
1616
- ``Foundation/UUID/BytesRepresentation``
17-
- ``Foundation/UUID/LowercasedRepresentation``
1817
- ``Foundation/UUID/UppercasedRepresentation``
19-
- ``Swift/Decodable/JSONRepresentation``
18+
19+
### Deprecations
20+
21+
- ``Foundation/Date/ISO8601Representation``
22+
- ``Foundation/UUID/LowercasedRepresentation``

Sources/StructuredQueriesCore/Documentation.docc/StructuredQueriesCore.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ struct Reminder {
1515
var title = ""
1616
var isCompleted = false
1717
var priority: Int?
18-
@Column(as: Date.ISO8601Representation?.self)
1918
var dueDate: Date?
2019
}
2120
```

Sources/StructuredQueriesCore/Internal/Deprecations.swift

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,134 @@
1+
import Foundation
2+
3+
// NB: Deprecated after 0.3.0:
4+
5+
extension Date {
6+
@available(
7+
*,
8+
deprecated,
9+
message: "ISO-8601 text is the default representation and is no longer explicitly needed."
10+
)
11+
public struct ISO8601Representation: QueryRepresentable {
12+
public var queryOutput: Date
13+
14+
public var iso8601String: String {
15+
queryOutput.iso8601String
16+
}
17+
18+
public init(queryOutput: Date) {
19+
self.queryOutput = queryOutput
20+
}
21+
22+
public init(iso8601String: String) throws {
23+
try self.init(queryOutput: Date(iso8601String: iso8601String))
24+
}
25+
}
26+
}
27+
28+
@available(
29+
*,
30+
deprecated,
31+
message: "ISO-8601 text is the default representation and is no longer explicitly needed."
32+
)
33+
extension Date? {
34+
public typealias ISO8601Representation = Date.ISO8601Representation?
35+
}
36+
37+
@available(
38+
*,
39+
deprecated,
40+
message: "ISO-8601 text is the default representation and is no longer explicitly needed."
41+
)
42+
extension Date.ISO8601Representation: QueryBindable {
43+
public var queryBinding: QueryBinding {
44+
.text(queryOutput.iso8601String)
45+
}
46+
}
47+
48+
@available(
49+
*,
50+
deprecated,
51+
message: "ISO-8601 text is the default representation and is no longer explicitly needed."
52+
)
53+
extension Date.ISO8601Representation: QueryDecodable {
54+
public init(decoder: inout some QueryDecoder) throws {
55+
try self.init(queryOutput: Date(iso8601String: String(decoder: &decoder)))
56+
}
57+
}
58+
59+
@available(
60+
*,
61+
deprecated,
62+
message: "ISO-8601 text is the default representation and is no longer explicitly needed."
63+
)
64+
extension Date.ISO8601Representation: SQLiteType {
65+
public static var typeAffinity: SQLiteTypeAffinity {
66+
String.typeAffinity
67+
}
68+
}
69+
70+
@available(
71+
*,
72+
deprecated,
73+
message: "Lowercased text is the default representation and is no longer explicitly needed."
74+
)
75+
extension UUID {
76+
public struct LowercasedRepresentation: QueryRepresentable {
77+
public var queryOutput: UUID
78+
79+
public init(queryOutput: UUID) {
80+
self.queryOutput = queryOutput
81+
}
82+
}
83+
}
84+
85+
@available(
86+
*,
87+
deprecated,
88+
message: "Lowercased text is the default representation and is no longer explicitly needed."
89+
)
90+
extension UUID? {
91+
public typealias LowercasedRepresentation = UUID.LowercasedRepresentation?
92+
}
93+
94+
@available(
95+
*,
96+
deprecated,
97+
message: "Lowercased text is the default representation and is no longer explicitly needed."
98+
)
99+
extension UUID.LowercasedRepresentation: QueryBindable {
100+
public var queryBinding: QueryBinding {
101+
.text(queryOutput.uuidString.lowercased())
102+
}
103+
}
104+
105+
@available(
106+
*,
107+
deprecated,
108+
message: "Lowercased text is the default representation and is no longer explicitly needed."
109+
)
110+
extension UUID.LowercasedRepresentation: QueryDecodable {
111+
public init(decoder: inout some QueryDecoder) throws {
112+
guard let uuid = try UUID(uuidString: String(decoder: &decoder)) else {
113+
throw InvalidString()
114+
}
115+
self.init(queryOutput: uuid)
116+
}
117+
118+
private struct InvalidString: Error {}
119+
}
120+
121+
@available(
122+
*,
123+
deprecated,
124+
message: "Lowercased text is the default representation and is no longer explicitly needed."
125+
)
126+
extension UUID.LowercasedRepresentation: SQLiteType {
127+
public static var typeAffinity: SQLiteTypeAffinity {
128+
String.typeAffinity
129+
}
130+
}
131+
1132
// NB: Deprecated after 0.1.1:
2133

3134
@available(*, deprecated, message: "Use 'MyCodableType.JSONRepresentation', instead.")

0 commit comments

Comments
 (0)