@@ -27,11 +27,12 @@ struct User {
2727 let id: Int
2828 var name: String
2929 var email: String
30+ var isActive: Bool = true
3031}
3132
3233// Build query (this package)
3334let statement = User
34- .where { $0 .email .hasSuffix (" @example.com" ) }
35+ .where { $0 .isActive && $0 . email .hasSuffix (" @example.com" ) }
3536 .order (by : \.name )
3637 .limit (10 )
3738
8990 .where { $0 .isActive }
9091 .order (by : \.name )
9192 .limit (10 )
92- // SQL: SELECT * FROM "users" WHERE "users"."isActive" ORDER BY "users"."name" LIMIT 10
93+ // SQL: SELECT "users"."id", "users"."name", "users"."email", "users"."isActive"
94+ // FROM "users"
95+ // WHERE "users"."isActive"
96+ // ORDER BY "users"."name"
97+ // LIMIT 10
9398```
9499
95100** INSERT with Draft types** (PostgreSQL NULL PRIMARY KEY handling):
@@ -99,14 +104,14 @@ User
99104User.insert {
100105 User.Draft (name : " Alice" , email : " alice@example.com" )
101106}
102- // SQL: INSERT INTO "users" ("name", "email") VALUES ('Alice', 'alice@example.com')
107+ // SQL: INSERT INTO "users" ("id", " name", "email", "isActive" ) VALUES (DEFAULT, 'Alice', 'alice@example.com', true )
103108
104109// Mixed records - uses DEFAULT for NULL PKs
105110User.insert {
106111 User (id : 1 , name : " Alice" , email : " alice@example.com" )
107112 User.Draft (name : " Bob" , email : " bob@example.com" )
108113}
109- // SQL: INSERT INTO "users" ("id", "name", "email") VALUES (1, 'Alice', 'alice@example.com'), (DEFAULT, 'Bob', 'bob@example.com')
114+ // SQL: INSERT INTO "users" ("id", "name", "email", "isActive" ) VALUES (1, 'Alice', 'alice@example.com', true ), (DEFAULT, 'Bob', 'bob@example.com', true )
110115```
111116
112117** UPDATE with RETURNING:**
@@ -131,37 +136,35 @@ User
131136
132137### PostgreSQL JSONB
133138
134- ** Containment operators (@>, <@ ):**
139+ ** Containment operator (@>):**
135140
136141``` swift
137- struct UserSettings : Codable {
138- var theme: String
139- var notifications: Bool
140- }
141-
142142@Table
143143struct User {
144144 let id: Int
145- var settings: UserSettings
145+ var name: String
146+
147+ @Column (as : Data.self )
148+ var settings: Data
146149}
147150
148151// Find users with dark theme
149- User.where { $0 .settings .contains (UserSettings ( theme : " dark" , notifications : true ) ) }
150- // SQL: WHERE "users"."settings" @> '{"theme":"dark","notifications":true}'
152+ User.where { $0 .settings .contains ([ " theme" : " dark" ] ) }
153+ // SQL: WHERE "users"."settings" @> '{"theme":"dark"}'::jsonb
151154```
152155
153- ** JSON path operators (->, ->>):**
156+ ** JSON path operator ( ->>):**
154157
155158``` swift
156- User.where { $0 .settings .getText (" theme" ) == " dark" }
159+ User.where { $0 .settings .fieldAsText (" theme" ) == " dark" }
157160// SQL: WHERE ("users"."settings" ->> 'theme') = 'dark'
158161```
159162
160- ** GIN indexing for fast JSONB queries :**
163+ ** Key existence operator (?) :**
161164
162165``` swift
163- User.createGINIndex ( on : \ .settings , operatorClass : . jsonb_path_ops )
164- // SQL: CREATE INDEX "users_settings_gin_idx" ON " users" USING GIN ( "settings" jsonb_path_ops)
166+ User.where { $0 .settings . hasKey ( " notifications " ) }
167+ // SQL: WHERE " users". "settings" ? 'notifications'
165168```
166169
167170### Window Functions
@@ -172,32 +175,35 @@ User.createGINIndex(on: \.settings, operatorClass: .jsonb_path_ops)
172175@Table
173176struct Employee {
174177 let id: Int
178+ var name: String
175179 var department: String
176180 var salary: Double
177181}
178182
179183Employee
180184 .select {
181- (
185+ let department = $0 .department
186+ let salary = $0 .salary
187+ return (
182188 $0 .name ,
183- $0 . salary ,
189+ salary,
184190 rank ().over {
185- $0 .partition (by : $1 . department )
186- .order (by : $1 . salary , .desc )
191+ $0 .partition (by : department)
192+ .order (by : salary.desc () )
187193 }
188194 )
189195 }
190- // SQL: SELECT "name", "salary", RANK() OVER (PARTITION BY "department" ORDER BY "salary" DESC)
196+ // SQL: SELECT "employees"."name", "employees"."salary", RANK() OVER (PARTITION BY "employees"."department" ORDER BY "employees"."salary" DESC)
197+ // FROM "employees"
191198```
192199
193200** Named windows (WINDOW clause):**
194201
195202``` swift
196203Employee
197204 .window (" dept_salary" ) {
198- WindowSpec ()
199- .partition (by : $0 .department )
200- .order (by : $0 .salary , .desc )
205+ $0 .partition (by : $1 .department )
206+ .order (by : $1 .salary .desc ())
201207 }
202208 .select {
203209 (
@@ -207,23 +213,9 @@ Employee
207213 rowNumber ().over (" dept_salary" )
208214 )
209215 }
210- // SQL: SELECT "name", RANK() OVER dept_salary, DENSE_RANK() OVER dept_salary, ROW_NUMBER() OVER dept_salary
216+ // SQL: SELECT "employees"." name", RANK() OVER dept_salary, DENSE_RANK() OVER dept_salary, ROW_NUMBER() OVER dept_salary
211217// FROM "employees"
212- // WINDOW dept_salary AS (PARTITION BY "department" ORDER BY "salary" DESC)
213- ```
214-
215- ** Running totals with SUM() window function:**
216-
217- ``` swift
218- Sale
219- .select {
220- (
221- $0 .date ,
222- $0 .amount ,
223- sum ($0 .amount ).over { $0 .order (by : $1 .date ) }
224- )
225- }
226- // SQL: SELECT "date", "amount", SUM("amount") OVER (ORDER BY "date")
218+ // WINDOW dept_salary AS (PARTITION BY "employees"."department" ORDER BY "employees"."salary" DESC)
227219```
228220
229221### Triggers
235227struct Product {
236228 let id: Int
237229 var name: String
230+ var price: Double
231+ var stock: Int
238232 var updatedAt: Date?
239233}
240234
0 commit comments