Skip to main content

nodedb_types/protocol/
opcodes.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Operation codes and response status for the native binary protocol.
4
5use serde::{Deserialize, Serialize};
6
7// ─── Operation Codes ────────────────────────────────────────────────
8
9/// Operation codes for the native binary protocol.
10///
11/// Encoded as a single `u8` in both the MessagePack frame and JSON frame
12/// (e.g. `{"op":3}` for `Status`). The `#[serde(try_from = "u8", into = "u8")]`
13/// attribute makes JSON encoding consistent with the numeric opcode values.
14///
15/// `#[non_exhaustive]` — new operation codes may be added as engines grow.
16/// Wire-side unknown-op handling is covered by `Unknown(u8)`;
17/// this attribute adds Rust API hygiene.
18#[non_exhaustive]
19#[repr(u8)]
20#[derive(
21    Debug,
22    Clone,
23    Copy,
24    PartialEq,
25    Eq,
26    Hash,
27    Serialize,
28    Deserialize,
29    zerompk::ToMessagePack,
30    zerompk::FromMessagePack,
31)]
32#[serde(try_from = "u8", into = "u8")]
33#[msgpack(c_enum)]
34pub enum OpCode {
35    // ── Auth & session ──────────────────────────────────────────
36    Auth = 0x01,
37    Ping = 0x02,
38    /// Report startup/readiness status. Returns the current startup phase
39    /// and whether the node is healthy. Does not require authentication.
40    Status = 0x03,
41
42    // ── Data operations (direct Data Plane dispatch) ────────────
43    PointGet = 0x10,
44    PointPut = 0x11,
45    PointDelete = 0x12,
46    VectorSearch = 0x13,
47    RangeScan = 0x14,
48    CrdtRead = 0x15,
49    CrdtApply = 0x16,
50    GraphRagFusion = 0x17,
51    AlterCollectionPolicy = 0x18,
52
53    // ── SQL & DDL ───────────────────────────────────────────────
54    Sql = 0x20,
55    Ddl = 0x21,
56    Explain = 0x22,
57    CopyFrom = 0x23,
58
59    // ── Session parameters ──────────────────────────────────────
60    Set = 0x30,
61    Show = 0x31,
62    Reset = 0x32,
63
64    // ── Transaction control ─────────────────────────────────────
65    Begin = 0x40,
66    Commit = 0x41,
67    Rollback = 0x42,
68
69    // ── Graph operations (direct Data Plane dispatch) ───────────
70    GraphHop = 0x50,
71    GraphNeighbors = 0x51,
72    GraphPath = 0x52,
73    GraphSubgraph = 0x53,
74    EdgePut = 0x54,
75    EdgeDelete = 0x55,
76    GraphAlgo = 0x56,
77    GraphMatch = 0x57,
78
79    // ── Spatial operations (direct Data Plane dispatch) ────────
80    SpatialScan = 0x19,
81
82    // ── Timeseries operations (direct Data Plane dispatch) ──────
83    TimeseriesScan = 0x1A,
84    TimeseriesIngest = 0x1B,
85
86    // ── Search operations (direct Data Plane dispatch) ──────────
87    TextSearch = 0x60,
88    HybridSearch = 0x61,
89
90    // ── Batch operations ────────────────────────────────────────
91    VectorBatchInsert = 0x70,
92    DocumentBatchInsert = 0x71,
93
94    // ── KV advanced operations ──────────────────────────────────
95    KvScan = 0x72,
96    KvExpire = 0x73,
97    KvPersist = 0x74,
98    KvGetTtl = 0x75,
99    KvBatchGet = 0x76,
100    KvBatchPut = 0x77,
101    KvFieldGet = 0x78,
102    KvFieldSet = 0x79,
103
104    // ── Document advanced operations ────────────────────────────
105    DocumentUpdate = 0x7A,
106    DocumentScan = 0x7B,
107    DocumentUpsert = 0x7C,
108    DocumentBulkUpdate = 0x7D,
109    DocumentBulkDelete = 0x7E,
110
111    // ── Vector advanced operations ──────────────────────────────
112    VectorInsert = 0x7F,
113    VectorMultiSearch = 0x80,
114    VectorDelete = 0x81,
115
116    // ── Columnar operations ─────────────────────────────────────
117    ColumnarScan = 0x82,
118    ColumnarInsert = 0x83,
119
120    // ── Query operations ────────────────────────────────────────
121    RecursiveScan = 0x84,
122
123    // ── Document DDL operations ─────────────────────────────────
124    DocumentTruncate = 0x85,
125    DocumentEstimateCount = 0x86,
126    DocumentInsertSelect = 0x87,
127    DocumentRegister = 0x88,
128    DocumentDropIndex = 0x89,
129
130    // ── KV DDL operations ───────────────────────────────────────
131    KvRegisterIndex = 0x8A,
132    KvDropIndex = 0x8B,
133    KvTruncate = 0x8C,
134
135    // ── Vector DDL operations ───────────────────────────────────
136    VectorSetParams = 0x8D,
137
138    // ── KV atomic operations ───────────────────────────────────
139    KvIncr = 0x8E,
140    KvIncrFloat = 0x8F,
141    KvCas = 0x90,
142    KvGetSet = 0x91,
143
144    // ── KV sorted index operations ─────────────────────────────
145    KvRegisterSortedIndex = 0x92,
146    KvDropSortedIndex = 0x93,
147    KvSortedIndexRank = 0x94,
148    KvSortedIndexTopK = 0x95,
149    KvSortedIndexRange = 0x96,
150    KvSortedIndexCount = 0x97,
151    KvSortedIndexScore = 0x98,
152}
153
154impl OpCode {
155    /// Returns true if this operation is a write that requires WAL append.
156    pub fn is_write(&self) -> bool {
157        matches!(
158            self,
159            OpCode::PointPut
160                | OpCode::PointDelete
161                | OpCode::CrdtApply
162                | OpCode::EdgePut
163                | OpCode::EdgeDelete
164                | OpCode::VectorBatchInsert
165                | OpCode::DocumentBatchInsert
166                | OpCode::AlterCollectionPolicy
167                | OpCode::TimeseriesIngest
168                | OpCode::KvExpire
169                | OpCode::KvPersist
170                | OpCode::KvBatchPut
171                | OpCode::KvFieldSet
172                | OpCode::DocumentUpdate
173                | OpCode::DocumentUpsert
174                | OpCode::DocumentBulkUpdate
175                | OpCode::DocumentBulkDelete
176                | OpCode::VectorInsert
177                | OpCode::VectorDelete
178                | OpCode::ColumnarInsert
179                | OpCode::DocumentTruncate
180                | OpCode::DocumentInsertSelect
181                | OpCode::DocumentRegister
182                | OpCode::DocumentDropIndex
183                | OpCode::KvRegisterIndex
184                | OpCode::KvDropIndex
185                | OpCode::KvTruncate
186                | OpCode::VectorSetParams
187                | OpCode::KvIncr
188                | OpCode::KvIncrFloat
189                | OpCode::KvCas
190                | OpCode::KvGetSet
191                | OpCode::KvRegisterSortedIndex
192                | OpCode::KvDropSortedIndex
193        )
194    }
195}
196
197impl From<OpCode> for u8 {
198    fn from(op: OpCode) -> u8 {
199        op as u8
200    }
201}
202
203/// Error returned when decoding an unknown `OpCode` byte from the wire.
204#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
205#[error("unknown OpCode byte: 0x{0:02X}")]
206pub struct UnknownOpCode(pub u8);
207
208impl TryFrom<u8> for OpCode {
209    type Error = UnknownOpCode;
210
211    fn try_from(value: u8) -> Result<Self, Self::Error> {
212        match value {
213            0x01 => Ok(OpCode::Auth),
214            0x02 => Ok(OpCode::Ping),
215            0x03 => Ok(OpCode::Status),
216            0x10 => Ok(OpCode::PointGet),
217            0x11 => Ok(OpCode::PointPut),
218            0x12 => Ok(OpCode::PointDelete),
219            0x13 => Ok(OpCode::VectorSearch),
220            0x14 => Ok(OpCode::RangeScan),
221            0x15 => Ok(OpCode::CrdtRead),
222            0x16 => Ok(OpCode::CrdtApply),
223            0x17 => Ok(OpCode::GraphRagFusion),
224            0x18 => Ok(OpCode::AlterCollectionPolicy),
225            0x19 => Ok(OpCode::SpatialScan),
226            0x1A => Ok(OpCode::TimeseriesScan),
227            0x1B => Ok(OpCode::TimeseriesIngest),
228            0x20 => Ok(OpCode::Sql),
229            0x21 => Ok(OpCode::Ddl),
230            0x22 => Ok(OpCode::Explain),
231            0x23 => Ok(OpCode::CopyFrom),
232            0x30 => Ok(OpCode::Set),
233            0x31 => Ok(OpCode::Show),
234            0x32 => Ok(OpCode::Reset),
235            0x40 => Ok(OpCode::Begin),
236            0x41 => Ok(OpCode::Commit),
237            0x42 => Ok(OpCode::Rollback),
238            0x50 => Ok(OpCode::GraphHop),
239            0x51 => Ok(OpCode::GraphNeighbors),
240            0x52 => Ok(OpCode::GraphPath),
241            0x53 => Ok(OpCode::GraphSubgraph),
242            0x54 => Ok(OpCode::EdgePut),
243            0x55 => Ok(OpCode::EdgeDelete),
244            0x56 => Ok(OpCode::GraphAlgo),
245            0x57 => Ok(OpCode::GraphMatch),
246            0x60 => Ok(OpCode::TextSearch),
247            0x61 => Ok(OpCode::HybridSearch),
248            0x70 => Ok(OpCode::VectorBatchInsert),
249            0x71 => Ok(OpCode::DocumentBatchInsert),
250            0x72 => Ok(OpCode::KvScan),
251            0x73 => Ok(OpCode::KvExpire),
252            0x74 => Ok(OpCode::KvPersist),
253            0x75 => Ok(OpCode::KvGetTtl),
254            0x76 => Ok(OpCode::KvBatchGet),
255            0x77 => Ok(OpCode::KvBatchPut),
256            0x78 => Ok(OpCode::KvFieldGet),
257            0x79 => Ok(OpCode::KvFieldSet),
258            0x7A => Ok(OpCode::DocumentUpdate),
259            0x7B => Ok(OpCode::DocumentScan),
260            0x7C => Ok(OpCode::DocumentUpsert),
261            0x7D => Ok(OpCode::DocumentBulkUpdate),
262            0x7E => Ok(OpCode::DocumentBulkDelete),
263            0x7F => Ok(OpCode::VectorInsert),
264            0x80 => Ok(OpCode::VectorMultiSearch),
265            0x81 => Ok(OpCode::VectorDelete),
266            0x82 => Ok(OpCode::ColumnarScan),
267            0x83 => Ok(OpCode::ColumnarInsert),
268            0x84 => Ok(OpCode::RecursiveScan),
269            0x85 => Ok(OpCode::DocumentTruncate),
270            0x86 => Ok(OpCode::DocumentEstimateCount),
271            0x87 => Ok(OpCode::DocumentInsertSelect),
272            0x88 => Ok(OpCode::DocumentRegister),
273            0x89 => Ok(OpCode::DocumentDropIndex),
274            0x8A => Ok(OpCode::KvRegisterIndex),
275            0x8B => Ok(OpCode::KvDropIndex),
276            0x8C => Ok(OpCode::KvTruncate),
277            0x8D => Ok(OpCode::VectorSetParams),
278            0x8E => Ok(OpCode::KvIncr),
279            0x8F => Ok(OpCode::KvIncrFloat),
280            0x90 => Ok(OpCode::KvCas),
281            0x91 => Ok(OpCode::KvGetSet),
282            0x92 => Ok(OpCode::KvRegisterSortedIndex),
283            0x93 => Ok(OpCode::KvDropSortedIndex),
284            0x94 => Ok(OpCode::KvSortedIndexRank),
285            0x95 => Ok(OpCode::KvSortedIndexTopK),
286            0x96 => Ok(OpCode::KvSortedIndexRange),
287            0x97 => Ok(OpCode::KvSortedIndexCount),
288            0x98 => Ok(OpCode::KvSortedIndexScore),
289            other => Err(UnknownOpCode(other)),
290        }
291    }
292}
293
294// ─── Response Status ────────────────────────────────────────────────
295
296/// Status code in response frames.
297///
298/// `#[non_exhaustive]` — additional status codes (e.g. `Throttled`, `Redirect`)
299/// may be added as the protocol evolves.
300#[non_exhaustive]
301#[repr(u8)]
302#[derive(
303    Debug,
304    Clone,
305    Copy,
306    PartialEq,
307    Eq,
308    Serialize,
309    Deserialize,
310    zerompk::ToMessagePack,
311    zerompk::FromMessagePack,
312)]
313#[msgpack(c_enum)]
314pub enum ResponseStatus {
315    /// Request completed successfully.
316    Ok = 0,
317    /// Partial result — more chunks follow with the same `seq`.
318    Partial = 1,
319    /// Request failed — see `error` field.
320    Error = 2,
321}