make temporary gui hack use sqlite store
This commit is contained in:
parent
c3c41a6092
commit
4d5cd581da
8 changed files with 180 additions and 83 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -445,18 +445,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard_wayland"
|
name = "clipboard_wayland"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8134163bd07c47ae3cc29babc42c255fdb315facc790950ae2d0e561ea6f2ec0"
|
checksum = "003f886bc4e2987729d10c1db3424e7f80809f3fc22dbc16c685738887cb37b8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"smithay-clipboard",
|
"smithay-clipboard",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard_x11"
|
name = "clipboard_x11"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5cf45b436634fee64c6d3981639b46a87eeea3c64e422643273fcefd1baef56c"
|
checksum = "4274ea815e013e0f9f04a2633423e14194e408a0576c943ce3d14ca56c50031c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"x11rb 0.13.0",
|
"x11rb 0.13.0",
|
||||||
|
@ -1121,8 +1121,11 @@ dependencies = [
|
||||||
name = "gui"
|
name = "gui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"dag-resolve",
|
"dag-resolve",
|
||||||
"iced",
|
"iced",
|
||||||
|
"rusqlite",
|
||||||
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3175,9 +3178,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.68"
|
version = "0.3.67"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
|
checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
|
|
@ -214,7 +214,7 @@ fn startup(path: impl AsRef<Path>, create: Option<&str>) -> Result<Opened> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync_state<R: Resolver + Debug>(mut from: State<R>, mut to: State<R>) -> Result<()> {
|
fn sync_state<R: Resolver + Debug>(from: &mut State<R>, to: &mut State<R>) -> Result<()> {
|
||||||
if from.room.get_root() != to.room.get_root() {
|
if from.room.get_root() != to.room.get_root() {
|
||||||
panic!("cannot sync events from two different rooms");
|
panic!("cannot sync events from two different rooms");
|
||||||
}
|
}
|
||||||
|
@ -224,18 +224,16 @@ fn sync_state<R: Resolver + Debug>(mut from: State<R>, mut to: State<R>) -> Resu
|
||||||
for event in &to.room.events {
|
for event in &to.room.events {
|
||||||
from.append_event(event.clone())?;
|
from.append_event(event.clone())?;
|
||||||
}
|
}
|
||||||
dbg!(
|
from.room.resolve_state(&mut *from.store);
|
||||||
from.room.resolve_state(*from.store),
|
to.room.resolve_state(&mut *to.store);
|
||||||
to.room.resolve_state(*to.store)
|
dbg!(&from.store, &to.store);
|
||||||
);
|
|
||||||
dbg!(from.room);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_event<R: Resolver + Debug>(mut state: State<R>, data: &str) -> Result<()> {
|
fn send_event<R: Resolver + Debug>(state: &mut State<R>, data: &str) -> Result<()> {
|
||||||
state.create_event(dbg!(serde_json::from_str(dbg!(data))?))?;
|
state.create_event(dbg!(serde_json::from_str(dbg!(data))?))?;
|
||||||
dbg!(&state.room);
|
dbg!(&state.room);
|
||||||
dbg!(&state.room.resolve_state(*state.store));
|
dbg!(&state.room.resolve_state(&mut *state.store));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,19 +270,19 @@ fn main() -> Result<()> {
|
||||||
};
|
};
|
||||||
match (cli, opened) {
|
match (cli, opened) {
|
||||||
(Cli::Init { .. }, _) => {},
|
(Cli::Init { .. }, _) => {},
|
||||||
(Cli::Send { repo: _, data }, Opened::Kv(state)) => send_event(state, &data)?,
|
(Cli::Send { repo: _, data }, Opened::Kv(mut state)) => send_event(&mut state, &data)?,
|
||||||
(Cli::Send { repo: _, data }, Opened::Forum(state)) => send_event(state, &data)?,
|
(Cli::Send { repo: _, data }, Opened::Forum(mut state)) => send_event(&mut state, &data)?,
|
||||||
(Cli::Info { repo: _ }, Opened::Kv(state)) => print_info(state)?,
|
(Cli::Info { repo: _ }, Opened::Kv(state)) => print_info(state)?,
|
||||||
(Cli::Info { repo: _ }, Opened::Forum(state)) => print_info(state)?,
|
(Cli::Info { repo: _ }, Opened::Forum(state)) => print_info(state)?,
|
||||||
(Cli::Sync { repo: _, other }, Opened::Kv(our_state)) => {
|
(Cli::Sync { repo: _, other }, Opened::Kv(mut our_state)) => {
|
||||||
match startup(other, None)? {
|
match startup(other, None)? {
|
||||||
Opened::Kv(their_state) => sync_state(our_state, their_state)?,
|
Opened::Kv(mut their_state) => sync_state(&mut our_state, &mut their_state)?,
|
||||||
_ => panic!("cannot sync different room types"),
|
_ => panic!("cannot sync different room types"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(Cli::Sync { repo: _, other }, Opened::Forum(our_state)) => {
|
(Cli::Sync { repo: _, other }, Opened::Forum(mut our_state)) => {
|
||||||
match startup(other, None)? {
|
match startup(other, None)? {
|
||||||
Opened::Forum(their_state) => sync_state(our_state, their_state)?,
|
Opened::Forum(mut their_state) => sync_state(&mut our_state, &mut their_state)?,
|
||||||
_ => panic!("cannot sync different room types"),
|
_ => panic!("cannot sync different room types"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,5 +6,8 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow = "1.0.79"
|
||||||
dag-resolve = { version = "0.1.0", path = "../lib" }
|
dag-resolve = { version = "0.1.0", path = "../lib" }
|
||||||
iced = { version = "0.10.0", features = ["debug"] }
|
iced = { version = "0.10.0", features = ["debug"] }
|
||||||
|
rusqlite = { version = "0.30.0", features = ["bundled"] }
|
||||||
|
serde_json = "1.0.113"
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use std::sync::Mutex;
|
use std::{path::Path, rc::Rc, sync::Mutex};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
use dag_resolve::{
|
use dag_resolve::{
|
||||||
actor::{ActorId, ActorSecret},
|
actor::{ActorId, ActorSecret},
|
||||||
event::{CoreContent, HashType, SignatureType},
|
event::{CoreContent, Event, HashType, SignatureType},
|
||||||
proto::table::{State, Table},
|
proto::table::{State as _, Table as _},
|
||||||
resolver::Resolver,
|
resolver::Resolver,
|
||||||
resolvers::kv::{KVEventContent, KVResolver},
|
resolvers::kv::{KVEventContent, KVResolver},
|
||||||
room::Room,
|
room::Room,
|
||||||
store::memory::MemoryStore,
|
|
||||||
};
|
};
|
||||||
use iced::{
|
use iced::{
|
||||||
keyboard::KeyCode,
|
keyboard::KeyCode,
|
||||||
|
@ -16,13 +16,11 @@ use iced::{
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Flags {
|
struct Flags {
|
||||||
room: Room<KVResolver>,
|
state: State<KVResolver>,
|
||||||
secret: ActorSecret,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Counter {
|
struct Main {
|
||||||
room: Mutex<Room<KVResolver>>,
|
state: Mutex<State<KVResolver>>,
|
||||||
secret: ActorSecret,
|
|
||||||
key: String,
|
key: String,
|
||||||
value: String,
|
value: String,
|
||||||
key_id: text_input::Id,
|
key_id: text_input::Id,
|
||||||
|
@ -39,17 +37,16 @@ enum Message {
|
||||||
FocusPrev,
|
FocusPrev,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application for Counter {
|
impl Application for Main {
|
||||||
type Executor = iced::executor::Default;
|
type Executor = iced::executor::Default;
|
||||||
type Message = Message;
|
type Message = Message;
|
||||||
type Theme = iced::Theme;
|
type Theme = iced::Theme;
|
||||||
type Flags = Flags;
|
type Flags = Flags;
|
||||||
|
|
||||||
fn new(flags: Self::Flags) -> (Self, Command<Self::Message>) {
|
fn new(flags: Self::Flags) -> (Self, Command<Self::Message>) {
|
||||||
let room = Mutex::new(flags.room);
|
let state = Mutex::new(flags.state);
|
||||||
let state = Self {
|
let state = Self {
|
||||||
room,
|
state,
|
||||||
secret: flags.secret,
|
|
||||||
key: String::new(),
|
key: String::new(),
|
||||||
value: String::new(),
|
value: String::new(),
|
||||||
key_id: text_input::Id::unique(),
|
key_id: text_input::Id::unique(),
|
||||||
|
@ -74,14 +71,11 @@ impl Application for Counter {
|
||||||
|
|
||||||
let key = std::mem::take(&mut self.key);
|
let key = std::mem::take(&mut self.key);
|
||||||
let value = std::mem::take(&mut self.value);
|
let value = std::mem::take(&mut self.value);
|
||||||
self.room
|
self.state
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.create_event(
|
.create_event(CoreContent::Custom(KVEventContent::Set(key, value)))
|
||||||
CoreContent::Custom(KVEventContent::Set(key, value)),
|
.unwrap()
|
||||||
&self.secret,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
Message::FocusNext => {
|
Message::FocusNext => {
|
||||||
let next = match &self.focused {
|
let next = match &self.focused {
|
||||||
|
@ -106,13 +100,14 @@ impl Application for Counter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<'_, Self::Message> {
|
fn view(&self) -> Element<'_, Self::Message> {
|
||||||
let mut room = self.room.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
let store = MemoryStore::new()
|
|
||||||
.init(room.get_resolver().get_state_config())
|
fn resolve<R: Resolver>(state: &mut State<R>) {
|
||||||
.unwrap();
|
state.room.resolve_state(&mut *state.store);
|
||||||
let state = room.resolve_state(*store);
|
}
|
||||||
dbg!(&state);
|
|
||||||
let rows = state.table("kv").unwrap().all().unwrap();
|
resolve(&mut state);
|
||||||
|
let rows = state.store.table("kv").unwrap().all().unwrap();
|
||||||
let mut column = Column::new();
|
let mut column = Column::new();
|
||||||
column = column.push(text(format!("{} keys", rows.len())).size(24));
|
column = column.push(text(format!("{} keys", rows.len())).size(24));
|
||||||
for row in rows {
|
for row in rows {
|
||||||
|
@ -159,22 +154,105 @@ impl Application for Counter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
#[derive(Debug)]
|
||||||
let (_actor, secret) = ActorId::new(SignatureType::Ed25519);
|
struct State<R: Resolver> {
|
||||||
let room = Room::builder()
|
db: Rc<rusqlite::Connection>,
|
||||||
.with_hasher(HashType::Sha256)
|
room: Room<R>,
|
||||||
.with_signer(SignatureType::Ed25519)
|
secret: ActorSecret,
|
||||||
.with_resolver(KVResolver)
|
store: Box<dag_resolve::store::sqlite::Database>,
|
||||||
.create(&secret)
|
}
|
||||||
.unwrap();
|
|
||||||
Counter::run(Settings {
|
impl<R: Resolver> State<R> {
|
||||||
|
fn create_event(&mut self, content: CoreContent<R::EventType>) -> Result<()> {
|
||||||
|
match self.room.create_event(content, &self.secret) {
|
||||||
|
Ok(event) => {
|
||||||
|
self.db.execute(
|
||||||
|
"INSERT INTO _events (id, json) VALUES (?, ?)",
|
||||||
|
(event.id().to_string(), serde_json::to_string(&event)?),
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(dag_resolve::Error::AlreadyExists) => Ok(()),
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_event(&mut self, event: Event<R::EventType>) -> Result<()> {
|
||||||
|
match self.room.append_event(event) {
|
||||||
|
Ok(event) => {
|
||||||
|
self.db.execute(
|
||||||
|
"INSERT INTO _events (id, json) VALUES (?, ?)",
|
||||||
|
(event.id().to_string(), serde_json::to_string(&event)?),
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(dag_resolve::Error::AlreadyExists) => Ok(()),
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open(path: impl AsRef<Path>) -> Result<State<KVResolver>> {
|
||||||
|
// restore repo
|
||||||
|
let db = rusqlite::Connection::open(path)?;
|
||||||
|
let actor: ActorId = db.query_row(
|
||||||
|
"SELECT value FROM _config WHERE key='actor_id'",
|
||||||
|
[],
|
||||||
|
|row| row.get(0).map(|s: String| s.parse()),
|
||||||
|
)??;
|
||||||
|
let secret: ActorSecret = db.query_row(
|
||||||
|
"SELECT value FROM _config WHERE key='actor_secret'",
|
||||||
|
[],
|
||||||
|
|row| row.get(0).map(|s: String| serde_json::from_str(&s)),
|
||||||
|
)??;
|
||||||
|
dbg!(&actor, &secret);
|
||||||
|
let mut q = db.prepare("SELECT json FROM _events")?;
|
||||||
|
let mut rows = q.query([])?;
|
||||||
|
|
||||||
|
let event_json: String = rows
|
||||||
|
.next()?
|
||||||
|
.expect("there's always one root event")
|
||||||
|
.get(0)?;
|
||||||
|
let event: Event<()> = serde_json::from_str(&event_json)?;
|
||||||
|
match event.content() {
|
||||||
|
CoreContent::Create(c) => match c.resolver.as_str() {
|
||||||
|
"kv" => {
|
||||||
|
let mut room = Room::from_root(KVResolver, serde_json::from_str(&event_json)?)?;
|
||||||
|
while let Some(row) = rows.next()? {
|
||||||
|
let s: String = row.get(0)?;
|
||||||
|
let ev = serde_json::from_str(&s)?;
|
||||||
|
room.append_event(ev)?;
|
||||||
|
}
|
||||||
|
drop(event);
|
||||||
|
drop(rows);
|
||||||
|
drop(q);
|
||||||
|
dbg!(&room);
|
||||||
|
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 {
|
||||||
|
db,
|
||||||
|
room,
|
||||||
|
secret,
|
||||||
|
store,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => unimplemented!("unknown or unimplemented resolver"),
|
||||||
|
},
|
||||||
|
_ => panic!("tried to start with non-create event"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let state = open("room.db")?;
|
||||||
|
Main::run(Settings {
|
||||||
default_font: Font::with_name("Hind Siliguri"),
|
default_font: Font::with_name("Hind Siliguri"),
|
||||||
flags: Flags { room, secret },
|
flags: Flags { state },
|
||||||
id: None,
|
id: None,
|
||||||
window: iced::window::Settings::default(),
|
window: iced::window::Settings::default(),
|
||||||
default_text_size: 16.0,
|
default_text_size: 16.0,
|
||||||
antialiasing: false,
|
antialiasing: false,
|
||||||
exit_on_close_request: true,
|
exit_on_close_request: true,
|
||||||
})
|
})?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,15 +65,15 @@ impl<R: Resolver> Room<R> {
|
||||||
&self.resolver
|
&self.resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_state<S>(&mut self, initial_state: S) -> S
|
pub fn resolve_state<S>(&self, state: &mut S)
|
||||||
where
|
where
|
||||||
S: proto::table::State,
|
S: proto::table::State,
|
||||||
{
|
{
|
||||||
let resolver = self.get_resolver();
|
let resolver = self.get_resolver();
|
||||||
let sorted = sort(|a, b| resolver.tiebreak(a, b), &self.events);
|
let sorted = sort(|a, b| resolver.tiebreak(a, b), &self.events);
|
||||||
let state = initial_state;
|
state.reset().unwrap();
|
||||||
for event in sorted {
|
for event in sorted {
|
||||||
let effects = resolver.resolve(&state, event);
|
let effects = resolver.resolve(state, event);
|
||||||
for effect in effects {
|
for effect in effects {
|
||||||
match effect {
|
match effect {
|
||||||
ResolverEffect::Insert { table, row } => {
|
ResolverEffect::Insert { table, row } => {
|
||||||
|
@ -82,7 +82,6 @@ impl<R: Resolver> Room<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_event(
|
pub fn create_event(
|
||||||
|
|
|
@ -109,7 +109,11 @@ pub trait State: Debug {
|
||||||
type Err: Debug;
|
type Err: Debug;
|
||||||
type Table: Table;
|
type Table: Table;
|
||||||
|
|
||||||
|
/// Get a table
|
||||||
fn table(&self, name: &str) -> Result<Self::Table, Self::Err>;
|
fn table(&self, name: &str) -> Result<Self::Table, Self::Err>;
|
||||||
|
|
||||||
|
/// TEMP: clear everything in the table. In the future, there will be methods for incremental reduction.
|
||||||
|
fn reset(&mut self) -> Result<(), Self::Err>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Table {
|
pub trait Table {
|
||||||
|
|
|
@ -40,6 +40,13 @@ impl State for MemoryStore {
|
||||||
fn table(&self, name: &str) -> Result<Self::Table, Self::Err> {
|
fn table(&self, name: &str) -> Result<Self::Table, Self::Err> {
|
||||||
self.tables.get(name).cloned().ok_or(())
|
self.tables.get(name).cloned().ok_or(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) -> Result<(), Self::Err> {
|
||||||
|
for table in self.tables.values_mut() {
|
||||||
|
table.map.write().unwrap().clear();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Table for MemoryTable {
|
impl Table for MemoryTable {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::{collections::HashMap, path::Path, rc::Rc};
|
use std::{collections::HashMap, path::Path, rc::Rc};
|
||||||
|
|
||||||
use crate::proto::table;
|
use crate::proto::table::{self, State};
|
||||||
use rusqlite::params_from_iter;
|
use rusqlite::params_from_iter;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -39,8 +39,30 @@ impl Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(mut self, config: table::StateConfig) -> Result<Box<Self>, Error> {
|
pub fn init(mut self, config: table::StateConfig) -> Result<Box<Self>, Error> {
|
||||||
|
self.config = Some(config);
|
||||||
|
self.reset()?;
|
||||||
|
Ok(Box::new(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl table::State for Database {
|
||||||
|
type Table = Table;
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn table(&self, name: &str) -> Result<Table, Self::Err> {
|
||||||
|
let Some(table) = self.config.as_ref().unwrap().tables.get(name) else {
|
||||||
|
panic!("table does not exist");
|
||||||
|
};
|
||||||
|
Ok(Table {
|
||||||
|
connection: self.connection.clone(),
|
||||||
|
name: name.to_owned(),
|
||||||
|
config: table.to_owned(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) -> Result<(), Self::Err> {
|
||||||
let mut sql = String::new();
|
let mut sql = String::new();
|
||||||
for (table_name, table_column) in &config.tables {
|
for (table_name, table_column) in &self.config.as_ref().unwrap().tables {
|
||||||
// FIXME: don't drop and resolve from scratch every time
|
// FIXME: don't drop and resolve from scratch every time
|
||||||
sql.push_str("DROP TABLE IF EXISTS '");
|
sql.push_str("DROP TABLE IF EXISTS '");
|
||||||
sql.push_str(&table_name.replace('\'', "''"));
|
sql.push_str(&table_name.replace('\'', "''"));
|
||||||
|
@ -64,24 +86,7 @@ impl Database {
|
||||||
sql.push_str(");\n");
|
sql.push_str(");\n");
|
||||||
}
|
}
|
||||||
self.connection.execute_batch(&sql).unwrap();
|
self.connection.execute_batch(&sql).unwrap();
|
||||||
self.config = Some(config);
|
Ok(())
|
||||||
Ok(Box::new(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl table::State for Database {
|
|
||||||
type Table = Table;
|
|
||||||
type Err = Error;
|
|
||||||
|
|
||||||
fn table(&self, name: &str) -> Result<Table, Self::Err> {
|
|
||||||
let Some(table) = self.config.as_ref().unwrap().tables.get(name) else {
|
|
||||||
panic!("table does not exist");
|
|
||||||
};
|
|
||||||
Ok(Table {
|
|
||||||
connection: self.connection.clone(),
|
|
||||||
name: name.to_owned(),
|
|
||||||
config: table.to_owned(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +94,7 @@ impl table::Table for Table {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
|
|
||||||
fn all(&self) -> Result<Vec<table::TableRow>, Self::Err> {
|
fn all(&self) -> Result<Vec<table::TableRow>, Self::Err> {
|
||||||
let mut sql = String::from("SELECT * FROM ");
|
let mut sql = String::from("SELECT * FROM '");
|
||||||
sql.push_str(&self.name.replace('\'', "''"));
|
sql.push_str(&self.name.replace('\'', "''"));
|
||||||
sql.push('\'');
|
sql.push('\'');
|
||||||
let mut sql_query = self.connection.prepare(&sql).unwrap();
|
let mut sql_query = self.connection.prepare(&sql).unwrap();
|
||||||
|
|
Loading…
Reference in a new issue