From 5e79c02f780c64cb7d88d9743b4813ba7421e120 Mon Sep 17 00:00:00 2001 From: Ellie Huxtable Date: Wed, 31 May 2023 22:44:36 +0100 Subject: [PATCH] wip --- .../20230531212437_create-records.sql | 10 +++ atuin-client/src/lib.rs | 1 + atuin-client/src/record/mod.rs | 2 + atuin-client/src/record/sqlite_store.rs | 70 +++++++++++++++++++ atuin-client/src/record/store.rs | 15 ++++ atuin-common/src/lib.rs | 1 + atuin-common/src/record.rs | 15 ++++ 7 files changed, 114 insertions(+) create mode 100644 atuin-client/record-migrations/20230531212437_create-records.sql create mode 100644 atuin-client/src/record/mod.rs create mode 100644 atuin-client/src/record/sqlite_store.rs create mode 100644 atuin-client/src/record/store.rs create mode 100644 atuin-common/src/record.rs diff --git a/atuin-client/record-migrations/20230531212437_create-records.sql b/atuin-client/record-migrations/20230531212437_create-records.sql new file mode 100644 index 00000000..120a9eac --- /dev/null +++ b/atuin-client/record-migrations/20230531212437_create-records.sql @@ -0,0 +1,10 @@ +-- Add migration script here +create table if not exists records ( + id text primary key, + host text not null, + timestamp integer not null, + + tag text not null, + version text not null, + data blob not null, +); diff --git a/atuin-client/src/lib.rs b/atuin-client/src/lib.rs index 497c5e74..087934a0 100644 --- a/atuin-client/src/lib.rs +++ b/atuin-client/src/lib.rs @@ -14,4 +14,5 @@ pub mod database; pub mod history; pub mod import; pub mod ordering; +pub mod record; pub mod settings; diff --git a/atuin-client/src/record/mod.rs b/atuin-client/src/record/mod.rs new file mode 100644 index 00000000..72c1f889 --- /dev/null +++ b/atuin-client/src/record/mod.rs @@ -0,0 +1,2 @@ +pub mod sqlite_store; +pub mod store; diff --git a/atuin-client/src/record/sqlite_store.rs b/atuin-client/src/record/sqlite_store.rs new file mode 100644 index 00000000..8ee195a9 --- /dev/null +++ b/atuin-client/src/record/sqlite_store.rs @@ -0,0 +1,70 @@ +// Here we are using sqlite as a pretty dumb store, and will not be running any complex queries. +// Multiple stores of multiple types are all stored in one chonky table (for now), and we just index +// by tag/host + +yo tomorrow morning me +drink that coffee +then wrap up this interface + +you will need to +- make sure the records use string IDs +- add the version in +- write some tests with a memory sqlite + +use std::path::Path; +use std::str::FromStr; + +use async_trait::async_trait; +use fs_err as fs; +use sqlx::{ + sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePool, SqlitePoolOptions, SqliteRow}, + Result, Row, +}; + +use atuin_common::record::Record; + +use super::store::Store; + +pub struct SqliteStore { + pool: SqlitePool, +} + +impl SqliteStore { + pub async fn new(path: impl AsRef) -> Result { + let path = path.as_ref(); + + debug!("opening sqlite database at {:?}", path); + + let create = !path.exists(); + if create { + if let Some(dir) = path.parent() { + fs::create_dir_all(dir)?; + } + } + + let opts = SqliteConnectOptions::from_str(path.as_os_str().to_str().unwrap())? + .journal_mode(SqliteJournalMode::Wal) + .create_if_missing(true); + + let pool = SqlitePoolOptions::new().connect_with(opts).await?; + + Self::setup_db(&pool).await?; + + Ok(Self { pool }) + } + + async fn setup_db(pool: &SqlitePool) -> Result<()> { + debug!("running sqlite database setup"); + + sqlx::migrate!("./record-migrations").run(pool).await?; + + Ok(()) + } +} + +#[async_trait] +impl Store for SqliteStore { + async fn push(record: Record) -> Result { + Ok(record) + } +} diff --git a/atuin-client/src/record/store.rs b/atuin-client/src/record/store.rs new file mode 100644 index 00000000..04a266f8 --- /dev/null +++ b/atuin-client/src/record/store.rs @@ -0,0 +1,15 @@ +use async_trait::async_trait; +use eyre::Result; + +use atuin_common::record::Record; + +/// A record store stores records +/// In more detail - we tend to need to process this into _another_ format to actually query it. +/// As is, the record store is intended as the source of truth for arbitratry data, which could +/// be shell history, kvs, etc. +#[async_trait] +pub trait Store { + async fn push(record: Record) -> Result; + async fn get(id: String) -> Result; + async fn len(host: String, tag: String) -> Result; +} diff --git a/atuin-common/src/lib.rs b/atuin-common/src/lib.rs index e76a7abb..b332e234 100644 --- a/atuin-common/src/lib.rs +++ b/atuin-common/src/lib.rs @@ -1,4 +1,5 @@ #![forbid(unsafe_code)] pub mod api; +pub mod record; pub mod utils; diff --git a/atuin-common/src/record.rs b/atuin-common/src/record.rs new file mode 100644 index 00000000..514ec786 --- /dev/null +++ b/atuin-common/src/record.rs @@ -0,0 +1,15 @@ +/// A single record stored inside of our local database +pub struct Record { + pub id: i64, + + pub host: String, + + pub timestamp: u64, + + /// The type of data we are storing here. It is probably useful to also + /// include some sort of version. For example, history.v2 + pub tag: String, + + /// Some data. This can be anything you wish to store. Use the tag field to know how to handle it. + pub data: Vec, +}