use std::borrow::Cow;
use async_trait::async_trait;
pub use fabruic;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{
connection::{AccessPolicy, QueryKey},
document::Document,
schema::{
self, collection,
map::{self},
view::{self, map::MappedValue},
Key,
},
transaction::{Executed, OperationResult, Transaction},
};
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct Payload<T> {
pub id: u32,
pub wrapped: T,
}
#[derive(Clone, Deserialize, Serialize, Debug)]
pub enum Request {
Server(ServerRequest),
Database {
database: String,
request: DatabaseRequest,
},
}
#[derive(Clone, Deserialize, Serialize, Debug)]
pub enum ServerRequest {
CreateDatabase(Database),
DeleteDatabase {
name: String,
},
ListDatabases,
ListAvailableSchemas,
}
#[derive(Clone, Deserialize, Serialize, Debug)]
pub enum DatabaseRequest {
Get {
collection: collection::Id,
id: u64,
},
GetMultiple {
collection: collection::Id,
ids: Vec<u64>,
},
Query {
view: Cow<'static, str>,
key: Option<QueryKey<Vec<u8>>>,
access_policy: AccessPolicy,
with_docs: bool,
},
Reduce {
view: Cow<'static, str>,
key: Option<QueryKey<Vec<u8>>>,
access_policy: AccessPolicy,
grouped: bool,
},
ApplyTransaction {
transaction: Transaction<'static>,
},
ListExecutedTransactions {
starting_id: Option<u64>,
result_limit: Option<usize>,
},
LastTransactionId,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub enum Response {
Server(ServerResponse),
Database(DatabaseResponse),
Error(crate::Error),
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub enum ServerResponse {
DatabaseCreated {
name: String,
},
DatabaseDeleted {
name: String,
},
Databases(Vec<Database>),
AvailableSchemas(Vec<schema::Id>),
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub enum DatabaseResponse {
Documents(Vec<Document<'static>>),
TransactionResults(Vec<OperationResult>),
ViewMappings(Vec<map::Serialized>),
ViewMappingsWithDocs(Vec<MappedDocument>),
ViewReduction(Vec<u8>),
ViewGroupedReduction(Vec<MappedValue<Vec<u8>, Vec<u8>>>),
ExecutedTransactions(Vec<Executed<'static>>),
LastTransactionId(Option<u64>),
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct MappedDocument {
pub key: Vec<u8>,
pub value: Vec<u8>,
pub source: Document<'static>,
}
impl MappedDocument {
pub fn deserialized<K: Key, V: Serialize + DeserializeOwned>(
self,
) -> Result<map::MappedDocument<K, V>, crate::Error> {
let key = Key::from_big_endian_bytes(&self.key)
.map_err(|err| crate::Error::Storage(view::Error::KeySerialization(err).to_string()))?;
let value = serde_cbor::from_slice(&self.value)
.map_err(|err| crate::Error::Storage(view::Error::from(err).to_string()))?;
Ok(map::MappedDocument {
document: self.source,
key,
value,
})
}
}
#[derive(Clone, PartialEq, Deserialize, Serialize, Debug)]
pub struct Database {
pub name: String,
pub schema: schema::Id,
}
#[async_trait]
pub trait ServerConnection: Send + Sync {
async fn create_database(&self, name: &str, schema: schema::Id) -> Result<(), crate::Error>;
async fn delete_database(&self, name: &str) -> Result<(), crate::Error>;
async fn list_databases(&self) -> Result<Vec<Database>, crate::Error>;
async fn list_available_schemas(&self) -> Result<Vec<schema::Id>, crate::Error>;
}
#[derive(Clone, thiserror::Error, Debug, Serialize, Deserialize)]
pub enum Error {
#[error("invalid database name: {0}")]
InvalidDatabaseName(String),
#[error("database '{0}' was not found")]
DatabaseNotFound(String),
#[error("a database with name '{0}' already exists")]
DatabaseNameAlreadyTaken(String),
#[error("unexpected response: {0}")]
UnexpectedResponse(String),
#[error("unexpected disconnection")]
Disconnected,
#[error(
"database '{database_name}' was created with schema '{stored_schema}', not '{schema}'"
)]
SchemaMismatch {
database_name: String,
schema: schema::Id,
stored_schema: schema::Id,
},
#[error("schema '{0}' was already registered")]
SchemaAlreadyRegistered(schema::Id),
#[error("schema '{0}' is not registered with this server")]
SchemaNotRegistered(schema::Id),
}