1use reifydb_codec::{
5 key::encoded::{EncodedKey, EncodedKeyRange},
6 row::bytes::EncodedBytes,
7};
8use reifydb_value::{Result, util::cowvec::CowVec};
9
10use crate::{
11 common::CommitVersion,
12 delta::Delta,
13 interface::catalog::storage::StorageId,
14 key::{
15 KeyRangeCodec,
16 any::TaggedKey,
17 row::{
18 PartitionedRowKey, PartitionedRowKeyRange, PartitionedSortedViewRowKey, RowKey, RowKeyRange,
19 SortedViewRowKey, StoragePartitionedRowKey, StorageRowKey,
20 },
21 series::{
22 PartitionedSeriesRowKey, PartitionedSeriesRowKeyRange, SeriesRowKey, SeriesRowKeyRange,
23 StoragePartitionedSeriesKey, StorageSeriesKey,
24 },
25 tag::KeyTag,
26 typed::BoundedKey,
27 },
28};
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31pub enum Tier {
32 Buffer,
33 Persistent,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37pub enum EntryLayout {
38 Row,
39 Series,
40 SortedView,
41}
42
43impl EntryLayout {
44 pub fn type_tag(&self) -> u8 {
45 match self {
46 Self::Row => 1,
47 Self::Series => 2,
48 Self::SortedView => 3,
49 }
50 }
51
52 pub fn from_type_tag(tag: u8) -> Option<Self> {
53 match tag {
54 1 => Some(Self::Row),
55 2 => Some(Self::Series),
56 3 => Some(Self::SortedView),
57 _ => None,
58 }
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
63pub enum EntryKind {
64 Multi,
65
66 Source(StorageId, EntryLayout),
67
68 PartitionedSource(StorageId, EntryLayout),
69}
70
71impl EntryKind {
72 pub fn caches_ranges(&self) -> bool {
73 matches!(self, Self::Source(_, EntryLayout::Row | EntryLayout::Series))
74 }
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
78pub enum StorageKey {
79 Table(StorageRowKey),
80 RingBuffer(StorageRowKey),
81 Queue(StorageRowKey),
82 View(StorageRowKey),
83
84 PartitionedTable(StoragePartitionedRowKey),
85 PartitionedRingBuffer(StoragePartitionedRowKey),
86 PartitionedQueue(StoragePartitionedRowKey),
87 PartitionedView(StoragePartitionedRowKey),
88
89 Series(StorageSeriesKey),
90 SeriesView(StorageSeriesKey),
91
92 PartitionedSeries(StoragePartitionedSeriesKey),
93 PartitionedSeriesView(StoragePartitionedSeriesKey),
94}
95
96fn row_storage_key(storage: StorageId, row: StorageRowKey) -> Option<StorageKey> {
97 match storage {
98 StorageId::Table(_) => Some(StorageKey::Table(row)),
99 StorageId::RingBuffer(_) => Some(StorageKey::RingBuffer(row)),
100 StorageId::Queue(_) => Some(StorageKey::Queue(row)),
101 StorageId::View(_) => Some(StorageKey::View(row)),
102 StorageId::Series(_) => None,
103 }
104}
105
106fn partitioned_row_storage_key(storage: StorageId, row: StoragePartitionedRowKey) -> Option<StorageKey> {
107 match storage {
108 StorageId::Table(_) => Some(StorageKey::PartitionedTable(row)),
109 StorageId::RingBuffer(_) => Some(StorageKey::PartitionedRingBuffer(row)),
110 StorageId::Queue(_) => Some(StorageKey::PartitionedQueue(row)),
111 StorageId::View(_) => Some(StorageKey::PartitionedView(row)),
112 StorageId::Series(_) => None,
113 }
114}
115
116fn series_storage_key(storage: StorageId, series: StorageSeriesKey) -> Option<StorageKey> {
117 match storage {
118 StorageId::Series(_) => Some(StorageKey::Series(series)),
119 StorageId::View(_) => Some(StorageKey::SeriesView(series)),
120 StorageId::Table(_) | StorageId::RingBuffer(_) | StorageId::Queue(_) => None,
121 }
122}
123
124fn partitioned_series_storage_key(storage: StorageId, series: StoragePartitionedSeriesKey) -> Option<StorageKey> {
125 match storage {
126 StorageId::Series(_) => Some(StorageKey::PartitionedSeries(series)),
127 StorageId::View(_) => Some(StorageKey::PartitionedSeriesView(series)),
128 StorageId::Table(_) | StorageId::RingBuffer(_) | StorageId::Queue(_) => None,
129 }
130}
131
132fn source_entry(storage: StorageId, layout: EntryLayout, key: Option<StorageKey>) -> (EntryKind, Option<StorageKey>) {
133 match key {
134 Some(key) => (EntryKind::Source(storage, layout), Some(key)),
135 None => (EntryKind::Multi, None),
136 }
137}
138
139fn partitioned_source_entry(
140 storage: StorageId,
141 layout: EntryLayout,
142 key: Option<StorageKey>,
143) -> (EntryKind, Option<StorageKey>) {
144 match key {
145 Some(key) => (EntryKind::PartitionedSource(storage, layout), Some(key)),
146 None => (EntryKind::Multi, None),
147 }
148}
149
150pub fn storage_key(key: &EncodedKey) -> (EntryKind, Option<StorageKey>) {
151 match KeyTag::of(key) {
152 Some(KeyTag::Row) => match RowKey::decode(key) {
153 Some(row_key) => source_entry(
154 row_key.storage,
155 EntryLayout::Row,
156 row_storage_key(row_key.storage, StorageRowKey::new(row_key.row)),
157 ),
158 None => (EntryKind::Multi, None),
159 },
160 Some(KeyTag::SeriesRow) => match SeriesRowKey::decode(key) {
161 Some(series_key) => source_entry(
162 series_key.storage,
163 EntryLayout::Series,
164 series_storage_key(series_key.storage, StorageSeriesKey::from(series_key)),
165 ),
166 None => (EntryKind::Multi, None),
167 },
168 Some(KeyTag::PartitionedRow) => match PartitionedRowKey::decode(key) {
169 Some(partitioned_key) => partitioned_source_entry(
170 partitioned_key.storage,
171 EntryLayout::Row,
172 partitioned_row_storage_key(
173 partitioned_key.storage,
174 StoragePartitionedRowKey::new(partitioned_key.partition, partitioned_key.row),
175 ),
176 ),
177 None => (EntryKind::Multi, None),
178 },
179 Some(KeyTag::PartitionedSeriesRow) => match PartitionedSeriesRowKey::decode(key) {
180 Some(partitioned_key) => partitioned_source_entry(
181 partitioned_key.storage,
182 EntryLayout::Series,
183 partitioned_series_storage_key(
184 partitioned_key.storage,
185 StoragePartitionedSeriesKey::from(partitioned_key),
186 ),
187 ),
188 None => (EntryKind::Multi, None),
189 },
190 Some(KeyTag::SortedViewRow) => match SortedViewRowKey::storage_of(key) {
191 Some(storage) => (EntryKind::Source(storage, EntryLayout::SortedView), None),
192 None => (EntryKind::Multi, None),
193 },
194 Some(KeyTag::PartitionedSortedViewRow) => match PartitionedSortedViewRowKey::storage_of(key) {
195 Some(storage) => (EntryKind::PartitionedSource(storage, EntryLayout::SortedView), None),
196 None => (EntryKind::Multi, None),
197 },
198 _ => (EntryKind::Multi, None),
199 }
200}
201
202pub fn storage_key_of(key: &TaggedKey) -> (EntryKind, Option<StorageKey>) {
203 match key {
204 TaggedKey::Row(row_key) => source_entry(
205 row_key.storage,
206 EntryLayout::Row,
207 row_storage_key(row_key.storage, StorageRowKey::new(row_key.row)),
208 ),
209 TaggedKey::SeriesRow(series_key) => source_entry(
210 series_key.storage,
211 EntryLayout::Series,
212 series_storage_key(series_key.storage, StorageSeriesKey::from(series_key.clone())),
213 ),
214 TaggedKey::PartitionedRow(partitioned_key) => partitioned_source_entry(
215 partitioned_key.storage,
216 EntryLayout::Row,
217 partitioned_row_storage_key(
218 partitioned_key.storage,
219 StoragePartitionedRowKey::new(partitioned_key.partition, partitioned_key.row),
220 ),
221 ),
222 TaggedKey::PartitionedSeriesRow(partitioned_key) => partitioned_source_entry(
223 partitioned_key.storage,
224 EntryLayout::Series,
225 partitioned_series_storage_key(
226 partitioned_key.storage,
227 StoragePartitionedSeriesKey::from(partitioned_key.clone()),
228 ),
229 ),
230 TaggedKey::SortedViewRow(sorted) => (EntryKind::Source(sorted.storage, EntryLayout::SortedView), None),
231 TaggedKey::PartitionedSortedViewRow(sorted) => {
232 (EntryKind::PartitionedSource(sorted.storage, EntryLayout::SortedView), None)
233 }
234 _ => (EntryKind::Multi, None),
235 }
236}
237
238pub fn classify_key_of(key: &TaggedKey) -> EntryKind {
239 storage_key_of(key).0
240}
241
242pub fn classify_key(key: &EncodedKey) -> EntryKind {
243 storage_key(key).0
244}
245
246pub fn classify_range(range: &EncodedKeyRange) -> Option<EntryKind> {
247 if let (Some(start), Some(_end)) = RowKeyRange::decode(range) {
248 return row_storage_key(start.storage, <StorageRowKey as BoundedKey>::low())
249 .map(|_| EntryKind::Source(start.storage, EntryLayout::Row));
250 }
251
252 if let (Some(start), Some(_end)) = SeriesRowKeyRange::decode(range) {
253 return series_storage_key(start, <StorageSeriesKey as BoundedKey>::low())
254 .map(|_| EntryKind::Source(start, EntryLayout::Series));
255 }
256
257 if let (Some(start), Some(_end)) = PartitionedRowKeyRange::decode(range) {
258 return partitioned_row_storage_key(start.storage, <StoragePartitionedRowKey as BoundedKey>::low())
259 .map(|_| EntryKind::PartitionedSource(start.storage, EntryLayout::Row));
260 }
261
262 if let (Some(start), Some(_end)) = PartitionedSeriesRowKeyRange::decode(range) {
263 return partitioned_series_storage_key(start, <StoragePartitionedSeriesKey as BoundedKey>::low())
264 .map(|_| EntryKind::PartitionedSource(start, EntryLayout::Series));
265 }
266
267 if let Some(storage) = SortedViewRowKey::range_storage_of(range) {
268 return Some(EntryKind::Source(storage, EntryLayout::SortedView));
269 }
270
271 if let Some(storage) = PartitionedSortedViewRowKey::range_storage_of(range) {
272 return Some(EntryKind::PartitionedSource(storage, EntryLayout::SortedView));
273 }
274
275 None
276}
277
278#[derive(Debug, Clone)]
279pub struct MultiVersionRow<K = EncodedKey> {
280 pub key: K,
281 pub bytes: EncodedBytes,
282 pub version: CommitVersion,
283}
284
285#[derive(Debug, Clone)]
286pub struct SingleVersionRow {
287 pub key: EncodedKey,
288 pub bytes: EncodedBytes,
289}
290
291#[derive(Debug, Clone)]
292pub struct MultiVersionBatch<K = EncodedKey> {
293 pub items: Vec<MultiVersionRow<K>>,
294
295 pub has_more: bool,
296}
297
298impl<K> MultiVersionBatch<K> {
299 pub fn empty() -> Self {
300 Self {
301 items: Vec::new(),
302 has_more: false,
303 }
304 }
305
306 pub fn is_empty(&self) -> bool {
307 self.items.is_empty()
308 }
309}
310
311pub trait MultiVersionCommit: Send + Sync {
312 fn commit(&self, deltas: CowVec<Delta>, version: CommitVersion) -> Result<()>;
313}
314
315pub trait MultiVersionGet: Send + Sync {
316 fn get(&self, key: &TaggedKey, version: CommitVersion) -> Result<Option<MultiVersionRow<TaggedKey>>>;
317}
318
319pub trait MultiVersionContains: Send + Sync {
320 fn contains(&self, key: &TaggedKey, version: CommitVersion) -> Result<bool>;
321}
322
323pub trait MultiVersionGetPrevious: Send + Sync {
324 fn get_previous_version(
325 &self,
326 key: &TaggedKey,
327 before_version: CommitVersion,
328 ) -> Result<Option<MultiVersionRow<TaggedKey>>>;
329}
330
331pub trait MultiVersionStore:
332 Send + Sync + Clone + MultiVersionCommit + MultiVersionGet + MultiVersionGetPrevious + MultiVersionContains + 'static
333{
334}
335
336#[derive(Debug, Clone)]
337pub struct SingleVersionBatch {
338 pub items: Vec<SingleVersionRow>,
339
340 pub has_more: bool,
341}
342
343impl SingleVersionBatch {
344 pub fn empty() -> Self {
345 Self {
346 items: Vec::new(),
347 has_more: false,
348 }
349 }
350
351 pub fn is_empty(&self) -> bool {
352 self.items.is_empty()
353 }
354}
355
356pub trait SingleVersionCommit: Send + Sync {
357 fn commit(&mut self, deltas: CowVec<Delta>) -> Result<()>;
358}
359
360pub trait SingleVersionGet: Send + Sync {
361 fn get(&self, key: &EncodedKey) -> Result<Option<SingleVersionRow>>;
362}
363
364pub trait SingleVersionContains: Send + Sync {
365 fn contains(&self, key: &EncodedKey) -> Result<bool>;
366}
367
368pub trait SingleVersionRange: Send + Sync {
369 fn range_batch(&self, range: EncodedKeyRange, batch_size: u64) -> Result<SingleVersionBatch>;
370
371 fn range(&self, range: EncodedKeyRange) -> Result<SingleVersionBatch> {
372 self.range_batch(range, 1024)
373 }
374
375 fn prefix(&self, prefix: &EncodedKey) -> Result<SingleVersionBatch> {
376 self.range(EncodedKeyRange::prefix(prefix))
377 }
378}
379
380pub trait SingleVersionRangeRev: Send + Sync {
381 fn range_rev_batch(&self, range: EncodedKeyRange, batch_size: u64) -> Result<SingleVersionBatch>;
382
383 fn range_rev(&self, range: EncodedKeyRange) -> Result<SingleVersionBatch> {
384 self.range_rev_batch(range, 1024)
385 }
386
387 fn prefix_rev(&self, prefix: &EncodedKey) -> Result<SingleVersionBatch> {
388 self.range_rev(EncodedKeyRange::prefix(prefix))
389 }
390}
391
392pub trait SingleVersionStore:
393 Send
394 + Sync
395 + Clone
396 + SingleVersionCommit
397 + SingleVersionGet
398 + SingleVersionContains
399 + SingleVersionRange
400 + SingleVersionRangeRev
401 + 'static
402{
403}
404
405#[cfg(test)]
406mod tests {
407 use reifydb_codec::key::encoded::EncodedKey;
408 use reifydb_value::value::{Value, partition::Partition, row_number::RowNumber};
409
410 use super::{EntryKind, EntryLayout, StorageKey, classify_key, classify_range, storage_key};
411 use crate::{
412 interface::catalog::{
413 id::{SeriesId, TableId, ViewId},
414 storage::StorageId,
415 },
416 key::{
417 any::TaggedKey,
418 row::{
419 PartitionedRowKey, PartitionedSortedViewRowKey, RowKey, RowSequenceKey,
420 SortedViewRowKey, StoragePartitionedRowKey, StorageRowKey,
421 },
422 series::{
423 PartitionedSeriesRowKey, PartitionedSeriesRowKeyRange, SeriesRowKey, SeriesRowKeyRange,
424 StoragePartitionedSeriesKey, StorageSeriesKey,
425 },
426 },
427 };
428
429 fn part(v: &str) -> Partition {
430 Partition::of(&[Value::Utf8(v.to_string())])
431 }
432
433 #[test]
434 fn storage_key_hands_back_the_identity_it_decoded() {
435 let storage = StorageId::Table(TableId(7));
438
439 let row = RowKey::encoded(storage, RowNumber(5));
440 assert_eq!(
441 storage_key(&row),
442 (
443 EntryKind::Source(storage, EntryLayout::Row),
444 Some(StorageKey::Table(StorageRowKey::new(RowNumber(5))))
445 )
446 );
447
448 let partitioned = PartitionedRowKey::encoded(storage, part("us"), RowNumber(5));
449 assert_eq!(
450 storage_key(&partitioned),
451 (
452 EntryKind::PartitionedSource(storage, EntryLayout::Row),
453 Some(StorageKey::PartitionedTable(StoragePartitionedRowKey::new(
454 part("us"),
455 RowNumber(5)
456 )))
457 )
458 );
459 }
460
461 #[test]
462 fn storage_key_names_the_storage_a_row_belongs_to() {
463 let row = StorageRowKey::new(RowNumber(5));
466 for (storage, expected) in [
467 (StorageId::table(7), StorageKey::Table(row)),
468 (StorageId::ringbuffer(7), StorageKey::RingBuffer(row)),
469 (StorageId::queue(7), StorageKey::Queue(row)),
470 (StorageId::view(7), StorageKey::View(row)),
471 ] {
472 assert_eq!(storage_key(&RowKey::encoded(storage, RowNumber(5))).1, Some(expected));
473 }
474 }
475
476 #[test]
477 fn a_series_key_carries_its_own_identity_on_a_series_and_on_a_view() {
478 let series = StorageSeriesKey::new(None, 5, 1);
481 for (storage, expected) in [
482 (StorageId::series(7), StorageKey::Series(series)),
483 (StorageId::view(7), StorageKey::SeriesView(series)),
484 ] {
485 let series = SeriesRowKey {
486 storage,
487 variant_tag: None,
488 key: 5,
489 sequence: 1,
490 }
491 .encode();
492 assert_eq!(
493 storage_key(&series),
494 (EntryKind::Source(storage, EntryLayout::Series), Some(expected))
495 );
496 }
497
498 let partitioned = StoragePartitionedSeriesKey::new(part("us"), None, 5, 1);
499 for (storage, expected) in [
500 (StorageId::series(7), StorageKey::PartitionedSeries(partitioned)),
501 (StorageId::view(7), StorageKey::PartitionedSeriesView(partitioned)),
502 ] {
503 let partitioned = PartitionedSeriesRowKey::encoded(storage, part("us"), None, 5, 1);
504 assert_eq!(
505 storage_key(&partitioned),
506 (EntryKind::PartitionedSource(storage, EntryLayout::Series), Some(expected))
507 );
508 }
509 }
510
511 #[test]
512 fn a_view_row_and_a_view_series_row_do_not_share_a_storage_key() {
513 let storage = StorageId::view(7);
516 let row = storage_key(&RowKey::encoded(storage, RowNumber(5))).1.unwrap();
517 let series = storage_key(
518 &SeriesRowKey {
519 storage,
520 variant_tag: None,
521 key: 5,
522 sequence: 5,
523 }
524 .encode(),
525 )
526 .1
527 .unwrap();
528 assert_ne!(row, series);
529 }
530
531 #[test]
532 fn a_layout_its_storage_cannot_hold_claims_no_entry_at_all() {
533 let storage = StorageId::series(7);
536 assert_eq!(storage_key(&RowKey::encoded(storage, RowNumber(5))), (EntryKind::Multi, None));
537
538 let series_on_a_table = SeriesRowKey {
539 storage: StorageId::table(7),
540 variant_tag: None,
541 key: 5,
542 sequence: 1,
543 }
544 .encode();
545 assert_eq!(storage_key(&series_on_a_table), (EntryKind::Multi, None));
546 }
547
548 #[test]
549 fn a_source_entry_never_holds_a_key_without_an_identity() {
550 let series = |storage| {
553 SeriesRowKey {
554 storage,
555 variant_tag: None,
556 key: 5,
557 sequence: 1,
558 }
559 .encode()
560 };
561
562 for storage in [
563 StorageId::table(7),
564 StorageId::ringbuffer(7),
565 StorageId::queue(7),
566 StorageId::view(7),
567 StorageId::series(7),
568 ] {
569 for key in [
570 RowKey::encoded(storage, RowNumber(5)),
571 PartitionedRowKey::encoded(storage, part("us"), RowNumber(5)),
572 series(storage),
573 PartitionedSeriesRowKey::encoded(storage, part("us"), None, 5, 1),
574 RowSequenceKey::encoded(storage),
575 ] {
576 let (entry, ident) = storage_key(&key);
577 match entry {
578 EntryKind::Multi => assert_eq!(ident, None),
579 EntryKind::Source(_, _) | EntryKind::PartitionedSource(_, _) => {
580 assert!(ident.is_some(), "{entry:?} took a key with no identity")
581 }
582 }
583 }
584 }
585 }
586
587 #[test]
588 fn an_entry_never_mixes_the_two_layouts() {
589 let storage = StorageId::view(7);
592 let row = storage_key(&RowKey::encoded(storage, RowNumber(5))).0;
593 let series = storage_key(
594 &SeriesRowKey {
595 storage,
596 variant_tag: None,
597 key: 5,
598 sequence: 1,
599 }
600 .encode(),
601 )
602 .0;
603
604 assert_eq!(row, EntryKind::Source(storage, EntryLayout::Row));
605 assert_eq!(series, EntryKind::Source(storage, EntryLayout::Series));
606
607 let partitioned_row = storage_key(&PartitionedRowKey::encoded(storage, part("us"), RowNumber(5))).0;
608 let partitioned_series =
609 storage_key(&PartitionedSeriesRowKey::encoded(storage, part("us"), None, 5, 1)).0;
610
611 assert_eq!(partitioned_row, EntryKind::PartitionedSource(storage, EntryLayout::Row));
612 assert_eq!(partitioned_series, EntryKind::PartitionedSource(storage, EntryLayout::Series));
613 }
614
615 #[test]
616 fn storage_key_agrees_with_classify_key_on_the_entry() {
617 let storage = StorageId::Table(TableId(7));
618 for key in [
619 RowKey::encoded(storage, RowNumber(5)),
620 PartitionedRowKey::encoded(storage, part("us"), RowNumber(5)),
621 RowSequenceKey::encoded(storage),
622 ] {
623 assert_eq!(storage_key(&key).0, classify_key(&key));
624 }
625 }
626
627 #[test]
628 fn an_over_long_row_kind_key_never_passes_as_a_row() {
629 let storage = StorageId::view(3);
633 let mut over_long = RowKey::encoded(storage, RowNumber(1)).as_slice().to_vec();
634 over_long.extend_from_slice(&[0xAA; 8]);
635 over_long.extend_from_slice(&99u64.to_be_bytes());
636
637 assert_eq!(storage_key(&EncodedKey::new(over_long)), (EntryKind::Multi, None));
638 }
639
640 #[test]
641 fn a_sorted_view_key_and_a_sorted_view_scan_range_classify_the_same_way() {
642 let storage = StorageId::view(3);
646
647 let mut sorted_view = SortedViewRowKey::storage_start(storage).as_slice().to_vec();
648 sorted_view.extend_from_slice(&[0xAA; 8]);
649 sorted_view.extend_from_slice(&99u64.to_be_bytes());
650 let sorted_view = EncodedKey::new(sorted_view);
651 let range = SortedViewRowKey::scan_range(storage, None).encode();
652 assert_eq!(classify_key(&sorted_view), EntryKind::Source(storage, EntryLayout::SortedView));
653 assert_eq!(classify_range(&range).unwrap_or(EntryKind::Multi), classify_key(&sorted_view));
654
655 let mut partitioned = PartitionedSortedViewRowKey::storage_start(storage).as_slice().to_vec();
656 partitioned.extend_from_slice(&[0xBB; 16]);
657 partitioned.extend_from_slice(&[0xAA; 8]);
658 partitioned.extend_from_slice(&99u64.to_be_bytes());
659 let partitioned = EncodedKey::new(partitioned);
660 let partitioned_range = PartitionedSortedViewRowKey::scan_range(storage, None).encode();
661 assert_eq!(classify_key(&partitioned), EntryKind::PartitionedSource(storage, EntryLayout::SortedView));
662 assert_eq!(classify_range(&partitioned_range).unwrap_or(EntryKind::Multi), classify_key(&partitioned));
663 }
664
665 #[test]
666 fn a_sorted_view_scan_range_never_reaches_the_narrowed_row_bucket() {
667 let storage = StorageId::view(3);
670 assert_ne!(
671 classify_range(&SortedViewRowKey::scan_range(storage, None).encode()),
672 Some(EntryKind::Source(storage, EntryLayout::Row))
673 );
674 assert_ne!(
675 classify_range(&PartitionedSortedViewRowKey::scan_range(storage, None).encode()),
676 Some(EntryKind::PartitionedSource(storage, EntryLayout::Row))
677 );
678 }
679
680 #[test]
681 fn storage_key_leaves_a_key_it_does_not_own_without_an_identity() {
682 assert_eq!(
683 storage_key(&RowSequenceKey::encoded(StorageId::Table(TableId(7)))),
684 (EntryKind::Multi, None)
685 );
686 }
687
688 #[test]
689 fn classify_key_partitioned_row_is_partitioned_source() {
690 let storage = StorageId::Table(TableId(7));
691 let key = PartitionedRowKey::encoded(storage, part("us"), RowNumber(1));
692 assert_eq!(classify_key(&key), EntryKind::PartitionedSource(storage, EntryLayout::Row));
693 }
694
695 #[test]
696 fn classify_key_partitioned_view_row_is_partitioned_source() {
697 let storage = StorageId::view(7);
699 let key = PartitionedRowKey::encoded(storage, part("us"), RowNumber(1));
700 assert_eq!(classify_key(&key), EntryKind::PartitionedSource(storage, EntryLayout::Row));
701 assert_ne!(
702 classify_key(&key),
703 EntryKind::PartitionedSource(StorageId::table(7), EntryLayout::Row),
704 "a view and a table sharing id 7 must not classify to the same entry"
705 );
706 }
707
708 #[test]
709 fn classify_key_row_is_still_source() {
710 let storage = StorageId::Table(TableId(7));
711 let key = RowKey::encoded(storage, RowNumber(1));
712 assert_eq!(classify_key(&key), EntryKind::Source(storage, EntryLayout::Row));
713 }
714
715 #[test]
716 fn classify_range_all_partition_forms_are_partitioned_source_for_table_and_view() {
717 for storage in [StorageId::Table(TableId(9)), StorageId::view(9)] {
719 let p = part("us");
720 let last = TaggedKey::from(PartitionedRowKey::new(storage, p, RowNumber(5)));
721 assert_eq!(
722 classify_range(&PartitionedRowKey::partition_range(storage, p).encode()),
723 Some(EntryKind::PartitionedSource(storage, EntryLayout::Row))
724 );
725 assert_eq!(
726 classify_range(
727 &PartitionedRowKey::partition_scan_range(storage, p, Some(&last)).encode()
728 ),
729 Some(EntryKind::PartitionedSource(storage, EntryLayout::Row))
730 );
731 assert_eq!(
732 classify_range(&PartitionedRowKey::scan_range(storage, None).encode()),
733 Some(EntryKind::PartitionedSource(storage, EntryLayout::Row))
734 );
735 assert_eq!(
736 classify_range(&PartitionedRowKey::full_scan(storage).encode()),
737 Some(EntryKind::PartitionedSource(storage, EntryLayout::Row))
738 );
739 }
740 }
741
742 #[test]
743 fn classify_range_row_range_is_still_source() {
744 let storage = StorageId::Table(TableId(9));
745 assert_eq!(
746 classify_range(&RowKey::full_scan(storage).encode()),
747 Some(EntryKind::Source(storage, EntryLayout::Row))
748 );
749 }
750
751 #[test]
752 fn classify_key_and_classify_range_agree_for_the_series_kinds() {
753 let series = StorageId::series(SeriesId(11));
756 let view = StorageId::View(ViewId(11));
757
758 for storage in [series, view] {
759 let key = SeriesRowKey {
760 storage,
761 variant_tag: None,
762 key: 5,
763 sequence: 1,
764 }
765 .encode();
766 assert_eq!(classify_key(&key), EntryKind::Source(storage, EntryLayout::Series));
767 assert_eq!(
768 classify_range(&SeriesRowKeyRange::full_scan(storage, None).encode()),
769 Some(EntryKind::Source(storage, EntryLayout::Series))
770 );
771
772 let partitioned = PartitionedSeriesRowKey::encoded(
773 storage,
774 Partition::of(&[Value::Utf8("us".to_string())]),
775 None,
776 5,
777 1,
778 );
779 assert_eq!(
780 classify_key(&partitioned),
781 EntryKind::PartitionedSource(storage, EntryLayout::Series)
782 );
783 assert_eq!(
784 classify_range(&PartitionedSeriesRowKeyRange::full_scan(storage).encode()),
785 Some(EntryKind::PartitionedSource(storage, EntryLayout::Series))
786 );
787 }
788 }
789}