feat(audit): add kinds param to findRolledUpActivityFeed
Filter is applied at the innermost events CTE to reduce rows entering the LAG/session CTEs. Existing callers pass ROLLUP_ELIGIBLE by default so behaviour is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -50,7 +50,8 @@ class AuditLogQueryRepositoryIntegrationTest {
|
||||
"INSERT INTO audit_log (kind, actor_id, document_id, payload) VALUES ('ANNOTATION_CREATED', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '{\"pageNumber\":1}')"
|
||||
})
|
||||
void findRolledUpActivityFeed_returnsAnnotationEntry() {
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 10);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 10,
|
||||
List.of("TEXT_SAVED","FILE_UPLOADED","ANNOTATION_CREATED","BLOCK_REVIEWED","COMMENT_ADDED","MENTION_CREATED"));
|
||||
|
||||
assertThat(rows).hasSize(1);
|
||||
assertThat(rows.get(0).getKind()).isEqualTo("ANNOTATION_CREATED");
|
||||
|
||||
@@ -36,6 +36,10 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
static final UUID DOC_ID = UUID.fromString("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee");
|
||||
static final UUID OTHER_DOC_ID = UUID.fromString("ffffffff-ffff-ffff-ffff-ffffffffffff");
|
||||
|
||||
static final List<String> ALL_ELIGIBLE_KINDS = List.of(
|
||||
"TEXT_SAVED", "FILE_UPLOADED", "ANNOTATION_CREATED",
|
||||
"BLOCK_REVIEWED", "COMMENT_ADDED", "MENTION_CREATED");
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
@Autowired AuditLogQueryRepository auditLogQueryRepository;
|
||||
@@ -97,7 +101,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED", base.plusSeconds(i * 480L));
|
||||
}
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).hasSize(1);
|
||||
ActivityFeedRow row = rows.get(0);
|
||||
@@ -119,7 +123,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED", sessionTwoStart);
|
||||
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED", sessionTwoStart.plusSeconds(300));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).hasSize(2);
|
||||
assertThat(rows.get(0).getCount()).isEqualTo(2);
|
||||
@@ -136,7 +140,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(USER_ID, DOC_ID, "ANNOTATION_CREATED", base.plusSeconds(i * 60L * 30L));
|
||||
}
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).hasSize(1);
|
||||
assertThat(rows.get(0).getCount()).isEqualTo(30);
|
||||
@@ -152,7 +156,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(USER_ID, DOC_ID, "COMMENT_ADDED", base.plusSeconds(60));
|
||||
insertAuditEvent(USER_ID, DOC_ID, "COMMENT_ADDED", base.plusSeconds(120));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).hasSize(3);
|
||||
assertThat(rows).allSatisfy(r -> {
|
||||
@@ -170,7 +174,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(USER_ID, DOC_ID, "METADATA_UPDATED", base.plusSeconds(60));
|
||||
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED", base.plusSeconds(120));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).hasSize(1);
|
||||
assertThat(rows.get(0).getKind()).isEqualTo("TEXT_SAVED");
|
||||
@@ -184,7 +188,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(USER_ID, DOC_ID, "FILE_UPLOADED", rollupStart.plusSeconds(300));
|
||||
insertAuditEvent(USER_ID, OTHER_DOC_ID, "FILE_UPLOADED", rollupStart.plusSeconds(900));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).hasSize(2);
|
||||
assertThat(rows).anySatisfy(r -> {
|
||||
@@ -209,7 +213,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
Instant.parse("2026-04-20T10:00:00Z"), Map.of("commentId", commentId.toString()));
|
||||
insertReplyNotification(USER_ID, DOC_ID, commentId);
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).anySatisfy(r ->
|
||||
assertThat(r.isYouParticipated()).isTrue()
|
||||
@@ -223,7 +227,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(OTHER_USER_ID, DOC_ID, "COMMENT_ADDED",
|
||||
Instant.parse("2026-04-20T10:00:00Z"), Map.of("commentId", commentId.toString()));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).allSatisfy(r ->
|
||||
assertThat(r.isYouParticipated()).isFalse()
|
||||
@@ -236,7 +240,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(OTHER_USER_ID, DOC_ID, "COMMENT_ADDED",
|
||||
Instant.parse("2026-04-20T10:00:00Z"), Map.of());
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).allSatisfy(r ->
|
||||
assertThat(r.isYouParticipated()).isFalse()
|
||||
@@ -251,7 +255,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
Instant.parse("2026-04-20T10:00:00Z"), Map.of("commentId", commentId.toString()));
|
||||
insertReplyNotification(OTHER_USER_ID, DOC_ID, commentId);
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).allSatisfy(r ->
|
||||
assertThat(r.isYouParticipated()).isFalse()
|
||||
@@ -264,7 +268,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(OTHER_USER_ID, DOC_ID, "MENTION_CREATED",
|
||||
Instant.parse("2026-04-20T10:00:00Z"), Map.of("mentionedUserId", USER_ID.toString()));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).anySatisfy(r ->
|
||||
assertThat(r.isYouMentioned()).isTrue()
|
||||
@@ -278,7 +282,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(USER_ID, DOC_ID, "COMMENT_ADDED",
|
||||
Instant.parse("2026-04-20T10:00:00Z"), Map.of("commentId", commentId.toString()));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).hasSize(1);
|
||||
assertThat(rows.get(0).getCommentId()).isEqualTo(commentId);
|
||||
@@ -292,7 +296,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
Instant.parse("2026-04-20T10:00:00Z"),
|
||||
Map.of("commentId", commentId.toString(), "mentionedUserId", USER_ID.toString()));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).hasSize(1);
|
||||
assertThat(rows.get(0).getCommentId()).isEqualTo(commentId);
|
||||
@@ -304,7 +308,7 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED",
|
||||
Instant.parse("2026-04-20T10:00:00Z"), Map.of("blockId", "ccc", "pageNumber", "1"));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).hasSize(1);
|
||||
assertThat(rows.get(0).getCommentId()).isNull();
|
||||
@@ -316,10 +320,92 @@ class AuditLogQueryRepositoryRolledUpTest {
|
||||
insertAuditEvent(USER_ID, DOC_ID, "MENTION_CREATED",
|
||||
Instant.parse("2026-04-20T10:00:00Z"), Map.of("mentionedUserId", OTHER_USER_ID.toString()));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40, ALL_ELIGIBLE_KINDS);
|
||||
|
||||
assertThat(rows).allSatisfy(r ->
|
||||
assertThat(r.isYouMentioned()).isFalse()
|
||||
);
|
||||
}
|
||||
|
||||
// ─── kinds filter ─────────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void rolledUpFeed_with_single_kind_returns_only_that_kind() {
|
||||
insertUserAndDocs();
|
||||
Instant base = Instant.parse("2026-04-20T10:00:00Z");
|
||||
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED", base);
|
||||
insertAuditEvent(USER_ID, DOC_ID, "FILE_UPLOADED", base.plusSeconds(60));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(
|
||||
USER_ID.toString(), 40, List.of("FILE_UPLOADED"));
|
||||
|
||||
assertThat(rows).hasSize(1);
|
||||
assertThat(rows.get(0).getKind()).isEqualTo("FILE_UPLOADED");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rolledUpFeed_with_multiple_kinds_returns_union() {
|
||||
insertUserAndDocs();
|
||||
Instant base = Instant.parse("2026-04-20T10:00:00Z");
|
||||
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED", base);
|
||||
insertAuditEvent(USER_ID, OTHER_DOC_ID, "FILE_UPLOADED", base.plusSeconds(60));
|
||||
insertAuditEvent(USER_ID, DOC_ID, "ANNOTATION_CREATED", base.plusSeconds(120));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(
|
||||
USER_ID.toString(), 40, List.of("TEXT_SAVED", "FILE_UPLOADED"));
|
||||
|
||||
assertThat(rows).hasSize(2);
|
||||
assertThat(rows).extracting(ActivityFeedRow::getKind)
|
||||
.containsExactlyInAnyOrder("TEXT_SAVED", "FILE_UPLOADED");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rolledUpFeed_with_default_returns_all_six_eligible_kinds() {
|
||||
insertUserAndDocs();
|
||||
Instant base = Instant.parse("2026-04-20T10:00:00Z");
|
||||
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED", base);
|
||||
insertAuditEvent(USER_ID, DOC_ID, "FILE_UPLOADED", base.plusSeconds(60));
|
||||
insertAuditEvent(USER_ID, DOC_ID, "ANNOTATION_CREATED", base.plusSeconds(120));
|
||||
insertAuditEvent(USER_ID, DOC_ID, "BLOCK_REVIEWED", base.plusSeconds(7300));
|
||||
insertAuditEvent(USER_ID, DOC_ID, "COMMENT_ADDED", base.plusSeconds(7360));
|
||||
insertAuditEvent(USER_ID, DOC_ID, "MENTION_CREATED", base.plusSeconds(7420));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(
|
||||
USER_ID.toString(), 40,
|
||||
List.of("TEXT_SAVED", "FILE_UPLOADED", "ANNOTATION_CREATED",
|
||||
"BLOCK_REVIEWED", "COMMENT_ADDED", "MENTION_CREATED"));
|
||||
|
||||
assertThat(rows).hasSize(6);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rolledUpFeed_excludes_rows_not_in_filter_set() {
|
||||
insertUserAndDocs();
|
||||
Instant base = Instant.parse("2026-04-20T10:00:00Z");
|
||||
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED", base);
|
||||
insertAuditEvent(USER_ID, OTHER_DOC_ID, "FILE_UPLOADED", base.plusSeconds(60));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(
|
||||
USER_ID.toString(), 40, List.of("TEXT_SAVED"));
|
||||
|
||||
assertThat(rows).hasSize(1);
|
||||
assertThat(rows.get(0).getKind()).isEqualTo("TEXT_SAVED");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rolledUpFeed_rollup_still_works_when_kind_set_is_filtered_to_single_rollable_kind() {
|
||||
insertUserAndDocs();
|
||||
Instant base = Instant.parse("2026-04-20T09:00:00Z");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED", base.plusSeconds(i * 480L));
|
||||
}
|
||||
insertAuditEvent(USER_ID, DOC_ID, "FILE_UPLOADED", base.plusSeconds(20));
|
||||
|
||||
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(
|
||||
USER_ID.toString(), 40, List.of("TEXT_SAVED"));
|
||||
|
||||
assertThat(rows).hasSize(1);
|
||||
assertThat(rows.get(0).getKind()).isEqualTo("TEXT_SAVED");
|
||||
assertThat(rows.get(0).getCount()).isEqualTo(10);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user