{"id":17757839,"url":"https://github.com/cipherstash/encrypt-query-language","last_synced_at":"2025-04-09T16:38:09.620Z","repository":{"id":258020743,"uuid":"860197522","full_name":"cipherstash/encrypt-query-language","owner":"cipherstash","description":"Index and search encrypted data in PostgreSQL with SQL","archived":false,"fork":false,"pushed_at":"2025-04-02T22:58:21.000Z","size":6312,"stargazers_count":18,"open_issues_count":2,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-02T23:30:11.119Z","etag":null,"topics":["encryption","encryption-in-use","postgres","postgresql","security"],"latest_commit_sha":null,"homepage":"https://cipherstash.com/docs","language":"PLpgSQL","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/cipherstash.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":"2024-09-20T02:11:56.000Z","updated_at":"2025-04-02T22:58:23.000Z","dependencies_parsed_at":"2024-11-13T00:17:21.744Z","dependency_job_id":"0a80bcf5-57d0-420b-b382-393d103bd4c3","html_url":"https://github.com/cipherstash/encrypt-query-language","commit_stats":null,"previous_names":["cipherstash/encrypt-query-language"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cipherstash%2Fencrypt-query-language","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cipherstash%2Fencrypt-query-language/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cipherstash%2Fencrypt-query-language/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cipherstash%2Fencrypt-query-language/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cipherstash","download_url":"https://codeload.github.com/cipherstash/encrypt-query-language/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248068543,"owners_count":21042515,"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":["encryption","encryption-in-use","postgres","postgresql","security"],"created_at":"2024-10-26T17:09:09.618Z","updated_at":"2025-04-09T16:38:09.613Z","avatar_url":"https://github.com/cipherstash.png","language":"PLpgSQL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Encrypt Query Language (EQL)\n\n[![Test EQL](https://github.com/cipherstash/encrypt-query-language/actions/workflows/test-eql.yml/badge.svg?branch=main)](https://github.com/cipherstash/encrypt-query-language/actions/workflows/test-eql.yml)\n[![Release EQL](https://github.com/cipherstash/encrypt-query-language/actions/workflows/release-eql.yml/badge.svg?branch=main)](https://github.com/cipherstash/encrypt-query-language/actions/workflows/release-eql.yml)\n\nEncrypt Query Language (EQL) is a set of abstractions for transmitting, storing, and interacting with encrypted data and indexes in PostgreSQL.\n\n\u003e [!TIP]\n\u003e **New to EQL?** Start with the higher level helpers for EQL in [Python](https://github.com/cipherstash/eqlpy), [Go](https://github.com/cipherstash/goeql), or [JavaScript](https://github.com/cipherstash/jseql) and [TypeScript](https://github.com/cipherstash/jseql), or the [examples](#helper-packages-and-examples) for those languages.\n\nStore encrypted data alongside your existing data:\n\n- Encrypted data is stored using a `jsonb` column type\n- Query encrypted data with specialized SQL functions\n- Index encrypted columns to enable searchable encryption\n- Integrate with [CipherStash Proxy](/docs/tutorials/PROXY.md) for transparent encryption/decryption.\n\n## Table of Contents\n\n- [Installation](#installation)\n  - [CipherStash Proxy](#cipherstash-proxy)\n- [Documentation](#documentation)\n- [Getting started](#getting-started)\n  - [Enable encrypted columns](#enable-encrypted-columns)\n  - [Configuring the column](#configuring-the-column)\n  - [Activating configuration](#activating-configuration)\n    - [Refreshing CipherStash Proxy Configuration](#refreshing-cipherstash-proxy-configuration)\n- [Storing data](#storing-data)\n  - [Inserting Data](#inserting-data)\n  - [Reading Data](#reading-data)\n- [Configuring indexes for searching data](#configuring-indexes-for-searching-data)\n  - [Adding an index (`cs_add_index_v1`)](#adding-an-index-cs_add_index_v1)\n- [Searching data with EQL](#searching-data-with-eql)\n  - [Equality search (`cs_unique_v1`)](#equality-search-cs_unique_v1)\n  - [Full-text search (`cs_match_v1`)](#full-text-search-cs_match_v1)\n  - [Range queries (`cs_ore_64_8_v1`)](#range-queries-cs_ore_64_8_v1)\n- [JSON and JSONB support](#json-and-jsonb-support)\n- [Frequently Asked Questions](#frequently-asked-questions)\n  - [How do I integrate CipherStash EQL with my application?](#how-do-i-integrate-cipherstash-eql-with-my-application)\n  - [Can I use EQL without the CipherStash Proxy?](#can-i-use-eql-without-the-cipherstash-proxy)\n  - [How is data encrypted in the database?](#how-is-data-encrypted-in-the-database)\n- [Helper packages](#helper-packages-and-examples)\n- [Releasing](#releasing)\n- [Developing](#developing)\n- [Testing](#testing)\n\n---\n\n## Installation\n\nThe simplest way to get up and running with EQL is to execute the install SQL file directly in your PostgreSQL database.\n\n1. Download the latest EQL install script:\n\n   ```sh\n   curl -sLo cipherstash-encrypt.sql https://github.com/cipherstash/encrypt-query-language/releases/latest/download/cipherstash-encrypt.sql\n   ```\n\n2. Run this command to install the custom types and functions:\n\n   ```sh\n   psql -f cipherstash-encrypt.sql\n   ```\n\n### CipherStash Proxy\n\nEQL relies on [CipherStash Proxy](docs/tutorials/PROXY.md) for low-latency encryption \u0026 decryption.\nWe plan to support direct language integration in the future.\n\nIf you want to use CipherStash Proxy with the below examples or the [helper packages](#helper-packages-and-examples), you can use the [playground environment](playground/README.md).\n\n## Documentation\n\nYou can read more about the EQL concepts and reference guides in the [documentation directory](docs/README.md).\n\n## Getting started\n\nOnce the custom types and functions are installed in your PostgreSQL database, you can start using EQL in your queries.\n\n### Enable encrypted columns\n\nDefine encrypted columns using the `cs_encrypted_v1` domain type, which extends the `jsonb` type with additional constraints to ensure data integrity.\n\n**Example:**\n\n```sql\nCREATE TABLE users (\n    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n    encrypted_email cs_encrypted_v1\n);\n```\n\n### Configuring the column\n\nInitialize the column using the `cs_add_column_v1` function to enable encryption and decryption via CipherStash Proxy.\n\n```sql\nSELECT cs_add_column_v1('users', 'encrypted_email');\n```\n\n**Note:** This function allows you to encrypt and decrypt data but does not enable searchable encryption. See [Querying Data with EQL](#querying-data-with-eql) for enabling searchable encryption.\n\n### Activating configuration\n\nAfter modifying configurations, activate them by running:\n\n```sql\nSELECT cs_encrypt_v1();\nSELECT cs_activate_v1();\n```\n\n**Important:** These functions must be run after any modifications to the configuration.\n\n#### Refreshing CipherStash Proxy Configuration\n\nCipherStash Proxy refreshes the configuration every 60 seconds. To force an immediate refresh, run:\n\n```sql\nSELECT cs_refresh_encrypt_config();\n```\n\n\u003e Note: This statement must be executed when connected to CipherStash Proxy.\n\u003e When connected to the database directly, it is a no-op.\n\n## Storing data\n\nEncrypted data is stored as `jsonb` values in the PostgreSQL database, regardless of the original data type.\n\nYou can read more about the data format [here](docs/reference/PAYLOAD.md).\n\n### Inserting Data\n\nWhen inserting data into the encrypted column, wrap the plaintext in the appropriate EQL payload. These statements must be run through the CipherStash Proxy to **encrypt** the data.\n\n**Example:**\n\n```sql\nINSERT INTO users (encrypted_email) VALUES (\n  '{\"v\":1,\"k\":\"pt\",\"p\":\"test@example.com\",\"i\":{\"t\":\"users\",\"c\":\"encrypted_email\"}}'\n);\n```\n\nData is stored in the PostgreSQL database as:\n\n```json\n{\n  \"c\": \"generated_ciphertext\",\n  \"i\": {\n    \"c\": \"encrypted_email\",\n    \"t\": \"users\"\n  },\n  \"k\": \"ct\",\n  \"m\": null,\n  \"o\": null,\n  \"u\": null,\n  \"v\": 1\n}\n```\n\n### Reading Data\n\nWhen querying data, select the encrypted column. CipherStash Proxy will **decrypt** the data automatically.\n\n**Example:**\n\n```sql\nSELECT encrypted_email FROM users;\n```\n\nData is returned as:\n\n```json\n{\n  \"k\": \"pt\",\n  \"p\": \"test@example.com\",\n  \"i\": {\n    \"t\": \"users\",\n    \"c\": \"encrypted_email\"\n  },\n  \"v\": 1,\n  \"q\": null\n}\n```\n\n\u003e Note: If you execute this query directly on the database, you will not see any plaintext data but rather the `jsonb` payload with the ciphertext.\n\n## Configuring indexes for searching data\n\nIn order to perform searchable operations on encrypted data, you must configure indexes for the encrypted columns.\n\n\u003e **IMPORTANT:** If you have existing data that's encrypted and you add or modify an index, all the data will need to be re-encrypted.\n\u003e This is due to the way CipherStash Proxy handles searchable encryption operations.\n\n### Adding an index (`cs_add_index_v1`)\n\nAdd an index to an encrypted column.\nThis function also behaves the same as `cs_add_column_v1` but with the additional index configuration.\n\n```sql\nSELECT cs_add_index_v1(\n  'table_name',       -- Name of the table\n  'column_name',      -- Name of the column\n  'index_name',       -- Index kind ('unique', 'match', 'ore', 'ste_vec')\n  'cast_as',          -- PostgreSQL type to cast decrypted data ('text', 'int', etc.)\n  'opts'              -- Index options as JSONB (optional)\n);\n```\n\nYou can read more about the index configuration options [here](docs/reference/INDEX.md).\n\n**Example (Unique index):**\n\n```sql\nSELECT cs_add_index_v1(\n  'users',\n  'encrypted_email',\n  'unique',\n  'text'\n);\n```\n\nAfter adding an index, you have to activate the configuration.\n\n```sql\nSELECT cs_encrypt_v1();\nSELECT cs_activate_v1();\n```\n\n## Searching data with EQL\n\nEQL provides specialized functions to interact with encrypted data, supporting operations like equality checks, range queries, and unique constraints.\n\nIn order to use the specialized functions, you must first configure the corresponding indexes.\n\n### Equality search (`cs_unique_v1`)\n\nEnable equality search on encrypted data.\n\n**Index configuration example:**\n\n```sql\nSELECT cs_add_index_v1(\n  'users',\n  'encrypted_email',\n  'unique',\n  'text'\n);\n```\n\n**Example:**\n\n```sql\nSELECT * FROM users\nWHERE cs_unique_v1(encrypted_email) = cs_unique_v1(\n  '{\"v\":1,\"k\":\"pt\",\"p\":\"test@example.com\",\"i\":{\"t\":\"users\",\"c\":\"encrypted_email\"},\"q\":\"unique\"}'\n);\n```\n\nEquivalent plaintext query:\n\n```sql\nSELECT * FROM users WHERE email = 'test@example.com';\n```\n\n### Full-text search (`cs_match_v1`)\n\nEnables basic full-text search on encrypted data.\n\n**Index configuration example:**\n\n```sql\nSELECT cs_add_index_v1(\n  'users',\n  'encrypted_email',\n  'match',\n  'text',\n  '{\"token_filters\": [{\"kind\": \"downcase\"}], \"tokenizer\": { \"kind\": \"ngram\", \"token_length\": 3 }}'\n);\n```\n\n**Example:**\n\n```sql\nSELECT * FROM users\nWHERE cs_match_v1(encrypted_email) @\u003e cs_match_v1(\n  '{\"v\":1,\"k\":\"pt\",\"p\":\"test\",\"i\":{\"t\":\"users\",\"c\":\"encrypted_email\"},\"q\":\"match\"}'\n);\n```\n\nEquivalent plaintext query:\n\n```sql\nSELECT * FROM users WHERE email LIKE '%test%';\n```\n\n### Range queries (`cs_ore_64_8_v1`)\n\nEnable range queries on encrypted data. Supports:\n\n- `ORDER BY`\n- `WHERE`\n\n**Example (Filtering):**\n\n```sql\nSELECT * FROM users\nWHERE cs_ore_64_8_v1(encrypted_date) \u003c cs_ore_64_8_v1(\n  '{\"v\":1,\"k\":\"pt\",\"p\":\"2023-10-05\",\"i\":{\"t\":\"users\",\"c\":\"encrypted_date\"},\"q\":\"ore\"}'\n);\n```\n\nEquivalent plaintext query:\n\n```sql\nSELECT * FROM users WHERE date \u003c '2023-10-05';\n```\n\n**Example (Ordering):**\n\n```sql\nSELECT id FROM users\nORDER BY cs_ore_64_8_v1(encrypted_field) DESC;\n```\n\nEquivalent plaintext query:\n\n```sql\nSELECT id FROM users ORDER BY field DESC;\n```\n\n**Example (Grouping):**\n\n```sql\nSELECT cs_grouped_value_v1(encrypted_field) COUNT(*)\n  FROM users\n  GROUP BY cs_ore_64_8_v1(encrypted_field)\n```\n\nEquivalent plaintext query:\n\n```sql\nSELECT field, COUNT(*) FROM users GROUP BY field;\n```\n\n## JSON and JSONB support\n\nEQL supports encrypting entire JSON and JSONB data sets.\nThis warrants a separate section in the documentation.\nYou can read more about the JSONB support in the [JSONB reference guide](docs/reference/JSON.md).\n\n## Frequently Asked Questions\n\n### How do I integrate CipherStash EQL with my application?\n\nUse CipherStash Proxy to intercept PostgreSQL queries and handle encryption and decryption automatically.\nThe proxy interacts with the database using the EQL functions and types defined in this documentation.\n\nUse the [helper packages](#helper-packages) to integate EQL functions into your application.\n\n### Can I use EQL without the CipherStash Proxy?\n\nNo, CipherStash Proxy is required to handle the encryption and decryption operations based on the configurations and indexes defined.\n\n### How is data encrypted in the database?\n\nData is encrypted using CipherStash's cryptographic schemes and stored in the `cs_encrypted_v1` column as a JSONB payload.\nEncryption and decryption are handled by CipherStash Proxy.\n\n## Helper packages and examples\n\nWe've created a few langauge specific packages to help you interact with the payloads:\n\n| Language   | ORM         | Example                                                           | Package                                                          |\n| ---------- | ----------- | ----------------------------------------------------------------- | ---------------------------------------------------------------- |\n| Go         | Xorm        | [Go/Xorm examples](./examples/go/xorm/README.md)                 | [goeql](https://github.com/cipherstash/goeql) |\n| TypeScript | Drizzle     | [Drizzle examples](./examples/javascript/apps/drizzle/README.md) | [jseql](https://github.com/cipherstash/jseql) |\n| TypeScript | Prisma      | [Drizzle examples](./examples/javascript/apps/prisma/README.md)  | [jseql](https://github.com/cipherstash/jseql) |\n| Python     | SQL Alchemy | [Python examples](./examples/python/jupyter_notebook/README.md)  | [eqlpy](https://github.com/cipherstash/eqlpy) |\n\n### Language specific packages\n\n- [Go](https://github.com/cipherstash/goeql)\n- [JavaScript/TypeScript](https://github.com/cipherstash/jseql)\n- [Python](https://github.com/cipherstash/eqlpy)\n\n## Releasing\n\nTo cut a [release](https://github.com/cipherstash/encrypt-query-language/releases) of EQL:\n\n1. Draft a [new release](https://github.com/cipherstash/encrypt-query-language/releases/new) on GitHub.\n1. Choose a tag, and create a new one with the prefix `eql-` followed by a [semver](https://semver.org/) (for example, `eql-1.2.3`).\n1. Generate the release notes.\n1. Optionally set the release to be the latest (you can set a release to be latest later on if you are testing out a release first).\n1. Click `Publish release`.\n\nThis will trigger the [Release EQL](https://github.com/cipherstash/encrypt-query-language/actions/workflows/release-eql.yml) workflow, which will build and attach artifacts to [the release](https://github.com/cipherstash/encrypt-query-language/releases/).\n\n## Developing\n\n\u003e [!IMPORTANT]\n\u003e **Before you follow the quickstart** you need to have this software installed:\n\u003e  - [mise](https://mise.jdx.dev/) — see the [installing mise](#installing-mise) instructions\n\u003e  - [Docker](https://www.docker.com/) — see Docker's [documentation for installing](https://docs.docker.com/get-started/get-docker/)\n\nLocal development quickstart:\n\n``` shell\n# Clone the repo\ngit clone https://github.com/cipherstash/encrypt-query-language\ncd encrypt-query-language\n\n# Install dependencies\nmise trust --yes\n\n# Build EQL installer and uninstaller, outputting to release/\nmise run build\n\n# Start a postgres instance (defaults to PostgreSQL 17)\nmise run postgres:up --extra-args \"--detach --wait\"\n\n# Run the tests (defaults to PostgreSQL 17)\nmise run test\n\n# Stop and remove all containers and networks\nmise run postgres:down\n```\n\n### Installing mise\n\n\u003e [!IMPORTANT]\n\u003e You must complete this step to set up a local development environment.\n\nLocal development and task running in CI is managed through [mise](https://mise.jdx.dev/).\n\nTo install mise:\n\n- If you're on macOS, run `brew install mise`\n- If you're on another platform, check out the mise [installation methods documentation](https://mise.jdx.dev/installing-mise.html#installation-methods)\n\nThen add mise to your shell:\n\n```shell\n# If you're running Bash\necho 'eval \"$(mise activate bash)\"' \u003e\u003e ~/.bashrc\n\n# If you're running Zsh\necho 'eval \"$(mise activate zsh)\"' \u003e\u003e ~/.zshrc\n```\n\nWe use [`cargo-binstall`](https://github.com/cargo-bins/cargo-binstall) for faster installation of tools installed via `mise` and Cargo.\nWe install `cargo-binstall` via `mise` when installing development and testing dependencies.\n\n\u003e [!TIP]\n\u003e We provide abbreviations for most of the commands that follow.\n\u003e For example, `mise run postgres:setup` can be abbreviated to `mise r s`.\n\u003e Run `mise tasks --extended` to see the task shortcuts.\n\n### How this project is organised\n\nDevelopment is managed through [mise](https://mise.jdx.dev/), both locally and [in CI](https://github.com/cipherstash/encrypt-query-language/actions).\n\nmise has tasks for:\n\n- Building EQL install and uninstall scripts (`build`)\n- Starting and stopping PostgreSQL containers (`postgres:up`, `postgres:down`)\n- Running unit and integration tests (`test`, `reset`)\n\nThese are the important files in the repo:\n\n```\n.\n├── mise.toml              \u003c-- the main config file for mise\n├── tasks/                 \u003c-- mise tasks\n├── sql/                   \u003c-- The individual SQL components that make up EQL\n├── docs/                  \u003c-- Tutorial, reference, and concept documentation\n├── tests/                 \u003c-- Unit and integration tests\n│   ├── docker-compose.yml \u003c-- Docker configuration for running PostgreSQL instances\n│   └── *.sql              \u003c-- Individual unit and integration tests\n├── release/               \u003c-- Build artifacts produced by the `build` task\n├── examples/              \u003c-- Example uses of EQL in different languages\n└── playground/            \u003c-- Playground enviroment for experimenting with EQL and CipherStash Proxy\n```\n\n## Testing\n\nThere are tests for checking EQL against PostgreSQL versions 14–17, that verify:\n\n- Adding, removing, and modifying encrypted data and indexes\n- Validating, applying, and removing configuration for encrypted data and encrypted indexes\n- Validating schemas for EQL configuration, encrypted data, and encrypted indexes\n- Using PostgreSQL operators on encrypted data and indexes (`=`, `\u003c\u003e`, `@\u003e`)\n\nThe easiest way to run the tests [is in GitHub Actions](./.github/workflows/test-eql.yml):\n\n- Automatically whenever there are changes in the `sql/`, `tests/`, or `tasks/` directories\n- By manually running [the workflow](https://github.com/cipherstash/encrypt-query-language/actions/workflows/test-eql.yml)\n\nThis is how the `test-eql.yml` workflow functions:\n\n```mermaid\n---\ntitle: Testing EQL\n---\nstateDiagram-v2\n    direction LR\n    classDef code font-family:monospace;\n\n\n    state \"🧍 Human makes changes to EQL sources\" as changes\n    state sources_fork \u003c\u003cfork\u003e\u003e\n    state sources_join \u003c\u003cjoin\u003e\u003e\n    state \"sql/*.sql\" as source_sql\n    state \"tasks/**/*\" as source_tasks\n    state \"tests/**/*\" as source_tests\n    state sources_changed \u003c\u003cchoice\u003e\u003e\n\n    state \"🛠️ Trigger GitHub Actions workflow test-eql.yml\" as build_triggered\n    state \"Matrix: Test EQL SQL components\" as matrix\n    state \"Test with Postgres 14\" as pg14\n    state \"Test with Postgres 15\" as pg15\n    state \"Test with Postgres 16\" as pg16\n    state \"Test with Postgres 17\" as pg17\n    state \"Check build results\" as check\n    state if_state \u003c\u003cchoice\u003e\u003e\n\n    changes --\u003e sources_fork\n    sources_fork --\u003e source_sql:::code\n    sources_fork --\u003e source_tests:::code\n    sources_fork --\u003e source_tasks:::code\n    source_sql --\u003e sources_join\n    source_tests --\u003e sources_join\n    source_tasks --\u003e sources_join\n    sources_join --\u003e source_changed_check\n    source_changed_check --\u003e sources_changed\n    sources_changed --\u003e build_triggered : Some changes\n    sources_changed --\u003e [*]: No changes\n\n    state \"Check source changes\" as source_changed_check\n\n    [*] --\u003e changes\n\n    build_triggered --\u003e matrix\n\n    state fork_state \u003c\u003cfork\u003e\u003e\n        matrix --\u003e fork_state\n        fork_state --\u003e pg14\n        fork_state --\u003e pg15\n        fork_state --\u003e pg16\n        fork_state --\u003e pg17\n\n    state join_state \u003c\u003cjoin\u003e\u003e\n        pg14 --\u003e join_state\n        pg15 --\u003e join_state\n        pg16 --\u003e join_state\n        pg17 --\u003e join_state\n\n    state \"✅ Pass build\" as build_pass\n    state \"❌ Fail build\" as build_fail\n    join_state --\u003e check\n    check --\u003e if_state\n    if_state --\u003e build_pass: All success\n    if_state --\u003e build_fail : Any failures\n    build_pass --\u003e [*]\n    build_fail --\u003e [*]\n```\n\nYou can also [run the tests locally](#running-tests-locally) when doing local development.\n\n### Running tests locally\n\n\u003e [!IMPORTANT]\n\u003e **Before you run the tests locally** you need to [set up a local dev environment](#developing).\n\nTo run tests locally with PostgreSQL 17:\n\n``` shell\n# Start a postgres instance (defaults to PostgreSQL 17)\nmise run postgres:up --extra-args \"--detach --wait\"\n\n# Run the tests (defaults to PostgreSQL 17)\nmise run test\n\n# Stop and remove all containers and networks\nmise run postgres:down\n```\n\nYou can run the same tasks for Postgres 14, 15, 16, and 17 by specifying arguments:\n\n```shell\n# Start a postgres 14 instance\nmise run postgres:up postgres-14 --extra-args \"--detach --wait\"\n\n# Run the tests against postgres 14\nmise run test --postgres 14\n\n# Stop postgres and remove all containers and networks\nmise run postgres:down\n```\n\nThe configuration for the Postgres containers in `tests/docker-compose.yml`.\n\nLimitations:\n\n- **Volumes for Postgres containers are not persistent.**\n  If you need to look at data in the container, uncomment a volume in\n  `tests/docker-compose.yml`\n- **You can't run multiple Postgres containers at the same time.**\n  All the containers bind to the same port (`7543`). If you want to run\n  multiple containers at the same time, you have to change the ports by\n  editing `tests/docker-compose.yml`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcipherstash%2Fencrypt-query-language","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcipherstash%2Fencrypt-query-language","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcipherstash%2Fencrypt-query-language/lists"}