Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
bc44c38
refactor(ddl): drop legacy identity fields from column classes
vistart Sep 21, 2026
82affdd
feat(ddl): render column attributes; backend identity syntax
vistart Sep 21, 2026
db9c7d0
test(ddl): classify ColumnAttributeSupport; use deriver.creation_plan()
vistart Sep 21, 2026
9d50811
fix(clickhouse): declare no per-column collation support
vistart Sep 21, 2026
7a5aaac
feat(clickhouse): advertise inline table and column comment capabilities
vistart Sep 23, 2026
5027c40
refactor(ddl): use core typed comment clause nodes
vistart Sep 23, 2026
033766a
fix(ddl): declare supports_column_comment in ClickHouseTableSupport
vistart Sep 23, 2026
64093ed
test: drop redundant __primary_key__ = "id" from fixtures
vistart Sep 23, 2026
2c74166
fix(ddl): stop silently dropping TABLESPACE / INHERITS
vistart Sep 23, 2026
6a4f113
feat(clickhouse): add type domain negative contract
vistart Sep 24, 2026
20fc085
test(ddl): cover table inheritance and tablespace
vistart Sep 24, 2026
227f2bd
refactor(clickhouse): use direct DDL expressions
vistart Sep 25, 2026
0fd1afd
docs: document repository search scope
vistart Sep 25, 2026
9346172
fix(protocol): declare partition support capabilities
vistart Sep 25, 2026
8741410
fix(clickhouse): make generated IDs process-aware
vistart Sep 25, 2026
777f1c1
test(ddl): cover DDLSource collection
vistart Sep 25, 2026
553f1ae
fix(view): stop the MV capability probe from claiming unsupported DDL
vistart Sep 26, 2026
54c6639
test(view): align the second case that asserted the old probe behaviour
vistart Sep 26, 2026
fe52b88
feat(view): support real ClickHouse materialized views
vistart Sep 26, 2026
b377232
fix(view): drop the unused typing.List import
vistart Sep 26, 2026
6d8d67f
fix(backend): repair unresolvable TYPE_CHECKING imports
vistart Sep 27, 2026
7e23db0
fix(scripts): stop the pre-commit hook from blocking commits on older…
vistart Sep 27, 2026
03c6d8c
ci: install core and testsuite from release branches
vistart Sep 27, 2026
fe4875f
chore: add changelog fragment for PR #1
vistart Sep 27, 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
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ jobs:
uses: actions/checkout@v6
with:
repository: rhosocial/python-activerecord
ref: feature/activerecord-derived-ddl
ref: release/v1.0.0.dev30
path: _activerecord

- name: Check out testsuite (feature branch)
uses: actions/checkout@v6
with:
repository: rhosocial/python-activerecord-testsuite
ref: feature/activerecord-derived-ddl
ref: release/v1.0.0.dev17
path: _testsuite

- name: Install activerecord and testsuite (editable)
Expand Down
6 changes: 6 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,9 @@ are bridged under `tests/rhosocial/activerecord_clickhouse_test/feature/`.
## Version Control and Changelog

This project adheres to the same version control, branching, commit message, and changelog management standards as the main `python-activerecord` project.

## Search Scope

- Use `rg` for repository searches; never use `grep`.
- Limit searches to this `python-activerecord` repository and its related testsuite/backend directories.
- Exclude `.git/`, `.venv*/`, `__pycache__/`, `build/`, `dist/`, and other cache directories.
1 change: 1 addition & 0 deletions changelog.d/1.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support real ClickHouse materialized views, advertise table and column comment capabilities with the core typed comment clause nodes, add a type domain negative contract, render DDL through direct DDL expressions, and cover `DDLSource` collection, table inheritance and tablespace.
1 change: 1 addition & 0 deletions changelog.d/1.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Stop the ClickHouse capability probe from claiming support for DDL it cannot emit, and stop silently dropping `TABLESPACE` and `INHERITS` from table declarations. Per-column collation support is now declared absent, generated IDs are made process-aware, and partition support capabilities are declared.
1 change: 1 addition & 0 deletions changelog.d/1.internal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Install core and testsuite from release branches in CI instead of the derived-DDL feature branch, repair TYPE_CHECKING imports broken by the expression namespace split, drop an unused `typing.List` import, and stop the pre-commit hook from blocking commits on revisions that predate `scripts/preflight.sh`.
1 change: 1 addition & 0 deletions changelog.d/20.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add real ClickHouse materialized view support: `ClickHouseCreateMaterializedViewExpression` covering both ClickHouse flavours (incremental with `TO <table>` or a mandatory `ENGINE`, plus `POPULATE`; and refreshable with `REFRESH EVERY|AFTER`, `OFFSET`, `RANDOMIZE FOR`, `DEPENDS ON`, `SETTINGS`, `APPEND [INCREMENTAL]` and `EMPTY`), `ClickHouseDropMaterializedViewExpression` (`DROP VIEW`), `ClickHouseRefreshMaterializedViewExpression` (`SYSTEM REFRESH VIEW`, optionally `SYSTEM WAIT VIEW`) and `ClickHouseModifyMaterializedViewRefreshExpression` (`ALTER TABLE ... MODIFY REFRESH`). Replaces the previous state where `supports_materialized_view()` reported `False` because the SQL-standard form could not be rendered. Server-side rules are validated in the constructor *and* the formatter: `ENGINE`/`TO` is mandatory, `REFRESH` needs at least one of `EVERY`/`AFTER`/`DEPENDS ON`, `OFFSET` requires `EVERY`, `APPEND INCREMENTAL` requires `APPEND`, and `POPULATE` conflicts with `REFRESH`.
31 changes: 26 additions & 5 deletions scripts/install-git-hooks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,42 @@
# Installs an optional pre-commit hook that runs scripts/preflight.sh so a
# broken import/lint is caught before the commit (and before a CI round-trip).
# Bypass a single commit with: git commit --no-verify
#
# Re-run this after pulling, and re-run it from the repository root. To remove
# the hook, delete .git/hooks/pre-commit (or the core.hooksPath directory).
set -euo pipefail

cd "$(dirname "$0")/.."

HOOK=".git/hooks/pre-commit"
if [ ! -d .git/hooks ]; then
echo "install-git-hooks: .git/hooks not found (not a git repo?)" >&2
exit 2
# git ignores .git/hooks entirely once core.hooksPath is set, so a hook written
# there would never run while this script still reported success.
HOOKS_PATH="$(git config core.hooksPath || true)"
if [ -n "$HOOKS_PATH" ]; then
echo "install-git-hooks: core.hooksPath is set to '$HOOKS_PATH'." >&2
echo "install-git-hooks: .git/hooks is ignored by git; writing the hook to" >&2
echo " '$HOOKS_PATH/pre-commit' instead." >&2
HOOK="$HOOKS_PATH/pre-commit"
mkdir -p "$HOOKS_PATH"
else
HOOK=".git/hooks/pre-commit"
if [ ! -d .git/hooks ]; then
echo "install-git-hooks: .git/hooks not found (not a git repo?)" >&2
exit 2
fi
fi

cat > "$HOOK" <<'HOOK_BODY'
#!/usr/bin/env bash
# Installed by scripts/install-git-hooks.sh — runs the local pre-flight.
# Skip with: git commit --no-verify
exec "$(git rev-parse --show-toplevel)/scripts/preflight.sh"
#
# The guard below matters on older revisions: this hook is a local, untracked
# artifact, so it survives a checkout of a commit that predates
# scripts/preflight.sh. Without the guard, exec fails with a bare
# "No such file or directory" and blocks the commit with nothing to act on.
PREFLIGHT="$(git rev-parse --show-toplevel)/scripts/preflight.sh"
[ -x "$PREFLIGHT" ] || exit 0
exec "$PREFLIGHT"
HOOK_BODY
chmod +x "$HOOK"

Expand Down
19 changes: 16 additions & 3 deletions src/rhosocial/activerecord/backend/impl/clickhouse/dialect.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
based on the ClickHouse version provided at initialization.
"""

from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING
from typing import Optional, Tuple, TYPE_CHECKING

from rhosocial.activerecord.backend.dialect.base import SQLDialectBase
from rhosocial.activerecord.backend.dialect.protocols import (
Expand Down Expand Up @@ -36,7 +36,9 @@
TruncateSupport,
TransactionControlSupport,
SQLFunctionSupport,
DDLTypeSupport,
DataTypeSupport,
UserDefinedTypeSupport,
DomainSupport,
)
from rhosocial.activerecord.backend.dialect.mixins import (
CollationMixin,
Expand Down Expand Up @@ -72,6 +74,8 @@
DQLMixin,
DMLMixin,
DDLColumnMixin,
UserDefinedTypeMixin,
DomainMixin,
TransactionControlMixin,
SetOperationMixin,
)
Expand Down Expand Up @@ -134,6 +138,7 @@
ClickHouseJoinMixin,
ClickHouseSetOperationMixin,
ClickHouseDQLMixin,
ClickHouseMaterializedViewMixin, # MV DDL overrides ClickHouseViewMixin and ViewMixin
ClickHouseViewMixin,
ClickHouseSchemaMixin,
ClickHouseDatabaseMixin,
Expand All @@ -146,6 +151,9 @@
from .reserved_words import CLICKHOUSE_RESERVED_WORDS
from .show.dialect import ClickHouseShowDialectMixin

if TYPE_CHECKING:
from rhosocial.activerecord.backend.expression.statements.ddl_alter import ModifyColumn


class ClickHouseDialect(
SQLDialectBase,
Expand Down Expand Up @@ -177,6 +185,7 @@ class ClickHouseDialect(
LateralJoinMixin,
ClickHouseJoinMixin,
JoinMixin,
ClickHouseMaterializedViewMixin, # MV DDL must precede ClickHouseViewMixin and ViewMixin
ClickHouseViewMixin,
ViewMixin,
ClickHouseSchemaMixin,
Expand Down Expand Up @@ -205,6 +214,8 @@ class ClickHouseDialect(
ClickHouseModifyColumnMixin,
ClickHouseJsonDualityViewMixin,
ClickHouseTypeSupportMixin,
UserDefinedTypeMixin,
DomainMixin,
ClickHouseOptimizerHintMixin,
ClickHouseTableStatementMixin,
ClickHouseMaintenanceMixin,
Expand Down Expand Up @@ -273,7 +284,9 @@ class ClickHouseDialect(
ClickHouseLoadXMLSupport,
ClickHouseAdminCommandSupport,
SQLFunctionSupport,
DDLTypeSupport,
DataTypeSupport,
UserDefinedTypeSupport,
DomainSupport,
):
"""
ClickHouse dialect implementation that adapts to the ClickHouse version.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@
ClickHouseDropDatabaseExpression,
)
from .dml import ClickHouseInsertExpression
from .materialized_view import (
ClickHouseCreateMaterializedViewExpression,
ClickHouseDropMaterializedViewExpression,
ClickHouseIntervalUnit,
ClickHouseModifyMaterializedViewRefreshExpression,
ClickHouseRefreshMaterializedViewExpression,
ClickHouseRefreshSchedule,
)
from .index import ClickHouseIndexDefinition
from .json import (
ClickHouseJSONExtractExpression,
Expand Down Expand Up @@ -240,4 +248,11 @@
"ClickHouseUInt64Type",
"ClickHouseUInt8Type",
"ClickHouseUUIDType",
# Materialized views
"ClickHouseCreateMaterializedViewExpression",
"ClickHouseDropMaterializedViewExpression",
"ClickHouseRefreshMaterializedViewExpression",
"ClickHouseModifyMaterializedViewRefreshExpression",
"ClickHouseRefreshSchedule",
"ClickHouseIntervalUnit",
]
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from rhosocial.activerecord.backend.expression.bases import BaseExpression
from rhosocial.activerecord.backend.expression.statements import ColumnDefinition
from rhosocial.activerecord.base.ddl.options import ColumnOptions
from rhosocial.activerecord.base import ColumnOptions

if TYPE_CHECKING: # pragma: no cover
from rhosocial.activerecord.backend.dialect import SQLDialectBase
Expand All @@ -47,10 +47,7 @@ def __init__(
constraints=None,
comment: Optional[str] = None,
generated_expression=None,
identity: Optional[str] = None,
identity_start: Optional[int] = None,
identity_increment: Optional[int] = None,
identity_clause=None,
attributes=None,
*,
codec: Optional[Sequence[str]] = None,
materialized: Optional[BaseExpression] = None,
Expand All @@ -64,10 +61,7 @@ def __init__(
constraints=constraints,
comment=comment,
generated_expression=generated_expression,
identity=identity,
identity_start=identity_start,
identity_increment=identity_increment,
identity_clause=identity_clause,
attributes=attributes,
)
if materialized is not None and not isinstance(materialized, BaseExpression):
raise TypeError("materialized must be a BaseExpression")
Expand All @@ -87,17 +81,12 @@ class ClickHouseColumnOptions(ColumnOptions):
def __init__(
self,
*,
identity_start: Optional[int] = None,
identity_increment: Optional[int] = None,
codec: Optional[Sequence[str]] = None,
materialized: Optional[BaseExpression] = None,
alias: Optional[BaseExpression] = None,
ttl: Optional[BaseExpression] = None,
):
super().__init__(
identity_start=identity_start,
identity_increment=identity_increment,
)
super().__init__()
if materialized is not None and not isinstance(materialized, BaseExpression):
raise TypeError("materialized must be a BaseExpression")
if alias is not None and not isinstance(alias, BaseExpression):
Expand Down
Loading