reifydb_catalog/transaction/
view.rs1use reifydb_core::interface::{
5 CommandTransaction, NamespaceId, QueryTransaction, TransactionalChanges, TransactionalViewChanges, ViewDef,
6 ViewId,
7 interceptor::{ViewDefInterceptor, WithInterceptors},
8};
9use reifydb_type::{
10 IntoFragment,
11 diagnostic::catalog::{view_already_exists, view_not_found},
12 error, internal, return_error,
13};
14use tracing::{instrument, warn};
15
16use crate::{
17 CatalogNamespaceQueryOperations, CatalogStore, store::view::ViewToCreate,
18 transaction::MaterializedCatalogTransaction,
19};
20
21pub trait CatalogViewCommandOperations {
22 fn create_view(&mut self, view: ViewToCreate) -> crate::Result<ViewDef>;
23
24 }
29
30pub trait CatalogTrackViewChangeOperations {
31 fn track_view_def_created(&mut self, view: ViewDef) -> crate::Result<()>;
32
33 fn track_view_def_updated(&mut self, pre: ViewDef, post: ViewDef) -> crate::Result<()>;
34
35 fn track_view_def_deleted(&mut self, view: ViewDef) -> crate::Result<()>;
36}
37
38pub trait CatalogViewQueryOperations: CatalogNamespaceQueryOperations {
39 fn find_view(&mut self, id: ViewId) -> crate::Result<Option<ViewDef>>;
40
41 fn find_view_by_name<'a>(
42 &mut self,
43 namespace: NamespaceId,
44 name: impl IntoFragment<'a>,
45 ) -> crate::Result<Option<ViewDef>>;
46
47 fn get_view(&mut self, id: ViewId) -> crate::Result<ViewDef>;
48
49 fn get_view_by_name<'a>(
50 &mut self,
51 namespace: NamespaceId,
52 name: impl IntoFragment<'a>,
53 ) -> crate::Result<ViewDef>;
54}
55
56impl<
57 CT: CommandTransaction
58 + MaterializedCatalogTransaction
59 + CatalogTrackViewChangeOperations
60 + WithInterceptors<CT>
61 + TransactionalChanges,
62> CatalogViewCommandOperations for CT
63{
64 #[instrument(level = "debug", skip(self, to_create))]
65 fn create_view(&mut self, to_create: ViewToCreate) -> reifydb_core::Result<ViewDef> {
66 if let Some(view) = self.find_view_by_name(to_create.namespace, &to_create.name)? {
67 let namespace = self.get_namespace(to_create.namespace)?;
68 return_error!(view_already_exists(to_create.fragment, &namespace.name, &view.name));
69 }
70 let result = CatalogStore::create_deferred_view(self, to_create)?;
71 self.track_view_def_created(result.clone())?;
72 ViewDefInterceptor::post_create(self, &result)?;
73 Ok(result)
74 }
75}
76
77impl<QT: QueryTransaction + MaterializedCatalogTransaction + TransactionalChanges> CatalogViewQueryOperations for QT {
78 #[instrument(level = "trace", skip(self))]
79 fn find_view(&mut self, id: ViewId) -> reifydb_core::Result<Option<ViewDef>> {
80 if let Some(view) = TransactionalViewChanges::find_view(self, id) {
83 return Ok(Some(view.clone()));
84 }
85
86 if TransactionalViewChanges::is_view_deleted(self, id) {
89 return Ok(None);
90 }
91
92 if let Some(view) = self.catalog().find_view(id, self.version()) {
94 return Ok(Some(view));
95 }
96
97 if let Some(view) = CatalogStore::find_view(self, id)? {
99 warn!("View with ID {:?} found in storage but not in MaterializedCatalog", id);
100 return Ok(Some(view));
101 }
102
103 Ok(None)
104 }
105
106 #[instrument(level = "trace", skip(self, name))]
107 fn find_view_by_name<'a>(
108 &mut self,
109 namespace: NamespaceId,
110 name: impl IntoFragment<'a>,
111 ) -> reifydb_core::Result<Option<ViewDef>> {
112 let name = name.into_fragment();
113
114 if let Some(view) = TransactionalViewChanges::find_view_by_name(self, namespace, name.as_borrowed()) {
117 return Ok(Some(view.clone()));
118 }
119
120 if TransactionalViewChanges::is_view_deleted_by_name(self, namespace, name.as_borrowed()) {
123 return Ok(None);
124 }
125
126 if let Some(view) = self.catalog().find_view_by_name(namespace, name.text(), self.version()) {
128 return Ok(Some(view));
129 }
130
131 if let Some(view) = CatalogStore::find_view_by_name(self, namespace, name.text())? {
133 warn!(
134 "View '{}' in namespace {:?} found in storage but not in MaterializedCatalog",
135 name.text(),
136 namespace
137 );
138 return Ok(Some(view));
139 }
140
141 Ok(None)
142 }
143
144 #[instrument(level = "trace", skip(self))]
145 fn get_view(&mut self, id: ViewId) -> reifydb_core::Result<ViewDef> {
146 self.find_view(id)?.ok_or_else(|| {
147 error!(internal!(
148 "View with ID {:?} not found in catalog. This indicates a critical catalog inconsistency.",
149 id
150 ))
151 })
152 }
153
154 #[instrument(level = "trace", skip(self, name))]
155 fn get_view_by_name<'a>(
156 &mut self,
157 namespace: NamespaceId,
158 name: impl IntoFragment<'a>,
159 ) -> reifydb_core::Result<ViewDef> {
160 let name = name.into_fragment();
161
162 let namespace_name = self.get_namespace(namespace)?.name;
163
164 self.find_view_by_name(namespace, name.as_borrowed())?
165 .ok_or_else(|| error!(view_not_found(name.as_borrowed(), &namespace_name, name.text())))
166 }
167}