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// query.rawQuery / query.rawStmtQuery
279// ============================================================================
280
281/// Method name for executing a raw SQL query (no parameter binding).
282pub const QUERY_RAW: &str = "query.rawQuery";
283/// Method name for executing a raw prepared-statement query (with bound params).
284pub const QUERY_RAW_STMT: &str = "query.rawStmtQuery";
285
286/// Raw SQL query request parameters.
287///
288/// Execute the SQL string as-is against the database and return the result rows
289/// as generic JSON objects.  No parameter binding is performed — embed literal
290/// values directly in the SQL string or use [`RawStmtQueryParams`] instead.
291#[derive(Debug, Clone, Serialize, Deserialize)]
292#[serde(rename_all = "camelCase")]
293pub struct RawQueryParams {
294    /// Protocol version (required in all requests).
295    pub protocol_version: u32,
296    /// Raw SQL string to execute.
297    pub sql: String,
298    /// Optional transaction ID.
299    #[serde(skip_serializing_if = "Option::is_none")]
300    pub transaction_id: Option<String>,
301}
302
303/// Raw prepared-statement query request parameters.
304///
305/// Execute the SQL string with bound parameters and return the result rows as
306/// generic JSON objects.  Use `$1`, `$2`, … (PostgreSQL) or `?` (MySQL /
307/// SQLite) as placeholders; parameters are bound in the order they appear in
308/// the `params` array.
309#[derive(Debug, Clone, Serialize, Deserialize)]
310#[serde(rename_all = "camelCase")]
311pub struct RawStmtQueryParams {
312    /// Protocol version (required in all requests).
313    pub protocol_version: u32,
314    /// Raw SQL string containing parameter placeholders.
315    pub sql: String,
316    /// Ordered list of parameter values to bind.
317    #[serde(default)]
318    pub params: Vec<Value>,
319    /// Optional transaction ID.
320    #[serde(skip_serializing_if = "Option::is_none")]
321    pub transaction_id: Option<String>,
322}
323
324// ============================================================================
325// schema.validate (reserved — not yet implemented in the engine)
326// ============================================================================
327
328/// Schema validation request parameters.
329///
330/// **Note:** This method is defined in the protocol spec but not yet
331/// implemented in the engine. The types are provided so clients can
332/// prepare for future support.
333#[derive(Debug, Clone, Serialize, Deserialize)]
334#[serde(rename_all = "camelCase")]
335pub struct SchemaValidateParams {
336    pub protocol_version: u32,
337    pub schema: String,
338}
339
340/// Schema validation result.
341///
342/// **Note:** Reserved for future use — see [`SchemaValidateParams`].
343#[derive(Debug, Clone, Serialize, Deserialize)]
344pub struct SchemaValidateResult {
345    /// Whether the schema is valid.
346    pub valid: bool,
347
348    /// Validation errors if any.
349    #[serde(skip_serializing_if = "Option::is_none")]
350    pub errors: Option<Vec<String>>,
351}
352
353// ============================================================================
354// Transaction types
355// ============================================================================
356
357/// Transaction isolation level.
358#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
359#[serde(rename_all = "camelCase")]
360pub enum IsolationLevel {
361    /// Read uncommitted — allows dirty reads.
362    ReadUncommitted,
363    /// Read committed — default for most databases.
364    ReadCommitted,
365    /// Repeatable read — prevents non-repeatable reads.
366    RepeatableRead,
367    /// Serializable — strictest isolation level.
368    Serializable,
369}
370
371impl IsolationLevel {
372    /// Returns the SQL representation (e.g., `"READ COMMITTED"`).
373    pub fn as_sql(&self) -> &'static str {
374        match self {
375            IsolationLevel::ReadUncommitted => "READ UNCOMMITTED",
376            IsolationLevel::ReadCommitted => "READ COMMITTED",
377            IsolationLevel::RepeatableRead => "REPEATABLE READ",
378            IsolationLevel::Serializable => "SERIALIZABLE",
379        }
380    }
381}
382
383/// Start a new interactive transaction.
384#[derive(Debug, Clone, Serialize, Deserialize)]
385#[serde(rename_all = "camelCase")]
386pub struct TransactionStartParams {
387    pub protocol_version: u32,
388    /// Maximum duration in milliseconds before the transaction is automatically
389    /// rolled back. Defaults to 5000 (5 seconds) if omitted.
390    #[serde(skip_serializing_if = "Option::is_none")]
391    pub timeout_ms: Option<u64>,
392    /// Optional isolation level override.
393    #[serde(skip_serializing_if = "Option::is_none")]
394    pub isolation_level: Option<IsolationLevel>,
395}
396
397/// Result of starting a transaction.
398#[derive(Debug, Clone, Serialize, Deserialize)]
399#[serde(rename_all = "camelCase")]
400pub struct TransactionStartResult {
401    /// Unique transaction identifier. Pass this as `transactionId` in
402    /// subsequent query requests.
403    pub id: String,
404}
405
406/// Commit an interactive transaction.
407#[derive(Debug, Clone, Serialize, Deserialize)]
408#[serde(rename_all = "camelCase")]
409pub struct TransactionCommitParams {
410    pub protocol_version: u32,
411    /// Transaction ID returned by `transaction.start`.
412    pub id: String,
413}
414
415/// Result of committing a transaction (empty on success).
416#[derive(Debug, Clone, Serialize, Deserialize)]
417pub struct TransactionCommitResult {}
418
419/// Rollback an interactive transaction.
420#[derive(Debug, Clone, Serialize, Deserialize)]
421#[serde(rename_all = "camelCase")]
422pub struct TransactionRollbackParams {
423    pub protocol_version: u32,
424    /// Transaction ID returned by `transaction.start`.
425    pub id: String,
426}
427
428/// Result of rolling back a transaction (empty on success).
429#[derive(Debug, Clone, Serialize, Deserialize)]
430pub struct TransactionRollbackResult {}
431
432/// A single operation inside a batch transaction.
433#[derive(Debug, Clone, Serialize, Deserialize)]
434#[serde(rename_all = "camelCase")]
435pub struct BatchOperation {
436    /// JSON-RPC method name (e.g., `"query.create"`).
437    pub method: String,
438    /// Method-specific params (same shape as the standalone request).
439    pub params: Value,
440}
441
442/// Execute multiple operations atomically in one transaction.
443#[derive(Debug, Clone, Serialize, Deserialize)]
444#[serde(rename_all = "camelCase")]
445pub struct TransactionBatchParams {
446    pub protocol_version: u32,
447    /// Ordered list of operations to execute.
448    pub operations: Vec<BatchOperation>,
449    /// Optional isolation level for the batch transaction.
450    #[serde(skip_serializing_if = "Option::is_none")]
451    pub isolation_level: Option<IsolationLevel>,
452    /// Optional timeout in milliseconds (default: 5000).
453    #[serde(skip_serializing_if = "Option::is_none")]
454    pub timeout_ms: Option<u64>,
455}
456
457/// Result of a batch transaction.
458#[derive(Debug, Clone, Serialize, Deserialize)]
459pub struct TransactionBatchResult {
460    /// One result per operation, in the same order as the input.
461    pub results: Vec<Box<RawValue>>,
462}