From 9bdcae7d3f19efec5f040ccde790c061d1399c73 Mon Sep 17 00:00:00 2001 From: hduoc2003 Date: Tue, 20 Feb 2024 19:06:01 +0700 Subject: [PATCH] cycle detected when checking effective visibilities see https://github.com/rust-lang/rust/issues/119502 --- .dockerignore | 18 +++++ .env.example | 4 + Cargo.toml | 27 +++++++ Dockerfile | 1 + diesel.toml | 9 +++ docker-compose.yml | 20 +++++ justfile | 4 + log4rs.yaml | 16 ++++ src/config.rs | 79 ++++++++++++++++++++ src/main.rs | 31 ++++++++ src/schema.rs | 123 +++++++++++++++++++++++++++++++ src/v1/api/controllers/mod.rs | 1 + src/v1/api/controllers/signup.rs | 32 ++++++++ src/v1/api/db/base.rs | 6 ++ src/v1/api/db/database.rs | 59 +++++++++++++++ src/v1/api/db/in_memory.rs | 10 +++ src/v1/api/db/mod.rs | 4 + src/v1/api/db/postgres.rs | 44 +++++++++++ src/v1/api/mod.rs | 6 ++ src/v1/api/models/mod.rs | 1 + src/v1/api/models/models.rs | 84 +++++++++++++++++++++ src/v1/api/models/users.rs | 29 ++++++++ src/v1/api/routes/mod.rs | 1 + src/v1/api/routes/signup.rs | 7 ++ src/v1/api/types/db.rs | 39 ++++++++++ src/v1/api/types/env.rs | 9 +++ src/v1/api/types/errors.rs | 0 src/v1/api/types/mod.rs | 3 + src/v1/api/utils/env.rs | 5 ++ src/v1/api/utils/errors.rs | 12 +++ src/v1/api/utils/mod.rs | 2 + src/v1/mod.rs | 1 + tests/blank.rs | 0 33 files changed, 687 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 Cargo.toml create mode 100644 Dockerfile create mode 100644 diesel.toml create mode 100644 docker-compose.yml create mode 100644 justfile create mode 100644 log4rs.yaml create mode 100644 src/config.rs create mode 100644 src/main.rs create mode 100644 src/schema.rs create mode 100644 src/v1/api/controllers/mod.rs create mode 100644 src/v1/api/controllers/signup.rs create mode 100644 src/v1/api/db/base.rs create mode 100644 src/v1/api/db/database.rs create mode 100644 src/v1/api/db/in_memory.rs create mode 100644 src/v1/api/db/mod.rs create mode 100644 src/v1/api/db/postgres.rs create mode 100644 src/v1/api/mod.rs create mode 100644 src/v1/api/models/mod.rs create mode 100644 src/v1/api/models/models.rs create mode 100644 src/v1/api/models/users.rs create mode 100644 src/v1/api/routes/mod.rs create mode 100644 src/v1/api/routes/signup.rs create mode 100644 src/v1/api/types/db.rs create mode 100644 src/v1/api/types/env.rs create mode 100644 src/v1/api/types/errors.rs create mode 100644 src/v1/api/types/mod.rs create mode 100644 src/v1/api/utils/env.rs create mode 100644 src/v1/api/utils/errors.rs create mode 100644 src/v1/api/utils/mod.rs create mode 100644 src/v1/mod.rs create mode 100644 tests/blank.rs diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8eec493 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,18 @@ +# gitignore +/result* +/target + +# Docker-specific +**/target +*.nix +/.cargo +.direnv +.git +/flake.lock +justfile +## Meta +.dockerignore +Dockerfile* +docker-compose.yml +shared +tempo-data diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ffbe421 --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +HOST= +PORT= +DATABASE= +DATABASE_URL= diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d492932 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "rust-demo-server" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +axum = "0.7.4" +env_logger = "0.11.2" +serde = { version = "1.0.196", features = ["derive"] } +serde_json = "1.0.113" +tokio = { version = "1.36.0", features = ["full"] } +tracing = { version = "0.1.40", features = ["log"] } +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } +uuid = { version = "1.7.0", features = ["v4"] } +# sqlx = { version = "0.7", features = [ "runtime-tokio", "migrate", "postgres" ] } +dotenv = "0.15.0" +strum = "0.26.1" +strum_macros = "0.26.1" +diesel = { version = "2.1.0", features = ["postgres", "chrono"] } +diesel-async = { version = "0.4.1", features = ["postgres", "bb8", "deadpool"] } +chrono = "0.4.34" +diesel-derive-enum = { version = "2.1.0", features = ["postgres"] } +lazy_static = "1.4.0" +bb8 = "0.8.3" + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ef2c726 --- /dev/null +++ b/Dockerfile @@ -0,0 +1 @@ +FROM rust:1.75.0 diff --git a/diesel.toml b/diesel.toml new file mode 100644 index 0000000..c028f4a --- /dev/null +++ b/diesel.toml @@ -0,0 +1,9 @@ +# For documentation on how to configure this file, +# see https://diesel.rs/guides/configuring-diesel-cli + +[print_schema] +file = "src/schema.rs" +custom_type_derives = ["diesel::query_builder::QueryId"] + +[migrations_directory] +dir = "migrations" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3685484 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +version: '3.9' +services: + db: + image: postgres:15.6 + restart: always + # set shared memory limit when using docker-compose + shm_size: 128mb + # or set shared memory limit when deploy via swarm stack + #volumes: + # - type: tmpfs + # target: /dev/shm + # tmpfs: + # size: 134217728 # 128*2^20 bytes = 128Mb + env_file: + - postgres.env + volumes: + - ./postgres-mount:/var/lib/postgresql/data + stdin_open: true + ports: + - "5433:5432" diff --git a/justfile b/justfile new file mode 100644 index 0000000..b7984a1 --- /dev/null +++ b/justfile @@ -0,0 +1,4 @@ +set shell := ["cmd.exe", "/c"] + +dev: + cargo watch -q -w src/ -x run diff --git a/log4rs.yaml b/log4rs.yaml new file mode 100644 index 0000000..7030117 --- /dev/null +++ b/log4rs.yaml @@ -0,0 +1,16 @@ +refresh_rate: 30 seconds +appenders: + stdout: + kind: console + encoder: + kind: json + file: + kind: file + path: "stderr.log" + encoder: + kind: json +root: + level: info + appenders: + - stdout + - file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..0388a24 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,79 @@ +use dotenv::dotenv; +use tokio::sync::OnceCell; + +use crate::v1::api::{db::database::Database, types::env::ENV, utils::env::get_env}; + +// Define a struct to represent server configuration +#[derive(Debug)] +struct ServerConfig { + host: String, + port: u16, +} + +// Define a struct to represent database configuration +#[derive(Debug)] +struct DatabaseConfig { + url: String, +} + +// Define a struct that aggregates server and database configuration +#[derive(Debug)] +pub struct Config { + server: ServerConfig, + db: DatabaseConfig, +} + +// Implement methods for the Config struct to access configuration values +impl Config { + // Getter method for the database URL + pub fn db_url(&self) -> &str { + &self.db.url + } + + // Getter method for the server host + pub fn server_host(&self) -> &str { + &self.server.host + } + + // Getter method for the server port + pub fn server_port(&self) -> u16 { + self.server.port + } +} + +// Create a static OnceCell to store the application configuration +pub static CONFIG: OnceCell = OnceCell::const_new(); + +// Asynchronously initialize the configuration +async fn init_config() -> Config { + // Load environment variables from a .env file if present + dotenv().ok(); + + // Create a ServerConfig instance with default values or values from environment variables + let server_config = ServerConfig { + host: get_env(ENV::HOST), + port: get_env(ENV::PORT).parse().unwrap(), + }; + + // Create a DatabaseConfig instance with a required DATABASE_URL environment variable + let database_config = DatabaseConfig { + url: get_env(ENV::DATABASE_URL), + }; + + // Create a Config instance by combining server and database configurations + Config { + server: server_config, + db: database_config, + } +} + +// Asynchronously retrieve the application configuration, initializing it if necessary +pub async fn config() -> &'static Config { + // Get the configuration from the OnceCell or initialize it if it hasn't been set yet + CONFIG.get_or_init(init_config).await +} + +#[derive(Clone)] +pub struct AppState { + pub db: Database +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..db4c7bb --- /dev/null +++ b/src/main.rs @@ -0,0 +1,31 @@ +use axum::Router; +use config::{config, AppState}; +use v1::api::{db::database::Database, routes::signup, types::{db::DatabaseType, env::ENV}, utils::env::get_env}; +// use v1::api::routes::signup::handle_signup; +mod v1; +mod config; +mod schema; + +#[tokio::main] +async fn main() { + let config = config().await; + + let db: Database = match get_env(ENV::DATABASE).as_str() { + "postgres" => Database::new(DatabaseType::Postgres).await, + "in-memory" => Database::new(DatabaseType::InMemory).await, + x => panic!("Only support postgres and in-memory database, not {}", x) + }; + + + let app_state = AppState { + db + }; + + let app = Router::new() + .nest("/v1/api", signup::routes()) + .with_state(app_state); + + let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", get_env(ENV::PORT))).await.unwrap(); + + axum::serve(listener, app).await.unwrap(); +} diff --git a/src/schema.rs b/src/schema.rs new file mode 100644 index 0000000..9baa1c7 --- /dev/null +++ b/src/schema.rs @@ -0,0 +1,123 @@ +// @generated automatically by Diesel CLI. + +pub mod sql_types { + #[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "status_enum"))] + pub struct StatusEnum; +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::StatusEnum; + + activities (id) { + id -> Int8, + user_id -> Int8, + task_id -> Int8, + #[max_length = 512] + title -> Varchar, + #[max_length = 2048] + description -> Nullable, + status -> StatusEnum, + created_at -> Timestamp, + updated_at -> Nullable, + planned_start_date -> Nullable, + planned_end_date -> Nullable, + actual_start_date -> Nullable, + actual_end_date -> Nullable, + content -> Nullable, + } +} + +diesel::table! { + comments (id) { + id -> Int8, + task_id -> Int8, + activity_id -> Nullable, + #[max_length = 100] + title -> Varchar, + created_at -> Timestamp, + updated_at -> Nullable, + content -> Nullable, + } +} + +diesel::table! { + tags (id) { + id -> Int8, + #[max_length = 75] + title -> Varchar, + #[max_length = 100] + slug -> Varchar, + } +} + +diesel::table! { + task_tags (task_id, tag_id) { + task_id -> Int8, + tag_id -> Int8, + } +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::StatusEnum; + + tasks (id) { + id -> Int8, + user_id -> Int8, + created_by -> Int8, + updated_by -> Int8, + #[max_length = 512] + title -> Varchar, + #[max_length = 2048] + description -> Nullable, + status -> StatusEnum, + created_at -> Timestamp, + updated_at -> Nullable, + planned_start_date -> Nullable, + planned_end_date -> Nullable, + actual_start_date -> Nullable, + actual_end_date -> Nullable, + content -> Nullable, + } +} + +diesel::table! { + users (id) { + id -> Int8, + is_admin -> Bool, + #[max_length = 50] + first_name -> Nullable, + #[max_length = 50] + last_name -> Nullable, + #[max_length = 50] + username -> Varchar, + #[max_length = 15] + mobile -> Nullable, + #[max_length = 50] + email -> Nullable, + #[max_length = 32] + password_hash -> Varchar, + registered_at -> Timestamptz, + last_login -> Nullable, + intro -> Nullable, + } +} + +diesel::joinable!(activities -> tasks (task_id)); +diesel::joinable!(activities -> users (user_id)); +diesel::joinable!(comments -> activities (activity_id)); +diesel::joinable!(comments -> tasks (task_id)); +diesel::joinable!(task_tags -> tags (tag_id)); +diesel::joinable!(task_tags -> tasks (task_id)); +diesel::joinable!(tasks -> users (user_id)); + +diesel::allow_tables_to_appear_in_same_query!( + activities, + comments, + tags, + task_tags, + tasks, + users, +); diff --git a/src/v1/api/controllers/mod.rs b/src/v1/api/controllers/mod.rs new file mode 100644 index 0000000..400ca8b --- /dev/null +++ b/src/v1/api/controllers/mod.rs @@ -0,0 +1 @@ +pub mod signup; diff --git a/src/v1/api/controllers/signup.rs b/src/v1/api/controllers/signup.rs new file mode 100644 index 0000000..1b9f930 --- /dev/null +++ b/src/v1/api/controllers/signup.rs @@ -0,0 +1,32 @@ +use axum::{extract::State, Json}; +use serde::{Deserialize, Serialize}; + +use crate::{config::AppState, v1::api::{db::base::DbBase, utils::errors::ErrorResponse}}; + +#[derive(Debug, Deserialize)] +struct Request { + username: String, + password: String +} + +#[derive(Debug, Serialize)] +struct Response { + +} + +pub async fn handle_signup( + State(mut state): State, + Json(req): Json +) -> Result, ErrorResponse> { + match state.db.add_user(&req.username, &req.password).await { + Ok(_) => { + Ok(Json(Response { + + })) + }, + Err(err) => { + Err(err) + }, + } + +} diff --git a/src/v1/api/db/base.rs b/src/v1/api/db/base.rs new file mode 100644 index 0000000..5687221 --- /dev/null +++ b/src/v1/api/db/base.rs @@ -0,0 +1,6 @@ +use crate::v1::api::utils::errors::ErrorResponse; + +pub trait DbBase { + async fn add_user(&mut self, username: &str, pass: &str) -> Result<(), ErrorResponse>; + +} diff --git a/src/v1/api/db/database.rs b/src/v1/api/db/database.rs new file mode 100644 index 0000000..5497f83 --- /dev/null +++ b/src/v1/api/db/database.rs @@ -0,0 +1,59 @@ +use diesel::prelude::*; +use diesel_async::pooled_connection::{bb8::Pool, AsyncDieselConnectionManager}; + +use crate::v1::api::{ + types::{db::DatabaseType, env::ENV}, + utils::env::get_env, +}; + +use super::{base::DbBase, in_memory::InMemoryDb, postgres::PostgresDb}; + +#[derive(Clone)] +pub struct Database { + database: Box, + // database: Box +} + +impl Database { + pub async fn new(db_type: DatabaseType) -> Self { + Database { + database: match db_type { + DatabaseType::Postgres => { + let database_url = get_env(ENV::DATABASE_URL); + // let conn = PgConnection::establish(&database_url) + // .unwrap_or_else(|_| panic!("Error connecting to {}", database_url)); + let config = + AsyncDieselConnectionManager::::new( + get_env(ENV::DATABASE_URL) + ); + let pool = Pool::builder().build(config).await.unwrap(); + + // checkout a connection from the pool + let mut conn = pool.get().await.unwrap(); + Box::new(PostgresDb { conn }) + // PostgresDb { conn } + } + DatabaseType::InMemory => Box::new(InMemoryDb), + // DatabaseType::InMemory => !panic!(), + }, + } + } + + pub async fn add_user( + &mut self, + username: &str, + pass: &str, + ) -> Result<(), crate::v1::api::utils::errors::ErrorResponse> { + self.database.add_user(username, pass).await + } +} + +// impl Database { +// fn add_user( +// &self, +// username: &str, +// pass: &str, +// ) -> Result<(), crate::v1::api::utils::errors::ErrorResponse> { +// self.database.add_user(username, pass) +// } +// } diff --git a/src/v1/api/db/in_memory.rs b/src/v1/api/db/in_memory.rs new file mode 100644 index 0000000..da4de1c --- /dev/null +++ b/src/v1/api/db/in_memory.rs @@ -0,0 +1,10 @@ +use super::base::DbBase; + +#[derive(Clone)] +pub struct InMemoryDb; + +impl DbBase for InMemoryDb { + async fn add_user(&mut self, username: &str, pass: &str) -> Result<(), crate::v1::api::utils::errors::ErrorResponse> { + todo!() + } +} diff --git a/src/v1/api/db/mod.rs b/src/v1/api/db/mod.rs new file mode 100644 index 0000000..336774c --- /dev/null +++ b/src/v1/api/db/mod.rs @@ -0,0 +1,4 @@ +pub mod base; +pub mod postgres; +pub mod in_memory; +pub mod database; diff --git a/src/v1/api/db/postgres.rs b/src/v1/api/db/postgres.rs new file mode 100644 index 0000000..b40c3b4 --- /dev/null +++ b/src/v1/api/db/postgres.rs @@ -0,0 +1,44 @@ +use axum::http::StatusCode; +use diesel_async::RunQueryDsl; +use diesel::{insert_into, SelectableHelper}; + +use crate::v1::api::utils::errors::ErrorResponse; +use crate::{schema::users, v1::api::models::users::{NewUser, User}}; +use diesel_async::{pooled_connection::AsyncDieselConnectionManager, AsyncPgConnection}; + +use super::base::DbBase; + +type Pool = bb8::Pool>; + +// pub struct PostgresDb( +// pub bb8::PooledConnection<'static, AsyncDieselConnectionManager>, +// ); +// #[derive(Clone)] +pub struct PostgresDb { + pub conn: bb8::PooledConnection<'static, AsyncDieselConnectionManager>, +} + +impl DbBase for PostgresDb { + async fn add_user(&mut self, username: &str, pass: &str) -> Result<(), ErrorResponse> { + match insert_into(users::table) + .values(&NewUser { + username, + password_hash: pass, + }) + .returning(User::as_returning()) + .get_result(&mut self.conn).await { + Ok(data) => { + println!("{:?}", data); + Ok(()) + }, + Err(err) => { + eprintln!("{}", err); + Err(ErrorResponse { + status: StatusCode::INTERNAL_SERVER_ERROR, + msg: err.to_string(), + }) + }, + } + } + +} diff --git a/src/v1/api/mod.rs b/src/v1/api/mod.rs new file mode 100644 index 0000000..46a3d97 --- /dev/null +++ b/src/v1/api/mod.rs @@ -0,0 +1,6 @@ +pub mod controllers; +pub mod models; +pub mod routes; +pub mod utils; +pub mod types; +pub mod db; diff --git a/src/v1/api/models/mod.rs b/src/v1/api/models/mod.rs new file mode 100644 index 0000000..913bd46 --- /dev/null +++ b/src/v1/api/models/mod.rs @@ -0,0 +1 @@ +pub mod users; diff --git a/src/v1/api/models/models.rs b/src/v1/api/models/models.rs new file mode 100644 index 0000000..33eb21b --- /dev/null +++ b/src/v1/api/models/models.rs @@ -0,0 +1,84 @@ +// Generated by diesel_ext + +#![allow(unused)] +#![allow(clippy::all)] + + +use chrono::NaiveDateTime; +use chrono::DateTime; +use chrono::offset::Utc; +#[derive(Queryable, Debug, Identifiable)] +pub struct Activity { + pub id: i64, + pub user_id: i64, + pub task_id: i64, + pub title: String, + pub description: Option, + pub status: /* TODO: unknown type StatusEnum */, + pub created_at: NaiveDateTime, + pub updated_at: Option, + pub planned_start_date: Option, + pub planned_end_date: Option, + pub actual_start_date: Option, + pub actual_end_date: Option, + pub content: Option, +} + +#[derive(Queryable, Debug, Identifiable)] +pub struct Comment { + pub id: i64, + pub task_id: i64, + pub activity_id: Option, + pub title: String, + pub created_at: NaiveDateTime, + pub updated_at: Option, + pub content: Option, +} + +#[derive(Queryable, Debug, Identifiable)] +pub struct Tag { + pub id: i64, + pub title: String, + pub slug: String, +} + +#[derive(Queryable, Debug, Identifiable)] +#[diesel(primary_key(task_id, tag_id))] +pub struct TaskTag { + pub task_id: i64, + pub tag_id: i64, +} + +#[derive(Queryable, Debug)] +pub struct Task { + pub id: i64, + pub user_id: i64, + pub created_by: i64, + pub updated_by: i64, + pub title: String, + pub description: Option, + pub status: /* TODO: unknown type StatusEnum */, + pub created_at: NaiveDateTime, + pub updated_at: Option, + pub planned_start_date: Option, + pub planned_end_date: Option, + pub actual_start_date: Option, + pub actual_end_date: Option, + pub content: Option, +} + +#[derive(Queryable, Debug)] +pub struct User { + pub id: i64, + pub is_admin: bool, + pub first_name: Option, + pub last_name: Option, + pub username: String, + pub mobile: Option, + pub email: Option, + pub password_hash: String, + pub registered_at: DateTime, + pub last_login: Option, + pub intro: Option, +} + diff --git a/src/v1/api/models/users.rs b/src/v1/api/models/users.rs new file mode 100644 index 0000000..7fee2f6 --- /dev/null +++ b/src/v1/api/models/users.rs @@ -0,0 +1,29 @@ +use diesel::prelude::*; +use chrono::NaiveDateTime; +use chrono::DateTime; +use chrono::offset::Utc; + +#[derive(Debug)] +#[derive(Queryable, Selectable)] +#[diesel(table_name = crate::schema::users)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct User { + pub id: i64, + pub is_admin: bool, + pub first_name: Option, + pub last_name: Option, + pub username: String, + pub mobile: Option, + pub email: Option, + pub password_hash: String, + pub registered_at: DateTime, + pub last_login: Option, + pub intro: Option, +} + +#[derive(serde::Deserialize, Insertable)] +#[diesel(table_name = crate::schema::users)] +pub struct NewUser<'a> { + pub username: &'a str, + pub password_hash: &'a str, +} diff --git a/src/v1/api/routes/mod.rs b/src/v1/api/routes/mod.rs new file mode 100644 index 0000000..400ca8b --- /dev/null +++ b/src/v1/api/routes/mod.rs @@ -0,0 +1 @@ +pub mod signup; diff --git a/src/v1/api/routes/signup.rs b/src/v1/api/routes/signup.rs new file mode 100644 index 0000000..0b42309 --- /dev/null +++ b/src/v1/api/routes/signup.rs @@ -0,0 +1,7 @@ +use axum::{routing::get, Router}; + +use crate::{config::AppState, v1::api::controllers::signup::handle_signup}; + +pub fn routes() -> Router { + Router::new().route("/signup", get(handle_signup)) +} diff --git a/src/v1/api/types/db.rs b/src/v1/api/types/db.rs new file mode 100644 index 0000000..c6a6ba8 --- /dev/null +++ b/src/v1/api/types/db.rs @@ -0,0 +1,39 @@ + +use strum_macros::AsRefStr; + +#[derive(AsRefStr)] +pub enum DatabaseType { + #[strum(serialize = "postgres")] + Postgres, + #[strum(serialize = "in-memory")] + InMemory +} + +#[derive(Debug)] +#[derive(diesel_derive_enum::DbEnum)] +#[ExistingTypePath = "crate::schema::sql_types::StatusEnum"] +pub enum ProgressStatus { + Pending, + InProgress, + Completed +} + +// impl FromSql for ProgressStatus { +// fn from_sql(bytes: ::RawValue<'_>) -> deserialize::Result { +// match String::from_sql(bytes)?.as_str() { +// "Pending" => Ok(ProgressStatus::Pending), +// "InProgress" => Ok(ProgressStatus::InProgress), +// "Completed" => Ok(ProgressStatus::Completed), +// x => Err(format!("Unrecognized variant {}", x).into()), +// } +// } +// } + +// impl ToSql for ProgressStatus { +// fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { +// match self { +// ProgressStatus::Pending => >::to_sql(&0, out), +// OrderStatus::Finished => >::to_sql(&1, out), +// } +// } +// } diff --git a/src/v1/api/types/env.rs b/src/v1/api/types/env.rs new file mode 100644 index 0000000..f9864a7 --- /dev/null +++ b/src/v1/api/types/env.rs @@ -0,0 +1,9 @@ +use strum_macros::AsRefStr; + +#[derive(AsRefStr)] +pub enum ENV { + HOST, + PORT, + DATABASE, + DATABASE_URL +} diff --git a/src/v1/api/types/errors.rs b/src/v1/api/types/errors.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/v1/api/types/mod.rs b/src/v1/api/types/mod.rs new file mode 100644 index 0000000..b08fb05 --- /dev/null +++ b/src/v1/api/types/mod.rs @@ -0,0 +1,3 @@ +pub mod env; +pub mod db; +pub mod errors; diff --git a/src/v1/api/utils/env.rs b/src/v1/api/utils/env.rs new file mode 100644 index 0000000..fe585ab --- /dev/null +++ b/src/v1/api/utils/env.rs @@ -0,0 +1,5 @@ +use crate::v1::api::types::env::ENV; + +pub fn get_env(key: ENV) -> String { + std::env::var(key.as_ref()).expect(&format!("{} must be set", key.as_ref())) +} diff --git a/src/v1/api/utils/errors.rs b/src/v1/api/utils/errors.rs new file mode 100644 index 0000000..bd83b52 --- /dev/null +++ b/src/v1/api/utils/errors.rs @@ -0,0 +1,12 @@ +use axum::{http::StatusCode, response::IntoResponse}; + +pub struct ErrorResponse { + pub status: StatusCode, + pub msg: String +} + +impl IntoResponse for ErrorResponse { + fn into_response(self) -> axum::response::Response { + (self.status, self.msg).into_response() + } +} diff --git a/src/v1/api/utils/mod.rs b/src/v1/api/utils/mod.rs new file mode 100644 index 0000000..441ed53 --- /dev/null +++ b/src/v1/api/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod env; +pub mod errors; diff --git a/src/v1/mod.rs b/src/v1/mod.rs new file mode 100644 index 0000000..e5fdf85 --- /dev/null +++ b/src/v1/mod.rs @@ -0,0 +1 @@ +pub mod api; diff --git a/tests/blank.rs b/tests/blank.rs new file mode 100644 index 0000000..e69de29