new data format with more information
This commit is contained in:
parent
18de2714d0
commit
07bfc65b67
8 changed files with 109 additions and 2 deletions
BIN
foods.db
BIN
foods.db
Binary file not shown.
|
|
@ -8,3 +8,5 @@ SELECT
|
||||||
color
|
color
|
||||||
FROM
|
FROM
|
||||||
food
|
food
|
||||||
|
ORDER BY
|
||||||
|
sort_order, name;
|
||||||
|
|
|
||||||
1
src/get_version.sql
Normal file
1
src/get_version.sql
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
PRAGMA user_version;
|
||||||
50
src/main.rs
50
src/main.rs
|
|
@ -9,7 +9,7 @@ use axum::{
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rusqlite::{CachedStatement, Connection, Row};
|
use rusqlite::{CachedStatement, Connection, Row, Transaction};
|
||||||
use tower_http::trace::TraceLayer;
|
use tower_http::trace::TraceLayer;
|
||||||
use tower_request_id::{RequestId, RequestIdLayer};
|
use tower_request_id::{RequestId, RequestIdLayer};
|
||||||
use tracing::{debug, error, info, info_span};
|
use tracing::{debug, error, info, info_span};
|
||||||
|
|
@ -123,6 +123,50 @@ impl<'conn> PreparedStatements {
|
||||||
|
|
||||||
type ConnState = Arc<Mutex<Connection>>;
|
type ConnState = Arc<Mutex<Connection>>;
|
||||||
|
|
||||||
|
fn get_version(tx: &Transaction) -> rusqlite::Result<usize> {
|
||||||
|
tx.query_one(include_str!("get_version.sql"), (), |row| row.get(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_migrations() -> [&'static str; 4] {
|
||||||
|
[
|
||||||
|
include_str!("migrations/1.sql"),
|
||||||
|
include_str!("migrations/2.sql"),
|
||||||
|
include_str!("migrations/3.sql"),
|
||||||
|
include_str!("migrations/4.sql"),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_migrations(conn: &mut Connection) -> rusqlite::Result<()> {
|
||||||
|
let migrations = get_migrations();
|
||||||
|
let num_migrations = migrations.len();
|
||||||
|
let tx = conn.transaction()?;
|
||||||
|
let version = get_version(&tx)?;
|
||||||
|
if version < migrations.len() {
|
||||||
|
info!(
|
||||||
|
migrations_to_apply = num_migrations - version,
|
||||||
|
"need to apply some migrations"
|
||||||
|
);
|
||||||
|
let mut mig_number = version;
|
||||||
|
for migration in migrations.iter().skip(version) {
|
||||||
|
mig_number += 1;
|
||||||
|
info!(mig_number, "applying migration");
|
||||||
|
debug!(migration = migration);
|
||||||
|
tx.execute_batch(migration)?;
|
||||||
|
if get_version(&tx)? != mig_number {
|
||||||
|
panic!(
|
||||||
|
"expected user_version to eq {} after applying migration {}. maybe a missing 'PRAGMA user_version =' ?",
|
||||||
|
mig_number, mig_number
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx.commit()?;
|
||||||
|
info!("applied all migrations");
|
||||||
|
} else {
|
||||||
|
info!("no migrations to apply");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), std::io::Error> {
|
async fn main() -> Result<(), std::io::Error> {
|
||||||
tracing_subscriber::registry()
|
tracing_subscriber::registry()
|
||||||
|
|
@ -142,13 +186,15 @@ async fn main() -> Result<(), std::io::Error> {
|
||||||
|
|
||||||
let db_connecion_str = "./foods.db".to_string();
|
let db_connecion_str = "./foods.db".to_string();
|
||||||
debug!(db_connecion_str, "opening database");
|
debug!(db_connecion_str, "opening database");
|
||||||
let conn = Connection::open(db_connecion_str).expect("failed to open database");
|
let mut conn = Connection::open(db_connecion_str).expect("failed to open database");
|
||||||
|
|
||||||
if let Err(e) = conn.execute(include_str!("create_tables.sql"), ()) {
|
if let Err(e) = conn.execute(include_str!("create_tables.sql"), ()) {
|
||||||
error!(?e, "failed to create tables");
|
error!(?e, "failed to create tables");
|
||||||
panic!("failed to create tables: {:#?}", e);
|
panic!("failed to create tables: {:#?}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_migrations(&mut conn).expect("failed to do database migrations");
|
||||||
|
|
||||||
PreparedStatements::check(&conn).expect("failed to prepare sql statements");
|
PreparedStatements::check(&conn).expect("failed to prepare sql statements");
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
|
|
|
||||||
6
src/migrations/1.sql
Normal file
6
src/migrations/1.sql
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
ALTER TABLE
|
||||||
|
food
|
||||||
|
ADD COLUMN
|
||||||
|
portion_weight INTEGER NOT NULL DEFAULT 100 CHECK (portion_weight > 0);
|
||||||
|
|
||||||
|
PRAGMA user_version = 1;
|
||||||
23
src/migrations/2.sql
Normal file
23
src/migrations/2.sql
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
ALTER TABLE
|
||||||
|
food
|
||||||
|
ADD COLUMN
|
||||||
|
-- per 100g
|
||||||
|
protein REAL NOT NULL DEFAULT 5.0 CHECK (protein > 0);
|
||||||
|
|
||||||
|
ALTER TABLE
|
||||||
|
food
|
||||||
|
ADD COLUMN
|
||||||
|
-- per 100g
|
||||||
|
fiber REAL NOT NULL DEFAULT 5.0 CHECK (fiber > 0);
|
||||||
|
|
||||||
|
ALTER TABLE
|
||||||
|
food
|
||||||
|
ADD COLUMN
|
||||||
|
protein_per_portion REAL NOT NULL GENERATED ALWAYS AS ((protein / 100) * portion_weight) VIRTUAL;
|
||||||
|
|
||||||
|
ALTER TABLE
|
||||||
|
food
|
||||||
|
ADD COLUMN
|
||||||
|
fiber_per_portion REAL NOT NULL GENERATED ALWAYS AS ((fiber / 100) * portion_weight) VIRTUAL;
|
||||||
|
|
||||||
|
PRAGMA user_version = 2;
|
||||||
6
src/migrations/3.sql
Normal file
6
src/migrations/3.sql
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
ALTER TABLE
|
||||||
|
food
|
||||||
|
ADD COLUMN
|
||||||
|
sort_order INTEGER NOT NULL DEFAULT 0;
|
||||||
|
|
||||||
|
PRAGMA user_version = 3;
|
||||||
23
src/migrations/4.sql
Normal file
23
src/migrations/4.sql
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
CREATE TABLE "sqlb_temp_table_1" (
|
||||||
|
"id" INTEGER,
|
||||||
|
"portion" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"kc_per_serving" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"target_servings" INTEGER NOT NULL DEFAULT 1,
|
||||||
|
"actual_servings" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"color" TEXT NOT NULL DEFAULT 'white',
|
||||||
|
"portion_weight" INTEGER NOT NULL DEFAULT 100 CHECK("portion_weight" > 0),
|
||||||
|
"protein" REAL NOT NULL DEFAULT 5.0 CHECK("protein" >= 0),
|
||||||
|
"fiber" REAL NOT NULL DEFAULT 5.0 CHECK("fiber" >= 0),
|
||||||
|
"protein_per_portion" REAL NOT NULL GENERATED ALWAYS AS (("protein" / 100) * "portion_weight") VIRTUAL,
|
||||||
|
"fiber_per_portion" REAL NOT NULL GENERATED ALWAYS AS (("fiber" / 100) * "portion_weight") VIRTUAL,
|
||||||
|
"sort_order" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY("id")
|
||||||
|
) STRICT;
|
||||||
|
INSERT INTO "main"."sqlb_temp_table_1" ("actual_servings","color","fiber","id","kc_per_serving","name","portion","portion_weight","protein","sort_order","target_servings") SELECT "actual_servings","color","fiber","id","kc_per_serving","name","portion","portion_weight","protein","sort_order","target_servings" FROM "main"."food";
|
||||||
|
PRAGMA defer_foreign_keys = '1';
|
||||||
|
DROP TABLE "main"."food";
|
||||||
|
ALTER TABLE "main"."sqlb_temp_table_1" RENAME TO "food";
|
||||||
|
PRAGMA defer_foreign_keys = '0';
|
||||||
|
|
||||||
|
PRAGMA user_version = 4;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue