Skip to content

feat(clickhouse): rename actor columns in ClickHouse adapter only#122

Merged
lohanidamodar merged 5 commits into
mainfrom
feat/actor-terminology-CLO-4357
May 18, 2026
Merged

feat(clickhouse): rename actor columns in ClickHouse adapter only#122
lohanidamodar merged 5 commits into
mainfrom
feat/actor-terminology-CLO-4357

Conversation

@lohanidamodar
Copy link
Copy Markdown
Contributor

@lohanidamodar lohanidamodar commented May 18, 2026

Summary

This PR narrows the scope to a ClickHouse-only column rename. The original draft renamed columns and the public API across both adapters — that broke Cloud (which still uses the Database adapter for per-project audit logs) and every library caller. Per product decision, the Database adapter and the public Audit API stay unchanged for this cycle; the Database backend will be deprecated separately.

What changed

  • ClickHouse adapter only: userIdactorId, userTypeactorType, userInternalIdactorInternalId (columns + matching indexes).
  • ClickHouse adapter accepts the legacy userId array key and Query::equal('userId', ...) filter and translates them to the new column internally.
  • ClickHouse-backed Log instances expose both actorId (canonical) and userId (legacy mirror) attribute keys so existing callers keep working.
  • Log::getActorId(), Log::getActorType(), Log::getActorInternalId() getters added for ClickHouse-aware callers.
  • CHANGELOG.md written for 2.4.0 (minor bump from 2.3.2).

What did NOT change

  • Public Audit API: Audit::log($userId, ...), Audit::getLogsByUser(...), Audit::countLogsByUser(...), Audit::getLogsByUserAndEvents(...), Audit::countLogsByUserAndEvents(...) keep their original names and signatures.
  • Adapter.php abstract contract: getByUser / countByUser / getByUserAndEvents / countByUserAndEvents unchanged.
  • Adapter/SQL.php shared base: userId attribute and idx_userId_event index unchanged.
  • Adapter/Database.php: completely unchanged — Cloud's per-project audit tables are unaffected.
  • Log::getUserId() still present and behaves as before for Database-backed logs.

Migration

  • ClickHouse audit tables: setup() will create new tables with actorId / actorType / actorInternalId columns. Existing ClickHouse data is not preserved automatically; this is acceptable because the activity-events surface backed by this schema is not yet in public use.
  • No migration is required for Database-backed audit logs.
  • Callers may opt in to the new Log::getActorId() / getActorType() / getActorInternalId() getters when reading ClickHouse-backed logs.

Version

2.4.0 — minor bump. No BC break.

Test plan

  • vendor/bin/pint --test passes on PHP 8.4
  • vendor/bin/phpstan analyse --level max src tests passes
  • vendor/bin/phpunit passes against MariaDB 10.11 + ClickHouse 25.11 (88 tests, 841 assertions)

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 18, 2026

Greptile Summary

This PR scopes the userIdactorId column rename to the ClickHouse adapter only, leaving the public Audit API, the Database adapter, and the shared SQL base class unchanged. Legacy callers are supported through internal translation of userId array keys on write and Query::equal('userId', ...) filters on read.

  • ClickHouse schema and indexes are renamed (userIdactorId, userTypeactorType, userInternalIdactorInternalId) with corresponding translateAttribute() remapping for WHERE/ORDER-BY queries.
  • Log gains three new typed getters (getActorId(), getActorType(), getActorInternalId()); read-path output documents expose both canonical actorId and legacy userId mirror keys.
  • CHANGELOG.md added for 2.4.0 with schema change details and migration guidance.

Confidence Score: 4/5

Safe to merge after fixing the Query::select() translation gap; all other read/write paths correctly translate legacy userId keys.

The write path and most query types correctly translate legacy userId/userType/userInternalId references. The one gap is Query::select(): column names are passed as $values rather than $attribute, so translateAttribute is never called on them — a caller passing Query::select(['userId']) hits validateAttributeName before translation and receives an exception.

src/Audit/Adapter/ClickHouse.php — specifically the TYPE_SELECT branch in parseQueries around line 1360.

Important Files Changed

Filename Overview
src/Audit/Adapter/ClickHouse.php Renames userId/userType/userInternalId columns to actorId/actorType/actorInternalId in schema, indexes, write path, and query building. Legacy translation works for WHERE/ORDER-BY/IS-NULL queries and write-path array keys, but Query::select() values skip translateAttribute, so Query::select(['userId']) throws at validateAttributeName.
src/Audit/Log.php Adds getActorId(), getActorType(), and getActorInternalId() typed getters; existing getUserId() is untouched. Changes are additive and safe.
tests/Audit/Adapter/ClickHouseTest.php Test fixtures and assertions updated to use actor* naming; covers attribute list, index list, batch insert, isNull/isNotNull, and select projection. No test covers Query::select(['userId']) legacy translation.
CHANGELOG.md New changelog entry for 2.4.0 documenting the ClickHouse-only column rename, legacy compatibility, new Log getters, and migration notes.

Comments Outside Diff (1)

  1. src/Audit/Adapter/ClickHouse.php, line 1360-1369 (link)

    P1 The translateAttribute() call at line 1145 is applied to $attribute (from $query->getAttribute()), covering WHERE-clause, ORDER-BY, and similar single-attribute query types. However, the TYPE_SELECT branch iterates over $values — not $attribute — and calls validateAttributeName($column) without first running each column through translateAttribute. Since getAttributes() no longer contains userId, any caller that passes Query::select(['userId', ...]) will receive Exception: Invalid attribute name: userId, breaking the legacy-compatibility contract the PR provides for other query methods.

Reviews (3): Last reviewed commit: "Merge branch 'main' into feat/actor-term..." | Re-trigger Greptile

Comment thread CHANGELOG.md Outdated
Comment thread CHANGELOG.md Outdated
lohanidamodar and others added 4 commits May 18, 2026 04:08
…/actorInternalId)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lohanidamodar lohanidamodar force-pushed the feat/actor-terminology-CLO-4357 branch from b724a7a to 39f47b5 Compare May 18, 2026 04:08
@lohanidamodar lohanidamodar changed the title feat!: rename userType/userId to actorType/actorId (BC break) feat(clickhouse): rename actor columns in ClickHouse adapter only May 18, 2026
Comment thread CHANGELOG.md
Comment on lines +5 to +18
## 2.4.0

### ClickHouse adapter — actor terminology

The ClickHouse adapter now stores its principal columns under "actor" terminology:
`actorId`, `actorType`, `actorInternalId`. The shared SQL base, the Database adapter,
and the public `Audit` API are unchanged — Database-backed audit logs continue to use
`userId`.

This is a non-breaking change for callers of the public API. `Audit::log($userId, ...)`,
`Audit::getLogsByUser(...)`, `Audit::countLogsByUser(...)`, and the equivalent
`*ByUserAndEvents` methods all keep their original signatures. The ClickHouse adapter
translates the legacy `userId` array key and `Query::equal('userId', ...)` filter
internally to the renamed `actorId` column.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Version number contradicts PR title and description

The CHANGELOG header says 2.4.0 and explicitly states "This is a non-breaking change for callers of the public API," but the PR title uses the feat! conventional-commit prefix, says "BC break," and states the next tag should be 3.0.0. Additionally, the PR description's renames table lists Adapter::getByActor(), Audit::getLogsByActor(), etc. — but none of those method renames appear in the code; Adapter.php and Audit.php still expose getByUser, countByUser, log(?string $userId, ...). A consumer reading the PR description will look for getByActor() and find it absent. Before merging, the CHANGELOG version and the PR description must agree: either the ClickHouse-only schema rename is a non-breaking 2.x release (matching the code), or the public PHP API methods still need to be renamed to make this a true 3.0.0 BC break.

Comment thread CHANGELOG.md
Comment on lines +40 to +44
ClickHouse audit tables will be recreated by `setup()` with the new column names.
Existing ClickHouse audit data is not preserved automatically — this is acceptable
because the activity-events surface backed by this schema is not yet in public use.
If preservation is needed, run `ALTER TABLE ... RENAME COLUMN` for each renamed
column before redeploying.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 "Recreated by setup()" is factually incorrect

setup() issues CREATE TABLE IF NOT EXISTS, so an existing table is never touched — it is not dropped and recreated. For any operator upgrading the library against a live ClickHouse instance, the table retains the old userId/userType/userInternalId columns, and every query the new code emits (which references actorId) will fail immediately. The phrase "will be recreated by setup()" may mislead operators into believing no manual action is required before redeploying. The sentence should clarify that setup() only creates the table for fresh installations, and that existing installations require the ALTER TABLE ... RENAME COLUMN steps listed below before redeploying.

@lohanidamodar lohanidamodar merged commit f3174d3 into main May 18, 2026
4 checks passed
@lohanidamodar lohanidamodar deleted the feat/actor-terminology-CLO-4357 branch May 18, 2026 04:48
lohanidamodar added a commit that referenced this pull request May 18, 2026
Brings in actor-terminology rename (PR #122), location-column drop /
N-part resource parser (PR #118), and country / userAgent test refactors.

Conflict resolution (src/Audit/Adapter/ClickHouse.php parseQueries):
- Kept main's call to translateAttribute() right after reading
  $query->getAttribute() so callers passing legacy 'userId' /
  'userType' / 'userInternalId' Query filters are rewritten to the
  renamed 'actorId' / 'actorType' / 'actorInternalId' columns before
  the typed-bindings layer compiles them.
- The column type map registered via withParamTypes() is derived from
  getAttributes() and already uses the actor* names, so once the
  attribute is translated the map binds it as String correctly.
- Public Audit API (Audit::log, getLogsByUser, countLogsByUser,
  getLogsByUserAndEvents, countLogsByUserAndEvents) is unchanged --
  the ClickHouse adapter's getByUser / countByUser implementations
  already build internal Query::equal('actorId', $userId) filters.

ClickHouseSqlSnapshotTest:
- Updated the synthetic audit type map and DDL snapshot to reflect
  actorId / actorType / actorInternalId columns, idx_actorId_event,
  and the dropped location column. Find / count / cursor snapshots
  now filter on actorId.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants