-
Notifications
You must be signed in to change notification settings - Fork 14
Add initial version of ParadeDB extension #122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
46d2dc3
824122a
fcbe268
c86df6b
5ed49e5
b255207
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| name: LocalStack ParadeDB Extension Tests | ||
|
|
||
| on: | ||
| push: | ||
| paths: | ||
| - paradedb/** | ||
| branches: | ||
| - main | ||
| pull_request: | ||
| paths: | ||
| - .github/workflows/paradedb.yml | ||
| - paradedb/** | ||
| workflow_dispatch: | ||
|
|
||
| env: | ||
| LOCALSTACK_DISABLE_EVENTS: "1" | ||
| LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }} | ||
|
|
||
| jobs: | ||
| integration-tests: | ||
| name: Run Integration Tests | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 10 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup LocalStack and extension | ||
| run: | | ||
| cd paradedb | ||
|
|
||
| docker pull localstack/localstack-pro & | ||
| docker pull paradedb/paradedb & | ||
| pip install localstack | ||
|
|
||
| make install | ||
| make lint | ||
| make dist | ||
| localstack extensions -v install file://$(ls ./dist/localstack_extension_paradedb-*.tar.gz) | ||
|
|
||
| DEBUG=1 localstack start -d | ||
| localstack wait | ||
|
|
||
| - name: Run integration tests | ||
| run: | | ||
| cd paradedb | ||
| make test | ||
|
|
||
| - name: Print logs | ||
| if: always() | ||
| run: | | ||
| localstack logs | ||
| localstack stop |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| { | ||
| description = "localstack-extensions"; | ||
|
|
||
| inputs = { | ||
| nixpkgs.url = "nixpkgs/nixpkgs-unstable"; | ||
| }; | ||
|
|
||
| outputs = { self, nixpkgs }@inputs: | ||
| ( | ||
| let | ||
| forAllSystems = nixpkgs.lib.genAttrs nixpkgs.lib.platforms.all; | ||
| in | ||
| { | ||
| devShell = forAllSystems (system: | ||
| let pkgs = import nixpkgs { inherit system; }; in | ||
| pkgs.mkShell { | ||
| buildInputs = with pkgs; [ uv python311 python311Packages.pip ty ]; | ||
| } | ||
| ); | ||
| } | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| .venv | ||
| dist | ||
| build | ||
| **/*.egg-info | ||
| .eggs |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| VENV_BIN = python3 -m venv | ||
| VENV_DIR ?= .venv | ||
| VENV_ACTIVATE = $(VENV_DIR)/bin/activate | ||
| VENV_RUN = . $(VENV_ACTIVATE) | ||
| TEST_PATH ?= tests | ||
|
|
||
| usage: ## Shows usage for this Makefile | ||
| @cat Makefile | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' | ||
|
|
||
| venv: $(VENV_ACTIVATE) | ||
|
|
||
| $(VENV_ACTIVATE): pyproject.toml | ||
| test -d .venv || $(VENV_BIN) .venv | ||
| $(VENV_RUN); pip install --upgrade pip setuptools plux | ||
| $(VENV_RUN); pip install -e .[dev] | ||
| touch $(VENV_DIR)/bin/activate | ||
|
|
||
| clean: | ||
| rm -rf .venv/ | ||
| rm -rf build/ | ||
| rm -rf .eggs/ | ||
| rm -rf *.egg-info/ | ||
|
|
||
| install: venv ## Install dependencies | ||
| $(VENV_RUN); python -m plux entrypoints | ||
|
|
||
| dist: venv ## Create distribution | ||
| $(VENV_RUN); python -m build | ||
|
|
||
| publish: clean-dist venv dist ## Publish extension to pypi | ||
| $(VENV_RUN); pip install --upgrade twine; twine upload dist/* | ||
|
|
||
| entrypoints: venv ## Generate plugin entrypoints for Python package | ||
| $(VENV_RUN); python -m plux entrypoints | ||
|
|
||
| format: ## Run ruff to format the codebase | ||
| $(VENV_RUN); python -m ruff format .; make lint | ||
|
|
||
| lint: ## Run ruff to lint the codebase | ||
| $(VENV_RUN); python -m ruff check --output-format=full . | ||
|
|
||
| test: ## Run integration tests (requires LocalStack running with the Extension installed) | ||
| $(VENV_RUN); pytest $(PYTEST_ARGS) $(TEST_PATH) | ||
|
|
||
| clean-dist: clean | ||
| rm -rf dist/ | ||
|
|
||
| .PHONY: clean clean-dist dist install publish usage venv format test |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| ParadeDB on LocalStack | ||
| ====================== | ||
|
|
||
| This repo contains a [LocalStack Extension](https://github.com/localstack/localstack-extensions) that facilitates developing [ParadeDB](https://www.paradedb.com)-based applications locally. | ||
|
|
||
| ParadeDB is an Elasticsearch alternative built on Postgres. It provides full-text search with BM25 scoring, hybrid search combining semantic and keyword search, and real-time analytics capabilities. | ||
|
|
||
| After installing the extension, a ParadeDB server instance will become available and can be accessed using standard PostgreSQL clients. | ||
|
|
||
| ## Connection Details | ||
|
|
||
| Once the extension is running, you can connect to ParadeDB using any PostgreSQL client with the following default credentials: | ||
|
|
||
| - **Host**: `localhost` (or the Docker host if running in a container) | ||
| - **Port**: `5432` (mapped from the container) | ||
| - **Database**: `mydatabase` | ||
| - **Username**: `myuser` | ||
| - **Password**: `mypassword` | ||
|
|
||
| Example connection using `psql`: | ||
| ```bash | ||
| psql -h localhost -p 5432 -U myuser -d mydatabase | ||
| ``` | ||
|
|
||
| Example connection using Python: | ||
| ```python | ||
| import psycopg2 | ||
|
|
||
| conn = psycopg2.connect( | ||
| host="localhost", | ||
| port=5432, | ||
| database="mydatabase", | ||
| user="myuser", | ||
| password="mypassword" | ||
| ) | ||
| ``` | ||
|
|
||
| ## ParadeDB Features | ||
|
|
||
| ParadeDB includes the **pg_search** extension, for both search and | ||
| analytics workloads. | ||
|
|
||
| Example using pg_search: | ||
| ```sql | ||
| -- Create a table with search index | ||
| CREATE TABLE products ( | ||
| id SERIAL PRIMARY KEY, | ||
| name TEXT, | ||
| description TEXT | ||
| ); | ||
|
|
||
| -- Create a BM25 search index | ||
| CALL paradedb.create_bm25( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is super wrong too. We have agents skills: https://docs.paradedb.com/welcome/ai-agents I'd recommend importing this to your Claude and trying again. |
||
| index_name => 'products_idx', | ||
| table_name => 'products', | ||
| key_field => 'id', | ||
| text_fields => paradedb.field('name') || paradedb.field('description') | ||
| ); | ||
|
|
||
| -- Search with BM25 scoring | ||
| SELECT * FROM products.search('description:electronics'); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is wrong |
||
| ``` | ||
|
|
||
| ## Configuration | ||
|
|
||
| The following environment variables can be passed to the LocalStack container to configure the extension: | ||
|
|
||
| * `PARADEDB_POSTGRES_USER`: PostgreSQL username (default: `myuser`) | ||
| * `PARADEDB_POSTGRES_PASSWORD`: PostgreSQL password (default: `mypassword`) | ||
| * `PARADEDB_POSTGRES_DB`: Default database name (default: `mydatabase`) | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| * Docker | ||
| * LocalStack Pro (free trial available) | ||
| * `localstack` CLI | ||
| * `make` | ||
|
|
||
| ## Install from GitHub repository | ||
|
|
||
| This extension can be installed directly from this Github repo via: | ||
|
|
||
| ```bash | ||
| localstack extensions install "git+https://github.com/localstack/localstack-extensions.git#egg=localstack-extension-paradedb&subdirectory=paradedb" | ||
| ``` | ||
|
|
||
| ## Install local development version | ||
|
|
||
| Please refer to the docs [here](https://github.com/localstack/localstack-extensions?tab=readme-ov-file#start-localstack-with-the-extension) for instructions on how to start the extension in developer mode. | ||
|
|
||
| ## Change Log | ||
|
|
||
| * `0.1.0`: Initial version of the extension | ||
|
|
||
| ## License | ||
|
|
||
| The code in this repo is available under the Apache 2.0 license. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| name = "localstack_paradedb" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| import os | ||
| import logging | ||
|
|
||
| from localstack_paradedb.utils.docker import DatabaseDockerContainerExtension | ||
|
|
||
| LOG = logging.getLogger(__name__) | ||
|
|
||
| # Environment variables for configuration | ||
| ENV_POSTGRES_USER = "PARADEDB_POSTGRES_USER" | ||
| ENV_POSTGRES_PASSWORD = "PARADEDB_POSTGRES_PASSWORD" | ||
| ENV_POSTGRES_DB = "PARADEDB_POSTGRES_DB" | ||
| ENV_POSTGRES_PORT = "PARADEDB_POSTGRES_PORT" | ||
|
|
||
| # Default values | ||
| DEFAULT_POSTGRES_USER = "myuser" | ||
| DEFAULT_POSTGRES_PASSWORD = "mypassword" | ||
| DEFAULT_POSTGRES_DB = "mydatabase" | ||
| DEFAULT_POSTGRES_PORT = 5432 | ||
|
|
||
|
|
||
| class ParadeDbExtension(DatabaseDockerContainerExtension): | ||
| name = "paradedb" | ||
|
|
||
| # Name of the Docker image to spin up | ||
| DOCKER_IMAGE = "paradedb/paradedb" | ||
|
|
||
| def __init__(self): | ||
| # Get configuration from environment variables | ||
| postgres_user = os.environ.get(ENV_POSTGRES_USER, DEFAULT_POSTGRES_USER) | ||
| postgres_password = os.environ.get(ENV_POSTGRES_PASSWORD, DEFAULT_POSTGRES_PASSWORD) | ||
| postgres_db = os.environ.get(ENV_POSTGRES_DB, DEFAULT_POSTGRES_DB) | ||
| postgres_port = int(os.environ.get(ENV_POSTGRES_PORT, DEFAULT_POSTGRES_PORT)) | ||
|
|
||
| # Environment variables to pass to the container | ||
| env_vars = { | ||
| "POSTGRES_USER": postgres_user, | ||
| "POSTGRES_PASSWORD": postgres_password, | ||
| "POSTGRES_DB": postgres_db, | ||
| } | ||
|
|
||
| super().__init__( | ||
| image_name=self.DOCKER_IMAGE, | ||
| container_ports=[postgres_port], | ||
| env_vars=env_vars, | ||
| ) | ||
|
|
||
| # Store configuration for connection info | ||
| self.postgres_user = postgres_user | ||
| self.postgres_password = postgres_password | ||
| self.postgres_db = postgres_db | ||
| self.postgres_port = postgres_port | ||
|
|
||
| def get_connection_info(self) -> dict: | ||
| """Return connection information for ParadeDB.""" | ||
| info = super().get_connection_info() | ||
| info.update({ | ||
| "database": self.postgres_db, | ||
| "user": self.postgres_user, | ||
| "password": self.postgres_password, | ||
| "port": self.postgres_port, | ||
| "connection_string": ( | ||
| f"postgresql://{self.postgres_user}:{self.postgres_password}" | ||
| f"@{self.container_host}:{self.postgres_port}/{self.postgres_db}" | ||
| ), | ||
| }) | ||
| return info |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use different values than
postgreshere. See: https://docs.paradedb.com/documentation/getting-started/install