From 86f905e672be5feeef6fa513be5c9428e8898125 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Sat, 14 Mar 2026 16:18:12 +0100 Subject: [PATCH] Preserve created_at on user upsert to avoid accumulating un-merged rows On re-login the upsert was inserting a new row with created_at=now(), causing ClickHouse ReplacingMergeTree to accumulate rows until background compaction. Now preserves the original created_at via INSERT...SELECT from the existing record. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../app/storage/ClickHouseUserRepository.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseUserRepository.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseUserRepository.java index 0d11d062..459b0a07 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseUserRepository.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseUserRepository.java @@ -47,14 +47,32 @@ public class ClickHouseUserRepository implements UserRepository { @Override public void upsert(UserInfo user) { - jdbc.update( - "INSERT INTO users (user_id, provider, email, display_name, roles, updated_at) VALUES (?, ?, ?, ?, ?, now64(3, 'UTC'))", - user.userId(), - user.provider(), - user.email(), - user.displayName(), - user.roles().toArray(new String[0]) - ); + // Preserve created_at from existing record on re-login. + // ReplacingMergeTree deduplicates by ORDER BY (user_id), keeping the row + // with the highest updated_at. + Optional existing = findById(user.userId()); + if (existing.isPresent()) { + jdbc.update( + "INSERT INTO users (user_id, provider, email, display_name, roles, created_at, updated_at) " + + "SELECT user_id, ?, ?, ?, ?, created_at, now64(3, 'UTC') " + + "FROM users FINAL WHERE user_id = ?", + user.provider(), + user.email(), + user.displayName(), + user.roles().toArray(new String[0]), + user.userId() + ); + } else { + jdbc.update( + "INSERT INTO users (user_id, provider, email, display_name, roles, updated_at) " + + "VALUES (?, ?, ?, ?, ?, now64(3, 'UTC'))", + user.userId(), + user.provider(), + user.email(), + user.displayName(), + user.roles().toArray(new String[0]) + ); + } } @Override