1
use arc_bytes::serde::Bytes;
2
use derive_where::derive_where;
3
use schema::SchemaName;
4
use serde::{Deserialize, Serialize};
5

            
6
use crate::{
7
    connection::{AccessPolicy, Authenticated, Database, QueryKey, Range, Sort},
8
    document::{DocumentId, OwnedDocument},
9
    keyvalue::{KeyOperation, Output},
10
    schema::{
11
        self,
12
        view::map::{self},
13
        CollectionName, NamedReference, ViewName,
14
    },
15
    transaction::{Executed, OperationResult, Transaction},
16
};
17

            
18
/// The current protocol version.
19
pub const CURRENT_PROTOCOL_VERSION: &str = "bonsai/pre/0";
20

            
21
/// A payload with an associated id.
22
207779
#[derive(Clone, Deserialize, Serialize, Debug)]
23
pub struct Payload<T> {
24
    /// The unique id for this payload.
25
    pub id: Option<u32>,
26
    /// The wrapped payload.
27
    pub wrapped: T,
28
}
29

            
30
/// A request made to a server.
31
154676
#[derive(Clone, Deserialize, Serialize)]
32
#[derive_where(Debug)]
33
103862
#[cfg_attr(feature = "actionable-traits", derive(actionable::Actionable))]
34
pub enum Request<T> {
35
    /// A server-related request.
36
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "none"))]
37
    Server(ServerRequest),
38

            
39
    /// A database-related request.
40
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "none"))]
41
    Database {
42
        /// The name of the database.
43
        database: String,
44
        /// The request made to the database.
45
        request: DatabaseRequest,
46
    },
47

            
48
    /// A database-related request.
49
    #[cfg_attr(
50
        feature = "actionable-traits",
51
        actionable(protection = "none", subaction)
52
    )]
53
    #[derive_where(skip_inner)]
54
    Api(T),
55
}
56

            
57
/// A server-related request.
58
3305
#[derive(Clone, Deserialize, Serialize, Debug)]
59
4412
#[cfg_attr(feature = "actionable-traits", derive(actionable::Actionable))]
60
pub enum ServerRequest {
61
    /// Creates a database.
62
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
63
    CreateDatabase {
64
        /// The database to create.
65
        database: Database,
66
        /// Only attempts to create the database if it doesn't already exist.
67
        only_if_needed: bool,
68
    },
69
    /// Deletes the database named `name`
70
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
71
    DeleteDatabase {
72
        /// The name of the database to delete.
73
        name: String,
74
    },
75
    /// Lists all databases.
76
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
77
    ListDatabases,
78
    /// Lists available schemas.
79
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
80
    ListAvailableSchemas,
81
    /// Creates a user.
82
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
83
    CreateUser {
84
        /// The unique username of the user to create.
85
        username: String,
86
    },
87
    /// Set's a user's password.
88
    #[cfg(feature = "password-hashing")]
89
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
90
    SetUserPassword {
91
        /// The username or id of the user.
92
        user: NamedReference<'static, u64>,
93
        /// The user's new password.
94
        password: crate::connection::SensitiveString,
95
    },
96
    /// Authenticate as a user.
97
    #[cfg(feature = "password-hashing")]
98
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "custom"))]
99
    Authenticate {
100
        /// The username or id of the user.
101
        user: NamedReference<'static, u64>,
102
        /// The method of authentication.
103
        authentication: crate::connection::Authentication,
104
    },
105

            
106
    /// Alter's a user's membership in a permission group.
107
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
108
    AlterUserPermissionGroupMembership {
109
        /// The username or id of the user.
110
        user: NamedReference<'static, u64>,
111

            
112
        /// The name or id of the group.
113
        group: NamedReference<'static, u64>,
114

            
115
        /// Whether the user should be in the group.
116
        should_be_member: bool,
117
    },
118

            
119
    /// Alter's a user's role
120
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
121
    AlterUserRoleMembership {
122
        /// The username or id of the user.
123
        user: NamedReference<'static, u64>,
124

            
125
        /// The name or id of the role.
126
        role: NamedReference<'static, u64>,
127

            
128
        /// Whether the user should have the role.
129
        should_be_member: bool,
130
    },
131
}
132

            
133
/// A database-related request.
134
132200
#[derive(Clone, Deserialize, Serialize, Debug)]
135
203253
#[cfg_attr(feature = "actionable-traits", derive(actionable::Actionable))]
136
pub enum DatabaseRequest {
137
    /// Retrieve a single document.
138
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
139
    Get {
140
        /// The collection of the document.
141
        collection: CollectionName,
142
        /// The id of the document.
143
        id: DocumentId,
144
    },
145
    /// Retrieve multiple documents.
146
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "custom"))]
147
    GetMultiple {
148
        /// The collection of the documents.
149
        collection: CollectionName,
150
        /// The ids of the documents.
151
        ids: Vec<DocumentId>,
152
    },
153
    /// Retrieve multiple documents.
154
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
155
    List {
156
        /// The collection of the documents.
157
        collection: CollectionName,
158
        /// The range of ids to list.
159
        ids: Range<DocumentId>,
160
        /// The order for the query into the collection.
161
        order: Sort,
162
        /// The maximum number of results to return.
163
        limit: Option<usize>,
164
    },
165
    /// Queries a view.
166
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
167
    Query {
168
        /// The name of the view.
169
        view: ViewName,
170
        /// The filter for the view.
171
        key: Option<QueryKey<Bytes>>,
172
        /// The order for the query into the view.
173
        order: Sort,
174
        /// The maximum number of results to return.
175
        limit: Option<usize>,
176
        /// The access policy for the query.
177
        access_policy: AccessPolicy,
178
        /// If true, [`DatabaseResponse::ViewMappingsWithDocs`] will be
179
        /// returned. If false, [`DatabaseResponse::ViewMappings`] will be
180
        /// returned.
181
        with_docs: bool,
182
    },
183
    /// Reduces a view.
184
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
185
    Reduce {
186
        /// The name of the view.
187
        view: ViewName,
188
        /// The filter for the view.
189
        key: Option<QueryKey<Bytes>>,
190
        /// The access policy for the query.
191
        access_policy: AccessPolicy,
192
        /// Whether to return a single value or values grouped by unique key. If
193
        /// true, [`DatabaseResponse::ViewGroupedReduction`] will be returned.
194
        /// If false, [`DatabaseResponse::ViewReduction`] is returned.
195
        grouped: bool,
196
    },
197
    /// Deletes the associated documents resulting from the view query.
198
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
199
    DeleteDocs {
200
        /// The name of the view.
201
        view: ViewName,
202
        /// The filter for the view.
203
        key: Option<QueryKey<Bytes>>,
204
        /// The access policy for the query.
205
        access_policy: AccessPolicy,
206
    },
207
    /// Applies a transaction.
208
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "custom"))]
209
    ApplyTransaction {
210
        /// The trasnaction to apply.
211
        transaction: Transaction,
212
    },
213
    /// Lists executed transactions.
214
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
215
    ListExecutedTransactions {
216
        /// The starting transaction id.
217
        starting_id: Option<u64>,
218
        /// The maximum number of results.
219
        result_limit: Option<usize>,
220
    },
221
    /// Queries the last transaction id.
222
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
223
    LastTransactionId,
224
    /// Creates a `PubSub` [`Subscriber`](crate::pubsub::Subscriber)
225
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
226
    CreateSubscriber,
227
    /// Publishes `payload` to all subscribers of `topic`.
228
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
229
    Publish {
230
        /// The topics to publish to.
231
        topic: String,
232
        /// The payload to publish.
233
        payload: Bytes,
234
    },
235
    /// Publishes `payload` to all subscribers of all `topics`.
236
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "custom"))]
237
    PublishToAll {
238
        /// The topics to publish to.
239
        topics: Vec<String>,
240
        /// The payload to publish.
241
        payload: Bytes,
242
    },
243
    /// Subscribes `subscriber_id` to messages for `topic`.
244
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
245
    SubscribeTo {
246
        /// The id of the [`Subscriber`](crate::pubsub::Subscriber).
247
        subscriber_id: u64,
248
        /// The topic to subscribe to.
249
        topic: String,
250
    },
251
    /// Unsubscribes `subscriber_id` from messages for `topic`.
252
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
253
    UnsubscribeFrom {
254
        /// The id of the [`Subscriber`](crate::pubsub::Subscriber).
255
        subscriber_id: u64,
256
        /// The topic to unsubscribe from.
257
        topic: String,
258
    },
259
    /// Unregisters the subscriber.
260
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "none"))]
261
    UnregisterSubscriber {
262
        /// The id of the [`Subscriber`](crate::pubsub::Subscriber).
263
        subscriber_id: u64,
264
    },
265
    /// Excutes a key-value store operation.
266
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
267
    ExecuteKeyOperation(KeyOperation),
268
    /// Compacts the collection.
269
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
270
    CompactCollection {
271
        /// The name of the collection to compact.
272
        name: CollectionName,
273
    },
274
    /// Compacts the key-value store.
275
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
276
    CompactKeyValueStore,
277
    /// Compacts the entire database.
278
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
279
    Compact,
280
}
281

            
282
/// A response from a server.
283
103918
#[derive(Clone, Serialize, Deserialize)]
284
#[derive_where(Debug)]
285
pub enum Response<T> {
286
    /// A request succeded but provided no output.
287
    Ok,
288
    /// A response to a [`ServerRequest`].
289
    Server(ServerResponse),
290
    /// A response to a [`DatabaseRequest`].
291
    Database(DatabaseResponse),
292
    /// A response to an Api request.
293
    #[derive_where(skip_inner)]
294
    Api(T),
295
    /// An error occurred processing a request.
296
    Error(crate::Error),
297
}
298

            
299
/// A response to a [`ServerRequest`].
300
3225
#[derive(Clone, Serialize, Deserialize, Debug)]
301
pub enum ServerResponse {
302
    /// A database with `name` was successfully created.
303
    DatabaseCreated {
304
        /// The name of the database to create.
305
        name: String,
306
    },
307
    /// A database with `name` was successfully removed.
308
    DatabaseDeleted {
309
        /// The name of the database to remove.
310
        name: String,
311
    },
312
    /// A list of available databases.
313
    Databases(Vec<Database>),
314
    /// A list of availble schemas.
315
    AvailableSchemas(Vec<SchemaName>),
316
    /// A user was created.
317
    UserCreated {
318
        /// The id of the user created.
319
        id: u64,
320
    },
321
    /// Successfully authenticated.
322
    Authenticated(Authenticated),
323
}
324

            
325
/// A response to a [`DatabaseRequest`].
326
99566
#[derive(Clone, Serialize, Deserialize, Debug)]
327
pub enum DatabaseResponse {
328
    /// One or more documents.
329
    Documents(Vec<OwnedDocument>),
330
    /// A number of documents were deleted.
331
    DocumentsDeleted(u64),
332
    /// Results of [`DatabaseRequest::ApplyTransaction`].
333
    TransactionResults(Vec<OperationResult>),
334
    /// Results of [`DatabaseRequest::Query`] when `with_docs` is false.
335
    ViewMappings(Vec<map::Serialized>),
336
    /// Results of [`DatabaseRequest::Query`] when `with_docs` is true.
337
    ViewMappingsWithDocs(map::MappedSerializedDocuments),
338
    /// Result of [`DatabaseRequest::Reduce`] when `grouped` is false.
339
    ViewReduction(Bytes),
340
    /// Result of [`DatabaseRequest::Reduce`] when `grouped` is true.
341
    ViewGroupedReduction(Vec<map::MappedSerializedValue>),
342
    /// Results of [`DatabaseRequest::ListExecutedTransactions`].
343
    ExecutedTransactions(Vec<Executed>),
344
    /// Result of [`DatabaseRequest::LastTransactionId`].
345
    LastTransactionId(Option<u64>),
346
    /// A new `PubSub` subscriber was created.
347
    SubscriberCreated {
348
        /// The unique ID of the subscriber.
349
        subscriber_id: u64,
350
    },
351
    /// A PubSub message was received.
352
    MessageReceived {
353
        /// The ID of the subscriber receiving the message.
354
        subscriber_id: u64,
355
        /// The topic the payload was received on.
356
        topic: String,
357
        /// The message payload.
358
        payload: Bytes,
359
    },
360
    /// Output from a [`KeyOperation`] being executed.
361
    KvOutput(Output),
362
}
363

            
364
/// A networking error.
365
#[derive(Clone, thiserror::Error, Debug, Serialize, Deserialize)]
366
pub enum Error {
367
    /// The server responded with a message that wasn't expected for the request
368
    /// sent.
369
    #[error("unexpected response: {0}")]
370
    UnexpectedResponse(String),
371

            
372
    /// The connection was interrupted.
373
    #[error("unexpected disconnection")]
374
    Disconnected,
375
}