{"id":29550126,"url":"https://github.com/Query-farm/evalexpr_rhai","last_synced_at":"2025-07-18T01:03:58.160Z","repository":{"id":246960115,"uuid":"824399240","full_name":"Query-farm/evalexpr_rhai","owner":"Query-farm","description":"A DuckDB extension to evaluate the Rhai scripting language as part of SQL.","archived":false,"fork":false,"pushed_at":"2025-06-10T00:50:01.000Z","size":797,"stargazers_count":19,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-04T17:18:30.835Z","etag":null,"topics":["database","duckdb","duckdb-extension","rhai","rhai-script","user-defined-functions"],"latest_commit_sha":null,"homepage":"https://query.farm/duckdb_extension_evalexpr_rhai.html","language":"C++","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/Query-farm.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,"zenodo":null}},"created_at":"2024-07-05T03:59:36.000Z","updated_at":"2025-06-20T10:58:31.000Z","dependencies_parsed_at":"2025-05-22T01:26:54.723Z","dependency_job_id":"026951b8-a3e4-4aaa-8961-6c62f0ed35cd","html_url":"https://github.com/Query-farm/evalexpr_rhai","commit_stats":null,"previous_names":["rustyconover/duckdb-evalexpr-rhai-extension","query-farm/evalexpr_rhai"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Query-farm/evalexpr_rhai","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Query-farm%2Fevalexpr_rhai","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Query-farm%2Fevalexpr_rhai/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Query-farm%2Fevalexpr_rhai/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Query-farm%2Fevalexpr_rhai/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Query-farm","download_url":"https://codeload.github.com/Query-farm/evalexpr_rhai/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Query-farm%2Fevalexpr_rhai/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265686645,"owners_count":23811210,"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","duckdb","duckdb-extension","rhai","rhai-script","user-defined-functions"],"created_at":"2025-07-18T01:02:32.173Z","updated_at":"2025-07-18T01:03:58.149Z","avatar_url":"https://github.com/Query-farm.png","language":"C++","funding_links":[],"categories":["C++"],"sub_categories":[],"readme":"# Rhai Extension for DuckDB\n\n---\n\n![Ducks reading and following scripts](./images/ducks-evalexpr-rhai.jpg)\n\nThis `evalexpr_rhai` extension adds functions that allow the [Rhai](https://rhai.rs) language to be evaluated in [DuckDB's](https://www.duckdb.org) SQL statements.\n\n## What is [Rhai](https://rhai.rs)?\n\n[\u003cimage align=\"right\" src=\"https://rhai.rs/book/images/logo/rhai-logo-transparent-colour-black.svg\" width=\"200px\"/\u003e](https://rhai.rs)\n\nA small, fast, easy-to-use scripting language and evaluation engine that integrates tightly with Rust.  It is very similar to Rust and JavaScript and uses dynamic typing.\n\nYou can learn more about Rhai by reading the [Rhai book](https://rhai.rs/book/).\n\n## Why add this extension to DuckDB?\n\nDuckDB offers a wide variety of SQL-based functions, but there are times when you want to write some code that is a bit more complicated than what SQL provides.\n\n## Examples\n\n```sql\nload json;\nload evalexpr_rhai;\n\n-- Just a simple evaluation of an expression.\n\nD select evalexpr_rhai('5+6').ok;\n┌───────────────────────────┐\n│ (evalexpr_rhai('5+6')).ok │\n│           json            │\n├───────────────────────────┤\n│ 11                        │\n└───────────────────────────\n```\n\nExpressions can either be passed in the statement itself or from a column in a database.  This means that you can evaluate expressions stored in columns for their result.\n\nIf a statement is passed as a constant expression it is compiled and cached for faster execution.\n\n```sql\n-- Setup a table that determines group members, the logic\n-- for membership can be managed by an administrator\ncreate table group_membership(group_name text, logic text);\n\ninsert into group_membership values\n  ('managers', 'context.name == \"George\" || context.name == \"Rusty\"'),\n  ('shift_leads', 'context.name == \"John\"'),\n  ('employees', 'context.name == \"Alex\"');\n\n-- Determine which groups the user is a member of\n-- by evaluating the logic from the membership table.\nselect distinct group_name\nfrom group_membership\nwhere\nevalexpr_rhai(logic, { name: 'John'}).ok\n┌─────────────┐\n│ group_name  │\n│   varchar   │\n├─────────────┤\n│ shift_leads │\n└─────────────┘\n```\n\nScripting can be more advanced than expressions, you create functions.  It wouldn't be a scripting example without an example of a [Collatz](https://en.wikipedia.org/wiki/Collatz_conjecture) sequence.\n\n```sql\n-- Define a macro that calculates the length of\n-- of the Collatz sequence from a starting value.\ncreate macro collatz_series_length(n) as\nevalexpr_rhai('\n   fn collatz_series(n) {\n       let count = 0;\n       while n \u003e 1 {\n         count += 1;\n         if n % 2 == 0 {\n             n /= 2;\n         } else {\n             n = n * 3 + 1;\n         }\n       }\n       return count\n  }\n  collatz_series(context.n)\n', {'n': n});\n\n-- Use the defined macro fucntion that calls the\n-- rhai function.\nselect range as n,\ncollatz_series_length(range).ok::integer as length from range(1000, 2000) limit 5;\n┌───────┬────────┐\n│   n   │ length │\n│ int64 │ int32  │\n├───────┼────────┤\n│  1000 │    111 │\n│  1001 │    142 │\n│  1002 │    111 │\n│  1003 │     41 │\n│  1004 │     67 │\n└───────┴────────┘\n```\n\n### How can I make the data from the current row accessible to a Rhai expression?\n\nYou can just pass the entire row via the context.\n\n```sql\ncreate table employees (name text, state text, zip integer);\ninsert into employees values\n  ('Jane', 'FL', 33139),\n  ('John', 'NJ', 08520);\n\nselect evalexpr_rhai(\n  '\n  context.row.name + \" is in \" + context.row.state\n  ',\n  {\n    row: employees\n  }) as result from employees;\n┌───────────────────────────────┐\n│            result             │\n│ union(ok json, error varchar) │\n├───────────────────────────────┤\n│ \"Jane is in FL\"               │\n│ \"John is in NJ\"               │\n└───────────────────────────────┘\n\n-- What about augmenting the context, what is passed there?\n-- just return the context.\nselect evalexpr_rhai('context',{\n    row_data: employees,\n    'fruit': 'banana'\n  }) as result from employees;\n┌────────────────────────────────────────────────────────────────────────┐\n│                                 result                                 │\n│                     union(ok json, error varchar)                      │\n├────────────────────────────────────────────────────────────────────────┤\n│ {\"fruit\":\"banana\",\"row_data\":{\"name\":\"Jane\",\"state\":\"FL\",\"zip\":33139}} │\n│ {\"fruit\":\"banana\",\"row_data\":{\"name\":\"John\",\"state\":\"NJ\",\"zip\":8520}}  │\n└────────────────────────────────────────────────────────────────────────┘\n```\n\n## API\n\n`evalexpr_rhai(VARCHAR, JSON) -\u003e UNION['ok': JSON, 'error': VARCHAR]`\n\nThe arguments in order are:\n\n1. The [Rhai](https://rhai.rs) expression to evaluate.\n2. Any context values that will be available to the Rhai expression by accessing a variable called `context`.\n\nThe return value is a [union](https://duckdb.org/docs/sql/data_types/union.html) type.  The union type is very similar to the [Result type from Rust](https://doc.rust-lang.org/std/result/).\n\nIf the Rhai expression was successfully evaluated the JSON result of the expression will be returned in the `ok` element of the union.  If there was an error evaluating the expression it will be returned in the `error` element of the expression.\n\n## When would I use this?\n\nYou should use this when you want to have a simple way to write business logic in a database and have it evaluated reasonably quickly.\n\n## Credits\n\n1. This DuckDB extension utilizes and is named after the [`rhai`](https://crates.io/crates/rhai).\n\n2. It also uses the [DuckDB Extension Template](https://github.com/duckdb/extension-template).\n\n3. This extension uses [Corrosion](https://github.com/corrosion-rs/corrosion) to combine CMake with a Rust/Cargo build process.\n\n4. I've gotten a lot of help from the generous DuckDB developer community.\n\n### Build Architecture\n\nFor the DuckDB extension to call the Rust code a tool called `cbindgen` is used to write the C++ headers for the exposed Rust interface.\n\nThe headers can be updated by running `make rust_binding_headers`.\n\n### Build steps\nNow to build the extension, run:\n```sh\nmake\n```\nThe main binaries that will be built are:\n```sh\n./build/release/duckdb\n./build/release/test/unittest\n./build/release/extension/evalexpr_rhai/evalexpr_rhai.duckdb_extension\n```\n- `duckdb` is the binary for the duckdb shell with the extension code automatically loaded.\n- `unittest` is the test runner of duckdb. Again, the extension is already linked into the binary.\n- `evalexpr_rhai.duckdb_extension` is the loadable binary as it would be distributed.\n\n## Running the extension\nTo run the extension code, simply start the shell with `./build/release/duckdb`.\n\nNow we can use the features from the extension directly in DuckDB.\n\n```\nD select evalexpr_rhai('42');\n┌───────────────────────────────┐\n│      evalexpr_rhai('42')      │\n│ union(ok json, error varchar) │\n├───────────────────────────────┤\n│ 42                            │\n└───────────────────────────────┘\n```\n\n## Running the tests\nDifferent tests can be created for DuckDB extensions. The primary way of testing DuckDB extensions should be the SQL tests in `./test/sql`. These SQL tests can be run using:\n```sh\nmake test\n```\n\n### Installing the deployed binaries\nTo install your extension binaries from S3, you will need to do two things. Firstly, DuckDB should be launched with the\n`allow_unsigned_extensions` option set to true. How to set this will depend on the client you're using. Some examples:\n\nCLI:\n```shell\nduckdb -unsigned\n```\n\nPython:\n```python\ncon = duckdb.connect(':memory:', config={'allow_unsigned_extensions' : 'true'})\n```\n\nNodeJS:\n```js\ndb = new duckdb.Database(':memory:', {\"allow_unsigned_extensions\": \"true\"});\n```\n\nSecondly, you will need to set the repository endpoint in DuckDB to the HTTP url of your bucket + version of the extension\nyou want to install. To do this run the following SQL query in DuckDB:\n```sql\nSET custom_extension_repository='bucket.s3.us-east-1.amazonaws.com/evalexpr_rhai/latest';\n```\nNote that the `/latest` path will allow you to install the latest extension version available for your current version of\nDuckDB. To specify a specific version, you can pass the version instead.\n\nAfter running these steps, you can install and load your extension using the regular INSTALL/LOAD commands in DuckDB:\n```sql\nINSTALL evalexpr_rhai\nLOAD evalexpr_rhai\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FQuery-farm%2Fevalexpr_rhai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FQuery-farm%2Fevalexpr_rhai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FQuery-farm%2Fevalexpr_rhai/lists"}