diff options
Diffstat (limited to 'backend/src')
| -rw-r--r-- | backend/src/databases.rs | 4 | ||||
| -rw-r--r-- | backend/src/main.rs | 41 | ||||
| -rw-r--r-- | backend/src/models/account.rs | 13 | ||||
| -rw-r--r-- | backend/src/models/budget_update.rs | 14 | ||||
| -rw-r--r-- | backend/src/models/category.rs | 10 | ||||
| -rw-r--r-- | backend/src/models/category_transaction.rs | 10 | ||||
| -rw-r--r-- | backend/src/models/category_transfer.rs | 11 | ||||
| -rw-r--r-- | backend/src/models/mod.rs | 6 | ||||
| -rw-r--r-- | backend/src/models/transaction.rs | 14 | ||||
| -rw-r--r-- | backend/src/routes/account.rs | 68 | ||||
| -rw-r--r-- | backend/src/routes/mod.rs | 1 | ||||
| -rw-r--r-- | backend/src/schema.rs | 71 |
12 files changed, 263 insertions, 0 deletions
diff --git a/backend/src/databases.rs b/backend/src/databases.rs new file mode 100644 index 0000000..461fc44 --- /dev/null +++ b/backend/src/databases.rs @@ -0,0 +1,4 @@ +use rocket_sync_db_pools::{database, diesel}; + +#[database("user_data")] +pub struct UserDataDb(diesel::SqliteConnection); diff --git a/backend/src/main.rs b/backend/src/main.rs new file mode 100644 index 0000000..db47ceb --- /dev/null +++ b/backend/src/main.rs @@ -0,0 +1,41 @@ +use diesel::SqliteConnection; +use diesel_migrations::MigrationHarness; +use diesel_migrations::{embed_migrations, EmbeddedMigrations}; +use rocket::fairing::AdHoc; +use rocket::{launch, routes, Build, Rocket}; + +use crate::databases::UserDataDb; + +pub mod databases; +pub mod models; +pub mod routes; +pub mod schema; + +pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); + +fn run_database_migrations(connection: &mut SqliteConnection) { + connection + .run_pending_migrations(MIGRATIONS) + .expect("Error running database migrations"); +} + +#[launch] +async fn rocket() -> Rocket<Build> { + rocket::build() + .attach(UserDataDb::fairing()) + .attach(AdHoc::on_liftoff("Database Migration", |rocket| { + Box::pin(async move { + let user_data_db = UserDataDb::get_one(rocket).await.expect( + "Failed to get connection to user data database in order to run migrations", + ); + user_data_db.run(run_database_migrations).await; + }) + })) + .mount( + "/", + routes![ + routes::account::get_all_accounts, + routes::account::create_account + ], + ) +} diff --git a/backend/src/models/account.rs b/backend/src/models/account.rs new file mode 100644 index 0000000..1a2aa41 --- /dev/null +++ b/backend/src/models/account.rs @@ -0,0 +1,13 @@ +use diesel::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive( + Insertable, Queryable, Identifiable, Selectable, Debug, PartialEq, Clone, Serialize, Deserialize, +)] +#[diesel(table_name = crate::schema::accounts)] +pub struct Account { + pub id: i32, + pub name: String, + pub opening_balance: i32, + pub opening_date: String, +} diff --git a/backend/src/models/budget_update.rs b/backend/src/models/budget_update.rs new file mode 100644 index 0000000..3843455 --- /dev/null +++ b/backend/src/models/budget_update.rs @@ -0,0 +1,14 @@ +use diesel::prelude::*; + +use crate::models::category::Category; + +#[derive(Queryable, Identifiable, Selectable, Associations, Debug, PartialEq)] +#[diesel(table_name = crate::schema::budget_updates)] +#[diesel(belongs_to(Category))] +pub struct BudgetUpdate { + pub id: i32, + pub category_id: i32, + pub date: String, + pub new_budget: i32, + pub new_period: i32, +} diff --git a/backend/src/models/category.rs b/backend/src/models/category.rs new file mode 100644 index 0000000..d7e25aa --- /dev/null +++ b/backend/src/models/category.rs @@ -0,0 +1,10 @@ +use diesel::prelude::*; + +#[derive(Queryable, Identifiable, Selectable, Debug, PartialEq)] +#[diesel(table_name = crate::schema::categories)] +pub struct Category { + pub id: i32, + pub name: String, + pub initial_budget: i32, + pub initial_period: i32, +} diff --git a/backend/src/models/category_transaction.rs b/backend/src/models/category_transaction.rs new file mode 100644 index 0000000..2163860 --- /dev/null +++ b/backend/src/models/category_transaction.rs @@ -0,0 +1,10 @@ +use diesel::prelude::*; + +#[derive(Queryable, Identifiable, Selectable, Debug, PartialEq)] +#[diesel(table_name = crate::schema::category_transactions)] +pub struct CategoryTransaction { + pub id: i32, + pub description: String, + pub quantity: i32, + pub category_id: i32, +} diff --git a/backend/src/models/category_transfer.rs b/backend/src/models/category_transfer.rs new file mode 100644 index 0000000..6cbda0e --- /dev/null +++ b/backend/src/models/category_transfer.rs @@ -0,0 +1,11 @@ +use diesel::prelude::*; + +#[derive(Queryable, Identifiable, Selectable, Debug, PartialEq)] +#[diesel(table_name = crate::schema::category_transfers)] +pub struct CategoryTransfer { + pub id: i32, + pub description: String, + pub quantity: i32, + pub from_category_id: i32, + pub to_category_id: i32, +} diff --git a/backend/src/models/mod.rs b/backend/src/models/mod.rs new file mode 100644 index 0000000..f70212a --- /dev/null +++ b/backend/src/models/mod.rs @@ -0,0 +1,6 @@ +pub mod account; +pub mod budget_update; +pub mod category; +pub mod category_transaction; +pub mod category_transfer; +pub mod transaction; diff --git a/backend/src/models/transaction.rs b/backend/src/models/transaction.rs new file mode 100644 index 0000000..a83a0ad --- /dev/null +++ b/backend/src/models/transaction.rs @@ -0,0 +1,14 @@ +use diesel::prelude::*; + +use crate::models::account::Account; + +#[derive(Queryable, Identifiable, Selectable, Associations, Debug, PartialEq)] +#[diesel(table_name = crate::schema::transactions)] +#[diesel(belongs_to(Account))] +pub struct Transaction { + pub id: i32, + pub description: String, + pub payee: String, + pub quantity: i32, + pub account_id: i32, +} diff --git a/backend/src/routes/account.rs b/backend/src/routes/account.rs new file mode 100644 index 0000000..e7f000c --- /dev/null +++ b/backend/src/routes/account.rs @@ -0,0 +1,68 @@ +use diesel::prelude::*; +use diesel::result::DatabaseErrorKind; +use rocket::error::ErrorKind; +use rocket::serde::json::Json; +use rocket::tokio::sync::oneshot::error::RecvError; +use rocket::{get, post, Responder}; + +use crate::databases::UserDataDb; +use crate::models::account::Account; +use crate::schema::accounts::dsl::accounts; + +#[get("/account")] +pub async fn get_all_accounts(user_data_db: UserDataDb) -> Json<Vec<Account>> { + user_data_db + .run(|connection| { + Json( + accounts + .select(Account::as_select()) + .load(connection) + .expect("Error getting accounts"), + ) + }) + .await +} + +#[derive(Responder)] +pub enum CreateAccountResponder { + #[response(status = 500, content_type = "text")] + InternalServerError(String), + + #[response(status = 202, content_type = "json")] + Created(Json<Account>), + + #[response(status = 400, content_type = "text")] + BadRequest(String), +} + +#[post("/account", data = "<account>", format = "json")] +pub async fn create_account( + account: Json<Account>, + user_data_db: UserDataDb, +) -> CreateAccountResponder { + let account = account.into_inner(); + let account_clone = account.clone(); + + let num_rows_inserted = user_data_db + .run(|connection| { + diesel::insert_into(accounts) + .values(vec![account_clone]) + .execute(connection) + }) + .await; + + match num_rows_inserted { + Ok(_) => CreateAccountResponder::Created(Json(account)), + Err(err) => match err { + diesel::result::Error::DatabaseError(DatabaseErrorKind::UniqueViolation, info) => { + let column = info.column_name().unwrap_or("account"); + CreateAccountResponder::BadRequest(format!( + "Error creating account: {column} was not unique." + )) + } + _ => CreateAccountResponder::InternalServerError(format!( + "Error creating account: {err}" + )), + }, + } +} diff --git a/backend/src/routes/mod.rs b/backend/src/routes/mod.rs new file mode 100644 index 0000000..b0edc6c --- /dev/null +++ b/backend/src/routes/mod.rs @@ -0,0 +1 @@ +pub mod account; diff --git a/backend/src/schema.rs b/backend/src/schema.rs new file mode 100644 index 0000000..d98a629 --- /dev/null +++ b/backend/src/schema.rs @@ -0,0 +1,71 @@ +// @generated automatically by Diesel CLI. + +diesel::table! { + accounts (id) { + id -> Integer, + name -> Text, + opening_balance -> Integer, + opening_date -> Text, + } +} + +diesel::table! { + budget_updates (id) { + id -> Integer, + category_id -> Integer, + date -> Text, + new_budget -> Integer, + new_period -> Integer, + } +} + +diesel::table! { + categories (id) { + id -> Integer, + name -> Text, + initial_budget -> Integer, + initial_period -> Integer, + } +} + +diesel::table! { + category_transactions (id) { + id -> Integer, + description -> Text, + quantity -> Integer, + category_id -> Integer, + } +} + +diesel::table! { + category_transfers (id) { + id -> Integer, + description -> Text, + quantity -> Integer, + from_category_id -> Integer, + to_category_id -> Integer, + } +} + +diesel::table! { + transactions (id) { + id -> Integer, + description -> Text, + payee -> Text, + quantity -> Integer, + account_id -> Integer, + } +} + +diesel::joinable!(budget_updates -> categories (category_id)); +diesel::joinable!(category_transactions -> categories (category_id)); +diesel::joinable!(transactions -> accounts (account_id)); + +diesel::allow_tables_to_appear_in_same_query!( + accounts, + budget_updates, + categories, + category_transactions, + category_transfers, + transactions, +); |
