Initial project structure

This commit is contained in:
Joe Bellus 2022-02-03 16:55:10 -05:00
commit 37e64cb9f2
16 changed files with 3468 additions and 0 deletions

3
.env Normal file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
DATABASE_URL=sqlite://data.db

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
data.db*

3168
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

19
Cargo.toml Normal file
View File

@ -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"

22
Makefile.toml Normal file
View File

@ -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" ]

View File

@ -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 );

1
rustfmt.toml Normal file
View File

@ -0,0 +1 @@
edition = "2021"

33
src/api/applications.rs Normal file
View File

@ -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);
}
}

35
src/api/mod.rs Normal file
View File

@ -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,
};
}

44
src/entity/application.rs Normal file
View File

@ -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(),
}
}
}

View File

@ -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 {}

26
src/entity/bookmark.rs Normal file
View File

@ -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 {}

View File

@ -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 {}

8
src/entity/mod.rs Normal file
View File

@ -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;

6
src/entity/prelude.rs Normal file
View File

@ -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;

47
src/main.rs Normal file
View File

@ -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
}