Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/agu-z/roc-pg
🐘 Use PostgreSQL databases from Roc
https://github.com/agu-z/roc-pg
database postgresql query-builder roc-lang
Last synced: 12 days ago
JSON representation
🐘 Use PostgreSQL databases from Roc
- Host: GitHub
- URL: https://github.com/agu-z/roc-pg
- Owner: agu-z
- License: upl-1.0
- Created: 2023-03-04T19:57:56.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-10-21T15:29:27.000Z (17 days ago)
- Last Synced: 2024-10-22T02:25:48.427Z (17 days ago)
- Topics: database, postgresql, query-builder, roc-lang
- Language: Roc
- Homepage:
- Size: 10.6 MB
- Stars: 41
- Watchers: 7
- Forks: 5
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- roc-awesome - agu-z/roc-pg
README
# roc-pg
Interface with PostgreSQL databases from Roc.
This package implements a PostgreSQL client on pure Roc that depends only on a TCP effect from the platform.
It exposes a simple API that allows you to run SQL commands as strings and a query builder that helps you write composable type-safe queries against your schema.
## Status
I'd like this to become a stable PostgreSQL interface for Roc, but this project is currently a work in progress.
You can already use this to build useful applications. However, until we have a platform with TLS support, you should stick to experiments or simple apps where you run the database in the same machine.
### Query Builder
The query builder is one of the most exciting features of this package, but more experimental than the lower-level API.
You can currently generate a Roc module from your schema that you can use through the functions exposed under [`Sql`](./src/Sql.roc) to compose type-safe `SELECT` statements.
The plan is to support all the other SQL commands, but that's coming later. In the meantime, you can perform those by creating a raw SQL command with `Pg.Cmd.new`.
**See an [example](./examples/store) of a simple HTTP API built with the query builder!**
## Examples
Connecting and performing a query
```haskell
task : Task (List { name: Str, price: Dec }) _
task =
client <- Pg.Client.withConnect {
host: "localhost",
port: 5432,
user: "postgres",
database: "postgres",
auth: Password "password"
}Pg.Cmd.new "select name, price from products"
|> Pg.Cmd.expectN (
Pg.Result.succeed {
name: <- Pg.Result.str "name" |> Pg.Result.apply,
price: <- Pg.Result.dec "price" |> Pg.Result.apply
}
)
|> Pg.Client.command client
```Parameterized queries
```elm
Pg.Cmd.new "select name, price from products where id = $1"
|> Pg.Cmd.bind [ Pg.Cmd.u32 productId ]
|> Pg.Cmd.expect1 (
Pg.Result.succeed {
name: <- Pg.Result.str "name" |> Pg.Result.apply,
price: <- Pg.Result.dec "price" |> Pg.Result.apply
}
)
|> Pg.Client.command client
```Prepared statements
```elm
selectUser <-
"select email from users where id = $1"
|> Pg.Client.prepare { client, name: "selectUser" }
|> awaitselectUser
|> Pg.Cmd.bind [ Pg.Cmd.u32 userId ]
|> Pg.Cmd.expect1 (Pg.Result.str "email")
|> Pg.Client.command client```
Batch commands in a single roundtrip (applicative)
```elm
Pg.Batch.succeed \email -> \products -> { email, products }
|> Pg.Batch.with
(
selectUser
|> Pg.Cmd.bind [ Pg.Cmd.u32 userId ]
|> Pg.Cmd.expect1 (Pg.Result.str "email")
)
|> Pg.Batch.with
(
Pg.Cmd.new
"""
select name, price from products
inner join orders on orders.product_id = products.id
where orders.id = $1
"""
|> Pg.Cmd.bind [ Pg.Cmd.u32 orderId ]
|> Pg.Cmd.expectN (
Pg.Result.succeed {
name: <- Pg.Result.str "name" |> Pg.Result.apply,
price: <- Pg.Result.dec "price" |> Pg.Result.apply
}
)
)
|> Pg.Client.batch client
```Note: `selectUser` referes to prepared statement in the previous example
Batch commands in a single roundtrip (list)
```elm
updateCmd = \product ->
Pg.Cmd.new "update products set desc = $1 where id = $2"
|> Pg.Cmd.bind [ Pg.Cmd.str product.desc, Pg.Cmd.u32 product.id ]productsToUpdate
|> List.map updateCmd
|> Pg.Batch.sequence
|> Pg.Client.batch client
```Note: `roc-pg` automatically reuses statements in a batch by only parsing (and describing) once per unique SQL string. This also works with applicative batches.
## Documentation
The API has been in a state of flux until recently. I have now started working on documentation, but the [examples](./examples) is probably the best we have for now.
Feel free to DM me at [Roc's Zulip](https://roc.zulipchat.com/#narrow/dm/489294-Agus-Zubiaga), though!
## Features
- [x] Connection handling
- [x] Parameterized queries
- [x] Decoding results
- [x] Decoding errors
- [ ] Authentication methods
- [x] Cleartext password
- [ ] MD5 password \*
- [ ] SASL / SCRAM-SHA-256 \*
- [x] Prepared statements
- [ ] Close prepared statements
- [x] Pipelining
- [x] Applicative batches
- [x] Sequence list of commands expecting same type
- [x] 🚀 Parse and Describe once per unique SQL string
- [ ] Bulk copying
- [ ] Cursors
- [ ] SSL \*
- [ ] Connection pooling \*
- [ ] Notifications (listen/notify)
- [ ] Notices\* Requires new platform primitives
This list does not include features of the query builder as I'm still figuring out those.
## Resources
- [PostgreSQL Protocol Flow](https://www.postgresql.org/docs/current/protocol-flow.html)
- [PostgreSQL Message Formats](https://www.postgresql.org/docs/current/protocol-message-formats.html)