{"id":13755849,"url":"https://github.com/agu-z/roc-pg","last_synced_at":"2025-03-17T01:31:06.247Z","repository":{"id":156900644,"uuid":"609644798","full_name":"agu-z/roc-pg","owner":"agu-z","description":"🐘 Use PostgreSQL databases from Roc","archived":false,"fork":false,"pushed_at":"2024-10-21T15:29:27.000Z","size":11116,"stargazers_count":45,"open_issues_count":6,"forks_count":5,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-03-16T00:12:40.453Z","etag":null,"topics":["database","postgresql","query-builder","roc-lang"],"latest_commit_sha":null,"homepage":"","language":"Roc","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"upl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agu-z.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-04T19:57:56.000Z","updated_at":"2025-01-08T10:12:43.000Z","dependencies_parsed_at":"2023-11-06T02:24:26.375Z","dependency_job_id":"628dd8de-bf91-4f85-9424-d11fe95bf04c","html_url":"https://github.com/agu-z/roc-pg","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agu-z%2Froc-pg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agu-z%2Froc-pg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agu-z%2Froc-pg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agu-z%2Froc-pg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agu-z","download_url":"https://codeload.github.com/agu-z/roc-pg/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243835959,"owners_count":20355613,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","postgresql","query-builder","roc-lang"],"created_at":"2024-08-03T11:00:31.677Z","updated_at":"2025-03-17T01:31:05.892Z","avatar_url":"https://github.com/agu-z.png","language":"Roc","funding_links":[],"categories":["Roc Packages 📦"],"sub_categories":[],"readme":"# roc-pg\n\nInterface with PostgreSQL databases from Roc.\n\nThis package implements a PostgreSQL client on pure Roc that depends only on a TCP effect from the platform. \n\nIt 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.\n\n## Status\n\nI'd like this to become a stable PostgreSQL interface for Roc, but this project is currently a work in progress.\n\nYou 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.\n\n### Query Builder\n\nThe query builder is one of the most exciting features of this package, but more experimental than the lower-level API.\n\nYou 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.\n\nThe 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`.\n\n**See an [example](./examples/store) of a simple HTTP API built with the query builder!**\n\n## Examples\n\nConnecting and performing a query\n\n```haskell\ntask : Task (List { name: Str, price: Dec }) _\ntask =\n    client \u003c- Pg.Client.withConnect {\n              host: \"localhost\",\n              port: 5432,\n              user: \"postgres\",\n              database: \"postgres\",\n              auth: Password \"password\"\n          }\n\n    Pg.Cmd.new \"select name, price from products\"\n    |\u003e Pg.Cmd.expectN (\n        Pg.Result.succeed { \n            name: \u003c- Pg.Result.str \"name\" |\u003e Pg.Result.apply, \n            price: \u003c- Pg.Result.dec \"price\" |\u003e Pg.Result.apply\n        }\n    ) \n    |\u003e Pg.Client.command client\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\nParameterized queries\n\u003c/summary\u003e\n\n```elm\nPg.Cmd.new \"select name, price from products where id = $1\"\n|\u003e Pg.Cmd.bind [ Pg.Cmd.u32 productId ]\n|\u003e Pg.Cmd.expect1 (\n    Pg.Result.succeed { \n        name: \u003c- Pg.Result.str \"name\" |\u003e Pg.Result.apply, \n        price: \u003c- Pg.Result.dec \"price\" |\u003e Pg.Result.apply\n    }\n) \n|\u003e Pg.Client.command client\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\nPrepared statements\n\u003c/summary\u003e\n\n```elm\nselectUser \u003c-\n    \"select email from users where id = $1\"\n    |\u003e Pg.Client.prepare { client, name: \"selectUser\" }\n    |\u003e await\n\nselectUser\n|\u003e Pg.Cmd.bind [ Pg.Cmd.u32 userId ]\n|\u003e Pg.Cmd.expect1 (Pg.Result.str \"email\")\n|\u003e Pg.Client.command client\n\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\nBatch commands in a single roundtrip (applicative)\n\u003c/summary\u003e\n\n```elm\nPg.Batch.succeed \\email -\u003e \\products -\u003e { email, products }\n|\u003e Pg.Batch.with\n    (\n        selectUser\n        |\u003e Pg.Cmd.bind [ Pg.Cmd.u32 userId ]\n        |\u003e Pg.Cmd.expect1 (Pg.Result.str \"email\")\n    )\n|\u003e Pg.Batch.with\n    (\n        Pg.Cmd.new\n            \"\"\"\n            select name, price from products\n            inner join orders on orders.product_id = products.id\n            where orders.id = $1\n            \"\"\"\n        |\u003e Pg.Cmd.bind [ Pg.Cmd.u32 orderId ]\n        |\u003e Pg.Cmd.expectN (\n            Pg.Result.succeed { \n                name: \u003c- Pg.Result.str \"name\" |\u003e Pg.Result.apply, \n                price: \u003c- Pg.Result.dec \"price\" |\u003e Pg.Result.apply\n            }\n        ) \n    )\n|\u003e Pg.Client.batch client\n```\n\nNote: `selectUser` referes to prepared statement in the previous example\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\nBatch commands in a single roundtrip (list)\n\u003c/summary\u003e\n\n```elm\nupdateCmd = \\product -\u003e\n    Pg.Cmd.new \"update products set desc = $1 where id = $2\"\n    |\u003e Pg.Cmd.bind [ Pg.Cmd.str product.desc, Pg.Cmd.u32 product.id ]\n\nproductsToUpdate\n|\u003e List.map updateCmd\n|\u003e Pg.Batch.sequence\n|\u003e Pg.Client.batch client\n```\n\nNote: `roc-pg` automatically reuses statements in a batch by only parsing (and describing) once per unique SQL string. This also works with applicative batches.\n\n\u003c/details\u003e\n\n## Documentation\n\nThe 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.\n\nFeel free to DM me at [Roc's Zulip](https://roc.zulipchat.com/#narrow/dm/489294-Agus-Zubiaga), though!\n\n\n## Features\n\n- [x] Connection handling\n- [x] Parameterized queries\n- [x] Decoding results\n- [x] Decoding errors\n- [ ] Authentication methods\n  - [x] Cleartext password\n  - [ ] MD5 password \\*\n  - [ ] SASL / SCRAM-SHA-256 \\*\n- [x] Prepared statements\n- [ ] Close prepared statements\n- [x] Pipelining\n  - [x] Applicative batches\n  - [x] Sequence list of commands expecting same type\n  - [x] 🚀 Parse and Describe once per unique SQL string\n- [ ] Bulk copying\n- [ ] Cursors\n- [ ] SSL \\*\n- [ ] Connection pooling \\*\n- [ ] Notifications (listen/notify)\n- [ ] Notices\n\n\\* Requires new platform primitives\n\nThis list does not include features of the query builder as I'm still figuring out those.\n\n\n## Resources\n\n- [PostgreSQL Protocol Flow](https://www.postgresql.org/docs/current/protocol-flow.html)\n- [PostgreSQL Message Formats](https://www.postgresql.org/docs/current/protocol-message-formats.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagu-z%2Froc-pg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagu-z%2Froc-pg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagu-z%2Froc-pg/lists"}