git.iko.soy/rowtype-yoga/purescript-yoga-postgres
on main help sign in
commit09fafa207dc9035898943a69ba6bba1c124aef20 authorMark <mark.eibes@gmail.com> dateFri 13 Feb 2026, 14:11 (8 months ago) parenta09869c
2 files changed+67−4
src/Yoga/Postgres/Schema.purs+55 test/Schema.purs+12−4
src/Yoga/Postgres/Schema.purs+55
@@ -240,3 +240,58 @@ instance
240240 let tableName = reflectSymbol (Proxy :: Proxy name)
241241 let conditions = whereClauseRL (Proxy :: Proxy whereRL) 1
242242 "SELECT * FROM " <> tableName <> " WHERE " <> intercalate " AND " conditions
243+
244+-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
245+-- UPDATE SQL generation
246+-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
247+
248+class ColumnCountRL :: RL.RowList Type -> Constraint
249+class ColumnCountRL rl where
250+ columnCountRL :: Proxy rl -> Int
251+
252+instance ColumnCountRL RL.Nil where
253+ columnCountRL _ = 0
254+
255+instance ColumnCountRL tail => ColumnCountRL (RL.Cons name typ tail) where
256+ columnCountRL _ = 1 + columnCountRL (Proxy :: Proxy tail)
257+
258+class UpdateSQLFor table setRow whereRow where
259+ updateSQLFor :: String
260+
261+instance
262+ ( IsSymbol name
263+ , RowToList setRow setRL
264+ , RowToList whereRow whereRL
265+ , WhereClauseRL setRL
266+ , WhereClauseRL whereRL
267+ , ColumnCountRL setRL
268+ ) =>
269+ UpdateSQLFor (Table name cols) setRow whereRow where
270+ updateSQLFor = do
271+ let tableName = reflectSymbol (Proxy :: Proxy name)
272+ let setClauses = whereClauseRL (Proxy :: Proxy setRL) 1
273+ let setCount = columnCountRL (Proxy :: Proxy setRL)
274+ let whereClauses = whereClauseRL (Proxy :: Proxy whereRL) (setCount + 1)
275+ "UPDATE " <> tableName
276+ <> " SET "
277+ <> intercalate ", " setClauses
278+ <> " WHERE "
279+ <> intercalate " AND " whereClauses
280+
281+-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
282+-- DELETE SQL generation
283+-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
284+
285+class DeleteSQLFor table whereRow where
286+ deleteSQLFor :: String
287+
288+instance
289+ ( IsSymbol name
290+ , RowToList whereRow whereRL
291+ , WhereClauseRL whereRL
292+ ) =>
293+ DeleteSQLFor (Table name cols) whereRow where
294+ deleteSQLFor = do
295+ let tableName = reflectSymbol (Proxy :: Proxy name)
296+ let conditions = whereClauseRL (Proxy :: Proxy whereRL) 1
297+ "DELETE FROM " <> tableName <> " WHERE " <> intercalate " AND " conditions
test/Schema.purs+12−4
@@ -69,15 +69,15 @@ configInsertSQL = insertSQLFor @ConfigTable
6969-- Phase 6: Type-safe UPDATE
7070-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
7171
72−-- updateResult :: PG.Connection -> Aff Int
73−-- updateResult conn = update @UsersTable { name: "Bob" } { id: 1 } conn
72+updateSQL :: String
73+updateSQL = updateSQLFor @UsersTable @(name :: String) @(id :: Int)
7474
7575-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
7676-- Phase 7: Type-safe DELETE
7777-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
7878
79−-- deleteResult :: PG.Connection -> Aff Int
80−-- deleteResult conn = delete @UsersTable { id: 1 } conn
79+deleteSQL :: String
80+deleteSQL = deleteSQLFor @UsersTable @(id :: Int)
8181
8282-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
8383-- Spec
@@ -114,3 +114,11 @@ spec = do
114114 configDDL `shouldSatisfy` contains (Pattern "score INTEGER NOT NULL DEFAULT 0")
115115 it "skips Default columns in INSERT" do
116116 configInsertSQL `shouldEqual` "INSERT INTO config () VALUES () RETURNING *"
117+
118+ describe "UPDATE SQL" do
119+ it "generates UPDATE with SET and WHERE" do
120+ updateSQL `shouldEqual` "UPDATE users SET name = $1 WHERE id = $2"
121+
122+ describe "DELETE SQL" do
123+ it "generates DELETE with WHERE" do
124+ deleteSQL `shouldEqual` "DELETE FROM users WHERE id = $1"