Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ If none exist, a read-only in-memory SQLite database is used (useful for testing

## Config schema for named queries

Use top-level `queries` for shared/global named queries and `connection_queries` for connection-specific SQL. `connection_queries` is the canonical schema for scoped queries: connection name -> query name -> SQL.
Use top-level `queries` for shared/global named queries and optional `connection_queries` for connection-specific SQL. `connection_queries` is the canonical schema for scoped queries: connection name -> query name -> SQL. Existing configs that omit `connection_queries` continue to work unchanged.

```json
{
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.3.0] - 2026-06-22

### Added
- Connection-scoped named queries via top-level `connection_queries`. The canonical shape is `connection_queries.<connection>.<query_name>`, allowing per-connection or per-dialect SQL while keeping existing top-level `queries` as shared/global queries.
- Agent-friendly scoped query discovery: `--list-queries` now returns `{"global": [...], "connections": {...}}` by default, and `--list-queries legacy` preserves the previous flat global-query list for compatibility.
- Public Python query discovery helpers: `list_queries(config_path, scoped=True)` returns the scoped discovery object, and `list_queries(config_path, connection="name")` returns effective query names for one connection.
- Official Docker image published to [`docker.io/fsistemas/sql2json`](https://hub.docker.com/r/fsistemas/sql2json), so the tool can be run with `podman run docker.io/fsistemas/sql2json ...` (or `docker run ...`) without building from source. It is now published as a multi-arch image for `linux/amd64` and `linux/arm64`. Supported tags: `latest` (newest stable) and immutable `X.Y.Z` (pinned). Documented in the README "Docker" section.

### Changed
- Named query lookup is now connection-aware: `sql2json --name <connection> --query <query>` checks `connection_queries.<connection>.<query>` first, then falls back to global `queries.<query>`, then preserves existing raw SQL / `@file.sql` behavior.
- Existing configs that only define top-level `queries` remain backwards-compatible; `queries` is now documented as the shared/global query scope.
- The `Dockerfile` now installs `sql2json` from PyPI (build arg `VERSION` pins a release; omitted installs the latest) instead of copying the working tree, so a tagged image always matches the published release. Its entrypoint is now the `sql2json` console script (was `python -m sql2json`), and it carries OCI image labels.
- Documented the local (Podman / Docker) image publish + verify step in `RELEASING.md` and CLAUDE.md, run after the PyPI publish. The tested multi-arch local path is rootful Podman (`sudo podman`) with host-level QEMU/binfmt on an amd64 maintainer machine.
- Reworked install/upgrade instructions across `README.md`, `AGENTS.md`, and `skills/sql2json/SKILL.md` to be cross-platform and environment-aware (Linux, macOS, Windows). The recommended install is now an isolated tool (`uv tool install` / `pipx install`) that bundles the Postgres and MySQL drivers by default (`"sql2json[postgres,mysql]"`), works on PEP 668 externally-managed systems, and documents the extras-quoting gotcha, the SQLite-only minimal variant, adding drivers later, the `--break-system-packages` escape hatch, and how to upgrade while keeping the drivers.
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ docker run --rm docker.io/fsistemas/sql2json --query "SELECT 1 AS a, 2 AS b"
# Build the Docker image (installs sql2json from PyPI; pass VERSION to pin a
# release, omit it for the latest). `podman build ...` works identically.
docker build -t sql2json . # latest PyPI release
docker build --build-arg VERSION=0.2.1 -t sql2json .
docker build --build-arg VERSION=0.3.0 -t sql2json .
# The official image is published at docker.io/fsistemas/sql2json (see RELEASING.md).
```

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ docker run --rm docker.io/fsistemas/sql2json --query "SELECT 1 AS a, 2 AS b"
| Tag | Meaning |
|---|---|
| `latest` | Newest **stable** release. Moves on every release — convenient, but not pinned. |
| `X.Y.Z` (e.g. `0.2.1`) | A specific release. **Immutable** — recommended for production and CI. |
| `X.Y.Z` (e.g. `0.3.0`) | A specific release. **Immutable** — recommended for production and CI. |

```bash
podman pull docker.io/fsistemas/sql2json:0.2.1 # pin a release
podman pull docker.io/fsistemas/sql2json:0.3.0 # pin a release
podman pull docker.io/fsistemas/sql2json:latest # newest stable
```

Expand Down Expand Up @@ -236,7 +236,7 @@ local checkout instead — for example to try an unreleased change — pass the

```bash
podman build -t sql2json . # latest PyPI release
podman build --build-arg VERSION=0.2.1 -t sql2json . # pin a release
podman build --build-arg VERSION=0.3.0 -t sql2json . # pin a release
podman run --rm sql2json --query "SELECT 1 AS a, 2 AS b"
```

Expand Down Expand Up @@ -415,7 +415,7 @@ Use `--config /path/to/config.json` to override.

Connection strings follow [SQLAlchemy URL format](https://docs.sqlalchemy.org/en/20/core/engines.html#database-urls). Query values starting with `@` are treated as paths to `.sql` files.

`connection_queries` is the canonical schema for queries that are valid only for a specific connection or SQL dialect. Its shape is a top-level map of connection name to query-name to SQL. `queries` remains valid for shared/global named queries that can run unchanged across connections.
`connection_queries` is optional and only needed for queries that are valid for a specific connection or SQL dialect. Its shape is a top-level map of connection name to query-name to SQL. Existing configs that omit this key continue to work unchanged; `queries` remains valid for shared/global named queries that can run unchanged across connections.

Named query lookup is connection-aware: `sql2json --name postgres --query now` first checks `connection_queries.postgres.now`; if it is not present, it falls back to `queries.now`; if neither exists, `--query` is treated as raw SQL or an `@/path.sql` file reference.

Expand Down
54 changes: 27 additions & 27 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ requesting one rather than bumping the version yourself.
1. **Bump the version** in `pyproject.toml`:

```toml
version = "0.2.1"
version = "0.3.0"
```

`sql2json` is pre-1.0 and follows [Semantic Versioning](https://semver.org/)
Expand All @@ -30,7 +30,7 @@ requesting one rather than bumping the version yourself.
`pyproject.toml` is the only place to edit.

2. **Update `CHANGELOG.md`** — move the `[Unreleased]` entries into a new dated
`[0.2.1]` section at the top, following
`[0.3.0]` section at the top, following
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format.

3. **Run the full quality gates** (everything CI enforces):
Expand All @@ -46,13 +46,13 @@ requesting one rather than bumping the version yourself.

```bash
git add pyproject.toml CHANGELOG.md
git commit -m "chore: bump version to 0.2.1"
git commit -m "chore: bump version to 0.3.0"
```

5. **Tag** (always prefix with `v`):

```bash
git tag v0.2.1
git tag v0.3.0
```

6. **Push the commit and tag together**:
Expand All @@ -64,7 +64,7 @@ requesting one rather than bumping the version yourself.
7. **Build and publish to PyPI**:

```bash
uv build # produces dist/sql2json-0.2.1.tar.gz and the wheel
uv build # produces dist/sql2json-0.3.0.tar.gz and the wheel
uv publish # uploads to PyPI
```

Expand Down Expand Up @@ -115,14 +115,14 @@ requesting one rather than bumping the version yourself.
# must print: aarch64

sudo podman login docker.io
sudo podman manifest rm docker.io/fsistemas/sql2json:0.2.1 2>/dev/null || true
sudo podman manifest rm docker.io/fsistemas/sql2json:0.3.0 2>/dev/null || true
sudo podman build --platform linux/amd64,linux/arm64 --pull=always \
--build-arg VERSION=0.2.1 \
--manifest docker.io/fsistemas/sql2json:0.2.1 .
sudo podman manifest push docker.io/fsistemas/sql2json:0.2.1 \
docker.io/fsistemas/sql2json:0.2.1
--build-arg VERSION=0.3.0 \
--manifest docker.io/fsistemas/sql2json:0.3.0 .
sudo podman manifest push docker.io/fsistemas/sql2json:0.3.0 \
docker.io/fsistemas/sql2json:0.3.0
# Stable releases only — also publish the moving `latest` tag:
sudo podman manifest push docker.io/fsistemas/sql2json:0.2.1 \
sudo podman manifest push docker.io/fsistemas/sql2json:0.3.0 \
docker.io/fsistemas/sql2json:latest
```

Expand All @@ -131,12 +131,12 @@ requesting one rather than bumping the version yourself.

```bash
podman build --platform linux/amd64,linux/arm64 --pull=always \
--build-arg VERSION=0.2.1 \
--manifest docker.io/fsistemas/sql2json:0.2.1 .
podman manifest push docker.io/fsistemas/sql2json:0.2.1 \
docker.io/fsistemas/sql2json:0.2.1
--build-arg VERSION=0.3.0 \
--manifest docker.io/fsistemas/sql2json:0.3.0 .
podman manifest push docker.io/fsistemas/sql2json:0.3.0 \
docker.io/fsistemas/sql2json:0.3.0
# Stable releases only — also publish the moving `latest` tag:
podman manifest push docker.io/fsistemas/sql2json:0.2.1 \
podman manifest push docker.io/fsistemas/sql2json:0.3.0 \
docker.io/fsistemas/sql2json:latest
```

Expand All @@ -147,10 +147,10 @@ requesting one rather than bumping the version yourself.
below):

```bash
podman build --platform linux/amd64 --pull=always --build-arg VERSION=0.2.1 \
-t docker.io/fsistemas/sql2json:0.2.1 \
podman build --platform linux/amd64 --pull=always --build-arg VERSION=0.3.0 \
-t docker.io/fsistemas/sql2json:0.3.0 \
-t docker.io/fsistemas/sql2json:latest .
podman push docker.io/fsistemas/sql2json:0.2.1
podman push docker.io/fsistemas/sql2json:0.3.0
podman push docker.io/fsistemas/sql2json:latest # stable releases only
```

Expand All @@ -170,24 +170,24 @@ requesting one rather than bumping the version yourself.

```bash
docker buildx build --platform linux/amd64,linux/arm64 \
--build-arg VERSION=0.2.1 \
-t docker.io/fsistemas/sql2json:0.2.1 \
--build-arg VERSION=0.3.0 \
-t docker.io/fsistemas/sql2json:0.3.0 \
-t docker.io/fsistemas/sql2json:latest \
--push .
```

**Tagging rules:** push the immutable `:0.2.1` tag every release; move
**Tagging rules:** push the immutable `:0.3.0` tag every release; move
`:latest` **only** for stable releases (never for pre-releases / RCs). Treat
published version tags as write-once.

**Verify** the pushed image (either tool):

```bash
podman pull docker.io/fsistemas/sql2json:0.2.1
podman run --rm docker.io/fsistemas/sql2json:0.2.1 --query "SELECT 1 AS a, 2 AS b"
podman pull docker.io/fsistemas/sql2json:0.3.0
podman run --rm docker.io/fsistemas/sql2json:0.3.0 --query "SELECT 1 AS a, 2 AS b"
# → [{"a": 1, "b": 2}]
podman run --rm --entrypoint pip docker.io/fsistemas/sql2json:0.2.1 \
show sql2json | grep ^Version # must read: Version: 0.2.1
podman run --rm --entrypoint pip docker.io/fsistemas/sql2json:0.3.0 \
show sql2json | grep ^Version # must read: Version: 0.3.0
```

## Notes
Expand All @@ -197,4 +197,4 @@ requesting one rather than bumping the version yourself.
- The build backend is **hatchling** (set in `pyproject.toml`). Do not use
`python setup.py` or `setuptools` commands.
- Verify the published release at <https://pypi.org/project/sql2json/> and that
`pip install sql2json==0.2.1` resolves the new version.
`pip install sql2json==0.3.0` resolves the new version.
2 changes: 1 addition & 1 deletion examples/python_api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ Public API used here:
- `list_queries`
- `parse_parameter`

`list_queries(path)` returns legacy global query names. Use `list_queries(path, scoped=True)` to return the full discovery shape (`{"global": [...], "connections": {...}}`), or `list_queries(path, connection="name")` to get the effective names for one connection, including connection-scoped queries and global fallbacks.
`list_queries(path)` returns legacy global query names. Use `list_queries(path, scoped=True)` to return the full discovery shape (`{"global": [...], "connections": {...}}`), or `list_queries(path, connection="name")` to get the effective names for one connection, including connection-scoped queries and global fallbacks. Existing configs that do not define `connection_queries` still work; scoped discovery returns an empty `connections` map for them.

Implementation helpers inside `sql2json.sql2json`, `sql2json.__main__`, or `sql2json.parameter.parameter_parser` are internal and should not be imported by users.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "sql2json"
version = "0.2.1"
version = "0.3.0"
description = "CLI to run SQL queries on any SQLAlchemy database and output JSON, CSV, or Excel"
readme = "README.md"
license = "MIT"
Expand Down
7 changes: 6 additions & 1 deletion roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ sql2json --list-connections
# → ["default", "mysql", "postgres"]

sql2json --list-queries
# → {"global": ["default", "sales_monthly", "total_sales"], "connections": {}}

sql2json --list-queries legacy
# → ["default", "sales_monthly", "total_sales"]
```

Expand Down Expand Up @@ -84,7 +87,9 @@ The functional API is already exported from `__init__.py` and works for both hum
from sql2json import list_connections, list_queries

list_connections(config_path=None) # → ["default", "mysql"]
list_queries(config_path=None) # → ["default", "sales_monthly"]
list_queries(config_path=None) # → ["default", "sales_monthly"] # global legacy names
list_queries(config_path=None, scoped=True)
# → {"global": ["default", "sales_monthly"], "connections": {}}
```

These are just the internals of Phase 1.2 exposed as importable functions.
Expand Down
12 changes: 6 additions & 6 deletions skills/sql2json/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ The config file lives at `~/.sql2json/config.json`. Create it with at least one
}
```

Use `queries` for shared/global named queries. Use `connection_queries` as the canonical schema for connection-specific SQL: connection name -> query name -> SQL. Existing global `queries` configs remain valid and act as fallbacks.
Use `queries` for shared/global named queries. Use optional `connection_queries` as the canonical schema for connection-specific SQL: connection name -> query name -> SQL. Existing configs that omit `connection_queries` remain valid, and global `queries` act as fallbacks.

Named query resolution is: `connection_queries.<connection>.<query>` first, then `queries.<query>`, then raw SQL or `@/path.sql` handling.

Expand Down Expand Up @@ -194,7 +194,7 @@ podman run --rm docker.io/fsistemas/sql2json --query "SELECT 1 AS a, 2 AS b"
docker run --rm docker.io/fsistemas/sql2json --query "SELECT 1 AS a, 2 AS b"

# Pin a production/CI release instead of using latest
podman pull docker.io/fsistemas/sql2json:0.2.1
podman pull docker.io/fsistemas/sql2json:0.3.0
```

The container runs as the unprivileged `app` user and reads config from
Expand All @@ -212,10 +212,10 @@ multi-arch path is rootful Podman with host-level QEMU/binfmt:
sudo podman run --rm --platform linux/arm64 --pull=always \
docker.io/library/alpine uname -m # must print: aarch64
sudo podman build --platform linux/amd64,linux/arm64 --pull=always \
--build-arg VERSION=0.2.1 \
--manifest docker.io/fsistemas/sql2json:0.2.1 .
sudo podman manifest push docker.io/fsistemas/sql2json:0.2.1 \
docker.io/fsistemas/sql2json:0.2.1
--build-arg VERSION=0.3.0 \
--manifest docker.io/fsistemas/sql2json:0.3.0 .
sudo podman manifest push docker.io/fsistemas/sql2json:0.3.0 \
docker.io/fsistemas/sql2json:0.3.0
```

## Sync strategy
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading