tarantool_rs/client/dmo/
operation.rs

1use std::io::Write;
2
3use rmpv::ValueRef;
4
5use crate::{errors::EncodingError, Tuple, TupleElement};
6
7/// Key of index in operation.
8///
9/// Can be string, unsigned or signed number ([docs](https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/update/#box-space-update)).
10#[derive(Debug)]
11pub struct DmoOperationFieldKey<'a>(ValueRef<'a>);
12
13impl<'a> From<&'a str> for DmoOperationFieldKey<'a> {
14    fn from(value: &'a str) -> Self {
15        Self(value.into())
16    }
17}
18
19impl<'a> From<u32> for DmoOperationFieldKey<'a> {
20    fn from(value: u32) -> Self {
21        Self(value.into())
22    }
23}
24
25impl<'a> From<i32> for DmoOperationFieldKey<'a> {
26    fn from(value: i32) -> Self {
27        Self(value.into())
28    }
29}
30
31// TODO: docs and doctests
32/// Operation in `upsert` or `update` request.
33#[derive(Debug)]
34pub struct DmoOperation<'a> {
35    // TODO: id support
36    // TODO: negative id support
37    operation: &'static str,
38    field_name: ValueRef<'a>,
39    args: Args<'a>,
40}
41
42impl<'a> DmoOperation<'a> {
43    fn new(
44        operation: &'static str,
45        field_name: impl Into<DmoOperationFieldKey<'a>>,
46        args: Args<'a>,
47    ) -> Self {
48        Self {
49            operation,
50            field_name: field_name.into().0,
51            args,
52        }
53    }
54
55    pub fn add(
56        field_name: impl Into<DmoOperationFieldKey<'a>>,
57        value: impl Into<ValueRef<'a>>,
58    ) -> Self {
59        Self::new(ops::ADD, field_name, Args::One(value.into()))
60    }
61
62    pub fn sub(
63        field_name: impl Into<DmoOperationFieldKey<'a>>,
64        value: impl Into<ValueRef<'a>>,
65    ) -> Self {
66        Self::new(ops::SUB, field_name, Args::One(value.into()))
67    }
68
69    pub fn and(
70        field_name: impl Into<DmoOperationFieldKey<'a>>,
71        value: impl Into<ValueRef<'a>>,
72    ) -> Self {
73        Self::new(ops::AND, field_name, Args::One(value.into()))
74    }
75
76    pub fn or(
77        field_name: impl Into<DmoOperationFieldKey<'a>>,
78        value: impl Into<ValueRef<'a>>,
79    ) -> Self {
80        Self::new(ops::OR, field_name, Args::One(value.into()))
81    }
82
83    pub fn xor(
84        field_name: impl Into<DmoOperationFieldKey<'a>>,
85        value: impl Into<ValueRef<'a>>,
86    ) -> Self {
87        Self::new(ops::XOR, field_name, Args::One(value.into()))
88    }
89
90    pub fn string_splice(
91        field_name: impl Into<DmoOperationFieldKey<'a>>,
92        from: usize,
93        len: usize,
94        value: &'a str,
95    ) -> Self {
96        Self::new(
97            ops::STRING_SPLICE,
98            field_name,
99            Args::Three(from.into(), len.into(), value.into()),
100        )
101    }
102
103    pub fn insert(
104        field_name: impl Into<DmoOperationFieldKey<'a>>,
105        value: impl Into<ValueRef<'a>>,
106    ) -> Self {
107        Self::new(ops::INSERT, field_name, Args::One(value.into()))
108    }
109
110    pub fn assign(
111        field_name: impl Into<DmoOperationFieldKey<'a>>,
112        value: impl Into<ValueRef<'a>>,
113    ) -> Self {
114        Self::new(ops::ASSIGN, field_name, Args::One(value.into()))
115    }
116
117    pub fn delete(field_name: impl Into<DmoOperationFieldKey<'a>>) -> Self {
118        Self::new(ops::DEL, field_name, Args::None)
119    }
120}
121
122impl<'a> TupleElement for DmoOperation<'a> {
123    fn encode_into_writer<W: Write>(&self, mut buf: W) -> Result<(), EncodingError> {
124        let arr_len = 2 + match self.args {
125            Args::None => 0,
126            Args::One(_) => 1,
127            Args::Three(_, _, _) => 3,
128        };
129        rmp::encode::write_array_len(&mut buf, arr_len)?;
130        rmp::encode::write_str(&mut buf, self.operation)?;
131        rmpv::encode::write_value_ref(&mut buf, &self.field_name)?;
132        match &self.args {
133            Args::None => {}
134            Args::One(x) => {
135                rmpv::encode::write_value_ref(&mut buf, x)?;
136            }
137            Args::Three(x, y, z) => {
138                rmpv::encode::write_value_ref(&mut buf, x)?;
139                rmpv::encode::write_value_ref(&mut buf, y)?;
140                rmpv::encode::write_value_ref(&mut buf, z)?;
141            }
142        }
143        Ok(())
144    }
145}
146
147/// Implementation for allow single operation to be used as argument for `update` and `upsert`.
148impl<'a> Tuple for DmoOperation<'a> {
149    fn encode_into_writer<W: Write>(&self, mut buf: W) -> Result<(), EncodingError> {
150        rmp::encode::write_array_len(&mut buf, 1)?;
151        TupleElement::encode_into_writer(self, &mut buf)?;
152        Ok(())
153    }
154}
155
156#[derive(Debug)]
157enum Args<'a> {
158    None,
159    One(rmpv::ValueRef<'a>),
160    Three(rmpv::ValueRef<'a>, rmpv::ValueRef<'a>, rmpv::ValueRef<'a>),
161}
162
163mod ops {
164    pub(super) const ADD: &str = "+";
165    pub(super) const SUB: &str = "-";
166    pub(super) const AND: &str = "&";
167    pub(super) const OR: &str = "|";
168    pub(super) const XOR: &str = "^";
169    pub(super) const STRING_SPLICE: &str = ":";
170    pub(super) const INSERT: &str = "|";
171    pub(super) const DEL: &str = "#";
172    pub(super) const ASSIGN: &str = "=";
173}