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
210168
#[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
156465
#[derive(Clone, Deserialize, Serialize)]
32
#[derive_where(Debug)]
33
105056
#[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
3311
#[derive(Clone, Deserialize, Serialize, Debug)]
59
4420
#[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
    /// Deletes a user.
88
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
89
    DeleteUser {
90
        /// The unique primary key of the user to be deleted.
91
        user: NamedReference<'static, u64>,
92
    },
93
    /// Set's a user's password.
94
    #[cfg(feature = "password-hashing")]
95
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
96
    SetUserPassword {
97
        /// The username or id of the user.
98
        user: NamedReference<'static, u64>,
99
        /// The user's new password.
100
        password: crate::connection::SensitiveString,
101
    },
102
    /// Authenticate as a user.
103
    #[cfg(feature = "password-hashing")]
104
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "custom"))]
105
    Authenticate {
106
        /// The username or id of the user.
107
        user: NamedReference<'static, u64>,
108
        /// The method of authentication.
109
        authentication: crate::connection::Authentication,
110
    },
111

            
112
    /// Alter's a user's membership in a permission group.
113
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
114
    AlterUserPermissionGroupMembership {
115
        /// The username or id of the user.
116
        user: NamedReference<'static, u64>,
117

            
118
        /// The name or id of the group.
119
        group: NamedReference<'static, u64>,
120

            
121
        /// Whether the user should be in the group.
122
        should_be_member: bool,
123
    },
124

            
125
    /// Alter's a user's role
126
    #[cfg_attr(feature = "actionable-traits", actionable(protection = "simple"))]
127
    AlterUserRoleMembership {
128
        /// The username or id of the user.
129
        user: NamedReference<'static, u64>,
130

            
131
        /// The name or id of the role.
132
        role: NamedReference<'static, u64>,
133

            
134
        /// Whether the user should have the role.
135
        should_be_member: bool,
136
    },
137
}
138

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

            
296
/// A response from a server.
297
105112
#[derive(Clone, Serialize, Deserialize)]
298
#[derive_where(Debug)]
299
pub enum Response<T> {
300
    /// A request succeded but provided no output.
301
    Ok,
302
    /// A response to a [`ServerRequest`].
303
    Server(ServerResponse),
304
    /// A response to a [`DatabaseRequest`].
305
    Database(DatabaseResponse),
306
    /// A response to an Api request.
307
    #[derive_where(skip_inner)]
308
    Api(T),
309
    /// An error occurred processing a request.
310
    Error(crate::Error),
311
}
312

            
313
/// A response to a [`ServerRequest`].
314
3225
#[derive(Clone, Serialize, Deserialize, Debug)]
315
pub enum ServerResponse {
316
    /// A database with `name` was successfully created.
317
    DatabaseCreated {
318
        /// The name of the database to create.
319
        name: String,
320
    },
321
    /// A database with `name` was successfully removed.
322
    DatabaseDeleted {
323
        /// The name of the database to remove.
324
        name: String,
325
    },
326
    /// A list of available databases.
327
    Databases(Vec<Database>),
328
    /// A list of availble schemas.
329
    AvailableSchemas(Vec<SchemaName>),
330
    /// A user was created.
331
    UserCreated {
332
        /// The id of the user created.
333
        id: u64,
334
    },
335
    /// Successfully authenticated.
336
    Authenticated(Authenticated),
337
}
338

            
339
/// A response to a [`DatabaseRequest`].
340
100752
#[derive(Clone, Serialize, Deserialize, Debug)]
341
pub enum DatabaseResponse {
342
    /// One or more documents.
343
    Documents(Vec<OwnedDocument>),
344
    /// A result count.
345
    Count(u64),
346
    /// Results of [`DatabaseRequest::ApplyTransaction`].
347
    TransactionResults(Vec<OperationResult>),
348
    /// Results of [`DatabaseRequest::Query`] when `with_docs` is false.
349
    ViewMappings(Vec<map::Serialized>),
350
    /// Results of [`DatabaseRequest::Query`] when `with_docs` is true.
351
    ViewMappingsWithDocs(map::MappedSerializedDocuments),
352
    /// Result of [`DatabaseRequest::Reduce`] when `grouped` is false.
353
    ViewReduction(Bytes),
354
    /// Result of [`DatabaseRequest::Reduce`] when `grouped` is true.
355
    ViewGroupedReduction(Vec<map::MappedSerializedValue>),
356
    /// Results of [`DatabaseRequest::ListExecutedTransactions`].
357
    ExecutedTransactions(Vec<Executed>),
358
    /// Result of [`DatabaseRequest::LastTransactionId`].
359
    LastTransactionId(Option<u64>),
360
    /// A new `PubSub` subscriber was created.
361
    SubscriberCreated {
362
        /// The unique ID of the subscriber.
363
        subscriber_id: u64,
364
    },
365
    /// A PubSub message was received.
366
    MessageReceived {
367
        /// The ID of the subscriber receiving the message.
368
        subscriber_id: u64,
369
        /// The topic the payload was received on.
370
        topic: String,
371
        /// The message payload.
372
        payload: Bytes,
373
    },
374
    /// Output from a [`KeyOperation`] being executed.
375
    KvOutput(Output),
376
}
377

            
378
/// A networking error.
379
#[derive(Clone, thiserror::Error, Debug, Serialize, Deserialize)]
380
pub enum Error {
381
    /// The server responded with a message that wasn't expected for the request
382
    /// sent.
383
    #[error("unexpected response: {0}")]
384
    UnexpectedResponse(String),
385

            
386
    /// The connection was interrupted.
387
    #[error("unexpected disconnection")]
388
    Disconnected,
389
}