aboutsummaryrefslogtreecommitdiffstats
path: root/crates/rocie-server/src/storage/migrate
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-03-19 02:42:02 +0100
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-03-19 02:42:02 +0100
commit6df299c87ba8faab75626d04392f874ec642c8dc (patch)
tree64744ae2dea2c726d72589ce290e88679e60c564 /crates/rocie-server/src/storage/migrate
parentchore(rocie-client): Re-generate the client api (diff)
downloadserver-6df299c87ba8faab75626d04392f874ec642c8dc.zip
feat(rocie-server): Provide default units (and other changes)
Diffstat (limited to 'crates/rocie-server/src/storage/migrate')
-rw-r--r--crates/rocie-server/src/storage/migrate/defaults.rs99
-rw-r--r--crates/rocie-server/src/storage/migrate/mod.rs72
-rw-r--r--crates/rocie-server/src/storage/migrate/sql/0->1.sql7
3 files changed, 168 insertions, 10 deletions
diff --git a/crates/rocie-server/src/storage/migrate/defaults.rs b/crates/rocie-server/src/storage/migrate/defaults.rs
new file mode 100644
index 0000000..3a2019c
--- /dev/null
+++ b/crates/rocie-server/src/storage/migrate/defaults.rs
@@ -0,0 +1,99 @@
+use crate::{
+ app::App,
+ storage::sql::{insert::Operations, unit::Unit, unit_property::UnitProperty},
+};
+
+#[expect(clippy::unnecessary_wraps, reason = "The API expects an Option<_>")]
+fn so(input: &'static str) -> Option<String> {
+ Some(s(input))
+}
+fn s(input: &'static str) -> String {
+ String::from(input)
+}
+
+macro_rules! register {
+ (
+ $app:ident # $unit_prop_description:literal, $unit_prop_name:literal
+ $(
+ -> $unit_full_name_singular:ident, $unit_full_name_plural:ident, $unit_short_name:ident
+ )*
+ ) => {
+ let mut ops = Operations::new(concat!(
+ "create",
+ $unit_prop_name,
+ "unit property (during provisioning)"
+ ));
+ let unit_property = UnitProperty::register(
+ s($unit_prop_name),
+ so($unit_prop_description),
+ &mut ops,
+ )
+ .id;
+ ops.apply(&$app).await?;
+
+ let mut ops = Operations::new(concat!(
+ "create default units for",
+ $unit_prop_name,
+ "property (during provisioning)"
+ ));
+
+ $(
+ Unit::register(
+ s(stringify!($unit_full_name_singular)),
+ s(stringify!($unit_full_name_plural)),
+ s(stringify!($unit_short_name)),
+ None,
+ unit_property,
+ &mut ops,
+ );
+ )*
+
+ ops.apply(&$app).await?;
+ };
+}
+
+pub(super) async fn add_defaults_0_to_1(app: &App) -> Result<(), apply_defaults::Error> {
+ register!(
+ app # "Time mesurement units", "Time"
+ -> second, seconds, s
+ -> minute, minutes, min
+ -> hour, hours, h
+ );
+
+ register!(
+ app # "Mass (weight) mesurement units", "Mass"
+ -> milligram, milligrams, mg
+ -> gram, grams, g
+ -> kilogram, kilograms, kg
+ );
+
+ register!(
+ app # "Volume mesurement units", "Volume"
+ -> milliliter, millilters, ml
+ -> deciliter, deciliters, dl
+ -> liter, liters, l
+
+ // English
+ -> tablespoon, tablespoons, tbsp
+ -> teaspoon, teaspoons, tsp
+
+ // Swedish
+ -> tesked, teskedar, tsk
+ -> matsked, matskedar, msk
+ );
+
+ Ok(())
+}
+
+pub(crate) mod apply_defaults {
+ use crate::storage::sql::insert::{self, apply};
+
+ #[derive(thiserror::Error, Debug)]
+ pub(crate) enum Error {
+ #[error("Failed to add new default unit-property the database: {0}")]
+ AddUnitProperty(#[from] apply::Error<insert::unit_property::Operation>),
+
+ #[error("Failed to add new default unit the database: {0}")]
+ AddUnit(#[from] apply::Error<insert::unit::Operation>),
+ }
+}
diff --git a/crates/rocie-server/src/storage/migrate/mod.rs b/crates/rocie-server/src/storage/migrate/mod.rs
index ae0732b..5c81580 100644
--- a/crates/rocie-server/src/storage/migrate/mod.rs
+++ b/crates/rocie-server/src/storage/migrate/mod.rs
@@ -7,10 +7,15 @@ use chrono::TimeDelta;
use log::{debug, info};
use sqlx::{Sqlite, SqlitePool, Transaction, query};
-use crate::app::App;
+use crate::{
+ app::App,
+ storage::sql::{config::Config, get::config},
+};
+
+mod defaults;
macro_rules! make_upgrade {
- ($app:expr, $old_version:expr, $new_version:expr, $sql_name:expr) => {
+ ($app:expr, $old_version:expr, $new_version:expr, $sql_name:expr) => {{
let mut tx = $app
.db
.begin()
@@ -57,8 +62,8 @@ macro_rules! make_upgrade {
new_version: $new_version,
})?;
- Ok(())
- };
+ Ok::<_, update::Error>(())
+ }};
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
@@ -135,11 +140,12 @@ impl DbVersion {
///
/// Each update is atomic, so if this function fails you are still guaranteed to have a
/// database at version `get_version`.
- #[allow(clippy::too_many_lines)]
async fn update(self, app: &App) -> Result<(), update::Error> {
match self {
Self::Empty => {
- make_upgrade! {app, Self::Empty, Self::One, "./sql/0->1.sql"}
+ make_upgrade! {app, Self::Empty, Self::One, "./sql/0->1.sql"}?;
+
+ Ok(())
}
// This is the current_version
@@ -158,7 +164,10 @@ impl Display for DbVersion {
}
}
pub(crate) mod update {
- use crate::storage::migrate::{DbVersion, db_version_set, get_db_version};
+ use crate::storage::{
+ migrate::{DbVersion, db_version_set, defaults, get_db_version},
+ sql::get::config,
+ };
#[derive(thiserror::Error, Debug)]
pub(crate) enum Error {
@@ -182,6 +191,11 @@ pub(crate) mod update {
#[error("Failed to commit the update transaction: {0}")]
TxnCommit(sqlx::Error),
+ #[error("Failed to access the rocie config: {0}")]
+ ConfigGet(#[from] config::get::Error),
+ #[error("Failed to add defaults to the database: {0}")]
+ AddDefaults(#[from] defaults::apply_defaults::Error),
+
#[error("Failed to perform the next chained update (to ver {new_version}): {err}")]
NextUpdate {
err: Box<Self>,
@@ -197,6 +211,12 @@ pub(crate) mod db_version_parse {
}
}
+async fn should_use_defaults(app: &App) -> Result<bool, config::get::Error> {
+ let config = Config::get(app).await?;
+
+ Ok(config.should_use_defaults)
+}
+
/// Returns the current data as UNIX time stamp.
pub(crate) fn get_current_date() -> i64 {
let start = SystemTime::now();
@@ -238,7 +258,7 @@ pub(crate) async fn get_version_db(pool: &SqlitePool) -> Result<DbVersion, get_d
)
.fetch_optional(pool)
.await
- .map_err(|err| get_db_version::Error::VersionTableExistance(err))?;
+ .map_err(get_db_version::Error::VersionTableExistance)?;
if let Some(output) = query {
assert_eq!(output.result, 1);
@@ -261,7 +281,7 @@ pub(crate) async fn get_version_db(pool: &SqlitePool) -> Result<DbVersion, get_d
)
.fetch_one(pool)
.await
- .map_err(|err| get_db_version::Error::VersionNumberFetch(err))?;
+ .map_err(get_db_version::Error::VersionNumberFetch)?;
Ok(DbVersion::from_db(
current_version.number,
@@ -288,6 +308,26 @@ pub(crate) mod get_db_version {
pub(crate) async fn migrate_db(app: &App) -> Result<(), migrate_db::Error> {
let current_version = get_version(app).await?;
+ if app.db_version_at_start.get().is_none() {
+ app.db_version_at_start
+ .set(current_version)
+ .expect("the cell to be unititialized, we checked");
+ }
+
+ if app.db_version_at_start.get() == Some(&DbVersion::Empty) {
+ // We cannot run this code in the normal update function, because for the empty db, there
+ // is no way to know if we want defaults.
+ //
+ // So we need to add the defaults later, which is achieved by another call to `migrate_db`
+ // in provision.
+ //
+ // That is kinda hacky, but I don't see a way around it.
+ // For defaults added in version Two and onward, the default mechanism should just work.
+ if should_use_defaults(app).await? {
+ defaults::add_defaults_0_to_1(app).await?;
+ }
+ }
+
if current_version == CURRENT_VERSION {
return Ok(());
}
@@ -300,7 +340,12 @@ pub(crate) async fn migrate_db(app: &App) -> Result<(), migrate_db::Error> {
}
pub(crate) mod migrate_db {
- use crate::storage::migrate::{get_db_version, update};
+ use actix_web::ResponseError;
+
+ use crate::storage::{
+ migrate::{defaults, get_db_version, update},
+ sql::get::config,
+ };
#[derive(thiserror::Error, Debug)]
pub(crate) enum Error {
@@ -309,5 +354,12 @@ pub(crate) mod migrate_db {
#[error("Failed to update the database: {0}")]
Upadate(#[from] update::Error),
+
+ #[error("Failed to access the rocie config: {0}")]
+ ConfigGet(#[from] config::get::Error),
+ #[error("Failed to add defaults to the database: {0}")]
+ AddDefaults(#[from] defaults::apply_defaults::Error),
}
+
+ impl ResponseError for Error {}
}
diff --git a/crates/rocie-server/src/storage/migrate/sql/0->1.sql b/crates/rocie-server/src/storage/migrate/sql/0->1.sql
index ba44c68..8f99322 100644
--- a/crates/rocie-server/src/storage/migrate/sql/0->1.sql
+++ b/crates/rocie-server/src/storage/migrate/sql/0->1.sql
@@ -178,3 +178,10 @@ CREATE TABLE txn_log (
timestamp INTEGER NOT NULL,
operation TEXT NOT NULL
) STRICT;
+
+CREATE TABLE config (
+ -- Make it impossible to insert more than one value here.
+ id INTEGER PRIMARY KEY NOT NULL CHECK (id = 0),
+ use_defaults INTEGER NOT NULL CHECK (use_defaults = 1 OR use_defaults = 0)
+) STRICT;
+INSERT INTO config (id, use_defaults) VALUES (0, 0);