option model (#5)

* option model

* enum model
This commit is contained in:
Aiden McClelland
2021-04-26 14:40:37 -06:00
committed by GitHub
parent 247c1712ba
commit 6094a4bb1c
6 changed files with 216 additions and 12 deletions

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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>,

View File

@@ -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>,