Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ad228cc
chore: bump version to 1.0.0.dev15
vistart May 30, 2026
70b05ce
test(basic): add bulk operations schema and provider
vistart May 30, 2026
d0c9e5f
fix: fill all PostgreSQL index and DDL feature coverage gaps (#39)
vistart Jun 1, 2026
e7f67ae
fix: remove redundant Postgres-specific expression subclasses, add do…
vistart Jun 2, 2026
af21612
test(relation): align Postgres coverage with testsuite contract
vistart Jun 3, 2026
e5d6887
test(postgres): add backend type integration coverage
vistart Jun 3, 2026
814d1c6
chore(deps): loosen pytest dependency constraints
vistart Jun 3, 2026
bd2a129
fix(postgres): declare JSONB expression formatter protocol
vistart Jun 3, 2026
dc78743
feat(postgres): add expression-level COLLATE support (#40)
vistart Jun 4, 2026
42cd978
feat(postgres): add SQL/XML standard expressions (#41)
vistart Jun 4, 2026
4efa96f
feat(postgres): add datetime interval expressions with EXPLAIN exampl…
vistart Jun 5, 2026
1570bac
chore(ci): add Python 3.15 experimental tests for PostgreSQL
vistart Jun 6, 2026
df84e80
fix: remove rhosocial-activerecord from requirements.txt
vistart Jun 6, 2026
58665f3
feat(postgres): add pg_partman partition support (#43)
vistart Jun 12, 2026
476928d
feat(postgres): add PGQ support with property graph query scenarios (…
vistart Jun 13, 2026
cf27673
refactor(postgres): restructure dialect protocol mixins into per-feat…
vistart Jun 13, 2026
9f51a4c
fix(postgres): replace deleted PostgresSQLSyntaxSupport ref in cli/in…
vistart Jun 14, 2026
b29d158
feat(relation): add bridge files for testsuite relation tests
vistart Jun 14, 2026
ff6d3ea
feat: add workflow_dispatch trigger for manual CI runs
vistart Jun 15, 2026
ea90b06
ci: switch testsuite dependency from GitHub to PyPI (v1.0.0.dev15)
vistart Jun 15, 2026
cd8710e
docs: add documentation for partition, PGQ, COLLATE, datetime interva…
vistart Jun 15, 2026
23bf4b9
docs: update CHANGELOG for v1.0.0.dev15
vistart Jun 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3,510 changes: 3,510 additions & 0 deletions .claude/version_control.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE/bugfix_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ Go over all the following points, and put an `x` in all the boxes that apply.
If you're unsure about any of these, don't hesitate to ask. We're here to help!
-->

- [ ] My code follows the project's [code style guidelines](./.gemini/code_style.md).
- [ ] My code follows the project's [code style guidelines](./.claude/code_style.md).
- [ ] I have performed a self-review of my own code.
- [ ] I have commented my code, particularly in hard-to-understand areas.
- [ ] I have made corresponding changes to the documentation (Docstrings, `README.md`, etc.).
- [ ] My changes generate no new warnings.
- [ ] I have added a [Changelog fragment](./.gemini/version_control.md#5-changelog-management-with-towncrier) (`changelog.d/<issue_number>.<type>.md`).
- [ ] I have added a [Changelog fragment](./.claude/version_control.md#5-changelog-management-with-towncrier) (`changelog.d/<issue_number>.<type>.md`).
- [ ] I have verified that my changes do not introduce SQL injection vulnerabilities.
- [ ] I have checked for potential performance regressions.

Expand Down
4 changes: 2 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE/feature_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ Go over all the following points, and put an `x` in all the boxes that apply.
If you're unsure about any of these, don't hesitate to ask. We're here to help!
-->

- [ ] My code follows the project's [code style guidelines](./.gemini/code_style.md).
- [ ] My code follows the project's [code style guidelines](./.claude/code_style.md).
- [ ] I have performed a self-review of my own code.
- [ ] I have commented my code, particularly in hard-to-understand areas.
- [ ] I have made corresponding changes to the documentation (Docstrings, `README.md`, etc.).
- [ ] My changes generate no new warnings.
- [ ] I have added a [Changelog fragment](./.gemini/version_control.md#5-changelog-management-with-towncrier) (`changelog.d/<issue_number>.<type>.md`).
- [ ] I have added a [Changelog fragment](./.claude/version_control.md#5-changelog-management-with-towncrier) (`changelog.d/<issue_number>.<type>.md`).
- [ ] I have verified that my changes do not introduce SQL injection vulnerabilities.
- [ ] I have checked for potential performance regressions.

Expand Down
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE/release_hotfix_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ For hotfixes, describe the specific tests performed to validate the fix.
Go over all the following points, and put an `x` in all the boxes that apply.
-->

- [ ] My changes follow the project's [version control guidelines](./.gemini/version_control.md) (especially for release and hotfix procedures).
- [ ] My changes follow the project's [version control guidelines](./.claude/version_control.md) (especially for release and hotfix procedures).
- [ ] I have updated the `CHANGELOG.md` using `towncrier build` (for releases).
- [ ] All necessary documentation (e.g., release notes, migration guides) has been prepared or updated.
- [ ] I have confirmed all CI checks have passed on the target branch after merging (post-merge verification).
Expand Down
218 changes: 210 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ on:
- main
- 'release/v**'
- 'maint/**'
workflow_dispatch:

permissions:
contents: read
Expand Down Expand Up @@ -67,8 +68,8 @@ jobs:

- name: Install activerecord and testsuite
run: |
pip install rhosocial-activerecord==1.0.0.dev27
pip install rhosocial-activerecord-testsuite==1.0.0.dev14
pip install git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev28#egg=rhosocial-activerecord
pip install rhosocial-activerecord-testsuite==1.0.0.dev15

- name: Create postgres scenario config
run: |
Expand Down Expand Up @@ -121,21 +122,39 @@ jobs:
python -m pytest \
--rootdir=. \
--confcutdir=. \
"$TESTSUITE_DIR/benchmark/crud" \
"$TESTSUITE_DIR/benchmark/crud/test_delete_async.py" \
"$TESTSUITE_DIR/benchmark/crud/test_delete_sync.py" \
"$TESTSUITE_DIR/benchmark/crud/test_insert_async.py" \
"$TESTSUITE_DIR/benchmark/crud/test_insert_sync.py" \
"$TESTSUITE_DIR/benchmark/crud/test_query_async.py" \
"$TESTSUITE_DIR/benchmark/crud/test_query_sync.py" \
"$TESTSUITE_DIR/benchmark/crud/test_update_async.py" \
"$TESTSUITE_DIR/benchmark/crud/test_update_sync.py" \
"$TESTSUITE_DIR/benchmark/query" \
"$TESTSUITE_DIR/benchmark/transaction" \
"$TESTSUITE_DIR/benchmark/mixin" \
-m benchmark \
--benchmark-size=small \
--benchmark-sort=mean \
--strict-markers \
--tb=short | tee benchmark-output.txt
python -m pytest \
--rootdir=. \
--confcutdir=. \
tests/benchmark/activerecord_bulk \
-m benchmark \
--benchmark-size=small \
--benchmark-sort=mean \
--strict-markers \
--tb=short | tee -a benchmark-output.txt
python -m pytest \
--rootdir=. \
--confcutdir=. \
tests/benchmark/backend \
-m benchmark \
--benchmark-size=small \
--benchmark-sort=mean \
--strict-markers \
--tb=short | tee -a benchmark-output.txt

- name: Run FastAPI benchmark suite
Expand Down Expand Up @@ -166,12 +185,16 @@ jobs:
echo
echo "- Python: 3.14"
echo "- postgres: 18"
echo "- Scope: testsuite generic benchmarks + PostgreSQL backend direct benchmarks"
echo "- Scope: testsuite generic benchmarks + ActiveRecord bulk benchmarks + PostgreSQL backend direct benchmarks"
echo "- Size: small"
echo "- Result: benchmark job fails only when benchmark execution or correctness checks fail."
echo
echo '```text'
grep -A 120 "benchmark:" benchmark-output.txt || cat benchmark-output.txt
if [ -f benchmark-output.txt ]; then
grep -A 120 "benchmark:" benchmark-output.txt || tail -n 200 benchmark-output.txt
else
echo "benchmark-output.txt was not generated."
fi
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

Expand All @@ -188,10 +211,119 @@ jobs:
echo "- Result: benchmark job fails only when FastAPI benchmark execution or correctness checks fail."
echo
echo '```text'
grep -A 120 "benchmark:" fastapi-benchmark-output.txt || cat fastapi-benchmark-output.txt
if [ -f fastapi-benchmark-output.txt ]; then
grep -A 120 "benchmark:" fastapi-benchmark-output.txt || tail -n 200 fastapi-benchmark-output.txt
else
echo "fastapi-benchmark-output.txt was not generated."
fi
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

test-experimental-python-315:
# Temporarily disabled until Python 3.15 beta/toolchain compatibility stabilizes.
if: ${{ false }}
name: Python ${{ matrix.python-version }} / postgres ${{ matrix.postgres-version }} (experimental)
runs-on: ubuntu-latest
permissions:
contents: read
continue-on-error: true
strategy:
fail-fast: false
matrix:
include:
- { python-version: '3.15.0-beta.2', postgres-version: '18', freethreaded: false }
- { python-version: '3.15.0-beta.2', postgres-version: '18', freethreaded: true }

services:
postgres:
image: postgres:${{ matrix.postgres-version }}
env:
POSTGRES_DB: test_db
POSTGRES_USER: root
POSTGRES_PASSWORD: password
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
postgres-exts:
image: vistart/postgres-exts:${{ matrix.postgres-version }}
env:
POSTGRES_DB: test_db
POSTGRES_USER: root
POSTGRES_PASSWORD: password
ports:
- 5433:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- name: Check out the repository
uses: actions/checkout@v6

- name: Set up Python ${{ matrix.python-version }}${{ matrix.freethreaded && ' free-threaded' || '' }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
freethreaded: ${{ matrix.freethreaded }}

- name: Install dependencies
run: |
pip install -r requirements.txt
pip install -r requirements-dev.txt

- name: Install activerecord and testsuite
run: |
pip install git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev28#egg=rhosocial-activerecord
pip install rhosocial-activerecord-testsuite==1.0.0.dev15

- name: Create postgres scenario config
run: |
cat > postgres_scenarios.yaml << EOF
scenarios:
postgres_default:
host: 127.0.0.1
port: 5432
database: test_db
username: root
password: password
postgres_exts:
host: 127.0.0.1
port: 5433
database: test_db
username: root
password: password
EOF
echo "POSTGRES_SCENARIOS_CONFIG_PATH=$(pwd)/postgres_scenarios.yaml" >> $GITHUB_ENV

- name: Install postgres client for health check
run: |
sudo apt-get update
sudo apt-get install --yes postgresql-client

- name: Wait for postgres service
run: |
until pg_isready -h 127.0.0.1 -p 5432 -U root; do
echo "Waiting for postgres..."
sleep 2
done
echo "postgres is ready!"
until pg_isready -h 127.0.0.1 -p 5433 -U root; do
echo "Waiting for postgres-exts..."
sleep 2
done
echo "postgres-exts is ready!"

- name: Run tests
run: |
export PYTHONPATH=src:tests
python -m pytest tests/ --tb=short --scenario-parallel -n 2 --dist=loadgroup

test:
name: Python ${{ matrix.python-version }} / postgres ${{ matrix.postgres-version }}
runs-on: ubuntu-latest
Expand Down Expand Up @@ -259,8 +391,8 @@ jobs:

- name: Install activerecord and testsuite
run: |
pip install rhosocial-activerecord==1.0.0.dev27
pip install rhosocial-activerecord-testsuite==1.0.0.dev14
pip install git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev28#egg=rhosocial-activerecord
pip install rhosocial-activerecord-testsuite==1.0.0.dev15

- name: Create postgres scenario config
run: |
Expand Down Expand Up @@ -321,3 +453,73 @@ jobs:
flags: unittests,python-${{ matrix.python-version }},postgres-${{ matrix.postgres-version }}
name: codecov-postgres-${{ matrix.python-version }}-${{ matrix.postgres-version }}
fail_ci_if_error: false

test-postgres-19:
name: Python 3.14 / postgres 19beta1 (PGQ)
runs-on: ubuntu-latest
continue-on-error: true

services:
postgres:
image: postgres:19beta1
env:
POSTGRES_DB: test_db
POSTGRES_USER: root
POSTGRES_PASSWORD: password
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- name: Check out the repository
uses: actions/checkout@v6

- name: Set up Python 3.14
uses: actions/setup-python@v6
with:
python-version: "3.14"

- name: Install dependencies
run: |
pip install -r requirements.txt
pip install -r requirements-dev.txt

- name: Install activerecord and testsuite
run: |
pip install git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev28#egg=rhosocial-activerecord
pip install rhosocial-activerecord-testsuite==1.0.0.dev15

- name: Create postgres scenario config
run: |
cat > postgres_scenarios.yaml << EOF
scenarios:
postgres_default:
host: 127.0.0.1
port: 5432
database: test_db
username: root
password: password
EOF
echo "POSTGRES_SCENARIOS_CONFIG_PATH=$(pwd)/postgres_scenarios.yaml" >> $GITHUB_ENV

- name: Install postgres client for health check
run: |
sudo apt-get update
sudo apt-get install --yes postgresql-client

- name: Wait for postgres service
run: |
until pg_isready -h 127.0.0.1 -p 5432 -U root; do
echo "Waiting for postgres..."
sleep 2
done
echo "postgres is ready!"

- name: Run tests
run: |
export PYTHONPATH=src:tests
python -m pytest tests/ --tb=short --scenario-parallel -n 2 --dist=loadgroup
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
## [v1.0.0.dev15] - 2026-06-15

### Added

- Added PostgreSQL expression-level `COLLATE` support with schema-qualified collation validation. ([#40](https://github.com/rhosocial/python-activerecord-postgres/issues/40))
- Added PostgreSQL support for core SQL/XML standard expressions, including XML construction, serialization, aggregation, and query/table expression capability declarations. ([#41](https://github.com/rhosocial/python-activerecord-postgres/issues/41))
- Added PostgreSQL dialect support for datetime interval expressions (`EXTRACT`, `DATE_PART`, `DATE_TRUNC`, `INTERVAL` add/subtract, date diff) with EXPLAIN-backed index usage verification tests. ([#42](https://github.com/rhosocial/python-activerecord-postgres/issues/42))
- Added comprehensive PostgreSQL partitioning support including ATTACH CONCURRENTLY/DEFAULT partition, partition auto-management via named expressions (monthly/quarterly), pg_partman create_parent parameter completion, enhanced partition metadata queries, and full test coverage ([#43](https://github.com/rhosocial/python-activerecord-postgres/issues/43))
- Add SQL/PGQ property graph query support and PostgreSQL 19 compatibility enhancements ([#44](https://github.com/rhosocial/python-activerecord-postgres/issues/44))



### Fixed

- Fill all PostgreSQL index, trigger, table, and extension protocol feature coverage gaps ([#39](https://github.com/rhosocial/python-activerecord-postgres/issues/39))


## [v1.0.0.dev14] - 2026-05-30

### Changed
Expand Down
41 changes: 41 additions & 0 deletions docs/en_US/ddl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,50 @@ The PostgreSQL backend supports the same type-safe DDL expressions as the core l
| `DropIndexExpression` | ✅ Full | |
| `CreateViewExpression` | ✅ Full | Materialized views support |
| `DropViewExpression` | ✅ Full | |
| `CreatePartitionExpression` | ✅ Full | RANGE, LIST, HASH partitioning (PG 10+) |
| `AttachPartitionExpression` | ✅ Full | Includes CONCURRENTLY (PG 14+) |
| `DetachPartitionExpression` | ✅ Full | Includes CONCURRENTLY (PG 14+) |
| `AlterIndexExpression` | ✅ Full | RENAME TO, SET TABLESPACE, SET/RESET storage params |
| `ReindexExpression` | ✅ Full | INDEX/TABLE/SCHEMA/DATABASE level, with CONCURRENTLY |

## PostgreSQL-Specific Features

### Partition Support

PostgreSQL 10+ supports declarative partitioning. See [Partition Documentation](../postgres_specific_features/partition.md).

```python
partition = PostgresCreatePartitionExpression(
dialect, parent_table="orders", partition_name="orders_2024_q1",
partition_type="RANGE", bounds="FROM ('2024-01-01') TO ('2024-04-01')",
)
```

### pg_partman Extension

See [Partition Documentation](../postgres_specific_features/partition.md) for pg_partman support.

### Index Operation Enhancements

```python
from rhosocial.activerecord.backend.impl.postgres.expression.ddl.index import (
PostgresAlterIndexExpression, PostgresAlterIndexActionType,
PostgresReindexExpression,
)

# ALTER INDEX ... RENAME TO
alter = PostgresAlterIndexExpression(
dialect, index_name="idx_old",
action=PostgresAlterIndexActionType.RENAME_TO("idx_new"),
)

# REINDEX CONCURRENTLY
reindex = PostgresReindexExpression(
dialect, target_type="INDEX", target_name="idx_corrupted",
concurrently=True,
)
```

### Index Types

PostgreSQL supports various index types:
Expand Down
Loading
Loading