Modularize, Model trait, list_owners
This commit is contained in:
46
src/models/mod.rs
Normal file
46
src/models/mod.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use serde::Deserialize;
|
||||
use std::fmt;
|
||||
|
||||
pub mod model;
|
||||
pub mod owner;
|
||||
pub mod shop;
|
||||
|
||||
pub use model::Model;
|
||||
pub use owner::Owner;
|
||||
pub use shop::Shop;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub enum Order {
|
||||
Asc,
|
||||
Desc,
|
||||
}
|
||||
|
||||
impl fmt::Display for Order {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Order::Asc => "ASC",
|
||||
Order::Desc => "DESC",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ListParams {
|
||||
limit: Option<i64>,
|
||||
offset: Option<i64>,
|
||||
order_by: Option<String>,
|
||||
order: Option<Order>,
|
||||
}
|
||||
|
||||
impl ListParams {
|
||||
pub fn get_order_by(&self) -> String {
|
||||
let default_order_by = "updated_at".to_string();
|
||||
let order_by = self.order_by.as_ref().unwrap_or(&default_order_by);
|
||||
let order = self.order.as_ref().unwrap_or(&Order::Desc);
|
||||
format!("{} {}", order_by, order)
|
||||
}
|
||||
}
|
||||
28
src/models/model.rs
Normal file
28
src/models/model.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use async_trait::async_trait;
|
||||
use sqlx::postgres::PgPool;
|
||||
use url::Url;
|
||||
|
||||
use super::ListParams;
|
||||
|
||||
#[async_trait]
|
||||
pub trait Model
|
||||
where
|
||||
Self: std::marker::Sized,
|
||||
{
|
||||
fn resource_name() -> &'static str;
|
||||
fn pk(&self) -> Option<i32>;
|
||||
fn url(&self, api_url: &Url) -> Result<Url> {
|
||||
if let Some(pk) = self.pk() {
|
||||
Ok(api_url.join(&format!("/{}s/{}", Self::resource_name(), pk))?)
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"Cannot get URL for {} with no primary key",
|
||||
Self::resource_name()
|
||||
))
|
||||
}
|
||||
}
|
||||
async fn get(db: &PgPool, id: i32) -> Result<Self>;
|
||||
async fn save(self, db: &PgPool) -> Result<Self>;
|
||||
async fn list(db: &PgPool, list_params: ListParams) -> Result<Vec<Self>>;
|
||||
}
|
||||
81
src/models/owner.rs
Normal file
81
src/models/owner.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use chrono::prelude::*;
|
||||
use ipnetwork::IpNetwork;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::postgres::PgPool;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::ListParams;
|
||||
use super::Model;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Owner {
|
||||
pub id: Option<i32>,
|
||||
pub name: String,
|
||||
pub api_key: Uuid,
|
||||
pub ip_address: Option<IpNetwork>,
|
||||
pub mod_version: String,
|
||||
pub created_at: Option<NaiveDateTime>,
|
||||
pub updated_at: Option<NaiveDateTime>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Model for Owner {
|
||||
fn resource_name() -> &'static str {
|
||||
"owner"
|
||||
}
|
||||
|
||||
fn pk(&self) -> Option<i32> {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn get(db: &PgPool, id: i32) -> Result<Self> {
|
||||
let timer = std::time::Instant::now();
|
||||
let result = sqlx::query_as!(Self, "SELECT * FROM owners WHERE id = $1", id)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
let elapsed = timer.elapsed();
|
||||
debug!("SELECT * FROM owners ... {:.3?}", elapsed);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn save(self, db: &PgPool) -> Result<Self> {
|
||||
let timer = std::time::Instant::now();
|
||||
let result = sqlx::query_as!(
|
||||
Self,
|
||||
"INSERT INTO owners
|
||||
(name, api_key, ip_address, mod_version, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, now(), now())
|
||||
RETURNING *",
|
||||
self.name,
|
||||
self.api_key,
|
||||
self.ip_address,
|
||||
self.mod_version,
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
let elapsed = timer.elapsed();
|
||||
debug!("INSERT INTO owners ... {:.3?}", elapsed);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn list(db: &PgPool, list_params: ListParams) -> Result<Vec<Self>> {
|
||||
let timer = std::time::Instant::now();
|
||||
let result = sqlx::query_as!(
|
||||
Self,
|
||||
"SELECT * FROM owners
|
||||
ORDER BY $1
|
||||
LIMIT $2
|
||||
OFFSET $3",
|
||||
list_params.get_order_by(),
|
||||
list_params.limit.unwrap_or(10),
|
||||
list_params.offset.unwrap_or(0),
|
||||
)
|
||||
.fetch_all(db)
|
||||
.await?;
|
||||
let elapsed = timer.elapsed();
|
||||
debug!("SELECT * FROM owners ... {:.3?}", elapsed);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
86
src/models/shop.rs
Normal file
86
src/models/shop.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use chrono::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
use super::ListParams;
|
||||
use super::Model;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Shop {
|
||||
pub id: Option<i32>,
|
||||
pub name: String,
|
||||
pub owner_id: i32,
|
||||
pub description: String,
|
||||
pub is_not_sell_buy: bool,
|
||||
pub sell_buy_list_id: i32,
|
||||
pub vendor_id: i32,
|
||||
pub vendor_gold: i32,
|
||||
pub created_at: Option<NaiveDateTime>,
|
||||
pub updated_at: Option<NaiveDateTime>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Model for Shop {
|
||||
fn resource_name() -> &'static str {
|
||||
"shop"
|
||||
}
|
||||
|
||||
fn pk(&self) -> Option<i32> {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn get(db: &PgPool, id: i32) -> Result<Self> {
|
||||
let timer = std::time::Instant::now();
|
||||
let result = sqlx::query_as!(Self, "SELECT * FROM shops WHERE id = $1", id)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
let elapsed = timer.elapsed();
|
||||
debug!("SELECT * FROM shops ... {:.3?}", elapsed);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn save(self, db: &PgPool) -> Result<Self> {
|
||||
let timer = std::time::Instant::now();
|
||||
let result = sqlx::query_as!(
|
||||
Self,
|
||||
"INSERT INTO shops
|
||||
(name, owner_id, description, is_not_sell_buy, sell_buy_list_id, vendor_id,
|
||||
vendor_gold, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, now(), now())
|
||||
RETURNING *",
|
||||
self.name,
|
||||
self.owner_id,
|
||||
self.description,
|
||||
self.is_not_sell_buy,
|
||||
self.sell_buy_list_id,
|
||||
self.vendor_id,
|
||||
self.vendor_gold,
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
let elapsed = timer.elapsed();
|
||||
debug!("INSERT INTO shops ... {:.3?}", elapsed);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn list(db: &PgPool, list_params: ListParams) -> Result<Vec<Self>> {
|
||||
let timer = std::time::Instant::now();
|
||||
let result = sqlx::query_as!(
|
||||
Self,
|
||||
"SELECT * FROM shops
|
||||
ORDER BY $1
|
||||
LIMIT $2
|
||||
OFFSET $3",
|
||||
list_params.get_order_by(),
|
||||
list_params.limit.unwrap_or(10),
|
||||
list_params.offset.unwrap_or(0),
|
||||
)
|
||||
.fetch_all(db)
|
||||
.await?;
|
||||
let elapsed = timer.elapsed();
|
||||
debug!("SELECT * FROM shops ... {:.3?}", elapsed);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user