├── .github └── workflows │ ├── publish.yml │ └── test.yml ├── .gitignore ├── README.md ├── pyproject.toml ├── sqlite_utils_jq.py └── tests └── test_jq.py /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] 16 | steps: 17 | - uses: actions/checkout@v3 18 | - name: Set up Python ${{ matrix.python-version }} 19 | uses: actions/setup-python@v4 20 | with: 21 | python-version: ${{ matrix.python-version }} 22 | cache: pip 23 | cache-dependency-path: setup.py 24 | - name: Install dependencies 25 | run: | 26 | pip install -e '.[test]' 27 | - name: Run tests 28 | run: | 29 | pytest 30 | deploy: 31 | runs-on: ubuntu-latest 32 | needs: [test] 33 | steps: 34 | - uses: actions/checkout@v3 35 | - name: Set up Python 36 | uses: actions/setup-python@v4 37 | with: 38 | python-version: "3.11" 39 | cache: pip 40 | cache-dependency-path: setup.py 41 | - name: Install dependencies 42 | run: | 43 | pip install setuptools wheel twine build 44 | - name: Publish 45 | env: 46 | TWINE_USERNAME: __token__ 47 | TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} 48 | run: | 49 | python -m build 50 | twine upload dist/* 51 | 52 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Set up Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v4 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | cache: pip 21 | cache-dependency-path: setup.py 22 | - name: Install dependencies 23 | run: | 24 | pip install -e '.[test]' 25 | - name: Run tests 26 | run: | 27 | pytest 28 | 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .venv 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | venv 6 | .eggs 7 | .pytest_cache 8 | *.egg-info 9 | .DS_Store 10 | .vscode 11 | dist 12 | build 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sqlite-utils-jq 2 | 3 | [![PyPI](https://img.shields.io/pypi/v/sqlite-utils-jq.svg)](https://pypi.org/project/sqlite-utils-jq/) 4 | [![Changelog](https://img.shields.io/github/v/release/simonw/sqlite-utils-jq?include_prereleases&label=changelog)](https://github.com/simonw/sqlite-utils-jq/releases) 5 | [![Tests](https://github.com/simonw/sqlite-utils-jq/workflows/Test/badge.svg)](https://github.com/simonw/sqlite-utils-jq/actions?query=workflow%3ATest) 6 | [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/simonw/sqlite-utils-jq/blob/main/LICENSE) 7 | 8 | Plugin adding a `jq()` SQL function to [sqlite-utils](https://sqlite-utils.datasette.io/). 9 | 10 | ## Installation 11 | 12 | Install this plugin in the same environment as `sqlite-utils`: 13 | ```bash 14 | sqlite-utils install sqlite-utils-jq 15 | ``` 16 | 17 | ## Usage 18 | 19 | This plugin adds a `jq()` function for executing [jq](https://jqlang.github.io/jq/) programs against JSON values. 20 | 21 | ```bash 22 | sqlite-utils memory "select jq(:doc, :expr) as result" \ 23 | -p doc '{"foo": "bar"}' \ 24 | -p expr '.foo' \ 25 | --table 26 | ``` 27 | Output: 28 | ``` 29 | result 30 | -------- 31 | "bar" 32 | ``` 33 | 34 | ## Development 35 | 36 | To set up this plugin locally, first checkout the code. Then create a new virtual environment: 37 | 38 | cd sqlite-utils-jq 39 | python3 -m venv venv 40 | source venv/bin/activate 41 | 42 | Now install the dependencies and test dependencies: 43 | 44 | pip install -e '.[test]' 45 | 46 | To run the tests: 47 | 48 | pytest 49 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "sqlite-utils-jq" 3 | version = "0.1" 4 | description = "Plugin adding a jq() SQL function to sqlite-utils" 5 | readme = "README.md" 6 | authors = [{name = "Simon Willison"}] 7 | license = {text = "Apache-2.0"} 8 | classifiers = [ 9 | "License :: OSI Approved :: Apache Software License" 10 | ] 11 | dependencies = [ 12 | "sqlite-utils", 13 | "jq" 14 | ] 15 | 16 | [project.optional-dependencies] 17 | test = ["pytest"] 18 | 19 | [project.urls] 20 | Homepage = "https://github.com/simonw/sqlite-utils-jq" 21 | Changelog = "https://github.com/simonw/sqlite-utils-jq/releases" 22 | Issues = "https://github.com/simonw/sqlite-utils-jq/issues" 23 | 24 | [project.entry-points.sqlite_utils] 25 | jq = "sqlite_utils_jq" 26 | -------------------------------------------------------------------------------- /sqlite_utils_jq.py: -------------------------------------------------------------------------------- 1 | import jq 2 | import json 3 | import sqlite_utils 4 | 5 | 6 | def sqlite_jq(value, expression): 7 | try: 8 | return json.dumps(jq.first(expression, json.loads(value))) 9 | except Exception as ex: 10 | return json.dumps({"error": str(ex)}) 11 | 12 | 13 | @sqlite_utils.hookimpl 14 | def prepare_connection(conn): 15 | conn.create_function("jq", 2, sqlite_jq) 16 | -------------------------------------------------------------------------------- /tests/test_jq.py: -------------------------------------------------------------------------------- 1 | import sqlite_utils 2 | 3 | 4 | def test_jq(): 5 | db = sqlite_utils.Database(memory=True) 6 | result = list(db.query("select jq(?, ?) as result", ('{"foo": "bar"}', ".foo"))) 7 | assert result == [{"result": '"bar"'}] 8 | --------------------------------------------------------------------------------