Skip to main content

nautilus_protocol/
methods.rs

1//! Nautilus protocol method definitions.
2//!
3//! This module defines stable method names and their request/response payloads.
4
5use serde::{Deserialize, Serialize};
6use serde_json::value::RawValue;
7use serde_json::Value;
8
9fn default_true() -> bool {
10    true
11}
12
13// Method name constants
14pub const ENGINE_HANDSHAKE: &str = "engine.handshake";
15pub const QUERY_FIND_MANY: &str = "query.findMany";
16pub const QUERY_FIND_FIRST: &str = "query.findFirst";
17pub const QUERY_FIND_UNIQUE: &str = "query.findUnique";
18pub const QUERY_FIND_UNIQUE_OR_THROW: &str = "query.findUniqueOrThrow";
19pub const QUERY_FIND_FIRST_OR_THROW: &str = "query.findFirstOrThrow";
20pub const QUERY_CREATE: &str = "query.create";
21pub const QUERY_CREATE_MANY: &str = "query.createMany";
22pub const QUERY_UPDATE: &str = "query.update";
23pub const QUERY_DELETE: &str = "query.delete";
24pub const QUERY_COUNT: &str = "query.count";
25/// Group records and compute aggregates (COUNT, AVG, SUM, MIN, MAX).
26pub const QUERY_GROUP_BY: &str = "query.groupBy";
27/// Method name for schema validation (reserved — not yet implemented in the engine).
28pub const SCHEMA_VALIDATE: &str = "schema.validate";
29
30// Transaction methods
31/// Start a new interactive transaction.
32pub const TRANSACTION_START: &str = "transaction.start";
33/// Commit an interactive transaction.
34pub const TRANSACTION_COMMIT: &str = "transaction.commit";
35/// Rollback an interactive transaction.
36pub const TRANSACTION_ROLLBACK: &str = "transaction.rollback";
37/// Execute a batch of operations atomically in a single transaction.
38pub const TRANSACTION_BATCH: &str = "transaction.batch";
39
40// ============================================================================
41// engine.handshake
42// ============================================================================
43
44/// Handshake request parameters.
45///
46/// The handshake must be the first request sent by a client to validate
47/// protocol compatibility.
48#[derive(Debug, Clone, Serialize, Deserialize)]
49#[serde(rename_all = "camelCase")]
50pub struct HandshakeParams {
51    /// Protocol version the client is using.
52    pub protocol_version: u32,
53
54    /// Optional client name (e.g., "nautilus-js").
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub client_name: Option<String>,
57
58    /// Optional client version (e.g., "0.1.0").
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub client_version: Option<String>,
61}
62
63/// Handshake response.
64#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(rename_all = "camelCase")]
66pub struct HandshakeResult {
67    /// Engine version.
68    pub engine_version: String,
69
70    /// Protocol version the engine supports.
71    pub protocol_version: u32,
72}
73
74// ============================================================================
75// query.findMany
76// ============================================================================
77
78/// Find many request parameters.
79#[derive(Debug, Clone, Serialize, Deserialize)]
80#[serde(rename_all = "camelCase")]
81pub struct FindManyParams {
82    /// Protocol version (required in all requests).
83    pub protocol_version: u32,
84
85    /// Model name (e.g., "User", "Post").
86    pub model: String,
87
88    /// Query arguments (filters, ordering, pagination, etc.).
89    /// Structure is flexible and parsed by the engine.
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub args: Option<Value>,
92
93    /// Optional transaction ID — if present, this query runs inside the given transaction.
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub transaction_id: Option<String>,
96
97    /// Optional chunk size for streaming large result sets.
98    /// When set, the engine emits multiple partial responses of at most `chunk_size` rows each.
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub chunk_size: Option<usize>,
101}
102
103// ============================================================================
104// query.findFirst
105// ============================================================================
106
107/// Find first request parameters (same shape as FindMany — optional full args).
108#[derive(Debug, Clone, Serialize, Deserialize)]
109#[serde(rename_all = "camelCase")]
110pub struct FindFirstParams {
111    pub protocol_version: u32,
112    pub model: String,
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub args: Option<Value>,
115    /// Optional transaction ID.
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub transaction_id: Option<String>,
118}
119
120// ============================================================================
121// query.findUnique / query.findUniqueOrThrow / query.findFirstOrThrow
122// ============================================================================
123
124/// Find unique request parameters.
125#[derive(Debug, Clone, Serialize, Deserialize)]
126#[serde(rename_all = "camelCase")]
127pub struct FindUniqueParams {
128    pub protocol_version: u32,
129    pub model: String,
130    pub filter: Value,
131    /// Optional transaction ID.
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub transaction_id: Option<String>,
134}
135
136/// Find unique or throw request parameters (same shape as FindUnique).
137pub type FindUniqueOrThrowParams = FindUniqueParams;
138
139/// Find first or throw request parameters (same shape as FindFirst).
140pub type FindFirstOrThrowParams = FindFirstParams;
141
142// ============================================================================
143// query.create
144// ============================================================================
145
146/// Create request parameters.
147#[derive(Debug, Clone, Serialize, Deserialize)]
148#[serde(rename_all = "camelCase")]
149pub struct CreateParams {
150    pub protocol_version: u32,
151    pub model: String,
152    pub data: Value,
153    /// Optional transaction ID.
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub transaction_id: Option<String>,
156    /// Whether to return the created row(s). Defaults to `true`.
157    #[serde(default = "default_true")]
158    pub return_data: bool,
159}
160
161// ============================================================================
162// query.createMany
163// ============================================================================
164
165/// Create many request parameters.
166#[derive(Debug, Clone, Serialize, Deserialize)]
167#[serde(rename_all = "camelCase")]
168pub struct CreateManyParams {
169    pub protocol_version: u32,
170    pub model: String,
171    pub data: Vec<Value>,
172    /// Optional transaction ID.
173    #[serde(skip_serializing_if = "Option::is_none")]
174    pub transaction_id: Option<String>,
175    /// Whether to return the created row(s). Defaults to `true`.
176    #[serde(default = "default_true")]
177    pub return_data: bool,
178}
179
180// ============================================================================
181// query.update
182// ============================================================================
183
184/// Update request parameters.
185#[derive(Debug, Clone, Serialize, Deserialize)]
186#[serde(rename_all = "camelCase")]
187pub struct UpdateParams {
188    pub protocol_version: u32,
189    pub model: String,
190    pub filter: Value,
191    pub data: Value,
192    /// Optional transaction ID.
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub transaction_id: Option<String>,
195    /// Whether to return the updated row(s). Defaults to `true`.
196    #[serde(default = "default_true")]
197    pub return_data: bool,
198}
199
200// ============================================================================
201// query.delete
202// ============================================================================
203
204/// Delete request parameters.
205#[derive(Debug, Clone, Serialize, Deserialize)]
206#[serde(rename_all = "camelCase")]
207pub struct DeleteParams {
208    pub protocol_version: u32,
209    pub model: String,
210    pub filter: Value,
211    /// Optional transaction ID.
212    #[serde(skip_serializing_if = "Option::is_none")]
213    pub transaction_id: Option<String>,
214    /// Whether to return the deleted row(s). Defaults to `true`.
215    #[serde(default = "default_true")]
216    pub return_data: bool,
217}
218
219// ============================================================================
220// query.count
221// ============================================================================
222
223/// Count request parameters.
224#[derive(Debug, Clone, Serialize, Deserialize)]
225#[serde(rename_all = "camelCase")]
226pub struct CountParams {
227    pub protocol_version: u32,
228    pub model: String,
229    /// Optional query arguments (where, take, skip).
230    #[serde(skip_serializing_if = "Option::is_none")]
231    pub args: Option<Value>,
232    /// Optional transaction ID.
233    #[serde(skip_serializing_if = "Option::is_none")]
234    pub transaction_id: Option<String>,
235}
236
237// ============================================================================
238// query.groupBy
239// ============================================================================
240
241/// Group-by request parameters.
242#[derive(Debug, Clone, Serialize, Deserialize)]
243#[serde(rename_all = "camelCase")]
244pub struct GroupByParams {
245    pub protocol_version: u32,
246    pub model: String,
247    /// Query arguments: by, where, having, take, skip, orderBy, count, avg, sum, min, max.
248    #[serde(skip_serializing_if = "Option::is_none")]
249    pub args: Option<Value>,
250    /// Optional transaction ID.
251    #[serde(skip_serializing_if = "Option::is_none")]
252    pub transaction_id: Option<String>,
253}
254
255// ============================================================================
256// Common response types
257// ============================================================================
258
259/// Query result containing data rows.
260#[derive(Debug, Clone, Serialize, Deserialize)]
261pub struct QueryResult {
262    /// Result data as JSON objects.
263    pub data: Vec<Value>,
264}
265
266/// Mutation result with count of affected rows.
267#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct MutationResult {
269    /// Number of rows affected.
270    pub count: usize,
271
272    /// Optional returning data for mutations that support RETURNING.
273    #[serde(skip_serializing_if = "Option::is_none")]
274    pub data: Option<Vec<Value>>,
275}
276
277// ============================================================================
278// schema.validate (reserved — not yet implemented in the engine)
279// ============================================================================
280
281/// Schema validation request parameters.
282///
283/// **Note:** This method is defined in the protocol spec but not yet
284/// implemented in the engine. The types are provided so clients can
285/// prepare for future support.
286#[derive(Debug, Clone, Serialize, Deserialize)]
287#[serde(rename_all = "camelCase")]
288pub struct SchemaValidateParams {
289    pub protocol_version: u32,
290    pub schema: String,
291}
292
293/// Schema validation result.
294///
295/// **Note:** Reserved for future use — see [`SchemaValidateParams`].
296#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct SchemaValidateResult {
298    /// Whether the schema is valid.
299    pub valid: bool,
300
301    /// Validation errors if any.
302    #[serde(skip_serializing_if = "Option::is_none")]
303    pub errors: Option<Vec<String>>,
304}
305
306// ============================================================================
307// Transaction types
308// ============================================================================
309
310/// Transaction isolation level.
311#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
312#[serde(rename_all = "camelCase")]
313pub enum IsolationLevel {
314    /// Read uncommitted — allows dirty reads.
315    ReadUncommitted,
316    /// Read committed — default for most databases.
317    ReadCommitted,
318    /// Repeatable read — prevents non-repeatable reads.
319    RepeatableRead,
320    /// Serializable — strictest isolation level.
321    Serializable,
322}
323
324impl IsolationLevel {
325    /// Returns the SQL representation (e.g., `"READ COMMITTED"`).
326    pub fn as_sql(&self) -> &'static str {
327        match self {
328            IsolationLevel::ReadUncommitted => "READ UNCOMMITTED",
329            IsolationLevel::ReadCommitted => "READ COMMITTED",
330            IsolationLevel::RepeatableRead => "REPEATABLE READ",
331            IsolationLevel::Serializable => "SERIALIZABLE",
332        }
333    }
334}
335
336/// Start a new interactive transaction.
337#[derive(Debug, Clone, Serialize, Deserialize)]
338#[serde(rename_all = "camelCase")]
339pub struct TransactionStartParams {
340    pub protocol_version: u32,
341    /// Maximum duration in milliseconds before the transaction is automatically
342    /// rolled back. Defaults to 5000 (5 seconds) if omitted.
343    #[serde(skip_serializing_if = "Option::is_none")]
344    pub timeout_ms: Option<u64>,
345    /// Optional isolation level override.
346    #[serde(skip_serializing_if = "Option::is_none")]
347    pub isolation_level: Option<IsolationLevel>,
348}
349
350/// Result of starting a transaction.
351#[derive(Debug, Clone, Serialize, Deserialize)]
352#[serde(rename_all = "camelCase")]
353pub struct TransactionStartResult {
354    /// Unique transaction identifier. Pass this as `transactionId` in
355    /// subsequent query requests.
356    pub id: String,
357}
358
359/// Commit an interactive transaction.
360#[derive(Debug, Clone, Serialize, Deserialize)]
361#[serde(rename_all = "camelCase")]
362pub struct TransactionCommitParams {
363    pub protocol_version: u32,
364    /// Transaction ID returned by `transaction.start`.
365    pub id: String,
366}
367
368/// Result of committing a transaction (empty on success).
369#[derive(Debug, Clone, Serialize, Deserialize)]
370pub struct TransactionCommitResult {}
371
372/// Rollback an interactive transaction.
373#[derive(Debug, Clone, Serialize, Deserialize)]
374#[serde(rename_all = "camelCase")]
375pub struct TransactionRollbackParams {
376    pub protocol_version: u32,
377    /// Transaction ID returned by `transaction.start`.
378    pub id: String,
379}
380
381/// Result of rolling back a transaction (empty on success).
382#[derive(Debug, Clone, Serialize, Deserialize)]
383pub struct TransactionRollbackResult {}
384
385/// A single operation inside a batch transaction.
386#[derive(Debug, Clone, Serialize, Deserialize)]
387#[serde(rename_all = "camelCase")]
388pub struct BatchOperation {
389    /// JSON-RPC method name (e.g., `"query.create"`).
390    pub method: String,
391    /// Method-specific params (same shape as the standalone request).
392    pub params: Value,
393}
394
395/// Execute multiple operations atomically in one transaction.
396#[derive(Debug, Clone, Serialize, Deserialize)]
397#[serde(rename_all = "camelCase")]
398pub struct TransactionBatchParams {
399    pub protocol_version: u32,
400    /// Ordered list of operations to execute.
401    pub operations: Vec<BatchOperation>,
402    /// Optional isolation level for the batch transaction.
403    #[serde(skip_serializing_if = "Option::is_none")]
404    pub isolation_level: Option<IsolationLevel>,
405    /// Optional timeout in milliseconds (default: 5000).
406    #[serde(skip_serializing_if = "Option::is_none")]
407    pub timeout_ms: Option<u64>,
408}
409
410/// Result of a batch transaction.
411#[derive(Debug, Clone, Serialize, Deserialize)]
412pub struct TransactionBatchResult {
413    /// One result per operation, in the same order as the input.
414    pub results: Vec<Box<RawValue>>,
415}