Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
036669d
feat(postgres): add pg_partman partition support
vistart Jun 6, 2026
d4d5685
fix(test): align partition tests with public protocol API
vistart Jun 6, 2026
0652f0a
fix(postgres): avoid table and partition protocol overlap
vistart Jun 6, 2026
5a66339
refactor(postgres): separate table and partition capabilities
vistart Jun 6, 2026
fc5284b
refactor(postgres): expressionize partition operation helpers
vistart Jun 6, 2026
9d6ee94
feat(postgres): align partition capability mapping
vistart Jun 7, 2026
e278b68
test(partition): add production time partition operation scenarios
vistart Jun 7, 2026
54d33e3
fix(ddl): generate DEFAULT partition clauses correctly
vistart Jun 7, 2026
a448dcf
test(query): add eager loading and split sync/async relation with bri…
vistart Jun 10, 2026
39bd69a
feat(provider): implement setup_profile_fixtures for Postgres sync/async
vistart Jun 10, 2026
2a6188e
refactor(dialect): split mixins into directory-based modules
vistart Jun 11, 2026
3850752
fix(ci): remove bridge file referencing non-existent testsuite module
vistart Jun 11, 2026
2b7107f
fix(test): import Profile from version-specific module, not base models
vistart Jun 11, 2026
3f57844
fix(test): allow TEXT[]/INTEGER[] in column definition and fix detach…
vistart Jun 11, 2026
7b65f8a
fix(protocol): declare format_column_definition in PostgresTableSupport
vistart Jun 11, 2026
8f74fc0
feat(partition): complete partitioning support with named expressions…
vistart Jun 12, 2026
f796a99
chore: add changelog fragment for PR #43
vistart Jun 12, 2026
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
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
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ jobs:
} >> "$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:
Expand Down
1 change: 1 addition & 0 deletions changelog.d/43.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
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
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ async def main():
test_backend = AsyncPostgresBackend(**postgres_config)
await test_backend.connect()
print(f"Backend threadsafety: {test_backend.threadsafety}")
print(f" 0 = None (not thread-safe)")
print(f" 1 = driver (only supports SQL)")
print(f" 2 = Full thread-safe (psycopg)")
print(f" 0 = None (not thread-safe)") # noqa: F541
print(f" 1 = driver (only supports SQL)") # noqa: F541
print(f" 2 = Full thread-safe (psycopg)") # noqa: F541
await test_backend.disconnect()

# Create connection pool with higher load
Expand All @@ -144,7 +144,7 @@ async def main():
backend_factory=lambda: AsyncPostgresBackend(**postgres_config)
)

print(f"\nPool configuration:")
print(f"\nPool configuration:") # noqa: F541
print(f" min_size: {config.min_size}")
print(f" max_size: {config.max_size}")
print(f" connection_mode: {config.connection_mode}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ def main():
test_backend = PostgresBackend(**postgres_config)
test_backend.connect()
print(f"Backend threadsafety: {test_backend.threadsafety}")
print(f" 0 = None (not thread-safe)")
print(f" 1 = driver (only supports SQL)")
print(f" 2 = Full thread-safe (psycopg)")
print(f" 0 = None (not thread-safe)") # noqa: F541
print(f" 1 = driver (only supports SQL)") # noqa: F541
print(f" 2 = Full thread-safe (psycopg)") # noqa: F541
test_backend.disconnect()

# Create connection pool with higher load
Expand All @@ -146,7 +146,7 @@ def main():
backend_factory=lambda: PostgresBackend(**postgres_config)
)

print(f"\nPool configuration:")
print(f"\nPool configuration:") # noqa: F541
print(f" min_size: {config.min_size}")
print(f" max_size: {config.max_size}")
print(f" connection_mode: {config.connection_mode}")
Expand Down
4 changes: 2 additions & 2 deletions docs/examples/chapter_05_worker_isolation/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import os
import yaml
from typing import Optional
from typing import Optional # noqa: F401

from rhosocial.activerecord.backend.impl.postgres import PostgresBackend
from rhosocial.activerecord.backend.impl.postgres.config import PostgresConnectionConfig
Expand Down Expand Up @@ -115,5 +115,5 @@ def setup_database(backend: PostgresBackend, drop_existing: bool = True) -> None
for table in reversed(list(SCHEMA_SQL.keys())):
backend.execute(f"DROP TABLE IF EXISTS {table} CASCADE")

for table, sql in SCHEMA_SQL.items():
for table, sql in SCHEMA_SQL.items(): # noqa: B007
backend.execute(sql)
20 changes: 10 additions & 10 deletions docs/examples/chapter_05_worker_isolation/exp1_shared_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@

from __future__ import annotations

import multiprocessing
import multiprocessing # noqa: F401
import os
import random
import sys
import time
import threading
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed
import threading # noqa: F401
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed # noqa: F401
from dataclasses import dataclass
from typing import List, Dict, Any, Optional
from typing import List, Dict, Any, Optional # noqa: F401
from decimal import Decimal

# Add parent directories to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))

from config import load_scenario_config, get_backend_class, setup_database
from models import User, Order, Post, Comment, ALL_MODELS
from config import load_scenario_config, get_backend_class, setup_database # noqa: F401
from models import User, Order, Post, Comment, ALL_MODELS # noqa: F401


@dataclass
Expand Down Expand Up @@ -153,7 +153,7 @@ def run_experiment(config_dict: Dict[str, Any], num_workers: int, ops_per_worker
and letting all worker processes share the same connection.
"""
print(f"\n{'='*70}")
print(f"Experiment 1: Shared Global Connection (ANTI-PATTERN)")
print(f"Experiment 1: Shared Global Connection (ANTI-PATTERN)") # noqa: F541
print(f"{'='*70}")
print(f"Workers: {num_workers}")
print(f"Operations per worker: {ops_per_worker}")
Expand Down Expand Up @@ -183,7 +183,7 @@ def run_experiment(config_dict: Dict[str, Any], num_workers: int, ops_per_worker
for i in range(10):
user = User(username=f"seed_user_{i}", email=f"seed{i}@test.com", balance=100.0)
user.save()
print(f" Created 10 seed users")
print(f" Created 10 seed users") # noqa: F541

# Run workers with shared connection
print(f"\nStep 3: Running {num_workers} workers with SHARED connection...")
Expand Down Expand Up @@ -230,7 +230,7 @@ def run_experiment(config_dict: Dict[str, Any], num_workers: int, ops_per_worker
# Show sample errors
all_errors = [e for r in results for e in r.errors]
if all_errors:
print(f"\n Sample errors (first 5):")
print(f"\n Sample errors (first 5):") # noqa: F541
for err in all_errors[:5]:
print(f" - {err[:100]}...")

Expand All @@ -243,7 +243,7 @@ def run_experiment(config_dict: Dict[str, Any], num_workers: int, ops_per_worker
for table in ['comments', 'orders', 'posts', 'users']:
backend.execute(f"DROP TABLE IF EXISTS `{table}`")
backend.execute("SET FOREIGN_KEY_CHECKS = 1")
except:
except: # noqa: E722
pass

backend.disconnect()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@

from __future__ import annotations

import multiprocessing
import multiprocessing # noqa: F401
import os
import random
import sys
import time
from concurrent.futures import ProcessPoolExecutor, as_completed
from dataclasses import dataclass
from typing import List, Dict, Any, Optional
from typing import List, Dict, Any, Optional # noqa: F401
from decimal import Decimal

# Add parent directories to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))

from config import load_scenario_config, get_backend_class, SCHEMA_SQL
from config import load_scenario_config, get_backend_class, SCHEMA_SQL # noqa: F401


@dataclass
Expand All @@ -51,7 +51,7 @@ def _ensure_tables_exist(backend) -> None:
backend.execute("SET FOREIGN_KEY_CHECKS = 0")
try:
# Just create if not exists - don't drop
for table, sql in SCHEMA_SQL.items():
for table, sql in SCHEMA_SQL.items(): # noqa: B007
# Modify to CREATE IF NOT EXISTS
sql_modified = sql.replace("CREATE TABLE IF NOT EXISTS", "CREATE TABLE IF NOT EXISTS")
try:
Expand Down Expand Up @@ -81,7 +81,7 @@ def worker_task_isolated_connection(
"""
from rhosocial.activerecord.backend.impl.mysql import MySQLBackend
from rhosocial.activerecord.backend.impl.mysql.config import MySQLConnectionConfig
from models import User, Order, Post, Comment, ALL_MODELS
from models import User, Order, Post, Comment, ALL_MODELS # noqa: F401

start_time = time.time()
errors = []
Expand Down Expand Up @@ -181,7 +181,7 @@ def worker_task_isolated_connection(
model.__backend__ = None
# Disconnect
backend.disconnect()
except:
except: # noqa: E722
pass

duration = time.time() - start_time
Expand All @@ -203,7 +203,7 @@ def run_experiment(config_dict: Dict[str, Any], num_workers: int, ops_per_worker
Each worker process creates its own connection and manages its lifecycle.
"""
print(f"\n{'='*70}")
print(f"Experiment 2: Process-Isolated Connections (CORRECT PATTERN)")
print(f"Experiment 2: Process-Isolated Connections (CORRECT PATTERN)") # noqa: F541
print(f"{'='*70}")
print(f"Workers: {num_workers}")
print(f"Operations per worker: {ops_per_worker}")
Expand Down Expand Up @@ -233,11 +233,11 @@ def run_experiment(config_dict: Dict[str, Any], num_workers: int, ops_per_worker
for model in ALL_MODELS:
model.__backend__ = None
setup_backend.disconnect()
print(f" Created 10 seed users")
print(f" Created 10 seed users") # noqa: F541

# Run workers with isolated connections
print(f"\nStep 2: Running {num_workers} workers with ISOLATED connections...")
print(f" Each worker creates its own database connection")
print(f" Each worker creates its own database connection") # noqa: F541

start_time = time.time()
results: List[TaskResult] = []
Expand Down Expand Up @@ -280,11 +280,11 @@ def run_experiment(config_dict: Dict[str, Any], num_workers: int, ops_per_worker
# Show sample errors
all_errors = [e for r in results for e in r.errors]
if all_errors:
print(f"\n Sample errors (first 5):")
print(f"\n Sample errors (first 5):") # noqa: F541
for err in all_errors[:5]:
print(f" - {err[:100]}...")
else:
print(f"\n ✅ No errors detected!")
print(f"\n ✅ No errors detected!") # noqa: F541

print(f"{'='*70}\n")

Expand All @@ -298,7 +298,7 @@ def run_experiment(config_dict: Dict[str, Any], num_workers: int, ops_per_worker
cleanup_backend.execute(f"DROP TABLE IF EXISTS `{table}`")
cleanup_backend.execute("SET FOREIGN_KEY_CHECKS = 1")
cleanup_backend.disconnect()
except:
except: # noqa: E722
pass

return {
Expand Down
38 changes: 19 additions & 19 deletions docs/examples/chapter_05_worker_isolation/exp3_endurance_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,32 @@
from __future__ import annotations

import argparse
import gc
import multiprocessing
import gc # noqa: F401
import multiprocessing # noqa: F401
import os
import random
import sys
import time
import traceback
import traceback # noqa: F401
from concurrent.futures import ProcessPoolExecutor, as_completed
from dataclasses import dataclass, field
from typing import List, Dict, Any, Optional
from typing import List, Dict, Any, Optional # noqa: F401
from decimal import Decimal
import threading
import threading # noqa: F401

# Add parent directories to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))

from config import load_scenario_config, get_backend_class, SCHEMA_SQL
from config import load_scenario_config, get_backend_class, SCHEMA_SQL # noqa: F401

# Import from core package worker_pool module
from rhosocial.activerecord.worker_pool import (
TaskDefinition,
TaskResult,
TaskMode,
TaskPriority,
register_handler,
WorkerPool,
TaskDefinition, # noqa: F401
TaskResult, # noqa: F401
TaskMode, # noqa: F401
TaskPriority, # noqa: F401
register_handler, # noqa: F401
WorkerPool, # noqa: F401
)


Expand Down Expand Up @@ -95,7 +95,7 @@ def worker_task(
"""
from rhosocial.activerecord.backend.impl.mysql import MySQLBackend
from rhosocial.activerecord.backend.impl.mysql.config import MySQLConnectionConfig
from models import User, Order, Post, Comment, ALL_MODELS
from models import User, Order, Post, Comment, ALL_MODELS # noqa: F401

start_time = time.time()
operations = 0
Expand Down Expand Up @@ -196,7 +196,7 @@ def record_error(error_msg: str):
for model in ALL_MODELS:
model.__backend__ = None
backend.disconnect()
except:
except: # noqa: E722
pass

duration = time.time() - start_time
Expand Down Expand Up @@ -284,7 +284,7 @@ def run_endurance_test(
if error_type == "connection":
stats.connection_issues += count

except Exception as e:
except Exception as e: # noqa: F841
stats.total_errors += 1
stats.error_breakdown["executor"] = stats.error_breakdown.get("executor", 0) + 1

Expand All @@ -296,7 +296,7 @@ def run_endurance_test(
# Progress report
if round_num % 5 == 0 or round_num == num_rounds:
elapsed = time.time() - start_time
avg_ops = stats.total_operations / round_num if round_num > 0 else 0
avg_ops = stats.total_operations / round_num if round_num > 0 else 0 # noqa: F841
print(f" Round {round_num}/{num_rounds}: "
f"{round_ops} ops, {round_errors} errors, "
f"{round_duration:.2f}s, "
Expand All @@ -319,7 +319,7 @@ def run_endurance_test(
print(f" Success rate: {(1 - stats.total_errors/(stats.total_operations+1))*100:.2f}%")

if stats.error_breakdown:
print(f"\n Error breakdown:")
print(f"\n Error breakdown:") # noqa: F541
for error_type, count in sorted(stats.error_breakdown.items()):
print(f" {error_type}: {count}")

Expand All @@ -346,7 +346,7 @@ def run_endurance_test(
cleanup_backend.execute(f"DROP TABLE IF EXISTS `{table}`")
cleanup_backend.execute("SET FOREIGN_KEY_CHECKS = 1")
cleanup_backend.disconnect()
except:
except: # noqa: E722
pass

return stats
Expand Down Expand Up @@ -384,7 +384,7 @@ def main():
print("\n" + "="*70)
print("Worker Isolation Experiment - Endurance Test")
print("="*70)
print(f"\nConfiguration:")
print(f"\nConfiguration:") # noqa: F541
print(f" Pattern: {args.pattern}")
print(f" Workers: {args.workers}")
print(f" Operations per round: {args.ops_per_round}")
Expand Down
Loading
Loading