rowquery 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rowquery-0.1.0 → rowquery-0.2.0}/.github/ISSUE_TEMPLATE/config.yml +1 -1
- rowquery-0.2.0/.github/workflows/test.yml +115 -0
- rowquery-0.2.0/CHANGELOG.md +85 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/CLAUDE.md +14 -3
- {rowquery-0.1.0 → rowquery-0.2.0}/CONTRIBUTING.md +1 -1
- {rowquery-0.1.0 → rowquery-0.2.0}/PKG-INFO +13 -9
- {rowquery-0.1.0 → rowquery-0.2.0}/README.md +6 -2
- rowquery-0.2.0/llms-full.txt +940 -0
- rowquery-0.2.0/llms.txt +21 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/pyproject.toml +6 -6
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/__init__.py +6 -0
- rowquery-0.2.0/row_query/adapters/mysql.py +109 -0
- rowquery-0.2.0/row_query/adapters/oracle.py +123 -0
- rowquery-0.2.0/row_query/adapters/postgresql.py +91 -0
- rowquery-0.2.0/row_query/adapters/protocol.py +106 -0
- rowquery-0.2.0/row_query/adapters/sqlite.py +85 -0
- rowquery-0.2.0/row_query/core/connection.py +220 -0
- rowquery-0.2.0/row_query/core/engine.py +128 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/core/exceptions.py +33 -3
- rowquery-0.2.0/row_query/core/execution.py +340 -0
- rowquery-0.2.0/row_query/core/lexer.py +183 -0
- rowquery-0.2.0/row_query/core/migration.py +198 -0
- rowquery-0.2.0/row_query/core/params.py +234 -0
- rowquery-0.2.0/row_query/core/pool.py +271 -0
- rowquery-0.2.0/row_query/core/sanitizer.py +206 -0
- rowquery-0.2.0/row_query/core/transaction.py +192 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/mapping/aggregate.py +90 -28
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/mapping/builder.py +65 -25
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/mapping/plan.py +5 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/contract/test_adapter_protocol.py +6 -20
- rowquery-0.2.0/tests/integration/test_server_backends.py +236 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/test_builder.py +0 -15
- rowquery-0.2.0/tests/unit/test_engine_regressions.py +164 -0
- rowquery-0.2.0/tests/unit/test_nested_collections.py +314 -0
- rowquery-0.2.0/tests/unit/test_pool.py +184 -0
- rowquery-0.2.0/tests/unit/test_review_regressions.py +390 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/test_sanitizer.py +3 -5
- rowquery-0.1.0/.github/workflows/test.yml +0 -48
- rowquery-0.1.0/CHANGELOG.md +0 -44
- rowquery-0.1.0/row_query/adapters/mysql.py +0 -111
- rowquery-0.1.0/row_query/adapters/oracle.py +0 -120
- rowquery-0.1.0/row_query/adapters/postgresql.py +0 -104
- rowquery-0.1.0/row_query/adapters/protocol.py +0 -81
- rowquery-0.1.0/row_query/adapters/sqlite.py +0 -98
- rowquery-0.1.0/row_query/core/connection.py +0 -132
- rowquery-0.1.0/row_query/core/engine.py +0 -419
- rowquery-0.1.0/row_query/core/migration.py +0 -148
- rowquery-0.1.0/row_query/core/params.py +0 -122
- rowquery-0.1.0/row_query/core/sanitizer.py +0 -233
- rowquery-0.1.0/row_query/core/transaction.py +0 -334
- {rowquery-0.1.0 → rowquery-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/.github/dependabot.yml +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/.github/workflows/quality.yml +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/.github/workflows/release.yml +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/.gitignore +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/.pre-commit-config.yaml +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/CODE_OF_CONDUCT.md +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/LICENSE +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/examples/01_basic_query.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/examples/02_model_mapping.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/examples/03_aggregate.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/examples/04_transactions.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/examples/05_async.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/examples/06_migrations.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/examples/07_repository.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/examples/README.md +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/adapters/__init__.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/core/__init__.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/core/enums.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/core/registry.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/mapping/__init__.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/mapping/model.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/mapping/protocol.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/repository/__init__.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/row_query/repository/base.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/__init__.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/conftest.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/contract/__init__.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/fixtures/sql/billing/invoice/list.sql +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/fixtures/sql/user/count.sql +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/fixtures/sql/user/get_by_id.sql +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/fixtures/sql/user/insert.sql +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/fixtures/sql/user/list.sql +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/integration/__init__.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/integration/test_sqlite.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/__init__.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/test_aggregate_mapper.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/test_engine.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/test_migration.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/test_model_mapper.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/test_params.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/test_registry.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/test_repository.py +0 -0
- {rowquery-0.1.0 → rowquery-0.2.0}/tests/unit/test_transaction.py +0 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, "001-*"]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
name: Test (Python ${{ matrix.python-version }})
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v5
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
|
|
27
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
28
|
+
uses: actions/setup-python@v6
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python-version }}
|
|
31
|
+
|
|
32
|
+
- name: Install dependencies
|
|
33
|
+
run: uv sync --extra sqlite --extra dev
|
|
34
|
+
|
|
35
|
+
- name: Run unit and contract tests
|
|
36
|
+
run: uv run pytest tests/unit/ tests/contract/ -v --cov=row_query --cov-report=xml --cov-report=term
|
|
37
|
+
|
|
38
|
+
- name: Run integration tests
|
|
39
|
+
run: uv run pytest tests/integration/ -m integration -v
|
|
40
|
+
|
|
41
|
+
- name: Upload coverage to Codecov
|
|
42
|
+
if: matrix.python-version == '3.12'
|
|
43
|
+
uses: codecov/codecov-action@v4
|
|
44
|
+
with:
|
|
45
|
+
file: ./coverage.xml
|
|
46
|
+
flags: unittests
|
|
47
|
+
name: codecov-umbrella
|
|
48
|
+
fail_ci_if_error: false
|
|
49
|
+
|
|
50
|
+
integration-servers:
|
|
51
|
+
name: Integration (PostgreSQL + MySQL + Oracle)
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
|
|
54
|
+
services:
|
|
55
|
+
postgres:
|
|
56
|
+
image: postgres:16-alpine
|
|
57
|
+
env:
|
|
58
|
+
POSTGRES_PASSWORD: rowquery
|
|
59
|
+
POSTGRES_DB: rowquery
|
|
60
|
+
ports:
|
|
61
|
+
- 5432:5432
|
|
62
|
+
options: >-
|
|
63
|
+
--health-cmd "pg_isready -U postgres"
|
|
64
|
+
--health-interval 5s
|
|
65
|
+
--health-timeout 5s
|
|
66
|
+
--health-retries 10
|
|
67
|
+
mysql:
|
|
68
|
+
image: mysql:8.4
|
|
69
|
+
env:
|
|
70
|
+
MYSQL_ROOT_PASSWORD: rowquery
|
|
71
|
+
MYSQL_DATABASE: rowquery
|
|
72
|
+
ports:
|
|
73
|
+
- 3306:3306
|
|
74
|
+
options: >-
|
|
75
|
+
--health-cmd "mysqladmin ping -prowquery --silent"
|
|
76
|
+
--health-interval 5s
|
|
77
|
+
--health-timeout 5s
|
|
78
|
+
--health-retries 20
|
|
79
|
+
oracle:
|
|
80
|
+
image: gvenzl/oracle-free:23-slim-faststart
|
|
81
|
+
env:
|
|
82
|
+
ORACLE_PASSWORD: rowquery
|
|
83
|
+
APP_USER: rowquery
|
|
84
|
+
APP_USER_PASSWORD: rowquery
|
|
85
|
+
ports:
|
|
86
|
+
- 1521:1521
|
|
87
|
+
options: >-
|
|
88
|
+
--health-cmd healthcheck.sh
|
|
89
|
+
--health-interval 10s
|
|
90
|
+
--health-timeout 5s
|
|
91
|
+
--health-retries 30
|
|
92
|
+
|
|
93
|
+
env:
|
|
94
|
+
ROWQUERY_TEST_POSTGRESQL: postgresql://postgres:rowquery@127.0.0.1:5432/rowquery
|
|
95
|
+
ROWQUERY_TEST_MYSQL: mysql://root:rowquery@127.0.0.1:3306/rowquery
|
|
96
|
+
ROWQUERY_TEST_ORACLE: oracle://rowquery:rowquery@127.0.0.1:1521/FREEPDB1
|
|
97
|
+
|
|
98
|
+
steps:
|
|
99
|
+
- uses: actions/checkout@v6
|
|
100
|
+
|
|
101
|
+
- name: Install uv
|
|
102
|
+
uses: astral-sh/setup-uv@v5
|
|
103
|
+
with:
|
|
104
|
+
enable-cache: true
|
|
105
|
+
|
|
106
|
+
- name: Set up Python
|
|
107
|
+
uses: actions/setup-python@v6
|
|
108
|
+
with:
|
|
109
|
+
python-version: "3.12"
|
|
110
|
+
|
|
111
|
+
- name: Install dependencies
|
|
112
|
+
run: uv sync --extra all --extra dev
|
|
113
|
+
|
|
114
|
+
- name: Run server integration tests
|
|
115
|
+
run: uv run pytest tests/integration/test_server_backends.py -m integration -v -rs
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.2.0] - 2026-10-21
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Transaction state no longer leaks between calls.** Connections are rolled back when they return to the pool, so reads no longer leave PostgreSQL sessions `idle in transaction`, MySQL `REPEATABLE READ` readers no longer see a stale snapshot, and a failed statement no longer leaves a PostgreSQL connection in the `current transaction is aborted` state.
|
|
14
|
+
- **Real connection pooling.** The pool now waits for a free connection (up to `pool_timeout`) instead of raising `RuntimeError` when exhausted, opens connections lazily, honours `pool_recycle`, and discards connections that fail the reset or are reported broken. `Engine` can be used from several threads (SQLite connections are opened with `check_same_thread=False`), and `asyncio.gather` with more tasks than `pool_size` works.
|
|
15
|
+
- **`%` in SQL for PostgreSQL/MySQL.** Literal `%` (e.g. `LIKE 'a%'`) is escaped when `:name` placeholders are converted to `%(name)s`.
|
|
16
|
+
- **Migrations**: files may contain several statements; versions are ordered numerically (`9_x` before `10_y`); the tracking table and inserts work on PostgreSQL, MySQL and Oracle; duplicate version numbers are rejected.
|
|
17
|
+
- **SQLSanitizer bypasses**: constructs whose extent differs between MySQL and PostgreSQL are rejected (backslashes inside any quoted literal or identifier, dollar-quoted strings, `#` outside literals, `--` not followed by whitespace, `
|
|
18
|
+
` inside `--` comments); the `allowed_verbs` check skips leading comments and rejects SQL whose verb cannot be determined (fail-closed); MySQL `/*! ... */` executable comments are rejected when comments are not stripped; unterminated block comments are rejected.
|
|
19
|
+
- `Engine.transaction()` acquires its connection on `__enter__` instead of at call time.
|
|
20
|
+
- Transactions now have the same query API as engines: `fetch_one` raises `MultipleRowsError`, plus `mapper=` and `fetch_scalar`.
|
|
21
|
+
- `fetch_one` reads at most two rows instead of the whole result.
|
|
22
|
+
- MySQL cursors are buffered and always closed, avoiding `Unread result found` after `fetch_scalar`/`fetch_one`.
|
|
23
|
+
- PostgreSQL connection strings are built with `psycopg.conninfo.make_conninfo` (passwords with spaces or quotes work); `ConnectionConfig.extra` is passed to every driver.
|
|
24
|
+
- Oracle: DSN defaults to port 1521 when `port` is unset; only ALL-CAPS column names are lowercased, so quoted mixed-case aliases are preserved.
|
|
25
|
+
- Single-word inline SQL (`VACUUM`, `COMMIT`) is no longer mistaken for a registry key.
|
|
26
|
+
- SQLite transactions and migrations now cover DDL: an explicit `BEGIN` is issued, so a failing transaction or migration rolls back `CREATE`/`ALTER`/`DROP` too (the `sqlite3` module only opens transactions implicitly before DML).
|
|
27
|
+
- A connection released after `close_pool()` is closed instead of being handed to the new pool; pool initialisation is thread-safe.
|
|
28
|
+
- MySQL connection liveness is checked locally instead of pinging the server on every acquire; pool health checks run outside the pool lock.
|
|
29
|
+
- Applied migrations are matched by version number, so renaming `9_x.sql` to `009_x.sql` does not re-apply it.
|
|
30
|
+
- Parameter conversion honours the backend's string-literal rules (`'C:\'` is a complete literal on PostgreSQL).
|
|
31
|
+
- Strict aggregate mapping also validates reference and value-object columns.
|
|
32
|
+
- Project URLs in `pyproject.toml` point to the correct GitHub repository.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- **Nested collections** in aggregate mappings: `.collection("lines.discounts", Discount, prefix="disc__", key="id")` nests a collection inside a previously declared one, at any depth. Children are deduplicated per parent instance; strict mode validates nested columns, prefixes and identity key columns (root, collections at every level, references) and reports collections by their full path. Dotted paths for `reference()` / `value_object()` are rejected at `build()`. `CollectionPlan.children` is now populated and used by `AggregateMapper`.
|
|
36
|
+
- Portable positional placeholders: `?` is converted to `%s` (PostgreSQL, MySQL) or `:1, :2, ...` (Oracle); `??` is a literal `?` (e.g. the PostgreSQL JSONB operator). SQL already using native `%s` / `%(name)s` placeholders is passed through unchanged.
|
|
37
|
+
- `QueryExecutionError` (database rejected the query) and `IntegrityError` (constraint violation), both carrying the driver exception as `__cause__`; `PoolTimeoutError`.
|
|
38
|
+
- `Engine.close()` / `AsyncEngine.close()`; `ConnectionManager.acquire()` / `release()`.
|
|
39
|
+
- CI runs the integration suite against PostgreSQL, MySQL and Oracle (23ai Free) service containers.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
- **Breaking:** errors that are not binding problems now raise `QueryExecutionError` instead of `ParameterBindingError` (which is now a subclass of `QueryExecutionError`). Catch `ExecutionError` or `QueryExecutionError` to handle all database errors.
|
|
43
|
+
- **Breaking (adapter protocol):** adapters now implement `connect`/`close_connection`/`is_connection_alive`/`execute` (async: `connect_async`/`close_connection_async`/`execute_async`) plus `begin`/`begin_async`, `positional_paramstyle` and `backslash_escapes`; pooling moved into `row_query.core.pool`. `TransactionManager`/`AsyncTransactionManager` take a connection manager instead of a raw connection.
|
|
44
|
+
- `ConnectionConfig.pool_timeout` and `pool_recycle` are floats and are now enforced.
|
|
45
|
+
|
|
46
|
+
## [0.1.2] - 2026-02-22
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
- **Inline SQL support**: All engine and transaction methods (`fetch_one`, `fetch_all`, `fetch_scalar`, `execute`) now accept raw SQL strings in addition to registry keys. A string containing whitespace is treated as inline SQL; a dot-separated identifier like `user.get_by_id` is resolved from the registry.
|
|
50
|
+
- **Flexible parameter binding**: `params` argument now accepts `dict` (named), `tuple`/`list` (positional), or a single scalar value (automatically wrapped in a tuple). Previously only `dict | None` was accepted.
|
|
51
|
+
- **`SQLSanitizer`** — configurable sanitizer applied to inline SQL before execution:
|
|
52
|
+
- `strip_comments` (default `True`): removes `--` line comments and `/* */` block comments while preserving string literals.
|
|
53
|
+
- `block_multiple_statements` (default `True`): rejects SQL containing a statement-terminating `;` followed by additional content (prevents query stacking attacks).
|
|
54
|
+
- `allowed_verbs` (default `None`): restricts the leading SQL keyword to a caller-supplied `frozenset` (e.g. `frozenset({"SELECT"})`). Registry queries are never sanitized.
|
|
55
|
+
- **`SQLSanitizationError`** exception (subclass of `ExecutionError`) raised when a sanitization check fails.
|
|
56
|
+
- **`is_raw_sql()`** and **`coerce_params()`** helpers exported from `row_query.core.params`.
|
|
57
|
+
- 65 new unit tests covering all sanitizer behaviour (`tests/unit/test_sanitizer.py`).
|
|
58
|
+
|
|
59
|
+
## [0.1.0] - 2025-02-16
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
- Initial alpha release
|
|
63
|
+
- Core query execution engine (`Engine`, `AsyncEngine`)
|
|
64
|
+
- Connection management with pooling support (`ConnectionManager`, `AsyncConnectionManager`)
|
|
65
|
+
- Multi-database adapter pattern supporting SQLite, PostgreSQL, MySQL, and Oracle
|
|
66
|
+
- SQL registry for loading `.sql` files into dot-separated namespaces (`SQLRegistry`)
|
|
67
|
+
- Parameter normalization supporting `:name` syntax across all database backends
|
|
68
|
+
- Model mapping for dataclasses, Pydantic models, and plain classes (`ModelMapper`)
|
|
69
|
+
- Aggregate mapping for complex object graph reconstruction with single-pass O(n) algorithm
|
|
70
|
+
- Collection mapping for one-to-many relationships in aggregate patterns
|
|
71
|
+
- Value object mapping for embedded entities in aggregates
|
|
72
|
+
- Reference mapping for foreign key relationships
|
|
73
|
+
- Transaction management with context manager support (`TransactionManager`, `AsyncTransactionManager`)
|
|
74
|
+
- Migration management system with version tracking (`MigrationManager`, `MigrationInfo`)
|
|
75
|
+
- Repository pattern base classes for DDD-style code organization (`Repository`, `AsyncRepository`)
|
|
76
|
+
- Comprehensive exception hierarchy with 18 custom exception classes
|
|
77
|
+
- Full type safety with mypy strict mode compliance
|
|
78
|
+
- Support for Python 3.10, 3.11, 3.12, and 3.13
|
|
79
|
+
- 125 unit, contract, and integration tests
|
|
80
|
+
|
|
81
|
+
[Unreleased]: https://github.com/MaksimShevtsov/RowQuery/compare/v0.2.0...HEAD
|
|
82
|
+
[0.2.0]: https://github.com/MaksimShevtsov/RowQuery/releases/tag/v0.2.0
|
|
83
|
+
[0.1.2]: https://github.com/MaksimShevtsov/RowQuery/releases/tag/v0.1.2
|
|
84
|
+
[0.1.1]: https://github.com/MaksimShevtsov/RowQuery/releases/tag/v0.1.1
|
|
85
|
+
[0.1.0]: https://github.com/MaksimShevtsov/RowQuery/releases/tag/v0.1.0
|
|
@@ -19,7 +19,9 @@ uv sync --extra all # Install all database drivers
|
|
|
19
19
|
## Commands
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
uv run pytest # Run all tests
|
|
22
|
+
uv run pytest # Run all tests
|
|
23
|
+
# Server integration tests run when ROWQUERY_TEST_POSTGRESQL / ROWQUERY_TEST_MYSQL
|
|
24
|
+
# are set to postgresql://user:pw@host:port/db and mysql://user:pw@host:port/db URLs
|
|
23
25
|
uv run pytest tests/unit/ # Unit tests only
|
|
24
26
|
uv run pytest tests/contract/ # Protocol contract tests
|
|
25
27
|
uv run pytest tests/integration/ # SQLite integration tests
|
|
@@ -32,13 +34,17 @@ uv run mypy row_query/ # Type check (strict mode)
|
|
|
32
34
|
|
|
33
35
|
- **`row_query/core/`** — Core engine
|
|
34
36
|
- `connection.py` — `ConnectionConfig` (Pydantic), `ConnectionManager`, `AsyncConnectionManager`
|
|
37
|
+
- `pool.py` — `SyncPool`/`AsyncPool`: bounded, lazy, timeout + recycle, rollback on release
|
|
38
|
+
- `execution.py` — `SyncExecutor`/`AsyncExecutor` (query API shared by engines and transactions), driver error translation
|
|
35
39
|
- `engine.py` — `Engine` and `AsyncEngine` (fetch_one, fetch_all, fetch_scalar, execute, transaction)
|
|
36
40
|
- `registry.py` — `SQLRegistry` (loads .sql files into dot-separated namespaces)
|
|
37
41
|
- `transaction.py` — `TransactionManager`, `AsyncTransactionManager`
|
|
38
42
|
- `migration.py` — `MigrationManager`, `MigrationInfo`
|
|
39
|
-
- `params.py` — `:name
|
|
43
|
+
- `params.py` — `:name`/`?` → driver placeholder conversion (escapes `%` for pyformat)
|
|
44
|
+
- `lexer.py` — SQL tokenizer (strings, `$$`, `E''`, identifiers, comments) and statement splitter
|
|
45
|
+
- `sanitizer.py` — fail-closed `SQLSanitizer` for inline SQL
|
|
40
46
|
- `enums.py` — `DatabaseBackend` enum
|
|
41
|
-
- `exceptions.py` — Full exception hierarchy
|
|
47
|
+
- `exceptions.py` — Full exception hierarchy
|
|
42
48
|
|
|
43
49
|
- **`row_query/adapters/`** — Database drivers
|
|
44
50
|
- `protocol.py` — `SyncAdapter`, `AsyncAdapter` runtime-checkable protocols
|
|
@@ -66,3 +72,8 @@ uv run mypy row_query/ # Type check (strict mode)
|
|
|
66
72
|
## Active Technologies
|
|
67
73
|
- Python >=3.10 + pydantic >=2.0.0 (core); psycopg >=3.1.0, aiosqlite, aiomysql, oracledb (optional per-backend)
|
|
68
74
|
- SQLite, PostgreSQL, MySQL, Oracle via adapter pattern
|
|
75
|
+
- Python >=3.10 (documented library) + N/A (documentation-only feature; no new code dependencies) (001-llm-docs)
|
|
76
|
+
- N/A (static markdown/text files in repository) (001-llm-docs)
|
|
77
|
+
|
|
78
|
+
## Recent Changes
|
|
79
|
+
- 001-llm-docs: Added Python >=3.10 (documented library) + N/A (documentation-only feature; no new code dependencies)
|
|
@@ -13,7 +13,7 @@ Thank you for your interest in contributing! This document provides guidelines f
|
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
15
|
# Clone repository
|
|
16
|
-
git clone https://github.com/
|
|
16
|
+
git clone https://github.com/MaksimShevtsov/RowQuery.git
|
|
17
17
|
cd RowQuery
|
|
18
18
|
|
|
19
19
|
# Install all dependencies (including all database drivers)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: rowquery
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A SQL-first Python library for querying and mapping data across multiple database backends.
|
|
5
|
-
Project-URL: Homepage, https://github.com/
|
|
6
|
-
Project-URL: Documentation, https://github.com/
|
|
7
|
-
Project-URL: Repository, https://github.com/
|
|
8
|
-
Project-URL: Issues, https://github.com/
|
|
9
|
-
Project-URL: Changelog, https://github.com/
|
|
5
|
+
Project-URL: Homepage, https://github.com/MaksimShevtsov/RowQuery
|
|
6
|
+
Project-URL: Documentation, https://github.com/MaksimShevtsov/RowQuery#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/MaksimShevtsov/RowQuery.git
|
|
8
|
+
Project-URL: Issues, https://github.com/MaksimShevtsov/RowQuery/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/MaksimShevtsov/RowQuery/blob/main/CHANGELOG.md
|
|
10
10
|
Author-email: Maksim Shevtsov <maksim.shautsou.dev@gmail.com>
|
|
11
11
|
License: MIT
|
|
12
12
|
License-File: LICENSE
|
|
@@ -52,8 +52,8 @@ Description-Content-Type: text/markdown
|
|
|
52
52
|
[](https://pypi.org/project/rowquery/)
|
|
53
53
|
[](https://pypi.org/project/rowquery/)
|
|
54
54
|
[](https://opensource.org/licenses/MIT)
|
|
55
|
-
[](https://github.com/MaksimShevtsov/RowQuery/actions/workflows/test.yml)
|
|
56
|
+
[](https://codecov.io/gh/MaksimShevtsov/RowQuery)
|
|
57
57
|
[](https://github.com/astral-sh/ruff)
|
|
58
58
|
|
|
59
59
|
A SQL-first Python library for querying and mapping data across multiple database backends.
|
|
@@ -119,6 +119,10 @@ count = engine.fetch_scalar("SELECT COUNT(*) FROM users")
|
|
|
119
119
|
rows = engine.fetch_all("SELECT * FROM users WHERE id IN (?, ?)", [1, 2])
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
+
Placeholders are portable: use `:name` with a dict or `?` with positional values on any
|
|
123
|
+
backend. RowQuery converts them to the driver's native style (`%(name)s` / `%s` for
|
|
124
|
+
PostgreSQL and MySQL, `:1` for Oracle) and escapes literal `%` such as `LIKE 'a%'`.
|
|
125
|
+
|
|
122
126
|
### 3. Map to Models
|
|
123
127
|
```python
|
|
124
128
|
from dataclasses import dataclass
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
[](https://pypi.org/project/rowquery/)
|
|
4
4
|
[](https://pypi.org/project/rowquery/)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
|
-
[](https://github.com/MaksimShevtsov/RowQuery/actions/workflows/test.yml)
|
|
7
|
+
[](https://codecov.io/gh/MaksimShevtsov/RowQuery)
|
|
8
8
|
[](https://github.com/astral-sh/ruff)
|
|
9
9
|
|
|
10
10
|
A SQL-first Python library for querying and mapping data across multiple database backends.
|
|
@@ -70,6 +70,10 @@ count = engine.fetch_scalar("SELECT COUNT(*) FROM users")
|
|
|
70
70
|
rows = engine.fetch_all("SELECT * FROM users WHERE id IN (?, ?)", [1, 2])
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
Placeholders are portable: use `:name` with a dict or `?` with positional values on any
|
|
74
|
+
backend. RowQuery converts them to the driver's native style (`%(name)s` / `%s` for
|
|
75
|
+
PostgreSQL and MySQL, `:1` for Oracle) and escapes literal `%` such as `LIKE 'a%'`.
|
|
76
|
+
|
|
73
77
|
### 3. Map to Models
|
|
74
78
|
```python
|
|
75
79
|
from dataclasses import dataclass
|