mirror of
https://github.com/Start9Labs/patch-db.git
synced 2026-03-26 10:21:53 +00:00
option model
This commit is contained in:
@@ -162,6 +162,11 @@ fn build_model_struct(
|
||||
#model_name(#inner_model::from(ptr))
|
||||
}
|
||||
}
|
||||
impl AsRef<patch_db::json_ptr::JsonPointer> for #model_name {
|
||||
fn as_ref(&self) -> &patch_db::json_ptr::JsonPointer {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl From<patch_db::Model<#base_name>> for #model_name {
|
||||
fn from(model: patch_db::Model<#base_name>) -> Self {
|
||||
#model_name(#inner_model::from(patch_db::json_ptr::JsonPointer::from(model)))
|
||||
@@ -237,6 +242,11 @@ fn build_model_struct(
|
||||
#model_name(From::from(ptr))
|
||||
}
|
||||
}
|
||||
impl AsRef<patch_db::json_ptr::JsonPointer> for #model_name {
|
||||
fn as_ref(&self) -> &patch_db::json_ptr::JsonPointer {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl From<patch_db::Model<#base_name>> for #model_name {
|
||||
fn from(model: patch_db::Model<#base_name>) -> Self {
|
||||
#model_name(model)
|
||||
|
||||
@@ -15,13 +15,15 @@ mod transaction;
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
pub use json_ptr;
|
||||
pub use locker::{LockType, Locker};
|
||||
pub use model::{BoxModel, HasModel, MapModel, Model, ModelData, ModelDataMut, VecModel};
|
||||
pub use model::{
|
||||
BoxModel, HasModel, MapModel, Model, ModelData, ModelDataMut, OptionModel, VecModel,
|
||||
};
|
||||
pub use patch::Revision;
|
||||
pub use patch_db_macro::HasModel;
|
||||
pub use store::{PatchDb, Store};
|
||||
pub use transaction::{Checkpoint, SubTransaction, Transaction};
|
||||
pub use json_ptr;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
|
||||
@@ -95,6 +95,14 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> AsRef<JsonPointer> for Model<T>
|
||||
where
|
||||
T: Serialize + for<'de> Deserialize<'de>,
|
||||
{
|
||||
fn as_ref(&self) -> &JsonPointer {
|
||||
&self.ptr
|
||||
}
|
||||
}
|
||||
impl<T> From<Model<T>> for JsonPointer
|
||||
where
|
||||
T: Serialize + for<'de> Deserialize<'de>,
|
||||
@@ -116,9 +124,10 @@ where
|
||||
}
|
||||
|
||||
pub trait HasModel {
|
||||
type Model: From<JsonPointer>;
|
||||
type Model: From<JsonPointer> + AsRef<JsonPointer>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoxModel<T: HasModel + Serialize + for<'de> Deserialize<'de>>(T::Model);
|
||||
impl<T: HasModel + Serialize + for<'de> Deserialize<'de>> Deref for BoxModel<T> {
|
||||
type Target = T::Model;
|
||||
@@ -131,6 +140,14 @@ impl<T: HasModel + Serialize + for<'de> Deserialize<'de>> From<Model<Box<T>>> fo
|
||||
BoxModel(T::Model::from(JsonPointer::from(model)))
|
||||
}
|
||||
}
|
||||
impl<T> AsRef<JsonPointer> for BoxModel<T>
|
||||
where
|
||||
T: HasModel + Serialize + for<'de> Deserialize<'de>,
|
||||
{
|
||||
fn as_ref(&self) -> &JsonPointer {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl<T: HasModel + Serialize + for<'de> Deserialize<'de>> From<JsonPointer> for BoxModel<T> {
|
||||
fn from(ptr: JsonPointer) -> Self {
|
||||
BoxModel(T::Model::from(ptr))
|
||||
@@ -140,6 +157,34 @@ impl<T: HasModel + Serialize + for<'de> Deserialize<'de>> HasModel for Box<T> {
|
||||
type Model = BoxModel<T>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OptionModel<T: HasModel + Serialize + for<'de> Deserialize<'de>>(T::Model);
|
||||
impl<T: HasModel + Serialize + for<'de> Deserialize<'de>> OptionModel<T> {
|
||||
pub async fn check<Tx: Checkpoint>(self, tx: &mut Tx) -> Result<Option<T::Model>, Error> {
|
||||
Ok(if tx.exists(self.0.as_ref(), None).await? {
|
||||
Some(self.0)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
impl<T: HasModel + Serialize + for<'de> Deserialize<'de>> From<Model<Option<T>>>
|
||||
for OptionModel<T>
|
||||
{
|
||||
fn from(model: Model<Option<T>>) -> Self {
|
||||
OptionModel(T::Model::from(JsonPointer::from(model)))
|
||||
}
|
||||
}
|
||||
impl<T: HasModel + Serialize + for<'de> Deserialize<'de>> From<JsonPointer> for OptionModel<T> {
|
||||
fn from(ptr: JsonPointer) -> Self {
|
||||
OptionModel(T::Model::from(ptr))
|
||||
}
|
||||
}
|
||||
impl<T: HasModel + Serialize + for<'de> Deserialize<'de>> HasModel for Option<T> {
|
||||
type Model = BoxModel<T>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VecModel<T: Serialize + for<'de> Deserialize<'de>>(Model<Vec<T>>);
|
||||
impl<T: Serialize + for<'de> Deserialize<'de>> Deref for VecModel<T> {
|
||||
type Target = Model<Vec<T>>;
|
||||
@@ -152,8 +197,8 @@ impl<T: Serialize + for<'de> Deserialize<'de>> VecModel<T> {
|
||||
self.child(&format!("{}", idx))
|
||||
}
|
||||
}
|
||||
impl<T: Serialize + for<'de> Deserialize<'de>> From<Model<Box<T>>> for VecModel<T> {
|
||||
fn from(model: Model<Box<T>>) -> Self {
|
||||
impl<T: Serialize + for<'de> Deserialize<'de>> From<Model<Vec<T>>> for VecModel<T> {
|
||||
fn from(model: Model<Vec<T>>) -> Self {
|
||||
VecModel(From::from(JsonPointer::from(model)))
|
||||
}
|
||||
}
|
||||
@@ -162,10 +207,19 @@ impl<T: Serialize + for<'de> Deserialize<'de>> From<JsonPointer> for VecModel<T>
|
||||
VecModel(From::from(ptr))
|
||||
}
|
||||
}
|
||||
impl<T> AsRef<JsonPointer> for VecModel<T>
|
||||
where
|
||||
T: Serialize + for<'de> Deserialize<'de>,
|
||||
{
|
||||
fn as_ref(&self) -> &JsonPointer {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl<T: Serialize + for<'de> Deserialize<'de>> HasModel for Vec<T> {
|
||||
type Model = VecModel<T>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MapModel<T: Serialize + for<'de> Deserialize<'de> + for<'a> Index<&'a str>>(Model<T>);
|
||||
impl<T: Serialize + for<'de> Deserialize<'de> + for<'a> Index<&'a str>> Deref for MapModel<T> {
|
||||
type Target = Model<T>;
|
||||
@@ -182,6 +236,15 @@ where
|
||||
self.child(idx)
|
||||
}
|
||||
}
|
||||
impl<T> MapModel<T>
|
||||
where
|
||||
T: Serialize + for<'de> Deserialize<'de> + for<'a> Index<&'a str>,
|
||||
for<'a, 'de> <T as Index<&'a str>>::Output: Serialize + Deserialize<'de> + HasModel,
|
||||
{
|
||||
pub fn idx_model(&self, idx: &str) -> OptionModel<<T as Index<&str>>::Output> {
|
||||
self.child(idx).into()
|
||||
}
|
||||
}
|
||||
impl<T: Serialize + for<'de> Deserialize<'de> + for<'a> Index<&'a str>> From<Model<Box<T>>>
|
||||
for MapModel<T>
|
||||
{
|
||||
@@ -196,6 +259,14 @@ impl<T: Serialize + for<'de> Deserialize<'de> + for<'a> Index<&'a str>> From<Jso
|
||||
MapModel(From::from(ptr))
|
||||
}
|
||||
}
|
||||
impl<T> AsRef<JsonPointer> for MapModel<T>
|
||||
where
|
||||
T: Serialize + for<'de> Deserialize<'de> + for<'a> Index<&'a str>,
|
||||
{
|
||||
fn as_ref(&self) -> &JsonPointer {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl<K, V> HasModel for HashMap<K, V>
|
||||
where
|
||||
K: Serialize + for<'de> Deserialize<'de> + Hash + Eq,
|
||||
|
||||
@@ -77,6 +77,7 @@ impl DiffPatch {
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn rebase(&mut self, onto: &DiffPatch) {
|
||||
let DiffPatch(Patch(ops)) = self;
|
||||
let DiffPatch(Patch(onto_ops)) = onto;
|
||||
@@ -148,6 +149,31 @@ impl DiffPatch {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exists(&self) -> Option<bool> {
|
||||
let mut res = None;
|
||||
for op in &(self.0).0 {
|
||||
match op {
|
||||
PatchOperation::Add(a) => {
|
||||
if a.path.is_empty() {
|
||||
res = Some(!a.value.is_null());
|
||||
}
|
||||
}
|
||||
PatchOperation::Replace(a) => {
|
||||
if a.path.is_empty() {
|
||||
res = Some(!a.value.is_null())
|
||||
}
|
||||
}
|
||||
PatchOperation::Remove(a) => {
|
||||
if a.path.is_empty() {
|
||||
res = Some(false)
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
impl Default for DiffPatch {
|
||||
fn default() -> Self {
|
||||
|
||||
@@ -123,6 +123,12 @@ impl Store {
|
||||
self.file.unlock(true).map_err(|e| e.1)?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn exists<S: AsRef<str>, V: SegList>(
|
||||
&self,
|
||||
ptr: &JsonPointer<S, V>,
|
||||
) -> Result<bool, Error> {
|
||||
Ok(ptr.get(self.get_data()?).unwrap_or(&Value::Null) != &Value::Null)
|
||||
}
|
||||
pub fn get<T: for<'de> Deserialize<'de>, S: AsRef<str>, V: SegList>(
|
||||
&self,
|
||||
ptr: &JsonPointer<S, V>,
|
||||
@@ -190,6 +196,12 @@ impl PatchDb {
|
||||
subscriber: Arc::new(subscriber),
|
||||
})
|
||||
}
|
||||
pub async fn exists<S: AsRef<str>, V: SegList>(
|
||||
&self,
|
||||
ptr: &JsonPointer<S, V>,
|
||||
) -> Result<bool, Error> {
|
||||
self.store.read().await.exists(ptr)
|
||||
}
|
||||
pub async fn get<T: for<'de> Deserialize<'de>, S: AsRef<str>, V: SegList>(
|
||||
&self,
|
||||
ptr: &JsonPointer<S, V>,
|
||||
|
||||
@@ -15,6 +15,11 @@ use crate::Error;
|
||||
|
||||
pub trait Checkpoint: Sized {
|
||||
fn rebase(&mut self) -> Result<(), Error>;
|
||||
fn exists<'a, S: AsRef<str> + Send + Sync + 'a, V: SegList + Send + Sync + 'a>(
|
||||
&'a mut self,
|
||||
ptr: &'a JsonPointer<S, V>,
|
||||
store_read_lock: Option<RwLockReadGuard<'a, Store>>,
|
||||
) -> BoxFuture<'a, Result<bool, Error>>;
|
||||
fn get_value<'a, S: AsRef<str> + Send + Sync + 'a, V: SegList + Send + Sync + 'a>(
|
||||
&'a mut self,
|
||||
ptr: &'a JsonPointer<S, V>,
|
||||
@@ -73,6 +78,23 @@ impl Transaction {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn exists<S: AsRef<str>, V: SegList>(
|
||||
&mut self,
|
||||
ptr: &JsonPointer<S, V>,
|
||||
store_read_lock: Option<RwLockReadGuard<'_, Store>>,
|
||||
) -> Result<bool, Error> {
|
||||
let exists = {
|
||||
let store_lock = self.db.store.clone();
|
||||
let store = if let Some(store_read_lock) = store_read_lock {
|
||||
store_read_lock
|
||||
} else {
|
||||
store_lock.read().await
|
||||
};
|
||||
self.rebase()?;
|
||||
ptr.get(store.get_data()?).unwrap_or(&Value::Null) != &Value::Null
|
||||
};
|
||||
Ok(self.updates.for_path(ptr).exists().unwrap_or(exists))
|
||||
}
|
||||
async fn get_value<S: AsRef<str>, V: SegList>(
|
||||
&mut self,
|
||||
ptr: &JsonPointer<S, V>,
|
||||
@@ -164,6 +186,13 @@ impl<'a> Checkpoint for &'a mut Transaction {
|
||||
fn rebase(&mut self) -> Result<(), Error> {
|
||||
Transaction::rebase(self)
|
||||
}
|
||||
fn exists<'b, S: AsRef<str> + Send + Sync + 'b, V: SegList + Send + Sync + 'b>(
|
||||
&'b mut self,
|
||||
ptr: &'b JsonPointer<S, V>,
|
||||
store_read_lock: Option<RwLockReadGuard<'b, Store>>,
|
||||
) -> BoxFuture<'b, Result<bool, Error>> {
|
||||
Transaction::exists(self, ptr, store_read_lock).boxed()
|
||||
}
|
||||
fn get_value<'b, S: AsRef<str> + Send + Sync + 'b, V: SegList + Send + Sync + 'b>(
|
||||
&'b mut self,
|
||||
ptr: &'b JsonPointer<S, V>,
|
||||
@@ -241,6 +270,23 @@ impl<Tx: Checkpoint + Send + Sync> SubTransaction<Tx> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn exists<S: AsRef<str> + Send + Sync, V: SegList + Send + Sync>(
|
||||
&mut self,
|
||||
ptr: &JsonPointer<S, V>,
|
||||
store_read_lock: Option<RwLockReadGuard<'_, Store>>,
|
||||
) -> Result<bool, Error> {
|
||||
let exists = {
|
||||
let store_lock = self.parent.store();
|
||||
let store = if let Some(store_read_lock) = store_read_lock {
|
||||
store_read_lock
|
||||
} else {
|
||||
store_lock.read().await
|
||||
};
|
||||
self.rebase()?;
|
||||
self.parent.exists(ptr, Some(store)).await?
|
||||
};
|
||||
Ok(self.updates.for_path(ptr).exists().unwrap_or(exists))
|
||||
}
|
||||
async fn get_value<S: AsRef<str> + Send + Sync, V: SegList + Send + Sync>(
|
||||
&mut self,
|
||||
ptr: &JsonPointer<S, V>,
|
||||
@@ -336,6 +382,13 @@ impl<'a, Tx: Checkpoint + Send + Sync> Checkpoint for &'a mut SubTransaction<Tx>
|
||||
fn rebase(&mut self) -> Result<(), Error> {
|
||||
SubTransaction::rebase(self)
|
||||
}
|
||||
fn exists<'b, S: AsRef<str> + Send + Sync + 'b, V: SegList + Send + Sync + 'b>(
|
||||
&'b mut self,
|
||||
ptr: &'b JsonPointer<S, V>,
|
||||
store_read_lock: Option<RwLockReadGuard<'b, Store>>,
|
||||
) -> BoxFuture<'b, Result<bool, Error>> {
|
||||
SubTransaction::exists(self, ptr, store_read_lock).boxed()
|
||||
}
|
||||
fn get_value<'b, S: AsRef<str> + Send + Sync + 'b, V: SegList + Send + Sync + 'b>(
|
||||
&'b mut self,
|
||||
ptr: &'b JsonPointer<S, V>,
|
||||
|
||||
Reference in New Issue
Block a user