tarantool_rs/client/schema/
index.rs

1use std::{borrow::Borrow, fmt, sync::Arc};
2
3use rmpv::Value;
4use serde::{de::DeserializeOwned, Deserialize};
5
6use super::{SpaceMetadata, SystemSpacesId, PRIMARY_INDEX_ID};
7use crate::{
8    client::ExecutorExt, tuple::Tuple, utils::UniqueIdName, DmoResponse, Executor, IteratorType,
9    Result, Transaction,
10};
11
12/// Index metadata from [system view](https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/system_views/).
13#[derive(Clone, Deserialize)]
14pub struct IndexMetadata {
15    space_id: u32,
16    index_id: u32,
17    pub(super) name: String,
18    #[serde(rename = "type")]
19    type_: String, // TODO: enum
20    _opts: Value,       // TODO: parse
21    _parts: Vec<Value>, // TODO: parse
22}
23
24impl fmt::Debug for IndexMetadata {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        f.debug_struct("IndexMetadata")
27            .field("space_id", &self.space_id)
28            .field("index_id", &self.index_id)
29            .field("name", &self.name)
30            .field("type_", &self.type_)
31            // TODO: uncomment when fields implemented
32            // .field("_opts", &self._opts)
33            // .field("_parts", &self._parts)
34            .finish()
35    }
36}
37
38impl IndexMetadata {
39    // TODO: replace space_id type from u32 to something generic
40    /// Load list of indices of single space.
41    pub async fn load_by_space_id(conn: impl ExecutorExt, space_id: u32) -> Result<Vec<Self>> {
42        conn.select(
43            SystemSpacesId::VIndex as u32,
44            0,
45            None,
46            None,
47            None,
48            (space_id,),
49        )
50        .await
51    }
52
53    /// Returns the id space to which this index belongs.
54    pub fn space_id(&self) -> u32 {
55        self.space_id
56    }
57
58    /// Returns the id of this index in space.
59    pub fn id(&self) -> u32 {
60        self.index_id
61    }
62
63    /// Returns whether this index is primary or not.
64    pub fn is_primary(&self) -> bool {
65        self.index_id == PRIMARY_INDEX_ID
66    }
67
68    /// Returns a name of this index.
69    pub fn name(&self) -> &str {
70        self.name.as_ref()
71    }
72
73    /// Returns a type of this index.
74    pub fn type_(&self) -> &str {
75        self.type_.as_ref()
76    }
77}
78
79impl UniqueIdName for IndexMetadata {
80    fn id(&self) -> &u32 {
81        &self.index_id
82    }
83
84    fn name(&self) -> &str {
85        &self.name
86    }
87}
88
89/// Tarantool index of specific space.
90///
91/// This is a wrapper around [`Executor`], which allow to make index-related requests
92/// on specific index.
93pub struct GenericIndex<E, M, S> {
94    executor: E,
95    metadata: M,
96    space_metadata: S,
97}
98
99/// Referenced index type, which rely on `Space` object.
100pub type Index<'a, E> = GenericIndex<E, &'a IndexMetadata, &'a SpaceMetadata>;
101
102/// Owned index type, which can exists without related `Space` object.
103pub type OwnedIndex<E> = GenericIndex<E, Arc<IndexMetadata>, Arc<SpaceMetadata>>;
104
105impl<E, M, S> Clone for GenericIndex<E, M, S>
106where
107    E: Clone,
108    M: Clone,
109    S: Clone,
110{
111    fn clone(&self) -> Self {
112        Self {
113            executor: self.executor.clone(),
114            metadata: self.metadata.clone(),
115            space_metadata: self.space_metadata.clone(),
116        }
117    }
118}
119
120impl<E, M, S> GenericIndex<E, M, S> {
121    pub(super) fn new(executor: E, metadata: M, space_metadata: S) -> Self {
122        Self {
123            executor,
124            metadata,
125            space_metadata,
126        }
127    }
128
129    pub fn into_executor(self) -> E {
130        self.executor
131    }
132}
133
134impl<E, M, S> GenericIndex<E, M, S>
135where
136    M: Borrow<IndexMetadata>,
137    S: Borrow<SpaceMetadata>,
138{
139    pub fn executor(&self) -> &E {
140        &self.executor
141    }
142
143    pub fn metadata(&self) -> &IndexMetadata {
144        self.metadata.borrow()
145    }
146
147    pub fn space_metadata(&self) -> &SpaceMetadata {
148        self.space_metadata.borrow()
149    }
150}
151
152impl<E, M, S> GenericIndex<E, M, S>
153where
154    E: Executor,
155    M: Borrow<IndexMetadata>,
156    S: Borrow<SpaceMetadata>,
157{
158    /// Call `select` on current index.
159    ///
160    /// For details see [`ExecutorExt::select`].
161    pub async fn select<T, A>(
162        &self,
163        limit: Option<u32>,
164        offset: Option<u32>,
165        iterator: Option<IteratorType>,
166        keys: A,
167    ) -> Result<Vec<T>>
168    where
169        T: DeserializeOwned,
170        A: Tuple + Send,
171    {
172        self.executor
173            .select(
174                self.space_metadata.borrow().id,
175                self.metadata.borrow().index_id,
176                limit,
177                offset,
178                iterator,
179                keys,
180            )
181            .await
182    }
183
184    /// Call `update` on current index.
185    ///
186    /// For details see [`ExecutorExt::update`].
187    pub async fn update<K, O>(&self, keys: K, ops: O) -> Result<DmoResponse>
188    where
189        K: Tuple + Send,
190        O: Tuple + Send,
191    {
192        self.executor
193            .update(
194                self.space_metadata.borrow().id,
195                self.metadata.borrow().index_id,
196                keys,
197                ops,
198            )
199            .await
200    }
201
202    /// Call `delete` on current index.
203    ///
204    /// For details see [`ExecutorExt::delete`].
205    pub async fn delete<T>(&self, keys: T) -> Result<DmoResponse>
206    where
207        T: Tuple + Send,
208    {
209        self.executor
210            .delete(
211                self.space_metadata.borrow().id,
212                self.metadata.borrow().index_id,
213                keys,
214            )
215            .await
216    }
217}
218
219impl OwnedIndex<Transaction> {
220    /// Commit inner tranasction.
221    pub async fn commit(self) -> Result<()> {
222        self.executor.commit().await
223    }
224
225    /// Rollback inner tranasction.
226    pub async fn rollback(self) -> Result<()> {
227        self.executor.rollback().await
228    }
229}