@@ -108,6 +108,27 @@ could be written as a single invocation of the macro:
108108All of the columns provided to trailing closures in the query builder are available statically on
109109each table type, so you can freely interpolate this schema information into the SQL string.
110110
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+
111132Note that the query's represented type cannot be inferred here, and so the `as` parameter is used
112133to let Swift know that we expect to decode the `Reminder` type when we execute the query.
113134
@@ -131,11 +152,12 @@ Values can be interpolated into `#sql` strings to produce dynamic queries:
131152 @Column {
132153 ```swift
133154 let isCompleted = true
155+
134156 #sql(
135157 """
136158 SELECT count(*)
137- FROM reminders
138- WHERE isCompleted = \( isCompleted)
159+ FROM \(Reminder.self)
160+ WHERE \(Reminder. isCompleted) = \(isCompleted)
139161 """,
140162 as: Reminder.self
141163 )
@@ -144,22 +166,22 @@ Values can be interpolated into `#sql` strings to produce dynamic queries:
144166 @Column {
145167 ```sql
146168 SELECT count(* )
147- FROM reminders
148- WHERE isCompleted = ?
169+ FROM " reminders"
170+ WHERE "reminders"." isCompleted" = ?
149171 -- [ 1]
150172 ```
151173 }
152174}
153175
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
155177is not what is happening. The interpolated value is captured as a separate statement binding in
156178order to protect against SQL injection.
157179
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:
160182
161183``` swift
162- let searchText = " get"
184+ let searchText = " % get% "
163185#sql (
164186 """
165187 SELECT \( Reminder.columns )
@@ -178,7 +200,7 @@ If you mean to bind the string as a value, you can update the interpolation to u
178200@Row {
179201 @Column {
180202 ```swift
181- let searchText = "get"
203+ let searchText = "% get% "
182204 #sql(
183205 """
184206 SELECT \( Reminder.columns)
@@ -205,12 +227,12 @@ If you mean to interpolate the string directly into the SQL you can use
205227@Row {
206228 @Column {
207229 ```swift
208- let searchText = "get"
230+ let searchText = "% get% "
209231 #sql(
210232 """
211233 SELECT \( Reminder.columns)
212234 FROM \( Reminder.self)
213- WHERE \( Reminder.title) COLLATE NOCASE LIKE '% \( raw: searchText)% '
235+ WHERE \( Reminder.title) COLLATE NOCASE LIKE '\( raw: searchText)'
214236 """,
215237 as: Reminder.self
216238 )
0 commit comments