{"id":32646350,"url":"https://github.com/easafe/purescript-droplet","last_synced_at":"2025-10-31T04:58:34.723Z","repository":{"id":45075427,"uuid":"257195369","full_name":"easafe/purescript-droplet","owner":"easafe","description":"Type-safe ORM for PureScript","archived":false,"fork":false,"pushed_at":"2025-09-21T17:05:30.000Z","size":538,"stargazers_count":30,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-21T17:42:14.234Z","etag":null,"topics":["database","edsl","mapper","orm","postgresql","purescript"],"latest_commit_sha":null,"homepage":"https://droplet.asafe.dev","language":"PureScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/easafe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"easafe","custom":["https://asafe.dev/donate"]}},"created_at":"2020-04-20T06:47:20.000Z","updated_at":"2025-09-21T17:05:33.000Z","dependencies_parsed_at":"2023-01-19T01:30:27.574Z","dependency_job_id":null,"html_url":"https://github.com/easafe/purescript-droplet","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/easafe/purescript-droplet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easafe%2Fpurescript-droplet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easafe%2Fpurescript-droplet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easafe%2Fpurescript-droplet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easafe%2Fpurescript-droplet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/easafe","download_url":"https://codeload.github.com/easafe/purescript-droplet/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easafe%2Fpurescript-droplet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281931716,"owners_count":26585792,"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","status":"online","status_checked_at":"2025-10-31T02:00:07.401Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","edsl","mapper","orm","postgresql","purescript"],"created_at":"2025-10-31T04:58:33.660Z","updated_at":"2025-10-31T04:58:34.717Z","avatar_url":"https://github.com/easafe.png","language":"PureScript","readme":"## purescript-droplet ![build status](https://github.com/easafe/purescript-droplet/actions/workflows/CI.yml/badge.svg)\n\nComposable, type-safe eDSL and query mapper for PureScript targeting PostgreSQL\n\n* eDSL made out of combinators (almost) identical to their SQL counterparts\n\n* Generated SQL matches eDSL one-to-one, and is guaranteed to be correct and unambiguous\n\n* Supports nearly all common SQL operations for ```SELECT```, ```INSERT```, ```UPDATE```, ``DELETE`` and others, including joins, aggregations, subqueries, etc\n\n* Very little boilerplate: query results are automatically mapped to records, (valid) queries never require type annotations\n\n* Migration support via [pebble](https://github.com/easafe/haskell-pebble)\n\n### Documentation\n\nSee the [project page](https://droplet.asafe.dev/) for an in-depth look, or [pursuit](https://pursuit.purescript.org/packages/purescript-droplet) for API docs\n\n### Quick start\n\nInstall\n\n```\nnpm i big-integer pg @easafe/pebble\n\nspago install droplet\n```\n\nCreate some tables\n\n```sql\ncreate table users (\n    id integer generated always as identity primary key,\n    name text not null,\n    birthday date null\n);\n\ncreate table messages (\n    id integer generated always as identity primary key,\n    sender integer not null,\n    recipient integer not null,\n    date timestamptz default now(),\n\n    constraint sender_user foreign key (sender) references users(id),\n    constraint recipient_user foreign key (recipient) references users(id)\n);\n```\n\nDefine some types for your SQL\n\n```purescript\n-- representation of the table itself\ntype UsersTable = Table \"users\" Users\n\nusers :: UsersTable\nusers = Table\n\nmessages :: Table \"messages\" Messages\nmessages = Table\n\n-- representation of the table's columns definitions\ntype Users = (\n    id :: Column Int (PrimaryKey /\\ Identity), -- primary key, generated always as identity\n    name :: String,\n    birthday :: Maybe Date -- nullable column\n)\n\ntype Messages = (\n    id :: Column Int (PrimaryKey /\\ Identity),\n    sender :: Column Int (ForeignKey \"id\" UsersTable), -- foreign key to table users\n    recipient :: Column Int (ForeignKey \"id\" UsersTable),\n    date :: Column DateTime (Constraint \"date_default_messages\" Default) -- column with named default constrain\n)\n\n-- representation of column names to be used in queries\nid :: Proxy \"id\"\nid = Proxy\n\nname :: Proxy \"name\"\nname = Proxy\n\nbirthday :: Proxy \"birthday\"\nbirthday = Proxy\n\nsender :: Proxy \"sender\"\nsender = Proxy\n\nrecipient :: Proxy \"recipient\"\nrecipient = Proxy\n\ndate :: Proxy \"date\"\ndate = Proxy\n\n-- alias\nu :: Proxy \"u\"\nu = Proxy\n\nm :: Proxy \"m\"\nm = Proxy\n\nt :: Proxy \"t\"\nt = Proxy\n```\n\n(Don't worry, table creation, typing and migration can be automated with [pebble](https://github.com/easafe/haskell-pebble))\n\nPrepare some queries\n\n```purescript\nmary :: _\nmary =\n    insert #\n    into users (name) #\n    values (\"Mary Sue\") # -- `name` is the only required field; it would be a type error to set `id`, as it is an identity column\n    returning id -- output inserted `id`\n\ngary :: Date -\u003e _\ngary bday =\n    insert #\n    into users (name /\\ birthday) # -- tuple for field list\n    values (\"Gary Stu\" /\\ Just bday) # -- set the nullable field `birthday`\n    returning id\n\nchat :: Int -\u003e Int -\u003e _\nchat from to = insert # into messages (sender /\\ recipient) # values (from /\\ to) -- `date` has a default value\n\nselectMessages :: _\nselectMessages =\n      select (id /\\ date) #\n      from messages\n\nselectUserMessages :: Int -\u003e _\nselectUserMessages userId =\n      selectMessages #\n      wher (id .=. userId) -- SQL operators are surrounded by dots; we can compare `id` to `userId` as `Column` type wrappers are automatically stripped\n\njoinUserMessages :: _\njoinUserMessages =\n      select (u ... name /\\ -- `alias ... column` is equivalent to SQL alias.column\n              (t ... name # as recipient) /\\ -- `name` is displayed as recipient\n              date) #\n      from (((messages # as m)\n            `join`\n            (users # as u) #\n            on (m ... sender .=. u ... id))\n            `join`\n            (users # as t) #\n            on (m ... recipient .=. t ... id))\n```\n\nConnect to the database\n\n```purescript\nconnectionInfo :: Configuration\nconnectionInfo = (Driver.defaultConfiguration \"database\") {\n      user = Just \"user\"\n}\n\nexample :: Aff Unit\nexample = do\n      pool \u003c- liftEffect $ Pool.newPool connectionInfo -- connection pool from PostgreSQL\n      Driver.withConnection pool case _ of\n            Left error -\u003e pure unit -- or some more sensible handling\n            Right connection -\u003e runSql connection\n```\n\nRun queries\n\n```purescript\nrunSql :: Connection -\u003e Aff Unit\nrunSql connection = do\n      now \u003c- liftEffect Now.nowDate\n      mRow \u003c- Driver.single connection mary -- run a query that returns a single row\n      gRow \u003c- Driver.single connection $ gary now\n      case mRow, gRow of\n            Right (Just {id: mId}), Right (Just {id: gId}) -\u003e void do\n                  mErr \u003c- Driver.execute connection $ chat mId gId -- run a query that doesn't produce an output\n                  gErr \u003c- Driver.execute connection $ chat gId mId\n\n                  mMessages \u003c- Driver.query connection $ selectUserMessages mId -- run a query that returns rows\n                  gMessages \u003c- Driver.query connection $ selectUserMessages gId -- rows are always records, the keys are the projected columns\n                  Driver.query connection joinUserMessages\n\n            _, _ -\u003e pure unit\n```\n\n### Licensing\n\nWrapper code around [pg](https://github.com/brianc/node-postgres) was adapted from [purescript-postgresql-client](https://github.com/rightfold/purescript-postgresql-client) so its license has been included in [PURESCRIPT-POSTGRESQL-CLIENT-LICENSE](PURESCRIPT-POSTGRESQL-CLIENT-LICENSE)\n\n### Funding\n\nIf this project is useful for you, consider [throwing a buck](https://asafe.dev/donate) to keep development possible\n","funding_links":["https://github.com/sponsors/easafe","https://asafe.dev/donate"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasafe%2Fpurescript-droplet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feasafe%2Fpurescript-droplet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasafe%2Fpurescript-droplet/lists"}