clean up code

This commit is contained in:
tezlm 2024-02-10 18:59:14 -08:00
parent 262415b29c
commit 7c2575990e
Signed by: tezlm
GPG key ID: 649733FCD94AFBBA
7 changed files with 116 additions and 103 deletions

View file

@ -1,6 +1,6 @@
use std::{
path::{Path, PathBuf},
sync::Arc,
rc::Rc,
};
use anyhow::Result;
@ -8,9 +8,9 @@ use clap::Parser;
use dag_resolve::{
actor::{ActorId, ActorSecret},
event::{CoreContent, Event, HashType, SignatureType},
resolver::Resolver,
resolvers::kv::{KVEventContent, KVResolver},
room::Room,
store::sqlite,
Error,
};
use rusqlite::Connection;
@ -33,8 +33,8 @@ enum Cli {
}
struct State {
db: Arc<Connection>,
room: Room<KVEventContent, ()>,
db: Rc<Connection>,
room: Room<KVResolver>,
secret: ActorSecret,
store: Box<dag_resolve::store::sqlite::Database>,
}
@ -90,7 +90,7 @@ fn get_repo(path: &Path, create: bool) -> Result<State> {
"#,
)?;
let (actor, secret) = ActorId::new(SignatureType::Ed25519);
let resolver = Box::new(KVResolver::<KVEventContent, sqlite::Table>::new());
let resolver = KVResolver::new();
let room = Room::builder()
.with_resolver(resolver)
.with_hasher(HashType::Sha256)
@ -110,7 +110,7 @@ fn get_repo(path: &Path, create: bool) -> Result<State> {
(event.id().to_string(), serde_json::to_string(&event)?),
)?;
}
let db = Arc::new(db);
let db = Rc::new(db);
let store = dag_resolve::store::sqlite::Database::from_conn(db.clone())
.init(room.get_resolver().get_state_config())?;
Ok(State {
@ -135,7 +135,7 @@ fn get_repo(path: &Path, create: bool) -> Result<State> {
dbg!(&actor, &secret);
let mut q = db.prepare("SELECT json FROM events")?;
let mut rows = q.query([])?;
let mut room: Option<Room<KVEventContent, ()>> = None;
let mut room: Option<Room<KVResolver>> = None;
while let Some(row) = rows.next()? {
let s: String = dbg!(row.get(0)?);
let ev = dbg!(serde_json::from_str(&s)?);
@ -144,7 +144,7 @@ fn get_repo(path: &Path, create: bool) -> Result<State> {
r.append_event(ev)?;
}
None => {
let resolver = Box::new(KVResolver::<KVEventContent, sqlite::Table>::new());
let resolver = KVResolver::new();
let r = Room::from_root(resolver, ev)?;
room = Some(r);
}
@ -153,7 +153,7 @@ fn get_repo(path: &Path, create: bool) -> Result<State> {
drop(rows);
drop(q);
let room = room.unwrap();
let db = Arc::new(db);
let db = Rc::new(db);
dbg!(&room);
let store = dag_resolve::store::sqlite::Database::from_conn(db.clone())
.init(room.get_resolver().get_state_config())?;

View file

@ -1,5 +1,6 @@
use crate::{
actor::{ActorId, ActorSecret, ActorSignature},
resolver::Resolver,
room::Room,
Error, Result,
};
@ -148,7 +149,7 @@ impl<T: Debug + Serialize + Clone> Event<T> {
Ok(())
}
pub fn verify_room<S>(&self, room: &Room<T, S>) -> Result<()> {
pub fn verify_room<R: Resolver<EventType = T>>(&self, room: &Room<R>) -> Result<()> {
self.verify()?;
let room_config = match &room.get_root().content {

View file

@ -1,18 +1,19 @@
use serde::Serialize;
use super::table::{State, StateConfig};
use crate::event::{Event, EventId};
use std::{cmp::Ordering, collections::HashSet, fmt::Debug};
use crate::store::sqlite;
use super::table::{State, StateConfig};
/// small shards of code designed to resolve state
pub trait Resolver<Type, S> {
pub trait Resolver {
type EventType: Debug + Serialize + Clone;
/// Given a set of ordered events, resolve the final state
fn resolve(&self, state: &mut dyn State<Table = sqlite::Table, Err = sqlite::Error>, event: &Event<Type>);
fn resolve<S: State>(&self, state: &mut S, event: &Event<Self::EventType>);
/// Given two events, decide which one comes first
/// if Ordering::Equal is returned, the event id is used
fn tiebreak(&self, a: &Event<Type>, b: &Event<Type>) -> Ordering;
fn tiebreak(&self, a: &Event<Self::EventType>, b: &Event<Self::EventType>) -> Ordering;
/// TEMP: Get the name/id of this resolver
fn name(&self) -> &str;
@ -53,14 +54,13 @@ pub fn sort<T: Debug + Serialize + Clone>(
sorted
}
impl<T, S> Debug for dyn Resolver<T, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Resolver({} -> {})",
std::any::type_name::<T>(),
std::any::type_name::<S>()
)
}
}
// impl<T, S> Debug for dyn Resolver<T, S> {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write!(
// f,
// "Resolver({} -> {})",
// std::any::type_name::<T>(),
// std::any::type_name::<S>()
// )
// }
// }

View file

@ -1,25 +1,28 @@
use serde::Serialize;
use crate::{
actor::ActorSecret, event::EventId, event::{CoreContent, CreateContent, Event, HashType, SignatureType}, proto, resolver::{sort, Resolver}, store::sqlite, Error, Result
actor::ActorSecret,
event::EventId,
event::{CoreContent, CreateContent, Event, HashType, SignatureType},
proto,
resolver::{sort, Resolver},
Error, Result,
};
use std::fmt::Debug;
#[derive(Debug)]
pub struct Room<T, S> {
pub events: Vec<Event<T>>,
pub struct Room<R: Resolver> {
pub events: Vec<Event<R::EventType>>,
pub heads: Vec<EventId>,
pub resolver: Box<dyn Resolver<T, S>>,
pub resolver: R,
}
impl<T: Debug + Serialize + Clone, S> Room<T, S> {
pub fn builder() -> RoomBuilder<T, S> {
impl<R: Resolver> Room<R> {
pub fn builder() -> RoomBuilder<R> {
RoomBuilder::new()
}
pub fn new(
resolver_name: impl Into<String>,
resolver: Box<dyn Resolver<T, S>>,
resolver: R,
hasher: HashType,
signer: SignatureType,
secret: &ActorSecret,
@ -41,7 +44,7 @@ impl<T: Debug + Serialize + Clone, S> Room<T, S> {
})
}
pub fn from_root(resolver: Box<dyn Resolver<T, S>>, event: Event<T>) -> Result<Self> {
pub fn from_root(resolver: R, event: Event<R::EventType>) -> Result<Self> {
Ok(Self {
heads: vec![event.id().clone()],
events: vec![event],
@ -49,19 +52,20 @@ impl<T: Debug + Serialize + Clone, S> Room<T, S> {
})
}
pub fn get_root(&self) -> &Event<T> {
pub fn get_root(&self) -> &Event<R::EventType> {
self.events
.first()
.as_ref()
.expect("room always has a root event")
}
pub fn get_resolver(&self) -> &dyn Resolver<T, S> {
self.resolver.as_ref()
pub fn get_resolver(&self) -> &R {
&self.resolver
}
pub fn resolve_state<A>(&mut self, initial_state: A) -> A
where A: proto::table::State<Err = sqlite::Error, Table = sqlite::Table>
where
A: proto::table::State,
{
let resolver = self.get_resolver();
let sorted = sort(|a, b| resolver.tiebreak(a, b), &self.events);
@ -74,9 +78,9 @@ impl<T: Debug + Serialize + Clone, S> Room<T, S> {
pub fn create_event(
&mut self,
event_content: CoreContent<T>,
event_content: CoreContent<R::EventType>,
secret: &ActorSecret,
) -> Result<&Event<T>> {
) -> Result<&Event<R::EventType>> {
let event = Event::builder(event_content, secret)
.with_references(std::mem::take(&mut self.heads))
.then_hash()?
@ -84,9 +88,9 @@ impl<T: Debug + Serialize + Clone, S> Room<T, S> {
self.append_event(event)
}
pub fn append_event<'a>(&'a mut self, event: Event<T>) -> Result<&'a Event<T>> {
pub fn append_event(&mut self, event: Event<R::EventType>) -> Result<&Event<R::EventType>> {
event.verify_room(self).expect("event failed verification");
if let Some(_) = self.events.iter().find(|p| p == &&event) {
if self.events.iter().any(|p| p == &event) {
return Err(Error::AlreadyExists);
}
self.events.push(event);
@ -97,13 +101,13 @@ impl<T: Debug + Serialize + Clone, S> Room<T, S> {
}
}
pub struct RoomBuilder<T, S> {
resolver: Option<Box<dyn Resolver<T, S>>>,
pub struct RoomBuilder<R: Resolver> {
resolver: Option<R>,
hasher: Option<HashType>,
signer: Option<SignatureType>,
}
impl<T: Clone + Debug + Serialize, S> Default for RoomBuilder<T, S> {
impl<R: Resolver> Default for RoomBuilder<R> {
fn default() -> Self {
Self {
resolver: None,
@ -113,12 +117,12 @@ impl<T: Clone + Debug + Serialize, S> Default for RoomBuilder<T, S> {
}
}
impl<T: Clone + Debug + Serialize, S> RoomBuilder<T, S> {
impl<R: Resolver> RoomBuilder<R> {
pub fn new() -> Self {
Self::default()
}
pub fn with_resolver(mut self, resolver: Box<dyn Resolver<T, S>>) -> Self {
pub fn with_resolver(mut self, resolver: R) -> Self {
self.resolver = Some(resolver);
self
}
@ -133,8 +137,8 @@ impl<T: Clone + Debug + Serialize, S> RoomBuilder<T, S> {
self
}
pub fn create(self, secret: &ActorSecret) -> Result<Room<T, S>> {
Room::<T, S>::new(
pub fn create(self, secret: &ActorSecret) -> Result<Room<R>> {
Room::new(
self.resolver
.as_ref()
.ok_or(Error::MissingBuilderData)?

View file

@ -6,42 +6,42 @@ use crate::{
event::{CoreContent, Event},
proto::table::{ColumnType, IndexType, State, StateConfig, Table, TableConfig, TableRow},
resolver::Resolver,
store::sqlite,
};
use std::{cmp::Ordering, collections::HashMap, fmt::Debug, marker::PhantomData};
use std::{cmp::Ordering, collections::HashMap, fmt::Debug};
#[derive(Debug)]
#[derive(Debug, Default)]
/// A basic key-value store
pub struct KVResolver<A, B> {
_a: PhantomData<A>,
_b: PhantomData<B>,
}
pub struct KVResolver;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum KVEventContent {
Set(String, String),
}
impl<A, B> KVResolver<A, B> {
impl KVResolver {
pub fn new() -> Self {
Self {
_a: PhantomData,
_b: PhantomData,
}
Self {}
}
}
impl<A: Debug, B: Table> Resolver<KVEventContent, ()> for KVResolver<A, B> {
fn resolve(&self, state: &mut dyn State<Table = sqlite::Table, Err = sqlite::Error>, event: &Event<KVEventContent>) {
impl Resolver for KVResolver {
type EventType = KVEventContent;
fn resolve<S: State>(&self, state: &mut S, event: &Event<KVEventContent>) {
dbg!(event);
let table = state.table("kv").unwrap();
let table = match state.table("kv") {
Ok(t) => t,
Err(_) => panic!("no table exists"),
};
match &event.content() {
CoreContent::Create(_) => {}
CoreContent::Custom(KVEventContent::Set(k, v)) => {
let res = table.insert(TableRow { values: HashMap::from_iter([
("key".into(), k.to_owned().into()),
("value".into(), v.to_owned().into()),
]) });
let res = table.insert(TableRow {
values: HashMap::from_iter([
("key".into(), k.to_owned().into()),
("value".into(), v.to_owned().into()),
]),
});
if res.is_err() {
panic!("could not insert");
}

View file

@ -1,55 +1,56 @@
use std::{collections::HashMap, path::Path, sync::Arc};
use std::{collections::HashMap, path::Path, rc::Rc};
use crate::proto::table;
use rusqlite::params_from_iter;
use thiserror::Error;
use crate::proto::table;
#[derive(Debug)]
pub struct Database {
connection: Arc<rusqlite::Connection>,
connection: Rc<rusqlite::Connection>,
config: Option<table::StateConfig>,
}
#[derive(Debug)]
pub struct Table {
connection: Arc<rusqlite::Connection>,
connection: Rc<rusqlite::Connection>,
name: String,
config: table::TableConfig,
}
#[derive(Debug, Error)]
pub enum Error {
}
pub enum Error {}
impl Database {
pub fn open(path: impl AsRef<Path>) -> Result<Self, Error> {
let db = rusqlite::Connection::open(path).unwrap();
Ok(Database {
connection: Arc::new(db),
connection: Rc::new(db),
config: None,
})
}
pub fn from_conn(conn: Arc<rusqlite::Connection>) -> Self {
Database { connection: conn, config: None }
pub fn from_conn(conn: Rc<rusqlite::Connection>) -> Self {
Database {
connection: conn,
config: None,
}
}
pub fn init(mut self, config: table::StateConfig) -> Result<Box<Self>, Error> {
let mut sql = String::new();
for (table_name, table_column) in &config.tables {
// FIXME: don't drop and resolve from scratch every time
sql.push_str("DROP TABLE IF EXISTS '");
sql.push_str(&table_name.replace("'", "''"));
sql.push_str(&table_name.replace('\'', "''"));
sql.push_str("';\n");
sql.push_str("CREATE TABLE '");
sql.push_str(&table_name.replace("'", "''"));
sql.push_str(&table_name.replace('\'', "''"));
sql.push_str("' (");
for (idx, (column_name, column_config)) in table_column.columns.iter().enumerate() {
if idx != 0 {
sql.push_str(", ");
}
sql.push_str(&column_name.replace("'", "''"));
sql.push_str(&column_name.replace('\'', "''"));
sql.push_str(match column_config {
table::ColumnType::String => " TEXT",
table::ColumnType::Text => " TEXT",
@ -95,25 +96,24 @@ impl table::Table for Table {
};
let has_index = self.config.indexes.iter().any(|idx| {
idx.column == column
&& match idx.index_type {
table::IndexType::Lookup => true,
table::IndexType::LookupUnique => true,
_ => false,
}
&& matches!(
idx.index_type,
table::IndexType::Lookup | table::IndexType::LookupUnique
)
});
if !has_index {
panic!("no lookup index");
}
let mut sql = String::from("SELECT * FROM ");
sql.push_str(&self.name.replace("'", "''"));
sql.push_str(&self.name.replace('\'', "''"));
sql.push_str(" WHERE ");
sql.push_str(&column.replace("'", "''"));
sql.push_str(&column.replace('\'', "''"));
sql.push_str(" = ");
match (column_config, value.into()) {
(table::ColumnType::String, table::ColumnValue::String(s)) => {
sql.push_str("'");
sql.push_str(&s.replace("'", "''"));
sql.push_str("'");
sql.push('\'');
sql.push_str(&s.replace('\'', "''"));
sql.push('\'');
}
(table::ColumnType::Integer, table::ColumnValue::Integer(i)) => {
sql.push_str(&i.to_string());
@ -188,13 +188,13 @@ impl table::Table for Table {
fn insert(&self, mut row: table::TableRow) -> Result<(), Self::Err> {
let mut sql = String::from("INSERT INTO ");
sql.push_str(&self.name.replace("'", "''"));
sql.push_str(&self.name.replace('\'', "''"));
sql.push_str(" (");
for (idx, name) in self.config.columns.keys().enumerate() {
if idx != 0 {
sql.push_str(", ");
}
sql.push_str(&name.replace("'", "''"));
sql.push_str(&name.replace('\'', "''"));
}
sql.push_str(") VALUES (");
use rusqlite::types::Value;
@ -203,16 +203,24 @@ impl table::Table for Table {
if idx != 0 {
sql.push_str(", ");
}
sql.push_str("?");
sql.push('?');
match (column_type, row.values.remove(name).unwrap()) {
(table::ColumnType::String, table::ColumnValue::String(s)) => params.push(Value::Text(s)),
(table::ColumnType::Integer, table::ColumnValue::Integer(i)) => params.push(Value::Integer(i.try_into().unwrap())),
(table::ColumnType::Float, table::ColumnValue::Float(r)) => params.push(Value::Real(r)),
(table::ColumnType::String, table::ColumnValue::String(s)) => {
params.push(Value::Text(s))
}
(table::ColumnType::Integer, table::ColumnValue::Integer(i)) => {
params.push(Value::Integer(i.try_into().unwrap()))
}
(table::ColumnType::Float, table::ColumnValue::Float(r)) => {
params.push(Value::Real(r))
}
_ => todo!(),
};
}
sql.push_str(")");
self.connection.execute(&sql, params_from_iter(params)).unwrap();
sql.push(')');
self.connection
.execute(&sql, params_from_iter(params))
.unwrap();
Ok(())
}
}

View file

@ -8,7 +8,7 @@ use dag_resolve::{
#[test]
fn test_example() {
let (_actor, secret) = ActorId::new(SignatureType::Ed25519);
let resolver = Box::new(KVResolver);
let resolver = KVResolver;
let mut room = Room::builder()
.with_resolver(resolver)
.with_hasher(HashType::Sha256)