{"id":17921858,"url":"https://github.com/zth/rescript-edgedb","last_synced_at":"2025-10-29T03:20:12.855Z","repository":{"id":196711632,"uuid":"696972897","full_name":"zth/rescript-edgedb","owner":"zth","description":"Use EdgeDB fully type safe in ReScript. Embed EdgeQL right in your ReScript source code.","archived":false,"fork":false,"pushed_at":"2024-08-22T21:49:26.000Z","size":198,"stargazers_count":44,"open_issues_count":3,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-11T03:50:12.870Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"ReScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zth.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"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-09-26T19:40:17.000Z","updated_at":"2024-08-31T14:49:27.000Z","dependencies_parsed_at":"2024-02-14T21:34:19.968Z","dependency_job_id":"35c1e89a-2d2d-4d00-aec7-5c63c7655e1d","html_url":"https://github.com/zth/rescript-edgedb","commit_stats":null,"previous_names":["zth/rescript-edgedb"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zth%2Frescript-edgedb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zth%2Frescript-edgedb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zth%2Frescript-edgedb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zth%2Frescript-edgedb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zth","download_url":"https://codeload.github.com/zth/rescript-edgedb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246970324,"owners_count":20862508,"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":[],"created_at":"2024-10-28T20:36:27.795Z","updated_at":"2025-10-29T03:20:12.769Z","avatar_url":"https://github.com/zth.png","language":"ReScript","readme":"# rescript-edgedb\n\nUse EdgeDB fully type safe in ReScript. Embed EdgeQL right in your ReScript source code.\n\n## Getting started\n\n\u003e There's a dedicated VSCode extension for `rescript-edgedb` that will give you a few goodies like in-editor errors for your ReScript EdgeQL queries. Install from here: https://marketplace.visualstudio.com/items?itemName=GabrielNordeborn.vscode-rescript-edgedb. Read more about [its capabilities here](#vscode-extension).\n\n```bash\nnpm i rescript-edgedb rescript-embed-lang\n```\n\nAlso make sure you have `@rescript/core \u003e= 1.3.0`. It's required from `rescript-edgedb \u003e=0.8.0`.\n\nSetup your `bsconfig.json`/`rescript.json`:\n\n```json\n\"bs-dependencies\": [\"@rescript/core\", \"rescript-edgedb\"]\n\"ppx-flags\": [\"rescript-embed-lang/ppx\"]\n```\n\nThe `rescript-edgedb` watcher needs to run for your EdgeQL to be compiled. Set up scripts in your `package.json` to do that:\n\n```json\n\"scripts\": {\n  \"build:edgedb\": \"rescript-edgedb generate --output ./src/__generated__ --src ./src\",\n  \"watch:edgedb\": \"npm run build:edgedb -- --watch\"\n}\n```\n\n\u003e The CLI will walk upwards looking for `edgedb.toml` in order to find how to connect to your database. So, you don't need to give the CLI any details on how to connect your database (although you can if you want).\n\n- `--src` should point to the root directory where you have ReScript files that contain `%edgeql` tags you want compiled. This directory will be searched (and watched) recursively.\n- `--output` should point to the directory where you want all _generated_ files to end up. This needs to be a directory that's part of your ReScript project, so the ReScript compiler can pick them up.\n\n### Writing queries\n\nFinally, after starting `npm run watch:edgedb` and ensuring the console output looks fine, we can write our first EdgeQL query:\n\n```rescript\n// Movies.res\nlet findMovies = %edgeql(`\n    # @name findMovies\n    select Movie {\n        title,\n        status,\n        actors: {\n            name,\n            age\n        }\n    } filter\n      .title = \u003cstr\u003e$movieTitle`)\n```\n\nExecuting the query is done by passing it the `client`, and arguments if it takes any.\n\n```rescript\nlet findMovies = %edgeql(`\n    # @name findMovies\n    select Movie {\n        title,\n        status,\n        actors: {\n            name,\n            age\n        }\n    } filter\n        .title = \u003cstr\u003e$movieTitle`)\n\n// array\u003cmovie\u003e\nlet movies = await client-\u003efindMovies({\n    movieTitle: title,\n})\n```\n\nThere's just one thing to notice in relation to regular EdgeQL - we require you to put a comment at the top of your query with a `@name` annotation, naming the query. This is because we need to be able to discern which query is which in the current ReScript file, since you can put as many queries as you want in the same ReScript file.\n\n### `let` binding or `module`\n\nEdgeQL can be written both as a `let` binding like above, or as a `module` binding:\n\n```rescript\n// Movies.res\nlet findMovies = %edgeql(`\n  # @name findMovies\n  select Movie {\n      title,\n      status,\n      actors: {\n          name,\n          age\n      }\n  } filter\n    .title = \u003cstr\u003e$movieTitle\n`)\n\nlet movies = await client-\u003efindMovies({\n  movieTitle: \"Jalla Jalla\",\n})\n\nmodule DeleteMovie = %edgeql(`\n  # @name deleteMovie\n  delete Movie filter\n    .title = \u003cstr\u003e$movieTitle\n`)\n\nlet _maybeDeletedMovie = await client-\u003eDeleteMovie.query({\n  title: \"Jalla Jalla\"\n})\n```\n\nThe _only_ difference between these two is that the `let` binding gives you access to the generated `query` (which you use to execute the query) directly, whereas the `module` binding gives you access to the _entire_ generated module for the EdgeQL you write. This includes `query` (like with the `let` binding), the generated types for all of the query contents (args and response), and an extra `transaction` function that you can use in transactions. More about transactions below.\n\n`let` binding style EdgeQL is the thing you'll use most of all - it's to the point, and can be defined anywhere. `module` bindings need to be at the top level. But, sometimes you need it.\n\n\u003e We might consider adding a \"transaction mode\" to the `let` binding as well in the future. Defining the queries inline is very powerful, and forcing you to define things at the top level because of `module` isn't the best DX at all times.\n\n### Using transactions\n\nThere's a `transaction` function emitted for each EdgeQL query. You can use that to do your operation in a transaction:\n\n```rescript\nlet client = EdgeDB.Client.make()\n\n// Remember to define your EdgeQL using a module, so you get easy access to all generated functions.\nmodule InsertMovie = %edgeql(`\n  # @name insertMovie\n  insert Movie {\n      title := \u003cstr\u003e$title,\n      status := \u003cPublishStatus\u003e$status\n  }`)\n\nawait client-\u003eEdgeDB.Client.transaction(async tx =\u003e {\n  await tx-\u003eInsertMovie.transaction({\n    title: \"Jalla Jalla\",\n    status: #Published\n  })\n})\n```\n\n### Cardinality\n\n\u003e Cardinality = how many results are returned from your query.\n\nEdgeDB and `rescript-edgedb` automatically manages the cardinality of each query for you. That means that you can always trust the return types of your query. For example, adding `limit 1` to the `findMovies` query above would make the return types `option\u003cmovie\u003e` instead of `array\u003cmovie\u003e`.\n\nSimilarily, you can design the query so that it expects there to always be exactly 1 response, and error if that's not the case. In that case, the return type would be `result\u003cmovie, EdgeDB.Error.operationError\u003e`.\n\nHere's a complete list of the responses your EdgeQL queries can produce:\n\n- `void` - Nothing. No results are returned at all.\n- `array\u003cresponse\u003e` - Many. A list of all results.\n- `option\u003cresponse\u003e` - Maybe one.\n- `result\u003cresponse, EdgeDB.Error.errorFromOperation\u003e` Exactly one. Or an error.\n\n## The CLI\n\nYou can get a full list of supported CLI commands by running `npx rescript-edgedb --help`. More documentation on the exact parameters available is coming.\n\n## So, how does it work?\n\n`rescript-edgedb` consists of 2 parts:\n\n1. A code generator that generates ReScript from your EdgeQL.\n2. A PPX transform that swaps your `%edgeql` tag to its corresponding generated code, via [`rescript-embed-lang`](https://github.com/zth/rescript-embed-lang).\n\nTake this query as an example:\n\n```rescript\n// Movies.res\nlet findMovies = %edgeql(`\n  # @name findMovies\n  select Movie {\n      title,\n      status,\n      actors: {\n          name,\n          age\n      }\n  } filter\n    .title = \u003cstr\u003e$movieTitle`)\n```\n\nThe `rescript-edgedb` tooling finds this `%edgeql` tag, and generates a file called `Movies__edgeql.res` from it, using code generation leveraging the official EdgeDB type generation tooling. That file will contain generated code and types for the `findMovies` query:\n\n```rescript\n// @sourceHash 18807b4839373ee493a3aaab68766f53\n// @generated This file is generated automatically by rescript-edgedb, do not edit manually\nmodule FindMoviesQuery = {\n  let queryText = `select Movie {\n        title,\n        status,\n        actors: {\n            name,\n            age\n        }\n    } filter\n      .title = \u003cstr\u003e$movieTitle`\n\n  type args = {\n    movieTitle: string,\n  }\n\n  type response_actors = {\n    name: string,\n    age: Null.t\u003cint\u003e,\n  }\n\n  type response = {\n    title: string,\n    status: [#Published | #Unpublished],\n    actors: array\u003cresponse_actors\u003e,\n  }\n\n  let query = (client: EdgeDB.Client.t, args: args): promise\u003carray\u003cresponse\u003e\u003e =\u003e {\n    client-\u003eEdgeDB.QueryHelpers.many(queryText, ~args)\n  }\n\n  let transaction = (transaction: EdgeDB.Transaction.t, args: args): promise\u003carray\u003cresponse\u003e\u003e =\u003e {\n    transaction-\u003eEdgeDB.TransactionHelpers.many(queryText, ~args)\n  }\n}\n```\n\nThanks to `rescript-embed-lang`, you don't have to think about that generated file at all. It's automatically managed for you.\n\n## VSCode extension\n\n`rescript-edgedb` comes with a dedicated [VSCode extension](https://marketplace.visualstudio.com/items?itemName=GabrielNordeborn.vscode-rescript-edgedb) designed to enhance the experience of using ReScript and EdgeDB together. Below is a list of how you use it, and what it can do.\n\n\u003e NOTE: Make sure you install the [official EdgeDB extension](https://marketplace.visualstudio.com/items?itemName=magicstack.edgedb) as well, so you get syntax highlighting and more.\n\n### Snippets\n\nSnippets for easily adding new `%edgeql` blocks are included:\n\n![snippets](https://github.com/zth/rescript-edgedb/assets/1457626/8dc1c54b-470d-4dee-9598-e26d35632286)\n\nThese appear as soon as you start writing `%edgeql` in a ReScript file.\n\n### In editor error messages\n\nAny errors for your EdgeQL queries will show directly in your ReScript files that define them:\n\n![in-editor-errors](https://github.com/zth/rescript-edgedb/assets/1457626/19f6bf01-5648-4354-b510-881ed9b05c3a)\n\n### Easily edit queries in the dedicated EdgeDB UI\n\nYou can easily open the local EdgeDB UI, edit your query in there (including running it, etc), and then insert the modified query back:\n\n![open-in-edgedb-ui](https://github.com/zth/rescript-edgedb/assets/1457626/e4dca50c-de60-4a78-8de9-f195a2cfd88d)\n\nIt works like this:\n\n1. Put the cursor in the query you want to edit.\n2. Activate code actions.\n3. Select the code action for opening the EdgeDB UI and copying the query.\n4. The local EdgeDB query editor UI will now open in your browser, and the EdgeQL query you had your cursor in will be copied to your clipboard.\n5. Paste the query into the query editor and make the edits you want.\n6. Copy the entire query text and go back to VSCode and the file which has your query.\n7. Activate code actions again and select the code action for inserting your modified query.\n8. Done!\n\n## FAQ\n\n**Should I check the generated files into source control?**\nYes, you should. This ensures building the project doesn't _have_ to rely on a running EdgeDB instance (which the code generation tooling requires).\n\n## Contributing\n\n`rescript-edgedb` leverages Bun for local development, including running tests.\n","funding_links":[],"categories":["ReScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzth%2Frescript-edgedb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzth%2Frescript-edgedb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzth%2Frescript-edgedb/lists"}