use crate::{TitoError, TitoModel};
use async_trait::async_trait;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use serde::Serialize;
use std::future::Future;
use std::ops::Range;
use uuid::Uuid;
pub trait TitoModelConstraints:
Default + Clone + Serialize + DeserializeOwned + Unpin + std::marker::Send + Sync + TitoModelTrait
{
}
impl<T> TitoModelConstraints for T where
T: Default
+ Clone
+ Serialize
+ DeserializeOwned
+ Unpin
+ std::marker::Send
+ Sync
+ TitoModelTrait
{
}
pub type TitoKey = Vec<u8>;
pub type TitoValue = Vec<u8>;
pub type TitoKvPair = (TitoKey, TitoValue);
pub type TitoRange = Range<TitoKey>;
#[derive(Debug, Clone)]
pub struct TitoModelOptions {
pub partition_count: u32,
}
impl Default for TitoModelOptions {
fn default() -> Self {
Self {
partition_count: 1,
}
}
}
impl TitoModelOptions {
pub fn with_partitions(partition_count: u32) -> Self {
Self { partition_count }
}
}
#[async_trait]
pub trait TitoEngine: Send + Sync + Clone {
type Transaction: TitoTransaction;
async fn begin_transaction(&self) -> Result<Self::Transaction, TitoError>;
async fn transaction<F, Fut, T, E>(&self, f: F) -> Result<T, E>
where
F: FnOnce(Self::Transaction) -> Fut + Clone + Send,
Fut: Future<Output = Result<T, E>> + Send,
T: Send,
E: From<TitoError> + Send + std::fmt::Debug;
async fn clear_active_transactions(&self) -> Result<(), TitoError>;
async fn delete_range(&self, start: &[u8], end: &[u8]) -> Result<(), TitoError>;
fn model<T: TitoModelConstraints>(self, options: TitoModelOptions) -> TitoModel<Self, T> {
TitoModel::new(self, options)
}
}
#[async_trait]
pub trait TitoTransaction: Send + Sync {
async fn get<K: AsRef<[u8]> + Send>(&self, key: K) -> Result<Option<TitoValue>, TitoError>;
async fn put<K: AsRef<[u8]> + Send, V: AsRef<[u8]> + Send>(
&self,
key: K,
value: V,
) -> Result<(), TitoError>;
async fn delete<K: AsRef<[u8]> + Send>(&self, key: K) -> Result<(), TitoError>;
async fn scan<K: AsRef<[u8]> + Send>(
&self,
range: Range<K>,
limit: u32,
) -> Result<Vec<TitoKvPair>, TitoError>;
async fn scan_reverse<K: AsRef<[u8]> + Send>(
&self,
range: Range<K>,
limit: u32,
) -> Result<Vec<TitoKvPair>, TitoError>;
async fn batch_get<K: AsRef<[u8]> + Send>(
&self,
keys: Vec<K>,
) -> Result<Vec<TitoKvPair>, TitoError>;
async fn commit(self) -> Result<(), TitoError>;
async fn rollback(self) -> Result<(), TitoError>;
}
pub struct TitoLockItem {
pub key: String,
pub value: String,
}
pub struct TitoUtilsConnectPayload {
pub uri: String,
}
pub struct TitoUtilsConnectInput {
pub payload: TitoUtilsConnectPayload,
}
#[derive(Debug, Clone)]
pub struct TitoEmbeddedRelationshipConfig {
pub source_field_name: String,
pub destination_field_name: String,
pub model: String,
}
pub type TitoRelationshipConfig = TitoEmbeddedRelationshipConfig;
#[derive(Debug, Clone)]
pub enum TitoIndexBlockType {
String,
Number,
Custom(std::string::String),
}
#[derive(Debug, Clone)]
pub enum FieldValue {
Simple(serde_json::Value),
HashMapEntry {
key: String,
value: serde_json::Value,
},
}
#[derive(Debug, Clone)]
pub struct TitoIndexField {
pub name: String,
pub r#type: TitoIndexBlockType,
}
#[derive(Debug, Clone)]
pub struct TitoTemporalIndex {
pub from_field: String,
pub to_field: String,
pub range_field: String,
}
pub struct TitoIndexConfig {
pub condition: bool,
pub fields: Vec<TitoIndexField>,
pub name: String,
}
#[derive(Debug, Clone)]
pub struct TitoRelIndexConfig {
pub name: String,
pub field: String,
}
pub trait TitoModelTrait {
fn relationships() -> Vec<TitoRelationshipConfig> {
vec![]
}
fn indexes(&self) -> Vec<TitoIndexConfig>;
fn table() -> String;
fn id(&self) -> String;
fn key_prefix() -> String {
format!("table:{}", Self::table())
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct ReverseIndex {
pub value: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct TitoId {
id: String,
r#type: String,
}
impl TitoId {
pub fn new(id: &str, r#type: &str) -> TitoId {
TitoId {
id: id.to_string(),
r#type: r#type.to_string(),
}
}
pub fn to_string(&self) -> String {
format!("{}:{}", self.r#type, self.id)
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct TitoScanPayload {
pub start: String,
pub end: Option<String>,
pub limit: Option<u32>,
pub cursor: Option<String>,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct TitoFindPayload {
pub start: String,
pub end: Option<String>,
pub limit: Option<u32>,
pub cursor: Option<String>,
pub rels: Vec<String>,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct TitoFindByIndexPayload {
pub index: String,
pub values: Vec<String>,
pub rels: Vec<String>,
pub limit: Option<u32>,
pub cursor: Option<String>,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct TitoFindByMultipleIndexPayload {
pub queries: Vec<TitoFindByMultipleIndexQuery>,
pub limit: Option<u32>,
pub cursor: Option<String>,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct TitoFindByMultipleIndexQuery {
pub index: String,
pub edge_name: Option<String>,
pub values: Vec<String>,
pub rels: Vec<String>,
pub end: Option<String>,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct TitoFindOneByIndexPayload {
pub index: String,
pub values: Vec<String>,
pub rels: Vec<String>,
}
#[derive(Default, Serialize, Debug)]
pub struct TitoPaginated<T> {
pub items: Vec<T>,
pub cursor: Option<String>,
}
#[derive(Default, Serialize, Deserialize, Debug)]
pub struct TitoCursor {
pub ids: Vec<Option<String>>,
}
impl TitoCursor {
pub fn first_id(&self) -> Result<String, TitoError> {
self.ids
.get(0)
.and_then(|id_option| id_option.as_ref())
.map(|id| id.to_string())
.ok_or(TitoError::InvalidInput(
"Cursor has no valid ID in first position".to_string(),
))
}
}
impl<T> TitoPaginated<T> {
pub fn new(items: Vec<T>, cursor: Option<String>) -> Self {
Self { items, cursor }
}
}
pub type DBUuid = Uuid;
#[derive(Debug, Clone)]
pub struct PartitionConfig {
pub partition: u32,
}
impl PartitionConfig {
pub fn new(partition: u32) -> Self {
Self { partition }
}
}
pub const PARTITION_DIGITS: usize = 4;