Initial project structure
This commit is contained in:
commit
37e64cb9f2
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
data.db*
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "vade"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
sea-orm = { version = "0.5.0", features = [ "sqlx-sqlite", "runtime-actix-native-tls", "macros", "mock"], default-features = false }
|
||||
tracing = "0.1.29"
|
||||
tracing-unwrap = "0.9.2"
|
||||
tracing-subscriber = { version = "0.3.7", features=["fmt"] }
|
||||
actix = "0.12.0"
|
||||
actix-cors = "0.5.4"
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
serde = { version = "1.0.136", features= [ "derive" ] }
|
||||
serde_json = "1.0.78"
|
||||
actix-web = "4.0.0-rc.2"
|
||||
actix-rt = "2.6.0"
|
|
@ -0,0 +1,22 @@
|
|||
[env]
|
||||
# can be defined as kcov, tarpaulin, ...
|
||||
CARGO_MAKE_COVERAGE_PROVIDER = "kcov"
|
||||
|
||||
[tasks.dropdb]
|
||||
command = "sqlx"
|
||||
args = ["database", "drop"]
|
||||
|
||||
[tasks.createdb]
|
||||
command = "sqlx"
|
||||
args = ["database", "create"]
|
||||
|
||||
[tasks.migratedb]
|
||||
command = "sqlx"
|
||||
args = ["migrate", "run"]
|
||||
|
||||
[tasks.resetdb]
|
||||
run_task = { name = ["dropdb", "createdb", "migratedb", "entity"] }
|
||||
|
||||
[tasks.entity]
|
||||
command = "sea-orm-cli"
|
||||
args = [ "generate", "entity", "-o", "src/entity", "--with-serde", "both" ]
|
|
@ -0,0 +1,5 @@
|
|||
-- Add migration script here
|
||||
CREATE TABLE application ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, app_name TEXT NOT NULL, url TEXT NOT NULL, description TEXT, active Boolean NOT NULL DEFAULT 1, glyph TEXT, application_category_id INTEGER);
|
||||
CREATE TABLE application_category ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, category_name TEXT NOT NULL, active BOOLEAN NOT NULL DEFAULT 1 );
|
||||
CREATE TABLE bookmark ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, category_name TEXT NOT NULL, active BOOLEAN NOT NULL DEFAULT 1, glyph TEXT, bookmark_category_id INTEGER);
|
||||
CREATE TABLE bookmark_category ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, category_name TEXT NOT NULL, active BOOLEAN NOT NULL DEFAULT 1, glyph TEXT );
|
|
@ -0,0 +1 @@
|
|||
edition = "2021"
|
|
@ -0,0 +1,33 @@
|
|||
use tracing::instrument;
|
||||
|
||||
use crate::api::api_prelude::*;
|
||||
|
||||
#[instrument]
|
||||
#[get("/applications")]
|
||||
pub async fn list_applications(state: web::Data<AppState>) -> Result<HttpResponse, Error> {
|
||||
let apps: Vec<application::Model> = Application::find().all(&state.db).await.unwrap();
|
||||
Ok(HttpResponse::Ok().json(apps))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::api::test_prelude::*;
|
||||
use actix_web::http::Method;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_list_applications() {
|
||||
let db = MockDatabase::new(DatabaseBackend::Sqlite)
|
||||
.append_query_results(vec![vec![application::Model {
|
||||
id: 1,
|
||||
app_name: "Application 1".into(),
|
||||
..Default::default()
|
||||
}]])
|
||||
.into_connection();
|
||||
|
||||
let req = actix_web::test::TestRequest::with_uri("/applications")
|
||||
.method(Method::GET)
|
||||
.to_request();
|
||||
let resp = call_endpoint!(req, db);
|
||||
assert_eq!(resp.status(), 200);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#[cfg(test)]
|
||||
#[macro_export]
|
||||
macro_rules! call_endpoint {
|
||||
($req:ident, $db:ident) => {{
|
||||
let state = AppState { db: $db };
|
||||
let a = App::new()
|
||||
.app_data(state)
|
||||
.service(crate::api::applications::list_applications);
|
||||
let mut app = actix_web::test::init_service(a).await;
|
||||
let resp = actix_web::test::call_service(&mut app, $req).await;
|
||||
resp
|
||||
}};
|
||||
}
|
||||
|
||||
pub mod applications;
|
||||
|
||||
mod api_prelude {
|
||||
pub use crate::entity::prelude::*;
|
||||
pub use crate::entity::*;
|
||||
pub use crate::AppState;
|
||||
pub use actix_web::{get, web, Error, HttpResponse};
|
||||
pub use sea_orm::prelude::*;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_prelude {
|
||||
pub use crate::entity::*;
|
||||
pub use crate::AppState;
|
||||
|
||||
pub use actix_web::dev::ServiceResponse;
|
||||
pub use actix_web::{test, web, App};
|
||||
pub use sea_orm::{
|
||||
entity::prelude::*, entity::*, tests_cfg::*, DatabaseBackend, MockDatabase, Transaction,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.5.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "application")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub app_name: String,
|
||||
pub url: String,
|
||||
pub description: Option<String>,
|
||||
pub active: bool,
|
||||
pub glyph: Option<String>,
|
||||
pub application_category_id: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::application_category::Entity",
|
||||
from = "Column::ApplicationCategoryId",
|
||||
to = "super::application_category::Column::Id"
|
||||
)]
|
||||
ApplicationCategory,
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for Model {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
id: Default::default(),
|
||||
app_name: Default::default(),
|
||||
url: Default::default(),
|
||||
description: Default::default(),
|
||||
active: Default::default(),
|
||||
glyph: Default::default(),
|
||||
application_category_id: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.5.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "application_category")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub category_name: String,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
panic!("No RelationDef")
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
|
@ -0,0 +1,26 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.5.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "bookmark")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub category_name: String,
|
||||
pub active: bool,
|
||||
pub glyph: Option<String>,
|
||||
pub bookmark_category_id: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
panic!("No RelationDef")
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
|
@ -0,0 +1,25 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.5.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "bookmark_category")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub category_name: String,
|
||||
pub active: bool,
|
||||
pub glyph: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
panic!("No RelationDef")
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
|
@ -0,0 +1,8 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.5.0
|
||||
|
||||
pub mod prelude;
|
||||
|
||||
pub mod application;
|
||||
pub mod application_category;
|
||||
pub mod bookmark;
|
||||
pub mod bookmark_category;
|
|
@ -0,0 +1,6 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.5.0
|
||||
|
||||
pub use super::application::Entity as Application;
|
||||
pub use super::application_category::Entity as ApplicationCategory;
|
||||
pub use super::bookmark::Entity as Bookmark;
|
||||
pub use super::bookmark_category::Entity as BookmarkCategory;
|
|
@ -0,0 +1,47 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use actix_web::{App, HttpServer};
|
||||
use sea_orm::{Database, DatabaseConnection};
|
||||
use tracing::{instrument, info};
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
mod api;
|
||||
|
||||
mod entity;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppState {
|
||||
pub db: DatabaseConnection,
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() {
|
||||
let subscriber = tracing_subscriber::registry().with(
|
||||
tracing_subscriber::fmt::Layer::new()
|
||||
.pretty()
|
||||
.with_writer(std::io::stdout)
|
||||
.with_ansi(true)
|
||||
.with_filter(tracing_subscriber::filter::LevelFilter::DEBUG),
|
||||
);
|
||||
tracing::subscriber::set_global_default(subscriber).expect("Unable to set a global collector");
|
||||
|
||||
let db = setup_database().await.unwrap();
|
||||
let state = Arc::new(AppState { db });
|
||||
|
||||
info!("Starting http server on 8080");
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.app_data(state.clone())
|
||||
.service(api::applications::list_applications)
|
||||
})
|
||||
.bind("127.0.0.1:8080")
|
||||
.unwrap()
|
||||
.run()
|
||||
.await
|
||||
.expect("Couldnt launch server");
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn setup_database() -> Result<DatabaseConnection, sea_orm::DbErr> {
|
||||
Database::connect("sqlite://data.db").await
|
||||
}
|
Loading…
Reference in New Issue