Skip to main content

reifydb_core/interface/
resolved.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::sync::Arc;
5
6use reifydb_type::{
7	error::NumberOutOfRangeDescriptor,
8	fragment::Fragment,
9	value::{constraint::TypeConstraint, r#type::Type},
10};
11use serde::{Deserialize, Serialize};
12
13use super::catalog::{
14	column::ColumnDef,
15	dictionary::DictionaryDef,
16	namespace::Namespace,
17	property::ColumnPropertyKind,
18	ringbuffer::RingBufferDef,
19	series::SeriesDef,
20	subscription::{SubscriptionColumnDef, SubscriptionDef},
21	table::TableDef,
22	view::ViewDef,
23	vtable::VTableDef,
24};
25
26/// Resolved namespace with both identifier and definition
27#[derive(Debug, Clone)]
28pub enum ResolvedNamespace {
29	Local(Arc<ResolvedNamespaceInner>),
30	Remote(Arc<ResolvedNamespaceInner>),
31}
32
33#[derive(Debug)]
34pub struct ResolvedNamespaceInner {
35	identifier: Fragment,
36	def: Namespace,
37}
38
39impl ResolvedNamespace {
40	pub fn new(identifier: Fragment, def: Namespace) -> Self {
41		let is_remote = def.is_remote();
42		let inner = Arc::new(ResolvedNamespaceInner {
43			identifier,
44			def,
45		});
46		if is_remote {
47			Self::Remote(inner)
48		} else {
49			Self::Local(inner)
50		}
51	}
52
53	fn inner(&self) -> &ResolvedNamespaceInner {
54		match self {
55			Self::Local(inner) | Self::Remote(inner) => inner,
56		}
57	}
58
59	/// Get the namespace name
60	pub fn name(&self) -> &str {
61		self.inner().def.name()
62	}
63
64	/// Get the namespace def
65	pub fn def(&self) -> &Namespace {
66		&self.inner().def
67	}
68
69	/// Get the fragment for error reporting
70	pub fn fragment(&self) -> &Fragment {
71		&self.inner().identifier
72	}
73
74	/// Whether this is a remote namespace
75	pub fn is_remote(&self) -> bool {
76		matches!(self, Self::Remote(_))
77	}
78
79	/// Get the remote address if this is a remote namespace
80	pub fn address(&self) -> Option<&str> {
81		self.inner().def.address()
82	}
83
84	/// Convert to owned version with 'static lifetime
85	pub fn to_static(&self) -> ResolvedNamespace {
86		let inner = self.inner();
87		ResolvedNamespace::new(Fragment::internal(inner.identifier.text()), inner.def.clone())
88	}
89}
90
91/// Resolved physical table
92#[derive(Debug, Clone)]
93pub struct ResolvedTable(Arc<ResolvedTableInner>);
94
95#[derive(Debug)]
96struct ResolvedTableInner {
97	pub identifier: Fragment,
98	pub namespace: ResolvedNamespace,
99	pub def: TableDef,
100}
101
102impl ResolvedTable {
103	pub fn new(identifier: Fragment, namespace: ResolvedNamespace, def: TableDef) -> Self {
104		Self(Arc::new(ResolvedTableInner {
105			identifier,
106			namespace,
107			def,
108		}))
109	}
110
111	/// Get the table name
112	pub fn name(&self) -> &str {
113		&self.0.def.name
114	}
115
116	/// Get the table def
117	pub fn def(&self) -> &TableDef {
118		&self.0.def
119	}
120
121	/// Get the namespace
122	pub fn namespace(&self) -> &ResolvedNamespace {
123		&self.0.namespace
124	}
125
126	/// Get the identifier
127	pub fn identifier(&self) -> &Fragment {
128		&self.0.identifier
129	}
130
131	/// Get fully qualified name
132	pub fn fully_qualified_name(&self) -> String {
133		format!("{}::{}", self.0.namespace.name(), self.name())
134	}
135
136	/// Get columns
137	pub fn columns(&self) -> &[ColumnDef] {
138		&self.0.def.columns
139	}
140
141	/// Find a column by name
142	pub fn find_column(&self, name: &str) -> Option<&ColumnDef> {
143		self.0.def.columns.iter().find(|c| c.name == name)
144	}
145
146	/// Convert to owned version with 'static lifetime
147	pub fn to_static(&self) -> ResolvedTable {
148		ResolvedTable(Arc::new(ResolvedTableInner {
149			identifier: Fragment::internal(self.0.identifier.text()),
150			namespace: self.0.namespace.clone(),
151			def: self.0.def.clone(),
152		}))
153	}
154}
155
156/// Resolved virtual table (system tables, information_schema)
157#[derive(Debug, Clone)]
158pub struct ResolvedTableVirtual(Arc<ResolvedTableVirtualInner>);
159
160#[derive(Debug)]
161struct ResolvedTableVirtualInner {
162	pub identifier: Fragment,
163	pub namespace: ResolvedNamespace,
164	pub def: VTableDef,
165}
166
167impl ResolvedTableVirtual {
168	pub fn new(identifier: Fragment, namespace: ResolvedNamespace, def: VTableDef) -> Self {
169		Self(Arc::new(ResolvedTableVirtualInner {
170			identifier,
171			namespace,
172			def,
173		}))
174	}
175
176	pub fn name(&self) -> &str {
177		&self.0.def.name
178	}
179
180	pub fn def(&self) -> &VTableDef {
181		&self.0.def
182	}
183
184	pub fn namespace(&self) -> &ResolvedNamespace {
185		&self.0.namespace
186	}
187
188	pub fn identifier(&self) -> &Fragment {
189		&self.0.identifier
190	}
191
192	pub fn columns(&self) -> &[ColumnDef] {
193		&self.0.def.columns
194	}
195
196	/// Convert to owned version with 'static lifetime
197	pub fn to_static(&self) -> ResolvedTableVirtual {
198		ResolvedTableVirtual(Arc::new(ResolvedTableVirtualInner {
199			identifier: Fragment::internal(self.0.identifier.text()),
200			namespace: self.0.namespace.clone(),
201			def: self.0.def.clone(),
202		}))
203	}
204}
205
206/// Resolved ring buffer
207#[derive(Debug, Clone)]
208pub struct ResolvedRingBuffer(Arc<ResolvedRingBufferInner>);
209
210#[derive(Debug)]
211struct ResolvedRingBufferInner {
212	pub identifier: Fragment,
213	pub namespace: ResolvedNamespace,
214	pub def: RingBufferDef,
215}
216
217impl ResolvedRingBuffer {
218	pub fn new(identifier: Fragment, namespace: ResolvedNamespace, def: RingBufferDef) -> Self {
219		Self(Arc::new(ResolvedRingBufferInner {
220			identifier,
221			namespace,
222			def,
223		}))
224	}
225
226	/// Get the ring buffer name
227	pub fn name(&self) -> &str {
228		&self.0.def.name
229	}
230
231	/// Get the ring buffer def
232	pub fn def(&self) -> &RingBufferDef {
233		&self.0.def
234	}
235
236	/// Get the namespace
237	pub fn namespace(&self) -> &ResolvedNamespace {
238		&self.0.namespace
239	}
240
241	/// Get the identifier
242	pub fn identifier(&self) -> &Fragment {
243		&self.0.identifier
244	}
245
246	/// Get fully qualified name
247	pub fn fully_qualified_name(&self) -> String {
248		format!("{}::{}", self.0.namespace.name(), self.name())
249	}
250
251	/// Get columns
252	pub fn columns(&self) -> &[ColumnDef] {
253		&self.0.def.columns
254	}
255
256	/// Find a column by name
257	pub fn find_column(&self, name: &str) -> Option<&ColumnDef> {
258		self.0.def.columns.iter().find(|c| c.name == name)
259	}
260
261	/// Convert to owned version with 'static lifetime
262	pub fn to_static(&self) -> ResolvedRingBuffer {
263		ResolvedRingBuffer(Arc::new(ResolvedRingBufferInner {
264			identifier: Fragment::internal(self.0.identifier.text()),
265			namespace: self.0.namespace.clone(),
266			def: self.0.def.clone(),
267		}))
268	}
269}
270
271/// Resolved dictionary
272#[derive(Debug, Clone)]
273pub struct ResolvedDictionary(Arc<ResolvedDictionaryInner>);
274
275#[derive(Debug)]
276struct ResolvedDictionaryInner {
277	pub identifier: Fragment,
278	pub namespace: ResolvedNamespace,
279	pub def: DictionaryDef,
280}
281
282impl ResolvedDictionary {
283	pub fn new(identifier: Fragment, namespace: ResolvedNamespace, def: DictionaryDef) -> Self {
284		Self(Arc::new(ResolvedDictionaryInner {
285			identifier,
286			namespace,
287			def,
288		}))
289	}
290
291	/// Get the dictionary name
292	pub fn name(&self) -> &str {
293		&self.0.def.name
294	}
295
296	/// Get the dictionary def
297	pub fn def(&self) -> &DictionaryDef {
298		&self.0.def
299	}
300
301	/// Get the namespace
302	pub fn namespace(&self) -> &ResolvedNamespace {
303		&self.0.namespace
304	}
305
306	/// Get the identifier
307	pub fn identifier(&self) -> &Fragment {
308		&self.0.identifier
309	}
310
311	/// Get fully qualified name
312	pub fn fully_qualified_name(&self) -> String {
313		format!("{}::{}", self.0.namespace.name(), self.name())
314	}
315
316	/// Convert to owned version with 'static lifetime
317	pub fn to_static(&self) -> ResolvedDictionary {
318		ResolvedDictionary(Arc::new(ResolvedDictionaryInner {
319			identifier: Fragment::internal(self.0.identifier.text()),
320			namespace: self.0.namespace.clone(),
321			def: self.0.def.clone(),
322		}))
323	}
324}
325
326/// Resolved series
327#[derive(Debug, Clone)]
328pub struct ResolvedSeries(Arc<ResolvedSeriesInner>);
329
330#[derive(Debug)]
331struct ResolvedSeriesInner {
332	pub identifier: Fragment,
333	pub namespace: ResolvedNamespace,
334	pub def: SeriesDef,
335}
336
337impl ResolvedSeries {
338	pub fn new(identifier: Fragment, namespace: ResolvedNamespace, def: SeriesDef) -> Self {
339		Self(Arc::new(ResolvedSeriesInner {
340			identifier,
341			namespace,
342			def,
343		}))
344	}
345
346	/// Get the series name
347	pub fn name(&self) -> &str {
348		&self.0.def.name
349	}
350
351	/// Get the series def
352	pub fn def(&self) -> &SeriesDef {
353		&self.0.def
354	}
355
356	/// Get the namespace
357	pub fn namespace(&self) -> &ResolvedNamespace {
358		&self.0.namespace
359	}
360
361	/// Get the identifier
362	pub fn identifier(&self) -> &Fragment {
363		&self.0.identifier
364	}
365
366	/// Get fully qualified name
367	pub fn fully_qualified_name(&self) -> String {
368		format!("{}.{}", self.0.namespace.name(), self.name())
369	}
370
371	/// Get columns
372	pub fn columns(&self) -> &[ColumnDef] {
373		&self.0.def.columns
374	}
375
376	/// Find a column by name
377	pub fn find_column(&self, name: &str) -> Option<&ColumnDef> {
378		self.0.def.columns.iter().find(|c| c.name == name)
379	}
380
381	/// Convert to owned version with 'static lifetime
382	pub fn to_static(&self) -> ResolvedSeries {
383		ResolvedSeries(Arc::new(ResolvedSeriesInner {
384			identifier: Fragment::internal(self.0.identifier.text()),
385			namespace: self.0.namespace.clone(),
386			def: self.0.def.clone(),
387		}))
388	}
389}
390
391/// Resolved subscription (global entity, no namespace)
392#[derive(Debug, Clone)]
393pub struct ResolvedSubscription(Arc<ResolvedSubscriptionInner>);
394
395#[derive(Debug)]
396struct ResolvedSubscriptionInner {
397	pub identifier: Fragment,
398	pub def: SubscriptionDef,
399}
400
401impl ResolvedSubscription {
402	pub fn new(identifier: Fragment, def: SubscriptionDef) -> Self {
403		Self(Arc::new(ResolvedSubscriptionInner {
404			identifier,
405			def,
406		}))
407	}
408
409	/// Get the subscription ID as a string identifier
410	pub fn id_str(&self) -> String {
411		format!("subscription_{}", self.0.def.id.0)
412	}
413
414	/// Get the subscription def
415	pub fn def(&self) -> &SubscriptionDef {
416		&self.0.def
417	}
418
419	/// Get the identifier
420	pub fn identifier(&self) -> &Fragment {
421		&self.0.identifier
422	}
423
424	/// Get columns
425	pub fn columns(&self) -> &[SubscriptionColumnDef] {
426		&self.0.def.columns
427	}
428
429	/// Find a column by name
430	pub fn find_column(&self, name: &str) -> Option<&SubscriptionColumnDef> {
431		self.0.def.columns.iter().find(|c| c.name == name)
432	}
433
434	/// Convert to owned version with 'static lifetime
435	pub fn to_static(&self) -> ResolvedSubscription {
436		ResolvedSubscription(Arc::new(ResolvedSubscriptionInner {
437			identifier: Fragment::internal(self.0.identifier.text()),
438			def: self.0.def.clone(),
439		}))
440	}
441}
442
443/// Resolved transaction view
444#[derive(Debug, Clone)]
445pub struct ResolvedView(Arc<ResolvedViewInner>);
446
447#[derive(Debug)]
448struct ResolvedViewInner {
449	pub identifier: Fragment,
450	pub namespace: ResolvedNamespace,
451	pub def: ViewDef,
452}
453
454impl ResolvedView {
455	pub fn new(identifier: Fragment, namespace: ResolvedNamespace, def: ViewDef) -> Self {
456		Self(Arc::new(ResolvedViewInner {
457			identifier,
458			namespace,
459			def,
460		}))
461	}
462
463	pub fn name(&self) -> &str {
464		&self.0.def.name
465	}
466
467	pub fn def(&self) -> &ViewDef {
468		&self.0.def
469	}
470
471	pub fn namespace(&self) -> &ResolvedNamespace {
472		&self.0.namespace
473	}
474
475	pub fn identifier(&self) -> &Fragment {
476		&self.0.identifier
477	}
478
479	pub fn columns(&self) -> &[ColumnDef] {
480		&self.0.def.columns
481	}
482
483	pub fn fully_qualified_name(&self) -> String {
484		format!("{}::{}", self.0.namespace.name(), self.name())
485	}
486
487	/// Convert to owned version with 'static lifetime
488	pub fn to_static(&self) -> ResolvedView {
489		ResolvedView(Arc::new(ResolvedViewInner {
490			identifier: Fragment::internal(self.0.identifier.text()),
491			namespace: self.0.namespace.clone(),
492			def: self.0.def.clone(),
493		}))
494	}
495}
496
497#[derive(Debug, Clone)]
498pub struct ResolvedDeferredView(Arc<ResolvedDeferredViewInner>);
499
500#[derive(Debug)]
501struct ResolvedDeferredViewInner {
502	pub identifier: Fragment,
503	pub namespace: ResolvedNamespace,
504	pub def: ViewDef,
505}
506
507impl ResolvedDeferredView {
508	pub fn new(identifier: Fragment, namespace: ResolvedNamespace, def: ViewDef) -> Self {
509		Self(Arc::new(ResolvedDeferredViewInner {
510			identifier,
511			namespace,
512			def,
513		}))
514	}
515
516	pub fn name(&self) -> &str {
517		&self.0.def.name
518	}
519
520	pub fn def(&self) -> &ViewDef {
521		&self.0.def
522	}
523
524	pub fn namespace(&self) -> &ResolvedNamespace {
525		&self.0.namespace
526	}
527
528	pub fn identifier(&self) -> &Fragment {
529		&self.0.identifier
530	}
531
532	pub fn columns(&self) -> &[ColumnDef] {
533		&self.0.def.columns
534	}
535
536	/// Convert to owned version with 'static lifetime
537	pub fn to_static(&self) -> ResolvedDeferredView {
538		ResolvedDeferredView(Arc::new(ResolvedDeferredViewInner {
539			identifier: Fragment::internal(self.0.identifier.text()),
540			namespace: self.0.namespace.clone(),
541			def: self.0.def.clone(),
542		}))
543	}
544}
545
546#[derive(Debug, Clone)]
547pub struct ResolvedTransactionalView(Arc<ResolvedTransactionalViewInner>);
548
549#[derive(Debug)]
550struct ResolvedTransactionalViewInner {
551	pub identifier: Fragment,
552	pub namespace: ResolvedNamespace,
553	pub def: ViewDef,
554}
555
556impl ResolvedTransactionalView {
557	pub fn new(identifier: Fragment, namespace: ResolvedNamespace, def: ViewDef) -> Self {
558		Self(Arc::new(ResolvedTransactionalViewInner {
559			identifier,
560			namespace,
561			def,
562		}))
563	}
564
565	pub fn name(&self) -> &str {
566		&self.0.def.name
567	}
568
569	pub fn def(&self) -> &ViewDef {
570		&self.0.def
571	}
572
573	pub fn namespace(&self) -> &ResolvedNamespace {
574		&self.0.namespace
575	}
576
577	pub fn identifier(&self) -> &Fragment {
578		&self.0.identifier
579	}
580
581	pub fn columns(&self) -> &[ColumnDef] {
582		&self.0.def.columns
583	}
584
585	/// Convert to owned version with 'static lifetime
586	pub fn to_static(&self) -> ResolvedTransactionalView {
587		ResolvedTransactionalView(Arc::new(ResolvedTransactionalViewInner {
588			identifier: Fragment::internal(self.0.identifier.text()),
589			namespace: self.0.namespace.clone(),
590			def: self.0.def.clone(),
591		}))
592	}
593}
594
595#[derive(Debug, Clone)]
596pub struct ResolvedSequence(Arc<ResolvedSequenceInner>);
597
598#[derive(Debug)]
599struct ResolvedSequenceInner {
600	pub identifier: Fragment,
601	pub namespace: ResolvedNamespace,
602	pub def: SequenceDef,
603}
604
605impl ResolvedSequence {
606	pub fn new(identifier: Fragment, namespace: ResolvedNamespace, def: SequenceDef) -> Self {
607		Self(Arc::new(ResolvedSequenceInner {
608			identifier,
609			namespace,
610			def,
611		}))
612	}
613
614	pub fn identifier(&self) -> &Fragment {
615		&self.0.identifier
616	}
617
618	pub fn namespace(&self) -> &ResolvedNamespace {
619		&self.0.namespace
620	}
621
622	pub fn def(&self) -> &SequenceDef {
623		&self.0.def
624	}
625}
626
627#[derive(Debug, Clone)]
628pub struct ResolvedIndex(Arc<ResolvedIndexInner>);
629
630#[derive(Debug)]
631struct ResolvedIndexInner {
632	pub identifier: Fragment,
633	pub table: ResolvedTable,
634	pub def: IndexDef,
635}
636
637impl ResolvedIndex {
638	pub fn new(identifier: Fragment, table: ResolvedTable, def: IndexDef) -> Self {
639		Self(Arc::new(ResolvedIndexInner {
640			identifier,
641			table,
642			def,
643		}))
644	}
645
646	pub fn identifier(&self) -> &Fragment {
647		&self.0.identifier
648	}
649
650	pub fn table(&self) -> &ResolvedTable {
651		&self.0.table
652	}
653
654	pub fn def(&self) -> &IndexDef {
655		&self.0.def
656	}
657}
658
659#[derive(Debug, Clone)]
660pub struct ResolvedFunction(Arc<ResolvedFunctionInner>);
661
662#[derive(Debug)]
663struct ResolvedFunctionInner {
664	pub identifier: Fragment,
665	pub namespace: Vec<ResolvedNamespace>,
666	pub def: FunctionDef,
667}
668
669impl ResolvedFunction {
670	pub fn new(identifier: Fragment, namespace: Vec<ResolvedNamespace>, def: FunctionDef) -> Self {
671		Self(Arc::new(ResolvedFunctionInner {
672			identifier,
673			namespace,
674			def,
675		}))
676	}
677
678	pub fn identifier(&self) -> &Fragment {
679		&self.0.identifier
680	}
681
682	pub fn namespace(&self) -> &[ResolvedNamespace] {
683		&self.0.namespace
684	}
685
686	pub fn def(&self) -> &FunctionDef {
687		&self.0.def
688	}
689}
690/// Unified enum for any resolved primitive type
691#[derive(Debug, Clone)]
692pub enum ResolvedPrimitive {
693	Table(ResolvedTable),
694	TableVirtual(ResolvedTableVirtual),
695	View(ResolvedView),
696	DeferredView(ResolvedDeferredView),
697	TransactionalView(ResolvedTransactionalView),
698	RingBuffer(ResolvedRingBuffer),
699	Dictionary(ResolvedDictionary),
700	Series(ResolvedSeries),
701}
702
703impl ResolvedPrimitive {
704	/// Get the identifier fragment
705	pub fn identifier(&self) -> &Fragment {
706		match self {
707			Self::Table(t) => t.identifier(),
708			Self::TableVirtual(t) => t.identifier(),
709			Self::View(v) => v.identifier(),
710			Self::DeferredView(v) => v.identifier(),
711			Self::TransactionalView(v) => v.identifier(),
712			Self::RingBuffer(r) => r.identifier(),
713			Self::Dictionary(d) => d.identifier(),
714			Self::Series(s) => s.identifier(),
715		}
716	}
717
718	/// Get the primitive name
719	pub fn name(&self) -> &str {
720		match self {
721			Self::Table(t) => t.name(),
722			Self::TableVirtual(t) => t.name(),
723			Self::View(v) => v.name(),
724			Self::DeferredView(v) => v.name(),
725			Self::TransactionalView(v) => v.name(),
726			Self::RingBuffer(r) => r.name(),
727			Self::Dictionary(d) => d.name(),
728			Self::Series(s) => s.name(),
729		}
730	}
731
732	/// Get the namespace if this primitive has one
733	pub fn namespace(&self) -> Option<&ResolvedNamespace> {
734		match self {
735			Self::Table(t) => Some(t.namespace()),
736			Self::TableVirtual(t) => Some(t.namespace()),
737			Self::View(v) => Some(v.namespace()),
738			Self::DeferredView(v) => Some(v.namespace()),
739			Self::TransactionalView(v) => Some(v.namespace()),
740			Self::RingBuffer(r) => Some(r.namespace()),
741			Self::Dictionary(d) => Some(d.namespace()),
742			Self::Series(s) => Some(s.namespace()),
743		}
744	}
745
746	/// Check if this primitive supports indexes
747	pub fn supports_indexes(&self) -> bool {
748		matches!(self, Self::Table(_))
749	}
750
751	/// Check if this primitive supports mutations
752	pub fn supports_mutations(&self) -> bool {
753		matches!(self, Self::Table(_) | Self::RingBuffer(_) | Self::Series(_))
754	}
755
756	/// Get columns for this primitive
757	pub fn columns(&self) -> &[ColumnDef] {
758		match self {
759			Self::Table(t) => t.columns(),
760			Self::TableVirtual(t) => t.columns(),
761			Self::View(v) => v.columns(),
762			Self::DeferredView(v) => v.columns(),
763			Self::TransactionalView(v) => v.columns(),
764			Self::RingBuffer(r) => r.columns(),
765			Self::Dictionary(_d) => unreachable!(), // Dictionary columns are dynamic (id, value)
766			Self::Series(s) => s.columns(),
767		}
768	}
769
770	/// Find a column by name
771	pub fn find_column(&self, name: &str) -> Option<&ColumnDef> {
772		self.columns().iter().find(|c| c.name == name)
773	}
774
775	/// Get the primitive kind name for error messages
776	pub fn kind_name(&self) -> &'static str {
777		match self {
778			Self::Table(_) => "table",
779			Self::TableVirtual(_) => "virtual table",
780			Self::View(_) => "view",
781			Self::DeferredView(_) => "deferred view",
782			Self::TransactionalView(_) => "transactional view",
783			Self::RingBuffer(_) => "ring buffer",
784			Self::Dictionary(_) => "dictionary",
785			Self::Series(_) => "series",
786		}
787	}
788
789	/// Get fully qualified name if available
790	pub fn fully_qualified_name(&self) -> Option<String> {
791		match self {
792			Self::Table(t) => Some(t.fully_qualified_name()),
793			Self::View(v) => Some(v.fully_qualified_name()),
794			Self::DeferredView(v) => Some(format!("{}::{}", v.namespace().name(), v.name())),
795			Self::TransactionalView(v) => Some(format!("{}::{}", v.namespace().name(), v.name())),
796			Self::TableVirtual(t) => Some(format!("{}::{}", t.namespace().name(), t.name())),
797			Self::RingBuffer(r) => Some(r.fully_qualified_name()),
798			Self::Dictionary(d) => Some(d.fully_qualified_name()),
799			Self::Series(s) => Some(s.fully_qualified_name()),
800		}
801	}
802
803	/// Convert to a table if this is a table primitive
804	pub fn as_table(&self) -> Option<&ResolvedTable> {
805		match self {
806			Self::Table(t) => Some(t),
807			_ => None,
808		}
809	}
810
811	/// Convert to a view if this is a view primitive
812	pub fn as_view(&self) -> Option<&ResolvedView> {
813		match self {
814			Self::View(v) => Some(v),
815			_ => None,
816		}
817	}
818
819	/// Convert to a ring buffer if this is a ring buffer primitive
820	pub fn as_ringbuffer(&self) -> Option<&ResolvedRingBuffer> {
821		match self {
822			Self::RingBuffer(r) => Some(r),
823			_ => None,
824		}
825	}
826
827	/// Convert to a dictionary if this is a dictionary primitive
828	pub fn as_dictionary(&self) -> Option<&ResolvedDictionary> {
829		match self {
830			Self::Dictionary(d) => Some(d),
831			_ => None,
832		}
833	}
834
835	/// Convert to a series if this is a series primitive
836	pub fn as_series(&self) -> Option<&ResolvedSeries> {
837		match self {
838			Self::Series(s) => Some(s),
839			_ => None,
840		}
841	}
842}
843
844/// Column with its resolved primitive
845#[derive(Debug, Clone)]
846pub struct ResolvedColumn(Arc<ResolvedColumnInner>);
847
848#[derive(Debug)]
849struct ResolvedColumnInner {
850	/// Original identifier with fragments
851	pub identifier: Fragment,
852	/// The resolved primitive this column belongs to
853	pub primitive: ResolvedPrimitive,
854	/// The column definition
855	pub def: ColumnDef,
856}
857
858impl ResolvedColumn {
859	pub fn new(identifier: Fragment, primitive: ResolvedPrimitive, def: ColumnDef) -> Self {
860		Self(Arc::new(ResolvedColumnInner {
861			identifier,
862			primitive,
863			def,
864		}))
865	}
866
867	/// Get the column name
868	pub fn name(&self) -> &str {
869		&self.0.def.name
870	}
871
872	/// Get the column def
873	pub fn def(&self) -> &ColumnDef {
874		&self.0.def
875	}
876
877	/// Get the identifier
878	pub fn identifier(&self) -> &Fragment {
879		&self.0.identifier
880	}
881
882	/// Get the primitive
883	pub fn primitive(&self) -> &ResolvedPrimitive {
884		&self.0.primitive
885	}
886
887	/// Get the type constraint of this column
888	pub fn type_constraint(&self) -> &TypeConstraint {
889		&self.0.def.constraint
890	}
891
892	/// Get the column type
893	pub fn column_type(&self) -> Type {
894		self.0.def.constraint.get_type()
895	}
896
897	/// Get the column policies
898	pub fn properties(&self) -> Vec<ColumnPropertyKind> {
899		self.0.def.properties.iter().map(|p| p.property.clone()).collect()
900	}
901
902	/// Check if column has auto increment
903	pub fn is_auto_increment(&self) -> bool {
904		self.0.def.auto_increment
905	}
906
907	/// Get the namespace this column belongs to
908	pub fn namespace(&self) -> Option<&ResolvedNamespace> {
909		self.0.primitive.namespace()
910	}
911
912	/// Get fully qualified name
913	pub fn qualified_name(&self) -> String {
914		match self.0.primitive.fully_qualified_name() {
915			Some(primitive_name) => {
916				format!("{}.{}", primitive_name, self.name())
917			}
918			None => format!("{}.{}", self.0.primitive.identifier().text(), self.name()),
919		}
920	}
921
922	/// Get the fragment for error reporting
923	pub fn fragment(&self) -> &Fragment {
924		&self.0.identifier
925	}
926
927	/// Convert to owned version with 'static lifetime
928	pub fn to_static(&self) -> ResolvedColumn {
929		ResolvedColumn(Arc::new(ResolvedColumnInner {
930			identifier: Fragment::internal(self.0.identifier.text()),
931			primitive: self.0.primitive.clone(),
932			def: self.0.def.clone(),
933		}))
934	}
935}
936
937// Helper function to convert ResolvedColumn to NumberOutOfRangeDescriptor
938// This is used in evaluation context for error reporting
939pub fn resolved_column_to_number_descriptor(column: &ResolvedColumn) -> NumberOutOfRangeDescriptor {
940	let (namespace, table) = match column.primitive() {
941		ResolvedPrimitive::Table(table) => {
942			(Some(table.namespace().name().to_string()), Some(table.name().to_string()))
943		}
944		ResolvedPrimitive::TableVirtual(table) => {
945			(Some(table.namespace().name().to_string()), Some(table.name().to_string()))
946		}
947		ResolvedPrimitive::RingBuffer(rb) => {
948			(Some(rb.namespace().name().to_string()), Some(rb.name().to_string()))
949		}
950		ResolvedPrimitive::View(view) => {
951			(Some(view.namespace().name().to_string()), Some(view.name().to_string()))
952		}
953		ResolvedPrimitive::DeferredView(view) => {
954			(Some(view.namespace().name().to_string()), Some(view.name().to_string()))
955		}
956		ResolvedPrimitive::TransactionalView(view) => {
957			(Some(view.namespace().name().to_string()), Some(view.name().to_string()))
958		}
959		ResolvedPrimitive::Dictionary(dict) => {
960			(Some(dict.namespace().name().to_string()), Some(dict.name().to_string()))
961		}
962		ResolvedPrimitive::Series(series) => {
963			(Some(series.namespace().name().to_string()), Some(series.name().to_string()))
964		}
965	};
966
967	NumberOutOfRangeDescriptor {
968		namespace,
969		table,
970		column: Some(column.name().to_string()),
971		column_type: Some(column.column_type()),
972	}
973}
974
975// Placeholder types - these will be defined properly in catalog
976#[derive(Debug, Clone, Serialize, Deserialize)]
977pub struct SequenceDef {
978	pub name: String,
979	pub current_value: i64,
980	pub increment: i64,
981}
982
983#[derive(Debug, Clone, Serialize, Deserialize)]
984pub struct IndexDef {
985	pub name: String,
986	pub columns: Vec<String>,
987	pub unique: bool,
988}
989
990#[derive(Debug, Clone, Serialize, Deserialize)]
991pub struct FunctionDef {
992	pub name: String,
993	pub parameters: Vec<String>,
994	pub return_type: String,
995}
996
997#[cfg(test)]
998pub mod tests {
999	use reifydb_type::{
1000		fragment::Fragment,
1001		value::{constraint::TypeConstraint, r#type::Type},
1002	};
1003
1004	use super::*;
1005	use crate::interface::catalog::{
1006		column::ColumnIndex,
1007		id::{ColumnId, NamespaceId, TableId},
1008	};
1009
1010	fn test_namespace_def() -> Namespace {
1011		Namespace::Local {
1012			id: NamespaceId(1),
1013			name: "public".to_string(),
1014			local_name: "public".to_string(),
1015			parent_id: NamespaceId::ROOT,
1016		}
1017	}
1018
1019	fn test_table_def() -> TableDef {
1020		TableDef {
1021			id: TableId(1),
1022			namespace: NamespaceId(1),
1023			name: "users".to_string(),
1024			columns: vec![
1025				ColumnDef {
1026					id: ColumnId(1),
1027					name: "id".to_string(),
1028					constraint: TypeConstraint::unconstrained(Type::Int8),
1029					properties: vec![],
1030					index: ColumnIndex(0),
1031					auto_increment: false,
1032					dictionary_id: None,
1033				},
1034				ColumnDef {
1035					id: ColumnId(2),
1036					name: "name".to_string(),
1037					constraint: TypeConstraint::unconstrained(Type::Utf8),
1038					properties: vec![],
1039					index: ColumnIndex(1),
1040					auto_increment: false,
1041					dictionary_id: None,
1042				},
1043			],
1044			primary_key: None,
1045		}
1046	}
1047
1048	#[test]
1049	fn test_resolved_namespace() {
1050		let identifier = Fragment::testing("public");
1051		let def = test_namespace_def();
1052		let resolved = ResolvedNamespace::new(identifier, def);
1053
1054		assert_eq!(resolved.name(), "public");
1055		assert_eq!(resolved.fragment().text(), "public");
1056	}
1057
1058	#[test]
1059	fn test_resolved_table() {
1060		let namespace_ident = Fragment::testing("public");
1061		let namespace = ResolvedNamespace::new(namespace_ident, test_namespace_def());
1062
1063		let table_ident = Fragment::testing("users");
1064		let table = ResolvedTable::new(table_ident, namespace.clone(), test_table_def());
1065
1066		assert_eq!(table.name(), "users");
1067		assert_eq!(table.fully_qualified_name(), "public::users");
1068		assert_eq!(table.columns().len(), 2);
1069		assert!(table.find_column("id").is_some());
1070		assert!(table.find_column("nonexistent").is_none());
1071	}
1072
1073	#[test]
1074	fn test_resolved_primitive_enum() {
1075		let namespace = ResolvedNamespace::new(Fragment::testing("public"), test_namespace_def());
1076
1077		let table = ResolvedTable::new(Fragment::testing("users"), namespace, test_table_def());
1078
1079		let primitive = ResolvedPrimitive::Table(table);
1080
1081		assert!(primitive.supports_indexes());
1082		assert!(primitive.supports_mutations());
1083		assert_eq!(primitive.kind_name(), "table");
1084		// effective_name removed - use identifier().text() instead
1085		assert_eq!(primitive.fully_qualified_name(), Some("public::users".to_string()));
1086		assert!(primitive.as_table().is_some());
1087		assert!(primitive.as_view().is_none());
1088	}
1089
1090	#[test]
1091	fn test_resolved_column() {
1092		let namespace = ResolvedNamespace::new(Fragment::testing("public"), test_namespace_def());
1093
1094		let table = ResolvedTable::new(Fragment::testing("users"), namespace, test_table_def());
1095
1096		let primitive = ResolvedPrimitive::Table(table);
1097
1098		let column_ident = Fragment::testing("id");
1099
1100		let column_def = ColumnDef {
1101			id: ColumnId(1),
1102			name: "id".to_string(),
1103			constraint: TypeConstraint::unconstrained(Type::Int8),
1104			properties: vec![],
1105			index: ColumnIndex(0),
1106			auto_increment: false,
1107			dictionary_id: None,
1108		};
1109
1110		let column = ResolvedColumn::new(column_ident, primitive, column_def);
1111
1112		assert_eq!(column.name(), "id");
1113		assert_eq!(column.type_constraint(), &TypeConstraint::unconstrained(Type::Int8));
1114		assert!(!column.is_auto_increment());
1115		assert_eq!(column.qualified_name(), "public::users.id");
1116	}
1117}