@@ -108,6 +108,27 @@ could be written as a single invocation of the macro:
108
108
All of the columns provided to trailing closures in the query builder are available statically on
109
109
each table type, so you can freely interpolate this schema information into the SQL string.
110
110
111
+ > Important: _ Always_ interpolate as much static schema information as possible into the SQL string
112
+ > to better ensure that queries are correct and will successfully decode.
113
+ >
114
+ > For example:
115
+ >
116
+ > ``` diff
117
+ > -SELECT * FROM reminders
118
+ > +SELECT \(Reminder.columns) FROM \(Reminder.self)
119
+ > ```
120
+ >
121
+ > * Selecting "`*`" requires that the column order in the database matches the field order in the
122
+ > Swift data type. Because StructuredQueries decodes columns in positional order, a query using
123
+ > "`*`" will fail to decode unless the field order matches exactly. Instead of leaving this to
124
+ > chance, prefer interpolating `Table.columns`, which will generate an explicit SQL column
125
+ > selection that matches the order of fields in the Swift data type.
126
+ > * Spelling out table and column names directly inside the query (_e.g._ "`reminders`") can lead
127
+ > to runtime errors due to typos or stale queries that refer to schema columns that have been
128
+ > renamed or removed. Instead, prefer interpolating `Table.columnName` to refer to a particular
129
+ > column (_e.g._, `Reminder.isCompleted`), and `Table.self` to refer to a table (_e.g._,
130
+ > `Reminder.self`).
131
+
111
132
Note that the query's represented type cannot be inferred here, and so the `as` parameter is used
112
133
to let Swift know that we expect to decode the `Reminder` type when we execute the query.
113
134
@@ -131,11 +152,12 @@ Values can be interpolated into `#sql` strings to produce dynamic queries:
131
152
@Column {
132
153
```swift
133
154
let isCompleted = true
155
+
134
156
#sql(
135
157
"""
136
158
SELECT count(*)
137
- FROM reminders
138
- WHERE isCompleted = \( isCompleted)
159
+ FROM \(Reminder.self)
160
+ WHERE \(Reminder. isCompleted) = \(isCompleted)
139
161
""",
140
162
as: Reminder.self
141
163
)
@@ -144,22 +166,22 @@ Values can be interpolated into `#sql` strings to produce dynamic queries:
144
166
@Column {
145
167
```sql
146
168
SELECT count(* )
147
- FROM reminders
148
- WHERE isCompleted = ?
169
+ FROM " reminders"
170
+ WHERE "reminders"." isCompleted" = ?
149
171
-- [ 1]
150
172
```
151
173
}
152
174
}
153
175
154
- Note that although it seems the literal value is being interpolated directly into the string, that
176
+ Note that although it seems that ` isCompleted ` is being interpolated directly into the string, that
155
177
is not what is happening. The interpolated value is captured as a separate statement binding in
156
178
order to protect against SQL injection.
157
179
158
- String bindings are handled in a special fashion to make it clear what the intended usage is. If
159
- you interpolate a string into a ` #sql ` string, you will get a deprecation warning:
180
+ String bindings are handled in a special fashion to make it clear what the intended usage is. If you
181
+ interpolate a string into a ` #sql ` string, you will get a deprecation warning:
160
182
161
183
``` swift
162
- let searchText = " get"
184
+ let searchText = " % get% "
163
185
#sql (
164
186
"""
165
187
SELECT \( Reminder.columns )
@@ -178,7 +200,7 @@ If you mean to bind the string as a value, you can update the interpolation to u
178
200
@Row {
179
201
@Column {
180
202
```swift
181
- let searchText = "get"
203
+ let searchText = "% get% "
182
204
#sql(
183
205
"""
184
206
SELECT \( Reminder.columns)
@@ -205,12 +227,12 @@ If you mean to interpolate the string directly into the SQL you can use
205
227
@Row {
206
228
@Column {
207
229
```swift
208
- let searchText = "get"
230
+ let searchText = "% get% "
209
231
#sql(
210
232
"""
211
233
SELECT \( Reminder.columns)
212
234
FROM \( Reminder.self)
213
- WHERE \( Reminder.title) COLLATE NOCASE LIKE '% \( raw: searchText)% '
235
+ WHERE \( Reminder.title) COLLATE NOCASE LIKE '\( raw: searchText)'
214
236
""",
215
237
as: Reminder.self
216
238
)
0 commit comments