reifydb_core/interface/catalog/
source.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later, see license.md file
3
4use reifydb_type::return_internal_error;
5use serde::{Deserialize, Serialize};
6
7use crate::interface::{
8	DictionaryId, FlowDef, FlowId, RingBufferId, TableDef, TableId, TableVirtualDef, TableVirtualId, ViewDef,
9	ViewId,
10};
11
12#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash, Serialize, Deserialize)]
13pub enum SourceId {
14	Table(TableId),
15	View(ViewId),
16	Flow(FlowId),
17	TableVirtual(TableVirtualId),
18	RingBuffer(RingBufferId),
19	Dictionary(DictionaryId),
20}
21
22impl std::fmt::Display for SourceId {
23	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24		match self {
25			SourceId::Table(id) => write!(f, "{}", id.0),
26			SourceId::View(id) => write!(f, "{}", id.0),
27			SourceId::Flow(id) => write!(f, "{}", id.0),
28			SourceId::TableVirtual(id) => write!(f, "{}", id.0),
29			SourceId::RingBuffer(id) => write!(f, "{}", id.0),
30			SourceId::Dictionary(id) => write!(f, "{}", id.0),
31		}
32	}
33}
34
35impl SourceId {
36	pub fn table(id: impl Into<TableId>) -> Self {
37		Self::Table(id.into())
38	}
39
40	pub fn view(id: impl Into<ViewId>) -> Self {
41		Self::View(id.into())
42	}
43
44	pub fn flow(id: impl Into<FlowId>) -> Self {
45		Self::Flow(id.into())
46	}
47
48	pub fn table_virtual(id: impl Into<TableVirtualId>) -> Self {
49		Self::TableVirtual(id.into())
50	}
51
52	pub fn ringbuffer(id: impl Into<RingBufferId>) -> Self {
53		Self::RingBuffer(id.into())
54	}
55
56	pub fn dictionary(id: impl Into<DictionaryId>) -> Self {
57		Self::Dictionary(id.into())
58	}
59}
60
61impl From<TableId> for SourceId {
62	fn from(id: TableId) -> Self {
63		SourceId::Table(id)
64	}
65}
66
67impl From<ViewId> for SourceId {
68	fn from(id: ViewId) -> Self {
69		SourceId::View(id)
70	}
71}
72
73impl From<FlowId> for SourceId {
74	fn from(id: FlowId) -> Self {
75		SourceId::Flow(id)
76	}
77}
78
79impl From<TableVirtualId> for SourceId {
80	fn from(id: TableVirtualId) -> Self {
81		SourceId::TableVirtual(id)
82	}
83}
84
85impl From<RingBufferId> for SourceId {
86	fn from(id: RingBufferId) -> Self {
87		SourceId::RingBuffer(id)
88	}
89}
90
91impl From<DictionaryId> for SourceId {
92	fn from(id: DictionaryId) -> Self {
93		SourceId::Dictionary(id)
94	}
95}
96
97impl PartialEq<u64> for SourceId {
98	fn eq(&self, other: &u64) -> bool {
99		match self {
100			SourceId::Table(id) => id.0.eq(other),
101			SourceId::View(id) => id.0.eq(other),
102			SourceId::Flow(id) => id.0.eq(other),
103			SourceId::TableVirtual(id) => id.0.eq(other),
104			SourceId::RingBuffer(id) => id.0.eq(other),
105			SourceId::Dictionary(id) => id.0.eq(other),
106		}
107	}
108}
109
110impl PartialEq<TableId> for SourceId {
111	fn eq(&self, other: &TableId) -> bool {
112		match self {
113			SourceId::Table(id) => id.0 == other.0,
114			_ => false,
115		}
116	}
117}
118
119impl PartialEq<ViewId> for SourceId {
120	fn eq(&self, other: &ViewId) -> bool {
121		match self {
122			SourceId::View(id) => id.0 == other.0,
123			_ => false,
124		}
125	}
126}
127
128impl PartialEq<FlowId> for SourceId {
129	fn eq(&self, other: &FlowId) -> bool {
130		match self {
131			SourceId::Flow(id) => id.0 == other.0,
132			_ => false,
133		}
134	}
135}
136
137impl PartialEq<TableVirtualId> for SourceId {
138	fn eq(&self, other: &TableVirtualId) -> bool {
139		match self {
140			SourceId::TableVirtual(id) => id.0 == other.0,
141			_ => false,
142		}
143	}
144}
145
146impl PartialEq<RingBufferId> for SourceId {
147	fn eq(&self, other: &RingBufferId) -> bool {
148		match self {
149			SourceId::RingBuffer(id) => id.0 == other.0,
150			_ => false,
151		}
152	}
153}
154
155impl PartialEq<DictionaryId> for SourceId {
156	fn eq(&self, other: &DictionaryId) -> bool {
157		match self {
158			SourceId::Dictionary(id) => id.0 == other.0,
159			_ => false,
160		}
161	}
162}
163
164impl From<SourceId> for u64 {
165	fn from(source: SourceId) -> u64 {
166		source.as_u64()
167	}
168}
169
170impl SourceId {
171	/// Returns the type discriminant as a u8 value
172	pub fn to_type_u8(&self) -> u8 {
173		match self {
174			SourceId::Table(_) => 1,
175			SourceId::View(_) => 2,
176			SourceId::Flow(_) => 3,
177			SourceId::TableVirtual(_) => 4,
178			SourceId::RingBuffer(_) => 5,
179			SourceId::Dictionary(_) => 6,
180		}
181	}
182
183	/// Returns the raw u64 value regardless of the source type
184	pub fn as_u64(&self) -> u64 {
185		match self {
186			SourceId::Table(id) => id.0,
187			SourceId::View(id) => id.0,
188			SourceId::Flow(id) => id.0,
189			SourceId::TableVirtual(id) => id.0,
190			SourceId::RingBuffer(id) => id.0,
191			SourceId::Dictionary(id) => id.0,
192		}
193	}
194
195	/// Creates a next source id for range operations (numerically next)
196	pub fn next(&self) -> SourceId {
197		match self {
198			SourceId::Table(table) => SourceId::table(table.0 + 1),
199			SourceId::View(view) => SourceId::view(view.0 + 1),
200			SourceId::Flow(flow) => SourceId::flow(flow.0 + 1),
201			SourceId::TableVirtual(table_virtual) => SourceId::table_virtual(table_virtual.0 + 1),
202			SourceId::RingBuffer(ringbuffer) => SourceId::ringbuffer(ringbuffer.0 + 1),
203			SourceId::Dictionary(dictionary) => SourceId::dictionary(dictionary.0 + 1),
204		}
205	}
206
207	/// Creates a previous source id for range operations (numerically
208	/// previous) In descending order encoding, this gives us the next
209	/// value in sort order Uses wrapping_sub to handle ID 0 correctly
210	/// (wraps to u64::MAX)
211	pub fn prev(&self) -> SourceId {
212		match self {
213			SourceId::Table(table) => SourceId::table(table.0.wrapping_sub(1)),
214			SourceId::View(view) => SourceId::view(view.0.wrapping_sub(1)),
215			SourceId::Flow(flow) => SourceId::flow(flow.0.wrapping_sub(1)),
216			SourceId::TableVirtual(table_virtual) => {
217				SourceId::table_virtual(table_virtual.0.wrapping_sub(1))
218			}
219			SourceId::RingBuffer(ringbuffer) => SourceId::ringbuffer(ringbuffer.0.wrapping_sub(1)),
220			SourceId::Dictionary(dictionary) => SourceId::dictionary(dictionary.0.wrapping_sub(1)),
221		}
222	}
223
224	pub fn to_table_id(self) -> crate::Result<TableId> {
225		if let SourceId::Table(table) = self {
226			Ok(table)
227		} else {
228			return_internal_error!(
229				"Data inconsistency: Expected SourceId::Table but found {:?}. \
230				This indicates a critical catalog inconsistency where a non-table source ID \
231				was used in a context that requires a table ID.",
232				self
233			)
234		}
235	}
236
237	pub fn to_view_id(self) -> crate::Result<ViewId> {
238		if let SourceId::View(view) = self {
239			Ok(view)
240		} else {
241			return_internal_error!(
242				"Data inconsistency: Expected SourceId::View but found {:?}. \
243				This indicates a critical catalog inconsistency where a non-view source ID \
244				was used in a context that requires a view ID.",
245				self
246			)
247		}
248	}
249
250	pub fn to_flow_id(self) -> crate::Result<FlowId> {
251		if let SourceId::Flow(flow) = self {
252			Ok(flow)
253		} else {
254			return_internal_error!(
255				"Data inconsistency: Expected SourceId::Flow but found {:?}. \
256				This indicates a critical catalog inconsistency where a non-flow source ID \
257				was used in a context that requires a flow ID.",
258				self
259			)
260		}
261	}
262
263	pub fn to_table_virtual_id(self) -> crate::Result<TableVirtualId> {
264		if let SourceId::TableVirtual(table_virtual) = self {
265			Ok(table_virtual)
266		} else {
267			return_internal_error!(
268				"Data inconsistency: Expected SourceId::TableVirtual but found {:?}. \
269				This indicates a critical catalog inconsistency where a non-virtual-table source ID \
270				was used in a context that requires a virtual table ID.",
271				self
272			)
273		}
274	}
275
276	pub fn to_ringbuffer_id(self) -> crate::Result<RingBufferId> {
277		if let SourceId::RingBuffer(ringbuffer) = self {
278			Ok(ringbuffer)
279		} else {
280			return_internal_error!(
281				"Data inconsistency: Expected SourceId::RingBuffer but found {:?}. \
282				This indicates a critical catalog inconsistency where a non-ring-buffer source ID \
283				was used in a context that requires a ring buffer ID.",
284				self
285			)
286		}
287	}
288
289	pub fn to_dictionary_id(self) -> crate::Result<DictionaryId> {
290		if let SourceId::Dictionary(dictionary) = self {
291			Ok(dictionary)
292		} else {
293			return_internal_error!(
294				"Data inconsistency: Expected SourceId::Dictionary but found {:?}. \
295				This indicates a critical catalog inconsistency where a non-dictionary source ID \
296				was used in a context that requires a dictionary ID.",
297				self
298			)
299		}
300	}
301}
302
303#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
304pub enum SourceDef {
305	Table(TableDef),
306	View(ViewDef),
307	Flow(FlowDef),
308	TableVirtual(TableVirtualDef),
309}
310
311impl SourceDef {
312	pub fn id(&self) -> SourceId {
313		match self {
314			SourceDef::Table(table) => table.id.into(),
315			SourceDef::View(view) => view.id.into(),
316			SourceDef::Flow(flow) => flow.id.into(),
317			SourceDef::TableVirtual(table_virtual) => table_virtual.id.into(),
318		}
319	}
320
321	pub fn source_type(&self) -> SourceId {
322		match self {
323			SourceDef::Table(table) => SourceId::Table(table.id),
324			SourceDef::View(view) => SourceId::View(view.id),
325			SourceDef::Flow(flow) => SourceId::Flow(flow.id),
326			SourceDef::TableVirtual(table_virtual) => SourceId::TableVirtual(table_virtual.id),
327		}
328	}
329}