1use reifydb_codec::key::encoded::EncodedKey;
5use reifydb_macro::KeyCodec;
6
7use super::KeyTag;
8use crate::{
9 interface::{catalog::flow::FlowId, cdc::CdcConsumerId},
10 key::{
11 any::{ByteEncoding, Field, KeyFields},
12 bound::TaggedKeyBoundRange,
13 },
14};
15
16pub trait ToConsumerKey {
17 fn to_consumer_key(&self) -> CdcConsumerKey;
18}
19
20impl ToConsumerKey for CdcConsumerKey {
21 fn to_consumer_key(&self) -> CdcConsumerKey {
22 self.clone()
23 }
24}
25
26impl ToConsumerKey for CdcConsumerId {
27 fn to_consumer_key(&self) -> CdcConsumerKey {
28 CdcConsumerKey {
29 consumer: self.clone(),
30 }
31 }
32}
33
34impl ToConsumerKey for FlowId {
35 fn to_consumer_key(&self) -> CdcConsumerKey {
36 CdcConsumerKey::new(CdcConsumerId::new(format!("flow:{}", self.0)))
37 }
38}
39
40#[derive(Debug, Clone, PartialEq, KeyCodec, Eq, PartialOrd, Ord, Hash)]
41#[key(tag = CdcConsumer)]
42pub struct CdcConsumerKey {
43 pub consumer: CdcConsumerId,
44}
45
46impl CdcConsumerKey {
47 pub fn new(consumer: impl Into<CdcConsumerId>) -> Self {
48 Self {
49 consumer: consumer.into(),
50 }
51 }
52
53 pub fn full_scan() -> TaggedKeyBoundRange {
54 TaggedKeyBoundRange::kind(Self::TAG)
55 }
56}
57
58#[cfg(test)]
59pub mod cdc_consumer_key_tests {
60 use std::ops::RangeBounds;
61
62 use super::{CdcConsumerKey, ToConsumerKey};
63 use crate::interface::{catalog::flow::FlowId, cdc::CdcConsumerId};
64
65 #[test]
66 fn test_encode_decode_cdc_consumer() {
67 let key = CdcConsumerKey {
68 consumer: CdcConsumerId::new("test-consumer"),
69 };
70
71 let encoded = key.encode();
72 let decoded = CdcConsumerKey::decode(&encoded).expect("Failed to decode key");
73
74 assert_eq!(decoded.consumer, CdcConsumerId::new("test-consumer"));
75 }
76
77 #[test]
78 fn test_cdc_consumer_keys_within_range() {
79 let key1 = CdcConsumerKey {
80 consumer: CdcConsumerId::new("consumer-a"),
81 }
82 .encode();
83
84 let key2 = CdcConsumerKey {
85 consumer: CdcConsumerId::new("consumer-b"),
86 }
87 .encode();
88
89 let key3 = CdcConsumerKey {
90 consumer: CdcConsumerId::new("consumer-z"),
91 }
92 .encode();
93
94 let range = CdcConsumerKey::full_scan().encode();
95
96 assert!(range.contains(&key1), "consumer-a key should be in range");
97 assert!(range.contains(&key2), "consumer-b key should be in range");
98 assert!(range.contains(&key3), "consumer-z key should be in range");
99 }
100
101 #[test]
102 fn test_flow_id_to_consumer_key() {
103 let flow_id = FlowId(42);
104 let encoded = flow_id.to_consumer_key().encode();
105
106 let decoded = CdcConsumerKey::decode(&encoded).expect("Failed to decode key");
107 assert_eq!(decoded.consumer, CdcConsumerId::new("flow:42"));
108 }
109
110 #[test]
111 fn test_flow_id_keys_within_range() {
112 let flow1 = FlowId(1).to_consumer_key().encode();
113 let flow2 = FlowId(100).to_consumer_key().encode();
114 let flow3 = FlowId(999).to_consumer_key().encode();
115
116 let range = CdcConsumerKey::full_scan().encode();
117
118 assert!(range.contains(&flow1), "flow:1 key should be in range");
119 assert!(range.contains(&flow2), "flow:100 key should be in range");
120 assert!(range.contains(&flow3), "flow:999 key should be in range");
121 }
122}
123
124pub fn should_exclude_from_cdc(kind: KeyTag) -> bool {
125 matches!(
126 kind,
127 KeyTag::OperatorState
128 | KeyTag::CdcConsumer | KeyTag::Metric
129 | KeyTag::SystemSequence
130 | KeyTag::RowSequence | KeyTag::ColumnSequence
131 | KeyTag::SystemVersion
132 | KeyTag::FlowVersion | KeyTag::RingBufferMetadata
133 | KeyTag::Index | KeyTag::ConfigStorage
134 | KeyTag::Token | KeyTag::VersionEpoch
135 | KeyTag::QueuePartition
136 | KeyTag::QueueItemState
137 | KeyTag::QueueDue | KeyTag::QueueKeyActive
138 )
139}
140
141#[cfg(test)]
142pub mod primary_key_tests {
143 use super::*;
144
145 #[test]
146 fn test_all_key_kinds_have_explicit_cdc_decision() {
147 let test_variant = KeyTag::Row;
151
152 match test_variant {
153 KeyTag::Namespace => {}
154 KeyTag::Table => {}
155 KeyTag::Row => {}
156 KeyTag::NamespaceTable => {}
157 KeyTag::SystemSequence => {}
158 KeyTag::Columns => {}
159 KeyTag::Column => {}
160 KeyTag::RowSequence => {}
161 KeyTag::ColumnProperty => {}
162 KeyTag::SystemVersion => {}
163 KeyTag::Index => {}
164 KeyTag::IndexEntry => {}
165 KeyTag::ColumnSequence => {}
166 KeyTag::CdcConsumer => {}
167 KeyTag::View => {}
168 KeyTag::NamespaceView => {}
169 KeyTag::PrimaryKey => {}
170 KeyTag::OperatorState => {}
171 KeyTag::RingBuffer => {}
172 KeyTag::NamespaceRingBuffer => {}
173 KeyTag::RingBufferMetadata => {}
174 KeyTag::Flow => {}
175 KeyTag::NamespaceFlow => {}
176 KeyTag::Operator => {}
177 KeyTag::OperatorByFlow => {}
178 KeyTag::FlowEdge => {}
179 KeyTag::FlowEdgeByFlow => {}
180 KeyTag::OutputFrontier => {}
181 KeyTag::Dictionary => {}
182 KeyTag::DictionaryEntry => {}
183 KeyTag::DictionaryEntryIndex => {}
184 KeyTag::NamespaceDictionary => {}
185 KeyTag::Metric => {}
186 KeyTag::FlowVersion => {}
187 KeyTag::RowShape => {}
188 KeyTag::SumType => {}
189 KeyTag::NamespaceSumType => {}
190 KeyTag::RowShapeField => {}
191 KeyTag::Handler => {}
192 KeyTag::NamespaceHandler => {}
193 KeyTag::VariantHandler => {}
194 KeyTag::Series => {}
195 KeyTag::NamespaceSeries => {}
196 KeyTag::SeriesPartitionMetadata => {}
197 KeyTag::Identity => {}
198 KeyTag::Role => {}
199 KeyTag::GrantedRole => {}
200 KeyTag::Policy => {}
201 KeyTag::PolicyOp => {}
202 KeyTag::Migration => {}
203 KeyTag::Authentication => {}
204 KeyTag::MigrationEvent => {}
205 KeyTag::ConfigStorage => {}
206 KeyTag::Token => {}
207 KeyTag::Source => {}
208 KeyTag::NamespaceSource => {}
209 KeyTag::Sink => {}
210 KeyTag::NamespaceSink => {}
211 KeyTag::RowSettings => {}
212 KeyTag::Procedure => {}
213 KeyTag::NamespaceProcedure => {}
214 KeyTag::ProcedureParam => {}
215 KeyTag::Binding => {}
216 KeyTag::OperatorRetention => {}
217 KeyTag::NamespaceBinding => {}
218 KeyTag::ColumnBlock => {}
219 KeyTag::SeriesColumnBlock => {}
220 KeyTag::TableColumnBlock => {}
221 KeyTag::IdentityAttribute => {}
222 KeyTag::IdentityAttributeValue => {}
223 KeyTag::PartitionedRow => {}
224 KeyTag::PartitionedSeriesRow => {}
225 KeyTag::Partition => {}
226 KeyTag::Queue => {}
227 KeyTag::NamespaceQueue => {}
228 KeyTag::QueueDeduplication => {}
229 KeyTag::QueuePartition => {}
230 KeyTag::QueueItemState => {}
231 KeyTag::QueueDue => {}
232 KeyTag::QueueAttempt => {}
233 KeyTag::QueueKeyActive => {}
234 KeyTag::VersionEpoch => {}
235 KeyTag::SeriesRow => {}
236 KeyTag::SortedViewRow => {}
237 KeyTag::PartitionedSortedViewRow => {}
238 KeyTag::Relationship => {} }
243 }
244
245 #[test]
246 fn test_sorted_view_rows_reach_the_cdc_log() {
247 assert!(!should_exclude_from_cdc(KeyTag::SortedViewRow));
250 assert!(!should_exclude_from_cdc(KeyTag::PartitionedSortedViewRow));
251 }
252
253 #[test]
254 fn test_exclude_operator_state() {
255 assert!(should_exclude_from_cdc(KeyTag::OperatorState));
256 }
257
258 #[test]
259 fn test_exclude_cdc_consumer() {
260 assert!(should_exclude_from_cdc(KeyTag::CdcConsumer));
261 }
262
263 #[test]
264 fn test_exclude_storage_tracker() {
265 assert!(should_exclude_from_cdc(KeyTag::Metric));
266 }
267
268 #[test]
269 fn test_exclude_system_sequence() {
270 assert!(should_exclude_from_cdc(KeyTag::SystemSequence));
271 }
272
273 #[test]
274 fn test_exclude_row_sequence() {
275 assert!(should_exclude_from_cdc(KeyTag::RowSequence));
276 }
277
278 #[test]
279 fn test_exclude_column_sequence() {
280 assert!(should_exclude_from_cdc(KeyTag::ColumnSequence));
281 }
282
283 #[test]
284 fn test_exclude_system_version() {
285 assert!(should_exclude_from_cdc(KeyTag::SystemVersion));
286 }
287
288 #[test]
289 fn test_exclude_transaction_version() {}
290
291 #[test]
292 fn test_exclude_ring_buffer_metadata() {
293 assert!(should_exclude_from_cdc(KeyTag::RingBufferMetadata));
294 }
295
296 #[test]
297 fn test_exclude_index() {
298 assert!(should_exclude_from_cdc(KeyTag::Index));
299 }
300
301 #[test]
302 fn test_include_namespace() {
303 assert!(!should_exclude_from_cdc(KeyTag::Namespace));
304 }
305
306 #[test]
307 fn test_include_table() {
308 assert!(!should_exclude_from_cdc(KeyTag::Table));
309 }
310
311 #[test]
312 fn test_include_row() {
313 assert!(!should_exclude_from_cdc(KeyTag::Row));
314 }
315
316 #[test]
317 fn test_include_series_row() {
318 assert!(!should_exclude_from_cdc(KeyTag::SeriesRow));
320 }
321
322 #[test]
323 fn test_include_partitioned_row() {
324 assert!(!should_exclude_from_cdc(KeyTag::PartitionedRow));
325 }
326
327 #[test]
328 fn test_include_partition() {
329 assert!(!should_exclude_from_cdc(KeyTag::Partition));
330 }
331
332 #[test]
333 fn test_include_namespace_table() {
334 assert!(!should_exclude_from_cdc(KeyTag::NamespaceTable));
335 }
336
337 #[test]
338 fn test_include_columns() {
339 assert!(!should_exclude_from_cdc(KeyTag::Columns));
340 }
341
342 #[test]
343 fn test_include_column() {
344 assert!(!should_exclude_from_cdc(KeyTag::Column));
345 }
346
347 #[test]
348 fn test_include_column_property() {
349 assert!(!should_exclude_from_cdc(KeyTag::ColumnProperty));
350 }
351
352 #[test]
353 fn test_include_index_entry() {
354 assert!(!should_exclude_from_cdc(KeyTag::IndexEntry));
355 }
356
357 #[test]
358 fn test_include_view() {
359 assert!(!should_exclude_from_cdc(KeyTag::View));
360 }
361
362 #[test]
363 fn test_include_namespace_view() {
364 assert!(!should_exclude_from_cdc(KeyTag::NamespaceView));
365 }
366
367 #[test]
368 fn test_include_primary_key() {
369 assert!(!should_exclude_from_cdc(KeyTag::PrimaryKey));
370 }
371
372 #[test]
373 fn test_include_ring_buffer() {
374 assert!(!should_exclude_from_cdc(KeyTag::RingBuffer));
375 }
376
377 #[test]
378 fn test_include_namespace_ring_buffer() {
379 assert!(!should_exclude_from_cdc(KeyTag::NamespaceRingBuffer));
380 }
381
382 #[test]
383 fn test_include_queue() {
384 assert!(!should_exclude_from_cdc(KeyTag::Queue));
385 }
386
387 #[test]
388 fn test_include_namespace_queue() {
389 assert!(!should_exclude_from_cdc(KeyTag::NamespaceQueue));
390 }
391
392 #[test]
393 fn test_include_queue_deduplication() {
394 assert!(!should_exclude_from_cdc(KeyTag::QueueDeduplication));
395 }
396
397 #[test]
398 fn test_exclude_queue_partition() {
399 assert!(should_exclude_from_cdc(KeyTag::QueuePartition));
400 }
401
402 #[test]
403 fn test_exclude_queue_item_state() {
404 assert!(should_exclude_from_cdc(KeyTag::QueueItemState));
405 }
406
407 #[test]
408 fn test_exclude_queue_due() {
409 assert!(should_exclude_from_cdc(KeyTag::QueueDue));
410 }
411
412 #[test]
413 fn test_exclude_queue_key_active() {
414 assert!(should_exclude_from_cdc(KeyTag::QueueKeyActive));
415 }
416
417 #[test]
418 fn test_include_queue_attempt() {
419 assert!(!should_exclude_from_cdc(KeyTag::QueueAttempt));
423 }
424
425 #[test]
426 fn test_include_operator_retention() {
427 assert!(!should_exclude_from_cdc(KeyTag::OperatorRetention));
428 }
429
430 #[test]
431 fn test_include_flow() {
432 assert!(!should_exclude_from_cdc(KeyTag::Flow));
433 }
434
435 #[test]
436 fn test_include_namespace_flow() {
437 assert!(!should_exclude_from_cdc(KeyTag::NamespaceFlow));
438 }
439
440 #[test]
441 fn test_include_operator() {
442 assert!(!should_exclude_from_cdc(KeyTag::Operator));
443 }
444
445 #[test]
446 fn test_include_operator_by_flow() {
447 assert!(!should_exclude_from_cdc(KeyTag::OperatorByFlow));
448 }
449
450 #[test]
451 fn test_include_flow_edge() {
452 assert!(!should_exclude_from_cdc(KeyTag::FlowEdge));
453 }
454
455 #[test]
456 fn test_include_flow_edge_by_flow() {
457 assert!(!should_exclude_from_cdc(KeyTag::FlowEdgeByFlow));
458 }
459
460 #[test]
461 fn test_include_dictionary() {
462 assert!(!should_exclude_from_cdc(KeyTag::Dictionary));
463 }
464
465 #[test]
466 fn test_include_dictionary_entry() {
467 assert!(!should_exclude_from_cdc(KeyTag::DictionaryEntry));
468 }
469
470 #[test]
471 fn test_include_dictionary_entry_index() {
472 assert!(!should_exclude_from_cdc(KeyTag::DictionaryEntryIndex));
473 }
474
475 #[test]
476 fn test_include_namespace_dictionary() {
477 assert!(!should_exclude_from_cdc(KeyTag::NamespaceDictionary));
478 }
479
480 #[test]
481 fn test_include_handler() {
482 assert!(!should_exclude_from_cdc(KeyTag::Handler));
483 }
484
485 #[test]
486 fn test_include_namespace_handler() {
487 assert!(!should_exclude_from_cdc(KeyTag::NamespaceHandler));
488 }
489
490 #[test]
491 fn test_include_variant_handler() {
492 assert!(!should_exclude_from_cdc(KeyTag::VariantHandler));
493 }
494
495 #[test]
496 fn test_include_shape() {
497 assert!(!should_exclude_from_cdc(KeyTag::RowShape));
498 }
499
500 #[test]
501 fn test_include_sum_type() {
502 assert!(!should_exclude_from_cdc(KeyTag::SumType));
503 }
504
505 #[test]
506 fn test_include_namespace_sum_type() {
507 assert!(!should_exclude_from_cdc(KeyTag::NamespaceSumType));
508 }
509
510 #[test]
511 fn test_include_shape_field() {
512 assert!(!should_exclude_from_cdc(KeyTag::RowShapeField));
513 }
514
515 #[test]
516 fn test_include_series() {
517 assert!(!should_exclude_from_cdc(KeyTag::Series));
518 }
519
520 #[test]
521 fn test_include_namespace_series() {
522 assert!(!should_exclude_from_cdc(KeyTag::NamespaceSeries));
523 }
524
525 #[test]
526 fn test_include_series_partition_metadata() {
527 assert!(!should_exclude_from_cdc(KeyTag::SeriesPartitionMetadata));
528 }
529
530 #[test]
531 fn test_include_identity() {
532 assert!(!should_exclude_from_cdc(KeyTag::Identity));
533 }
534
535 #[test]
536 fn test_include_role() {
537 assert!(!should_exclude_from_cdc(KeyTag::Role));
538 }
539
540 #[test]
541 fn test_include_granted_role() {
542 assert!(!should_exclude_from_cdc(KeyTag::GrantedRole));
543 }
544
545 #[test]
546 fn test_include_identity_attribute() {
547 assert!(!should_exclude_from_cdc(KeyTag::IdentityAttribute));
548 }
549
550 #[test]
551 fn test_include_identity_attribute_value() {
552 assert!(!should_exclude_from_cdc(KeyTag::IdentityAttributeValue));
553 }
554
555 #[test]
556 fn test_include_authentication() {
557 assert!(!should_exclude_from_cdc(KeyTag::Authentication));
558 }
559
560 #[test]
561 fn test_include_policy() {
562 assert!(!should_exclude_from_cdc(KeyTag::Policy));
563 }
564
565 #[test]
566 fn test_include_policy_op() {
567 assert!(!should_exclude_from_cdc(KeyTag::PolicyOp));
568 }
569
570 #[test]
571 fn test_include_migration() {
572 assert!(!should_exclude_from_cdc(KeyTag::Migration));
573 }
574
575 #[test]
576 fn test_include_migration_event() {
577 assert!(!should_exclude_from_cdc(KeyTag::MigrationEvent));
578 }
579
580 #[test]
581 fn test_exclude_flow_version() {
582 assert!(should_exclude_from_cdc(KeyTag::FlowVersion));
583 }
584
585 #[test]
586 fn test_exclude_config() {
587 assert!(should_exclude_from_cdc(KeyTag::ConfigStorage));
588 }
589
590 #[test]
591 fn test_exclude_version_epoch() {
592 assert!(should_exclude_from_cdc(KeyTag::VersionEpoch));
593 }
594}