Initial work
This commit is contained in:
commit
554e645f92
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
/.idea
|
||||
3166
Cargo.lock
generated
Normal file
3166
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
Cargo.toml
Normal file
21
Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "monzo-ingestion"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
axum = "0.6.20"
|
||||
tokio = { version = "1.32.0", features = ["full"] }
|
||||
sea-orm = { version = "0.12", features = [
|
||||
"sqlx-postgres",
|
||||
"runtime-tokio-rustls",
|
||||
"macros"
|
||||
] }
|
||||
|
||||
serde = { version = "1.0.188", features = ["derive"] }
|
||||
serde_json = "1.0.105"
|
||||
tracing-subscriber = "0.3.17"
|
||||
tracing = "0.1.37"
|
||||
|
||||
[workspace]
|
||||
members = [".", "migration", "entity"]
|
||||
13
entity/Cargo.toml
Normal file
13
entity/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "entity"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "entity"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
sea-orm = { version = "^0" }
|
||||
serde = { version = "1.0.158", features = ["derive"] }
|
||||
19
entity/src/expenditure.rs
Normal file
19
entity/src/expenditure.rs
Normal file
@ -0,0 +1,19 @@
|
||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "expenditure")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub transaction_id: i32,
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub category: String,
|
||||
pub amount: Decimal,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
6
entity/src/mod.rs
Normal file
6
entity/src/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
|
||||
|
||||
pub mod prelude;
|
||||
|
||||
pub mod expenditure;
|
||||
pub mod transaction;
|
||||
4
entity/src/prelude.rs
Normal file
4
entity/src/prelude.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
|
||||
|
||||
pub use super::expenditure::Entity as Expenditure;
|
||||
pub use super::transaction::Entity as Transaction;
|
||||
24
entity/src/transaction.rs
Normal file
24
entity/src/transaction.rs
Normal file
@ -0,0 +1,24 @@
|
||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "transaction")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub id: String,
|
||||
pub transaction_type: String,
|
||||
pub total_amount: Decimal,
|
||||
pub timestamp: DateTime,
|
||||
pub title: String,
|
||||
pub emoji: Option<String>,
|
||||
pub notes: Option<String>,
|
||||
pub receipt: Option<String>,
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
19
migration/Cargo.toml
Normal file
19
migration/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "migration"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "migration"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
async-std = { version = "1", features = ["attributes", "tokio1"] }
|
||||
|
||||
[dependencies.sea-orm-migration]
|
||||
version = "0.12.0"
|
||||
features = [
|
||||
"runtime-tokio-rustls", # `ASYNC_RUNTIME` feature
|
||||
"sqlx-postgres", # `DATABASE_DRIVER` feature
|
||||
]
|
||||
41
migration/README.md
Normal file
41
migration/README.md
Normal file
@ -0,0 +1,41 @@
|
||||
# Running Migrator CLI
|
||||
|
||||
- Generate a new migration file
|
||||
```sh
|
||||
cargo run -- generate MIGRATION_NAME
|
||||
```
|
||||
- Apply all pending migrations
|
||||
```sh
|
||||
cargo run
|
||||
```
|
||||
```sh
|
||||
cargo run -- up
|
||||
```
|
||||
- Apply first 10 pending migrations
|
||||
```sh
|
||||
cargo run -- up -n 10
|
||||
```
|
||||
- Rollback last applied migrations
|
||||
```sh
|
||||
cargo run -- down
|
||||
```
|
||||
- Rollback last 10 applied migrations
|
||||
```sh
|
||||
cargo run -- down -n 10
|
||||
```
|
||||
- Drop all tables from the database, then reapply all migrations
|
||||
```sh
|
||||
cargo run -- fresh
|
||||
```
|
||||
- Rollback all applied migrations, then reapply all migrations
|
||||
```sh
|
||||
cargo run -- refresh
|
||||
```
|
||||
- Rollback all applied migrations
|
||||
```sh
|
||||
cargo run -- reset
|
||||
```
|
||||
- Check the status of all migrations
|
||||
```sh
|
||||
cargo run -- status
|
||||
```
|
||||
12
migration/src/lib.rs
Normal file
12
migration/src/lib.rs
Normal file
@ -0,0 +1,12 @@
|
||||
pub use sea_orm_migration::prelude::*;
|
||||
|
||||
pub mod m20230904_141851_create_monzo_tables;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||
vec![Box::new(m20230904_141851_create_monzo_tables::Migration)]
|
||||
}
|
||||
}
|
||||
114
migration/src/m20230904_141851_create_monzo_tables.rs
Normal file
114
migration/src/m20230904_141851_create_monzo_tables.rs
Normal file
@ -0,0 +1,114 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.create_table(
|
||||
Table::create()
|
||||
.table(Transaction::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Transaction::Id)
|
||||
.string()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Transaction::TransactionType)
|
||||
.string()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Transaction::TotalAmount)
|
||||
.decimal()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Transaction::Timestamp)
|
||||
.timestamp()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Transaction::Title)
|
||||
.string()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Transaction::Emoji)
|
||||
.string(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Transaction::Notes)
|
||||
.string(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Transaction::Receipt)
|
||||
.string(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Transaction::Description)
|
||||
.string(),
|
||||
)
|
||||
.to_owned()
|
||||
).await?;
|
||||
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Expenditure::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Expenditure::TransactionId)
|
||||
.integer()
|
||||
.not_null(),
|
||||
)
|
||||
.col(ColumnDef::new(Expenditure::Category).string().not_null())
|
||||
.primary_key(
|
||||
Index::create()
|
||||
.col(Expenditure::TransactionId)
|
||||
.col(Expenditure::Category),
|
||||
)
|
||||
.col(ColumnDef::new(Expenditure::Amount).decimal().not_null())
|
||||
.to_owned(),
|
||||
).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Expenditure::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_table(Table::drop().table(Transaction::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Transaction {
|
||||
Table,
|
||||
Id,
|
||||
TransactionType,
|
||||
Timestamp,
|
||||
Title,
|
||||
Emoji,
|
||||
Notes,
|
||||
Receipt,
|
||||
TotalAmount,
|
||||
Description,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Expenditure {
|
||||
Table,
|
||||
Category,
|
||||
Amount,
|
||||
TransactionId,
|
||||
}
|
||||
6
migration/src/main.rs
Normal file
6
migration/src/main.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
cli::run_cli(migration::Migrator).await;
|
||||
}
|
||||
30
src/main.rs
Normal file
30
src/main.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use axum::{
|
||||
routing::{get, post},
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
Json, Router,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::SocketAddr;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// initialize tracing
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// build our application with a route
|
||||
let app = Router::new()
|
||||
// `GET /` goes to `root`
|
||||
.route("/", get(root))
|
||||
// `POST /users` goes to `create_user`
|
||||
.route("/users", post(create_user));
|
||||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
tracing::debug!("listening on {}", addr);
|
||||
axum::Server::bind(&addr)
|
||||
.serve(app.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user