Add files list route

This commit is contained in:
Raphaël Thériault 2019-10-08 14:17:08 -04:00
parent 6ebc25235e
commit a8f926f66e
9 changed files with 114 additions and 43 deletions

1
Cargo.lock generated
View File

@ -574,6 +574,7 @@ dependencies = [
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"dotenv 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libsqlite3-sys 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -9,9 +9,10 @@ actix-web = "1.0.8"
cfg-if = "0.1.10"
chrono = "0.4.9"
dirs = "2.0.2"
env_logger = "0.7.0"
futures = "0.1.29"
num_cpus = "1.10.1"
toml = "0.5.3"
env_logger = "0.7.0"
[dependencies.diesel]
version = "1.4.2"
features = ["r2d2", "sqlite"]

View File

@ -1,6 +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'))
created INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
updated INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
)

View File

@ -1,6 +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'))
created INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
updated INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
)

View File

@ -1,6 +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'))
created INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
updated INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
)

View File

@ -3,7 +3,6 @@ extern crate diesel;
#[macro_use]
extern crate serde;
use chrono::{DateTime, Utc};
use diesel::r2d2::{self, ConnectionManager};
use diesel::sqlite::SqliteConnection;
@ -16,10 +15,12 @@ pub mod setup;
pub type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
/// Date and time range
type DateTimeRange = (Option<DateTime<Utc>>, Option<DateTime<Utc>>);
type DateTimeRange = (Option<i32>, Option<i32>);
/// Date and time range specifying ranges for creation and update
pub struct SelectRange {
created: DateTimeRange,
updated: DateTimeRange,
/// Creation time range
pub created: DateTimeRange,
/// Update time range
pub updated: DateTimeRange,
}

View File

@ -1,9 +1,14 @@
#[macro_use]
extern crate cfg_if;
#[macro_use]
extern crate serde;
use filite::queries;
use filite::setup::{self, Config};
use filite::{Pool, SelectRange};
use actix_web::{middleware, web, App, HttpServer, HttpResponse, Responder};
use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer, Responder};
use futures::Future;
use std::process;
#[cfg(not(debug_assertions))]
@ -34,6 +39,72 @@ fn init() -> Config {
})
}
/// Query string for SELECT queries
#[derive(Deserialize)]
struct SelectQuery {
/// Left creation bounder timestamp
cf: Option<i32>,
/// Right creation bounder timestamp
ct: Option<i32>,
/// Left update bounder timestamp
uf: Option<i32>,
/// Right update bounder timestamp
ut: Option<i32>,
/// Query size limit
limit: Option<i64>,
/// Whether to sort the results in ascending order
asc: Option<bool>,
/// Whether to sort the results by creation date
created: Option<bool>,
}
/// Filters for SELECT queries
struct SelectFilters {
/// Creation and update date and time ranges
range: SelectRange,
/// Query size limit
limit: Option<i64>,
/// Whether to sort the results in ascending order
order_asc: bool,
/// Whether to sort the results by creation date
order_created: bool,
}
impl From<SelectQuery> for SelectFilters {
fn from(query: SelectQuery) -> Self {
SelectFilters {
range: SelectRange {
created: (query.cf, query.ct),
updated: (query.uf, query.ut),
},
limit: query.limit,
order_asc: query.asc.unwrap_or(false),
order_created: query.created.unwrap_or(false),
}
}
}
/// GET multiple file entries
fn get_files(
query: web::Query<SelectQuery>,
pool: web::Data<Pool>,
) -> impl Future<Item = HttpResponse, Error = Error> {
let filters = SelectFilters::from(query.into_inner());
web::block(move || {
queries::files::select(
filters.range,
filters.limit,
filters.order_asc,
filters.order_created,
pool,
)
})
.then(|result| match result {
Ok(files) => Ok(HttpResponse::Ok().json(files)),
Err(_) => Ok(HttpResponse::InternalServerError().into()),
})
}
fn index() -> impl Responder {
HttpResponse::Ok().body("Hello world!")
}
@ -60,6 +131,7 @@ fn main() {
.data(pool.clone())
.wrap(middleware::Logger::default())
.route("/", web::get().to(index))
.service(web::resource("/f").route(web::get().to_async(get_files)))
})
.bind(&format!("localhost:{}", port))
.unwrap_or_else(|e| {

View File

@ -5,7 +5,7 @@ pub mod files {
use crate::schema::files;
/// An entry from the `files` table
#[derive(Queryable, Identifiable)]
#[derive(Queryable, Identifiable, Serialize)]
pub struct File {
/// Primary key, its radix 36 value is used as an url
pub id: i32,
@ -33,7 +33,7 @@ pub mod links {
use crate::schema::links;
/// An entry from the `links` table
#[derive(Queryable, Identifiable)]
#[derive(Queryable, Identifiable, Serialize)]
pub struct Link {
/// Primary key, its radix 36 value is used as an url
pub id: i32,
@ -61,7 +61,7 @@ pub mod texts {
use crate::schema::texts;
/// An entry from the `texts` table
#[derive(Queryable, Identifiable)]
#[derive(Queryable, Identifiable, Serialize)]
pub struct Text {
/// Primary key, its radix 36 value is used as an url
pub id: i32,

View File

@ -26,20 +26,16 @@ pub mod files {
let mut query = files.into_boxed();
if let Some(cf) = range.created.0 {
let timestamp = cf.timestamp() as i32;
query = query.filter(created.ge(timestamp));
query = query.filter(created.ge(cf));
}
if let Some(ct) = range.created.1 {
let timestamp = ct.timestamp() as i32;
query = query.filter(created.lt(timestamp));
query = query.filter(created.lt(ct));
}
if let Some(uf) = range.updated.0 {
let timestamp = uf.timestamp() as i32;
query = query.filter(updated.ge(timestamp));
query = query.filter(updated.ge(uf));
}
if let Some(ut) = range.updated.1 {
let timestamp = ut.timestamp() as i32;
query = query.filter(updated.lt(timestamp));
query = query.filter(updated.lt(ut));
}
if let Some(limit) = limit {
@ -53,6 +49,10 @@ pub mod files {
(true, true) => query.order(created.asc()),
};
if let Some(limit) = limit {
query = query.limit(limit);
}
query.load::<File>(conn)
}
@ -139,20 +139,16 @@ pub mod links {
let mut query = links.into_boxed();
if let Some(cf) = range.created.0 {
let timestamp = cf.timestamp() as i32;
query = query.filter(created.ge(timestamp));
query = query.filter(created.ge(cf));
}
if let Some(ct) = range.created.1 {
let timestamp = ct.timestamp() as i32;
query = query.filter(created.lt(timestamp));
query = query.filter(created.lt(ct));
}
if let Some(uf) = range.updated.0 {
let timestamp = uf.timestamp() as i32;
query = query.filter(updated.ge(timestamp));
query = query.filter(updated.ge(uf));
}
if let Some(ut) = range.updated.1 {
let timestamp = ut.timestamp() as i32;
query = query.filter(updated.lt(timestamp));
query = query.filter(updated.lt(ut));
}
if let Some(limit) = limit {
@ -166,6 +162,10 @@ pub mod links {
(true, true) => query.order(created.asc()),
};
if let Some(limit) = limit {
query = query.limit(limit);
}
query.load::<Link>(conn)
}
@ -250,24 +250,16 @@ pub mod texts {
let mut query = texts.into_boxed();
if let Some(cf) = range.created.0 {
let timestamp = cf.timestamp() as i32;
query = query.filter(created.ge(timestamp));
query = query.filter(created.ge(cf));
}
if let Some(ct) = range.created.1 {
let timestamp = ct.timestamp() as i32;
query = query.filter(created.lt(timestamp));
query = query.filter(created.lt(ct));
}
if let Some(uf) = range.updated.0 {
let timestamp = uf.timestamp() as i32;
query = query.filter(updated.ge(timestamp));
query = query.filter(updated.ge(uf));
}
if let Some(ut) = range.updated.1 {
let timestamp = ut.timestamp() as i32;
query = query.filter(updated.lt(timestamp));
}
if let Some(limit) = limit {
query = query.limit(limit);
query = query.filter(updated.lt(ut));
}
query = match (order_asc, order_created) {
@ -277,6 +269,10 @@ pub mod texts {
(true, true) => query.order(created.asc()),
};
if let Some(limit) = limit {
query = query.limit(limit);
}
query.load::<Text>(conn)
}