@@ -14,6 +14,17 @@ you can use the static description of its properties to build type-safe queries.
1414schema of your app is defined first and foremost in your database, and then you define Swift types
1515that represent those database definitions.
1616
17+ * [ Defining a table] ( #Defining-a-table )
18+ * [ Customizing a table] ( #Customizing-a-table )
19+ * [ Table names] ( #Table-names )
20+ * [ Column names] ( #Column-names )
21+ * [ Custom data types] ( #Custom-data-types )
22+ * [ RawRepresentable] ( #RawRepresentable )
23+ * [ JSON] ( #JSON )
24+ * [ Default representations for dates and UUIDs] ( #Default-representations-for-dates-and-UUIDs )
25+ * [ Primary keyed tables] ( #Primary-keyed-tables )
26+ * [ Ephemeral columns] ( #Ephemeral-columns )
27+
1728### Defining a table
1829
1930Suppose your database has a table defined with the following create statement:
@@ -152,113 +163,6 @@ with your table's columns, instead. For these data types you must either define
152163The library comes with several `QueryRepresentable` conformances to aid in representing dates,
153164UUIDs, and JSON, and you can define your own conformances for your own custom data types.
154165
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-
262166#### RawRepresentable
263167
264168Simple data types, in particular ones conforming to `RawRepresentable` whose `RawValue` is a string
@@ -398,6 +302,106 @@ RemindersList.leftJoin(Reminder.all) {
398302 $0.id == $1.id // 🛑 Requires the types 'Reminder.ID' and 'RemindersList.ID' be equivalent
399303}
400304
305+ #### Default representations for dates and UUIDs
306+
307+ While some relational databases, like MySQL and Postgres, have native types for dates and UUIDs,
308+ SQLite does _not_, and instead can represent them in a variety of ways. In order to lessen the
309+ friction of building queries with dates and UUIDs, the library has decided to provide a default
310+ representation for dates and UUIDs, and if that choice does not fit your schema you can explicitly
311+ specify the representation you want.
312+
313+ ##### Dates
314+
315+ Dates in SQLite have 3 different representations:
316+
317+ * Text column interpreted as ISO-8601-formatted string.
318+ * Int column interpreted as number of seconds since Unix epoch.
319+ * Double column interpreted as a Julian day (number of days since November 24, 4713 BC).
320+
321+ By default, StructuredQueries will bind and decode dates as ISO-8601 text. If you want the library
322+ to use a different representation (_i.e._ integer or double), you can provide an explicit query
323+ representation to the `@Column` macro's `as:` argument. ``Foundation/Date/UnixTimeRepresentation``
324+ will store the date as an integer, and ``Foundation/Date/JulianDayRepresentation`` will store the
325+ date as a floating point number.
326+
327+ For example:
328+
329+ ```swift
330+ @Table struct Reminder {
331+ let id: Int
332+ @Column(as: Date.UnixTimeRepresentation.self)
333+ var date: Date
334+ }
335+ ```
336+
337+ And StructuredQueries will take care of formatting the value for the database:
338+
339+ @Row {
340+ @Column {
341+ ```swift
342+ Reminder.insert(
343+ Reminder.Draft(date: Date())
344+ )
345+ ```
346+ }
347+ @Column {
348+ ```sql
349+ INSERT INTO " reminders"
350+ (" date " )
351+ VALUES
352+ (1517184480)
353+ ```
354+ }
355+ }
356+
357+ If you use the non-default date representation in your schema, then while querying against a
358+ date column with a Swift Date, you will need to explicitly bundle up the Swift date into the
359+ appropriate representation to use various query helpers. This can be done using the `#bind` macro:
360+
361+ ```swift
362+ Reminder.where { $0.created > #bind(startDate) }
363+ ```
364+
365+ > Note: When using the default representation for dates (ISO-8601 text) you do not need to use
366+ > the `#bind` macro:
367+ >
368+ > ```swift
369+ > Reminder.where { $0.created > startDate }
370+ > ```
371+
372+ ##### UUIDs
373+
374+ SQLite also does not have type-level support for UUIDs. By default, the library will bind and decode
375+ UUIDs as lowercased, hexadecimal text, but it also provides custom representations. This includes
376+ ``Foundation/UUID/UppercasedRepresentation`` for uppercased text, as well as
377+ ``Foundation/UUID/BytesRepresentation`` for raw bytes.
378+
379+ To use such custom representations, you can provide it to the `@Column` macro's `as:` parameter:
380+
381+ ```swift
382+ @Table struct Reminder {
383+ @Column(as: UUID.BytesRepresentation.self)
384+ let id: UUID
385+ var title = " "
386+ }
387+ ```
388+
389+ If you use the non-default UUID representation in your schema, then while querying against a UUID
390+ column with a Swift UUID, you will need to explicitly bundle up the Swift UUID into the appropriate
391+ representation to use various query helpers. This can be done using
392+ the `#bind` macro:
393+
394+ ```swift
395+ Reminder.where { $0.id != #bind(reminder.id) }
396+ ```
397+
398+ > Note: When using the default representation for UUID (lower-cased text) you do not need to use
399+ > the `#bind` macro:
400+ >
401+ > ```swift
402+ > Reminder.where { $0.id != reminder.id }
403+ > ```
404+
401405### Primary keyed tables
402406
403407It is possible to tell let the `@Table` macro know which property of your data type is the primary
0 commit comments