fraiseql_wire/protocol/message.rs
1//! Protocol message types
2
3use bytes::Bytes;
4
5/// Frontend message (client → server)
6#[derive(Debug, Clone)]
7pub enum FrontendMessage {
8 /// Startup message
9 Startup {
10 /// Protocol version
11 version: i32,
12 /// Connection parameters
13 params: Vec<(String, String)>,
14 },
15
16 /// Password message
17 Password(String),
18
19 /// Query message
20 Query(String),
21
22 /// Terminate message
23 Terminate,
24
25 /// SASL initial response message
26 SaslInitialResponse {
27 /// SASL mechanism name (e.g., "SCRAM-SHA-256")
28 mechanism: String,
29 /// SASL client first message data
30 data: Vec<u8>,
31 },
32
33 /// SASL response message
34 SaslResponse {
35 /// SASL client final message data
36 data: Vec<u8>,
37 },
38
39 /// SSLRequest message (TLS negotiation)
40 SslRequest,
41}
42
43/// Backend message (server → client)
44#[derive(Debug, Clone)]
45pub enum BackendMessage {
46 /// Authentication request
47 Authentication(AuthenticationMessage),
48
49 /// Backend key data (for cancellation)
50 BackendKeyData {
51 /// Process ID
52 process_id: i32,
53 /// Secret key
54 secret_key: i32,
55 },
56
57 /// Command complete
58 CommandComplete(String),
59
60 /// Data row
61 DataRow(Vec<Option<Bytes>>),
62
63 /// Error response
64 ErrorResponse(ErrorFields),
65
66 /// Notice response
67 NoticeResponse(ErrorFields),
68
69 /// Parameter status
70 ParameterStatus {
71 /// Parameter name
72 name: String,
73 /// Parameter value
74 value: String,
75 },
76
77 /// Ready for query
78 ReadyForQuery {
79 /// Transaction status
80 status: u8,
81 },
82
83 /// Row description
84 RowDescription(Vec<FieldDescription>),
85}
86
87/// Authentication message types
88#[derive(Debug, Clone)]
89pub enum AuthenticationMessage {
90 /// Authentication OK
91 Ok,
92
93 /// Cleartext password required
94 CleartextPassword,
95
96 /// MD5 password required
97 Md5Password {
98 /// Salt for MD5 hash
99 salt: [u8; 4],
100 },
101
102 /// SASL authentication mechanisms available (Postgres 10+)
103 Sasl {
104 /// List of SASL mechanism names (e.g., ["SCRAM-SHA-256"])
105 mechanisms: Vec<String>,
106 },
107
108 /// SASL continuation message (server challenge)
109 SaslContinue {
110 /// SASL server first/continue message data
111 data: Vec<u8>,
112 },
113
114 /// SASL final message (server verification)
115 SaslFinal {
116 /// SASL server final message data
117 data: Vec<u8>,
118 },
119}
120
121/// Field description (column metadata)
122#[derive(Debug, Clone)]
123pub struct FieldDescription {
124 /// Column name
125 pub name: String,
126 /// Table OID (0 if not a table column)
127 pub table_oid: i32,
128 /// Column attribute number (0 if not a table column)
129 pub column_attr: i16,
130 /// Data type OID
131 pub type_oid: u32,
132 /// Data type size
133 pub type_size: i16,
134 /// Type modifier
135 pub type_modifier: i32,
136 /// Format code (0 = text, 1 = binary)
137 pub format_code: i16,
138}
139
140/// Error/notice fields
141#[derive(Debug, Clone, Default)]
142pub struct ErrorFields {
143 /// Severity (ERROR, WARNING, etc.)
144 pub severity: Option<String>,
145 /// SQLSTATE code
146 pub code: Option<String>,
147 /// Human-readable message
148 pub message: Option<String>,
149 /// Additional detail
150 pub detail: Option<String>,
151 /// Hint
152 pub hint: Option<String>,
153 /// Position in query string
154 pub position: Option<String>,
155}
156
157impl std::fmt::Display for ErrorFields {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 if let Some(ref msg) = self.message {
160 write!(f, "{}", msg)?;
161 }
162 if let Some(ref code) = self.code {
163 write!(f, " ({})", code)?;
164 }
165 Ok(())
166 }
167}