hook up beginnings of sqlite persistence

This commit is contained in:
Hailey Somerville
2020-08-04 23:09:44 +10:00
parent b3f7192b24
commit 90d1f8a9fa
6 changed files with 82 additions and 11 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ release:
./frontend-exec.sh ./build.sh --release && cargo build --release
run:
./frontend-exec.sh ./build.sh && cargo run workspace/
./frontend-exec.sh ./build.sh && cargo run workspace
check:
./frontend-exec.sh cargo check --target=wasm32-unknown-unknown && cargo check
+4
View File
@@ -0,0 +1,4 @@
pub static MIGRATIONS: &'static [(i32, &'static str)] = &[
(0, include_str!("migrations/0_init.sql")),
// (20200804, include_str!("migrations/20200804_create_media_tables.sql")),
];
+1
View File
@@ -0,0 +1 @@
CREATE TABLE schema_migrations (version INTEGER NOT NULL);
+57
View File
@@ -0,0 +1,57 @@
use std::path::Path;
use sqlx::sqlite::{SqlitePool, SqliteConnectOptions};
mod migrations;
async fn schema_version(pool: &SqlitePool) -> Result<Option<i32>, sqlx::Error> {
let result = sqlx::query_as::<_, (i32,)>("SELECT version FROM schema_migrations WHERE rowid = 1")
.fetch_one(pool)
.await;
match result {
Ok((schema_version,)) => Ok(Some(schema_version)),
Err(sqlx::Error::Database(e)) if e.message() == "no such table: schema_migrations" => Ok(None),
Err(e) => Err(e),
}
}
async fn update_schema_version(pool: &SqlitePool, ver: i32) -> Result<(), sqlx::Error> {
sqlx::query(r"
INSERT INTO schema_migrations (rowid, version) VALUES (1, ?)
ON CONFLICT (rowid) DO UPDATE SET version = excluded.version;
")
.bind(ver)
.execute(pool)
.await?;
Ok(())
}
pub async fn attach(path: &Path) -> Result<SqlitePool, sqlx::Error> {
let pool = SqlitePool::connect_with(SqliteConnectOptions::new()
.filename(path)
.create_if_missing(true)).await?;
let schema_version = schema_version(&pool).await?;
let mut migrations = migrations::MIGRATIONS.to_vec();
// migrations should already be sorted, but we should ensure it is anyway:
migrations.sort_by_key(|(ver, _)| *ver);
// retain only migrations yet to be performed on this database
migrations.retain(|(ver, _)| Some(*ver) > schema_version);
// run migrations to bring database up to date
for (_, sql) in &migrations {
sqlx::query(sql).execute(&pool).await?;
}
// update database schema version if migrations were performed
if let Some((ver, _)) = migrations.last() {
update_schema_version(&pool, *ver).await?;
}
Ok(pool)
}
+1
View File
@@ -1,3 +1,4 @@
mod db;
mod engine;
mod icecast;
mod listen;
+18 -10
View File
@@ -4,6 +4,7 @@ use std::sync::Arc;
use derive_more::From;
use futures::stream::Stream;
use sqlx::SqlitePool;
use tokio::fs::{self, File};
use tokio::io::{self, AsyncWriteExt};
use tokio::sync::Mutex;
@@ -12,6 +13,7 @@ use uuid::Uuid;
use mixlab_protocol::{WorkspaceState, PerformanceInfo};
use crate::db;
use crate::engine::{self, EngineHandle, EngineEvents, EngineError, EngineSession, WorkspaceEmbryo};
use crate::persist;
@@ -23,7 +25,7 @@ pub struct ProjectHandle {
struct ProjectBase {
path: PathBuf,
library: HashMap<Uuid, MediaInfo>,
database: SqlitePool,
}
type ProjectBaseRef = Arc<Mutex<ProjectBase>>;
@@ -32,15 +34,21 @@ type ProjectBaseRef = Arc<Mutex<ProjectBase>>;
pub enum OpenError {
Io(io::Error),
Json(serde_json::Error),
Database(sqlx::Error),
NotDirectory,
}
impl ProjectBase {
fn open_at(path: PathBuf) -> Self {
ProjectBase {
async fn attach(path: PathBuf) -> Result<Self, sqlx::Error> {
let mut sqlite_path = path.clone();
sqlite_path.set_extension("mixlab");
let database = db::attach(&sqlite_path).await?;
Ok(ProjectBase {
path,
library: HashMap::new(),
}
database,
})
}
async fn read_workspace(&self) -> Result<persist::Workspace, io::Error> {
@@ -91,10 +99,10 @@ impl ProjectBase {
}
async fn finalize_media_upload(&mut self, id: Uuid, info: UploadInfo) -> Result<(), io::Error> {
self.library.insert(id, MediaInfo {
name: info.name,
kind: info.kind,
});
// self.library.insert(id, MediaInfo {
// name: info.name,
// kind: info.kind,
// });
// TODO persist
@@ -124,7 +132,7 @@ pub async fn open_or_create(path: PathBuf) -> Result<ProjectHandle, OpenError> {
}
}
let base = ProjectBase::open_at(path);
let base = ProjectBase::attach(path).await?;
let workspace = base.read_workspace().await?;
// start engine update thread