This commit is contained in:
parent
6c54873ca2
commit
dd4cb7fcc6
11 changed files with 36 additions and 26 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -106,6 +106,12 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arc-swap"
|
||||||
|
version = "1.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "argh"
|
name = "argh"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
|
@ -1230,6 +1236,7 @@ dependencies = [
|
||||||
name = "owl"
|
name = "owl"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arc-swap",
|
||||||
"argh",
|
"argh",
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
|
|
|
@ -25,3 +25,4 @@ env_logger = "0.11.8"
|
||||||
parking_lot = { version = "0.12.3", features = ["send_guard"] }
|
parking_lot = { version = "0.12.3", features = ["send_guard"] }
|
||||||
crossbeam = { version = "0.8.4", features = ["crossbeam-channel"] }
|
crossbeam = { version = "0.8.4", features = ["crossbeam-channel"] }
|
||||||
once_cell = "1.21.3"
|
once_cell = "1.21.3"
|
||||||
|
arc-swap = "1.7.1"
|
||||||
|
|
|
@ -61,10 +61,10 @@ pub fn relation(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let relation_name = struct_name.to_string().to_case(Case::Snake);
|
let relation_name = struct_name.to_string().to_case(Case::Snake);
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
#[derive(owl::Serialize, owl::Deserialize, Default)]
|
#[derive(owl::Serialize, owl::Deserialize, Default, Clone)]
|
||||||
#input_struct
|
#input_struct
|
||||||
|
|
||||||
#[derive(owl::Deserialize, owl::Serialize, Debug)]
|
#[derive(owl::Deserialize, owl::Serialize, Debug, Clone)]
|
||||||
pub struct #struct_ref_name {
|
pub struct #struct_ref_name {
|
||||||
pub id: Id,
|
pub id: Id,
|
||||||
pub inner: owl::db::relation::RelationReference
|
pub inner: owl::db::relation::RelationReference
|
||||||
|
@ -166,7 +166,7 @@ pub fn model(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let relation_name = struct_name.to_string().to_case(Case::Snake);
|
let relation_name = struct_name.to_string().to_case(Case::Snake);
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize, Clone)]
|
||||||
#input_struct
|
#input_struct
|
||||||
impl owl::db::store::Saveable for #struct_name {}
|
impl owl::db::store::Saveable for #struct_name {}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use chrono::Utc;
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
// historic field
|
// historic field
|
||||||
#[derive(Deserialize, Serialize, Default, Debug, PartialEq)]
|
#[derive(Deserialize, Serialize, Default, Debug, PartialEq, Clone)]
|
||||||
pub struct Historic<T> {
|
pub struct Historic<T> {
|
||||||
pub values: Vec<(chrono::DateTime<Utc>, T)>,
|
pub values: Vec<(chrono::DateTime<Utc>, T)>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use arc_swap::ArcSwap;
|
||||||
use parking_lot::{RwLock, RwLockReadGuard};
|
use parking_lot::{RwLock, RwLockReadGuard};
|
||||||
use std::{
|
use std::{
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
|
@ -170,7 +171,7 @@ impl Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update every model in `entries` according to `u(_)`
|
/// Update every model in `entries` according to `u(_)`
|
||||||
pub fn update<T: 'static + Serialize + Identifiable + Send + Sync, F: Fn(&mut T)>(
|
pub fn update<T: 'static + Serialize + Identifiable + Send + Sync + Clone, F: Fn(&mut T)>(
|
||||||
&self,
|
&self,
|
||||||
entries: &mut [Model<T>],
|
entries: &mut [Model<T>],
|
||||||
u: F,
|
u: F,
|
||||||
|
@ -259,7 +260,7 @@ impl Database {
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
let model = Model {
|
let model = Model {
|
||||||
inner: Arc::new(RwLock::new(m)),
|
inner: Arc::new(ArcSwap::new(Arc::new(m))),
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.cached {
|
if self.cached {
|
||||||
|
@ -284,9 +285,10 @@ impl Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = data.read();
|
let data = data.read();
|
||||||
|
let data = (*data).deref();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
Store::save(&T::model_id(), data.deref(), self.named, &*self.storage);
|
Store::save(&T::model_id(), data, self.named, &*self.storage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,7 +298,7 @@ impl Database {
|
||||||
data: T,
|
data: T,
|
||||||
) -> Model<T> {
|
) -> Model<T> {
|
||||||
let model = Model {
|
let model = Model {
|
||||||
inner: Arc::new(RwLock::new(data)),
|
inner: Arc::new(ArcSwap::new(Arc::new(data))),
|
||||||
};
|
};
|
||||||
self.save_model(&model);
|
self.save_model(&model);
|
||||||
let id = model.full_id().to_string();
|
let id = model.full_id().to_string();
|
||||||
|
@ -313,7 +315,7 @@ impl Database {
|
||||||
// TODO : cache eviction based on ref counts
|
// TODO : cache eviction based on ref counts
|
||||||
|
|
||||||
pub struct Model<T> {
|
pub struct Model<T> {
|
||||||
inner: Arc<RwLock<T>>,
|
inner: Arc<ArcSwap<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Model<File> {
|
impl Model<File> {
|
||||||
|
@ -325,7 +327,7 @@ impl Model<File> {
|
||||||
impl<T: Identifiable> Model<T> {
|
impl<T: Identifiable> Model<T> {
|
||||||
pub fn from_raw(raw: T) -> Model<T> {
|
pub fn from_raw(raw: T) -> Model<T> {
|
||||||
Model {
|
Model {
|
||||||
inner: Arc::new(RwLock::new(raw)),
|
inner: Arc::new(ArcSwap::new(Arc::new(raw))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,23 +339,23 @@ impl<T: Identifiable> Model<T> {
|
||||||
self.read().reference()
|
self.read().reference()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&self) -> RwLockReadGuard<T> {
|
pub fn read(&self) -> arc_swap::Guard<Arc<T>> {
|
||||||
self.inner.read()
|
self.inner.load()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static + Serialize + Identifiable + Send + Sync> Model<T> {
|
impl<T: 'static + Serialize + Identifiable + Send + Sync + Clone> Model<T> {
|
||||||
pub fn write<F: Fn(&mut T)>(&mut self, db: &Database, u: F) {
|
pub fn write<F: Fn(&mut T)>(&mut self, db: &Database, u: F) {
|
||||||
let mut me = self.inner.write();
|
let mut me = (**self.inner.load()).clone();
|
||||||
u(me.deref_mut());
|
u(&mut me);
|
||||||
drop(me);
|
self.inner.swap(Arc::new(me));
|
||||||
db.save_model(self);
|
db.save_model(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the model inline without writing to `Database`
|
/// Update the model inline without writing to `Database`
|
||||||
pub fn write_raw_inline<F: Fn(&mut T)>(&mut self, u: F) {
|
pub fn write_raw_inline<F: Fn(&mut T)>(&mut self, u: F) {
|
||||||
let mut me = self.inner.write();
|
let mut me = (**self.inner.load()).clone();
|
||||||
u(me.deref_mut());
|
u(&mut me);
|
||||||
drop(me);
|
drop(me);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,7 +369,7 @@ impl<T: 'static + Serialize + Identifiable + Send + Sync> ModelObj for Model<T>
|
||||||
impl<T> Clone for Model<T> {
|
impl<T> Clone for Model<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: Arc::clone(&self.inner),
|
inner: self.inner.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ fn sha256(input: &[u8]) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A generic file
|
/// A generic file
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
#[model]
|
#[model]
|
||||||
pub struct File {
|
pub struct File {
|
||||||
id: Id,
|
id: Id,
|
||||||
|
|
|
@ -6,7 +6,7 @@ pub use crate as owl;
|
||||||
use crate::db::id::Id;
|
use crate::db::id::Id;
|
||||||
|
|
||||||
/// Represents a geographical location with an ID, coordinates, and optional address
|
/// Represents a geographical location with an ID, coordinates, and optional address
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
#[model]
|
#[model]
|
||||||
pub struct Location {
|
pub struct Location {
|
||||||
pub id: Id,
|
pub id: Id,
|
||||||
|
|
|
@ -5,7 +5,7 @@ pub use crate as owl;
|
||||||
use crate::db::id::Id;
|
use crate::db::id::Id;
|
||||||
|
|
||||||
/// Represents a mail address with an ID and the address itself
|
/// Represents a mail address with an ID and the address itself
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
#[model]
|
#[model]
|
||||||
pub struct MailAddress {
|
pub struct MailAddress {
|
||||||
/// Unique identifier for the mail address
|
/// Unique identifier for the mail address
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub struct Person {
|
||||||
pub locations: Historic<Vec<IdRef<Location>>>,
|
pub locations: Historic<Vec<IdRef<Location>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
|
||||||
pub enum Gender {
|
pub enum Gender {
|
||||||
Male,
|
Male,
|
||||||
Female,
|
Female,
|
||||||
|
|
|
@ -5,7 +5,7 @@ pub use crate as owl;
|
||||||
use crate::db::id::Id;
|
use crate::db::id::Id;
|
||||||
|
|
||||||
/// Represents a phone number with an ID, the phone number itself, and the country code.
|
/// Represents a phone number with an ID, the phone number itself, and the country code.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
#[model]
|
#[model]
|
||||||
pub struct PhoneNumber {
|
pub struct PhoneNumber {
|
||||||
id: Id,
|
id: Id,
|
||||||
|
|
|
@ -437,7 +437,7 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RelationRef:
|
pub trait RelationRef:
|
||||||
Identifiable + for<'a> Deserialize<'a> + Serialize + Send + Sync + 'static
|
Identifiable + for<'a> Deserialize<'a> + Serialize + Send + Sync + 'static + Clone
|
||||||
{
|
{
|
||||||
fn top(&self) -> IdRef<serde_json::Value>;
|
fn top(&self) -> IdRef<serde_json::Value>;
|
||||||
fn sub(&self) -> IdRef<serde_json::Value>;
|
fn sub(&self) -> IdRef<serde_json::Value>;
|
||||||
|
@ -445,7 +445,7 @@ pub trait RelationRef:
|
||||||
fn update_meta(&mut self, weight: Option<f64>, meta: Option<serde_json::Value>);
|
fn update_meta(&mut self, weight: Option<f64>, meta: Option<serde_json::Value>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||||
pub struct RelationReference {
|
pub struct RelationReference {
|
||||||
pub top: IdRef<serde_json::Value>,
|
pub top: IdRef<serde_json::Value>,
|
||||||
pub sub: IdRef<serde_json::Value>,
|
pub sub: IdRef<serde_json::Value>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue