Initial commit

This commit is contained in:
Raphaël Thériault 2019-10-07 17:43:34 -04:00
commit d5ac4b8b6a
15 changed files with 2142 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# Rust build artifacts
target/
**/*.rs.bk
# User specific files
.env
**/*.db
# JetBrains settings
.idea/

1756
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

18
Cargo.toml Normal file
View File

@ -0,0 +1,18 @@
[package]
name = "filite"
version = "0.1.0"
authors = ["Raphaël Thériault <raphael_theriault@outlook.com>"]
edition = "2018"
[dependencies]
actix-web = "1.0.8"
chrono = "0.4.9"
[dependencies.diesel]
version = "1.4.2"
features = ["r2d2", "sqlite"]
[dependencies.libsqlite3-sys]
version = "0.12.0"
features = ["bundled"]
[dev-dependencies]
dotenv = "0.14.1"

2
diesel.toml Normal file
View File

@ -0,0 +1,2 @@
[print_schema]
file = "src/schema.rs"

0
migrations/.gitkeep Normal file
View File

View File

@ -0,0 +1 @@
DROP TABLE files

View File

@ -0,0 +1,6 @@
CREATE TABLE files (
id INTEGER NOT NULL PRIMARY KEY,
filepath TEXT NOT NULL,
created INTEGER NOT NULL DEFAULT (datetime('now')),
updated INTEGER NOT NULL DEFAULT (datetime('now'))
)

View File

@ -0,0 +1 @@
DROP TABLE links

View File

@ -0,0 +1,6 @@
CREATE TABLE links (
id INTEGER NOT NULL PRIMARY KEY,
forward TEXT NOT NULL,
created INTEGER NOT NULL DEFAULT (datetime('now')),
updated INTEGER NOT NULL DEFAULT (datetime('now'))
)

View File

@ -0,0 +1 @@
DROP TABLE texts

View File

@ -0,0 +1,6 @@
CREATE TABLE texts (
id INTEGER NOT NULL PRIMARY KEY,
contents TEXT NOT NULL,
created INTEGER NOT NULL DEFAULT (datetime('now')),
updated INTEGER NOT NULL DEFAULT (datetime('now'))
)

28
src/lib.rs Normal file
View File

@ -0,0 +1,28 @@
#[macro_use]
extern crate diesel;
use diesel::r2d2::{self, ConnectionManager};
use diesel::sqlite::SqliteConnection;
pub mod models;
pub mod queries;
pub mod schema;
/// SQLite database connection pool
pub type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
/// Functions used for the initial setup
pub mod setup {
use crate::Pool;
use diesel::r2d2::{self, ConnectionManager};
use diesel::sqlite::SqliteConnection;
/// Creates a SQLite database connection pool
pub fn create_pool(url: &str) -> Pool {
let manager = ConnectionManager::<SqliteConnection>::new(url);
r2d2::Pool::builder()
.build(manager)
.expect("Can't create pool.")
}
}

67
src/models.rs Normal file
View File

@ -0,0 +1,67 @@
//! Database models
/// Models from the `files` table
pub mod files {
use crate::schema::files;
/// An entry from the `files` table
#[derive(Queryable, Identifiable)]
pub struct File {
pub id: i32,
pub filepath: String,
pub created: i32,
pub updated: i32,
}
/// A new entry to the `files` table
#[derive(Insertable)]
#[table_name = "files"]
pub struct NewFile<'a> {
pub id: i32,
pub filepath: &'a str,
}
}
/// Models from the `links` table
pub mod links {
use crate::schema::links;
/// An entry from the `links` table
#[derive(Queryable, Identifiable)]
pub struct Link {
pub id: i32,
pub forward: String,
pub created: i32,
pub updated: i32,
}
/// A new entry to the `links` table
#[derive(Insertable)]
#[table_name = "links"]
pub struct NewLink<'a> {
pub id: i32,
pub forward: &'a str,
}
}
/// Models from the `texts` table
pub mod texts {
use crate::schema::texts;
/// An entry from the `texts` table
#[derive(Queryable, Identifiable)]
pub struct Text {
pub id: i32,
pub contents: String,
pub created: i32,
pub updated: i32,
}
/// A new entry to the `texts` table
#[derive(Insertable)]
#[table_name = "texts"]
pub struct NewText<'a> {
pub id: i32,
pub contents: &'a str,
}
}

212
src/queries.rs Normal file
View File

@ -0,0 +1,212 @@
//! Helper functions for SQL queries
// A lot of duplicate code here could be merged by using macros
/// Queries affecting the `files` table
pub mod files {
use crate::models::files::*;
use crate::schema::files::dsl::*;
use crate::schema::files::table;
use crate::Pool;
use actix_web::web::Data;
use diesel::prelude::*;
use diesel::result::QueryResult;
/// SELECT a single file entry given its id
pub fn find(g_id: i32, pool: Data<Pool>) -> QueryResult<File> {
let conn: &SqliteConnection = &pool.get().unwrap();
files.find(g_id).first::<File>(conn)
}
/// INSERT a file entry
pub fn insert(p_id: i32, p_filepath: &str, pool: Data<Pool>) -> QueryResult<File> {
let conn: &SqliteConnection = &pool.get().unwrap();
let new_file = NewFile {
id: p_id,
filepath: p_filepath,
};
diesel::insert_into(table).values(&new_file).execute(conn)?;
find(p_id, pool)
}
/// UPDATE a file entry
pub fn update(
p_id: i32,
new_id: Option<i32>,
new_filepath: Option<&str>,
pool: Data<Pool>,
) -> QueryResult<File> {
let conn: &SqliteConnection = &pool.get().unwrap();
let file = find(p_id, pool)?;
let query = diesel::update(&file);
let time_update = updated.eq(chrono::Utc::now().timestamp() as i32);
match (new_id, new_filepath) {
(Some(new_id), Some(new_filepath)) => {
query
.set((id.eq(new_id), filepath.eq(new_filepath), time_update))
.execute(conn)?;
}
(Some(new_id), None) => {
query.set((id.eq(new_id), time_update)).execute(conn)?;
}
(None, Some(new_filepath)) => {
query
.set((filepath.eq(new_filepath), time_update))
.execute(conn)?;
}
(None, None) => {
return Ok(file);
}
}
Ok(file)
}
/// DELETE a file entry
pub fn delete(d_id: i32, pool: Data<Pool>) -> QueryResult<()> {
let conn: &SqliteConnection = &pool.get().unwrap();
diesel::delete(files.find(d_id)).execute(conn)?;
Ok(())
}
}
/// Queries affecting the `links` table
pub mod links {
use crate::models::links::*;
use crate::schema::links::dsl::*;
use crate::schema::links::table;
use crate::Pool;
use actix_web::web::Data;
use diesel::prelude::*;
use diesel::result::QueryResult;
/// SELECT a single link entry given its id
pub fn find(g_id: i32, pool: Data<Pool>) -> QueryResult<Link> {
let conn: &SqliteConnection = &pool.get().unwrap();
links.find(g_id).first::<Link>(conn)
}
/// INSERT a link entry
pub fn insert(p_id: i32, p_forward: &str, pool: Data<Pool>) -> QueryResult<Link> {
let conn: &SqliteConnection = &pool.get().unwrap();
let new_link = NewLink {
id: p_id,
forward: p_forward,
};
diesel::insert_into(table).values(&new_link).execute(conn)?;
find(p_id, pool)
}
/// UPDATE a link entry
pub fn update(
p_id: i32,
new_id: Option<i32>,
new_forward: Option<&str>,
pool: Data<Pool>,
) -> QueryResult<Link> {
let conn: &SqliteConnection = &pool.get().unwrap();
let link = find(p_id, pool)?;
let query = diesel::update(&link);
let time_update = updated.eq(chrono::Utc::now().timestamp() as i32);
match (new_id, new_forward) {
(Some(new_id), Some(new_forward)) => {
query
.set((id.eq(new_id), forward.eq(new_forward), time_update))
.execute(conn)?;
}
(Some(new_id), None) => {
query.set((id.eq(new_id), time_update)).execute(conn)?;
}
(None, Some(new_forward)) => {
query
.set((forward.eq(new_forward), time_update))
.execute(conn)?;
}
(None, None) => (),
}
Ok(link)
}
/// DELETE a link entry
pub fn delete(d_id: i32, pool: Data<Pool>) -> QueryResult<()> {
let conn: &SqliteConnection = &pool.get().unwrap();
diesel::delete(links.find(d_id)).execute(conn)?;
Ok(())
}
}
/// Queries affecting the `texts` table
pub mod texts {
use crate::models::texts::*;
use crate::schema::texts::dsl::*;
use crate::schema::texts::table;
use crate::Pool;
use actix_web::web::Data;
use diesel::prelude::*;
use diesel::result::QueryResult;
/// SELECT a single text entry given its id
pub fn find(g_id: i32, pool: Data<Pool>) -> QueryResult<Text> {
let conn: &SqliteConnection = &pool.get().unwrap();
texts.find(g_id).first::<Text>(conn)
}
/// INSERT a text entry
pub fn insert(p_id: i32, p_contents: &str, pool: Data<Pool>) -> QueryResult<Text> {
let conn: &SqliteConnection = &pool.get().unwrap();
let new_text = NewText {
id: p_id,
contents: p_contents,
};
diesel::insert_into(table).values(&new_text).execute(conn)?;
find(p_id, pool)
}
/// UPDATE a text entry
pub fn update(
p_id: i32,
new_id: Option<i32>,
new_contents: Option<&str>,
pool: Data<Pool>,
) -> QueryResult<Text> {
let conn: &SqliteConnection = &pool.get().unwrap();
let text = find(p_id, pool)?;
let query = diesel::update(&text);
let time_update = updated.eq(chrono::Utc::now().timestamp() as i32);
match (new_id, new_contents) {
(Some(new_id), Some(new_contents)) => {
query
.set((id.eq(new_id), contents.eq(new_contents), time_update))
.execute(conn)?;
}
(Some(new_id), None) => {
query.set((id.eq(new_id), time_update)).execute(conn)?;
}
(None, Some(new_contents)) => {
query
.set((contents.eq(new_contents), time_update))
.execute(conn)?;
}
(None, None) => (),
}
Ok(text)
}
/// DELETE a text entry
pub fn delete(d_id: i32, pool: Data<Pool>) -> QueryResult<()> {
let conn: &SqliteConnection = &pool.get().unwrap();
diesel::delete(texts.find(d_id)).execute(conn)?;
Ok(())
}
}

28
src/schema.rs Normal file
View File

@ -0,0 +1,28 @@
table! {
files (id) {
id -> Integer,
filepath -> Text,
created -> Integer,
updated -> Integer,
}
}
table! {
links (id) {
id -> Integer,
forward -> Text,
created -> Integer,
updated -> Integer,
}
}
table! {
texts (id) {
id -> Integer,
contents -> Text,
created -> Integer,
updated -> Integer,
}
}
allow_tables_to_appear_in_same_query!(files, links, texts,);