mirror of
https://github.com/flibusta-apps/library_updater.git
synced 2026-03-03 15:10:53 +01:00
Add simple rust implementation
This commit is contained in:
864
src/types.rs
Normal file
864
src/types.rs
Normal file
@@ -0,0 +1,864 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
use sql_parse::Expression;
|
||||
use tokio_postgres::Client;
|
||||
|
||||
use crate::utils::{fix_annotation_text, parse_lang, remove_wrong_chars};
|
||||
|
||||
pub trait FromVecExpression<T> {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> T;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Update {
|
||||
async fn before_update(
|
||||
client: &Client,
|
||||
) -> Result<(), Box<tokio_postgres::Error>>;
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Author {
|
||||
pub id: u64,
|
||||
pub last_name: String,
|
||||
pub first_name: String,
|
||||
pub middle_name: String,
|
||||
}
|
||||
|
||||
impl FromVecExpression<Author> for Author {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> Author {
|
||||
Author {
|
||||
id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("Author.id"),
|
||||
},
|
||||
last_name: match &value[3] {
|
||||
sql_parse::Expression::String(v) => remove_wrong_chars(&v.value),
|
||||
_ => panic!("Author.last_name"),
|
||||
},
|
||||
first_name: match &value[1] {
|
||||
sql_parse::Expression::String(v) => remove_wrong_chars(&v.value),
|
||||
_ => panic!("Author.first_name"),
|
||||
},
|
||||
middle_name: match &value[2] {
|
||||
sql_parse::Expression::String(v) => remove_wrong_chars(&v.value),
|
||||
_ => panic!("Author.middle_name"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for Author {
|
||||
async fn before_update(
|
||||
client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"
|
||||
CREATE OR REPLACE FUNCTION update_author(
|
||||
source_ smallint, remote_id_ int, first_name_ varchar, last_name_ varchar, middle_name_ varchar
|
||||
) RETURNS void AS $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT * FROM authors WHERE source = source_ AND remote_id = remote_id_) THEN
|
||||
UPDATE authors SET first_name = first_name_, last_name = last_name_, middle_name = middle_name_
|
||||
WHERE source = source_ AND remote_id = remote_id_;
|
||||
RETURN;
|
||||
END IF;
|
||||
INSERT INTO authors (source, remote_id, first_name, last_name, middle_name)
|
||||
VALUES (source_, remote_id_, first_name_, last_name_, middle_name_);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
"
|
||||
, &[]).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"SELECT update_author($1, $2, cast($3 as varchar), cast($4 as varchar), cast($5 as varchar));",
|
||||
&[&source_id, &(self.id as i32), &self.first_name, &self.last_name, &self.middle_name]
|
||||
).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Book {
|
||||
pub id: u64,
|
||||
pub title: String,
|
||||
pub lang: String,
|
||||
pub file_type: String,
|
||||
pub uploaded: NaiveDate,
|
||||
pub is_deleted: bool,
|
||||
pub pages: u64,
|
||||
}
|
||||
|
||||
impl FromVecExpression<Book> for Book {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> Book {
|
||||
Book {
|
||||
id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("Book.id"),
|
||||
},
|
||||
title: match &value[3] {
|
||||
sql_parse::Expression::String(v) => remove_wrong_chars(&v.value),
|
||||
_ => panic!("Book.title"),
|
||||
},
|
||||
lang: match &value[5] {
|
||||
sql_parse::Expression::String(v) => parse_lang(&v.value),
|
||||
_ => panic!("Book.lang"),
|
||||
},
|
||||
file_type: match &value[8] {
|
||||
sql_parse::Expression::String(v) => v.value.to_string(),
|
||||
_ => panic!("Book.file_type"),
|
||||
},
|
||||
uploaded: match &value[2] {
|
||||
sql_parse::Expression::String(v) => {
|
||||
NaiveDateTime::parse_from_str(&v.value.to_string(), "%Y-%m-%d %H:%M:%S")
|
||||
.unwrap()
|
||||
.date()
|
||||
}
|
||||
_ => panic!("Book.uploaded"),
|
||||
},
|
||||
is_deleted: match &value[11] {
|
||||
sql_parse::Expression::String(v) => v.value == "1",
|
||||
_ => panic!("Book.is_deleted"),
|
||||
},
|
||||
pages: match &value[20] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("Book.id"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for Book {
|
||||
async fn before_update(
|
||||
client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"
|
||||
CREATE OR REPLACE FUNCTION update_book(
|
||||
source_ smallint, remote_id_ int, title_ varchar, lang_ varchar,
|
||||
file_type_ varchar, uploaded_ date, is_deleted_ boolean, pages_ int
|
||||
) RETURNS void AS $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT * FROM books WHERE source = source_ AND remote_id = remote_id_) THEN
|
||||
UPDATE books SET title = title_, lang = lang_, file_type = file_type_,
|
||||
uploaded = uploaded_, is_deleted = is_deleted, pages = pages_
|
||||
WHERE source = source_ AND remote_id = remote_id_;
|
||||
RETURN;
|
||||
END IF;
|
||||
INSERT INTO books (source, remote_id, title, lang, file_type, uploaded, is_deleted, pages)
|
||||
VALUES (source_, remote_id_, title_, lang_, file_type_, uploaded_, is_deleted_, pages_);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
"
|
||||
, &[]).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"SELECT update_book($1, $2, cast($3 as varchar), cast($4 as varchar), cast($5 as varchar), $6, $7, $8);",
|
||||
&[&source_id, &(self.id as i32), &self.title, &self.lang, &self.file_type, &self.uploaded, &self.is_deleted, &(self.pages as i32)]
|
||||
).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BookAuthor {
|
||||
pub book_id: u64,
|
||||
pub author_id: u64,
|
||||
// TODO: position
|
||||
}
|
||||
|
||||
impl FromVecExpression<BookAuthor> for BookAuthor {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> BookAuthor {
|
||||
BookAuthor {
|
||||
book_id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("BookAuthor.book_id"),
|
||||
},
|
||||
author_id: match &value[1] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("BookAuthor.author_id"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for BookAuthor {
|
||||
async fn before_update(
|
||||
client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"
|
||||
CREATE OR REPLACE FUNCTION update_book_author(source_ smallint, book_ integer, author_ integer) RETURNS void AS $$
|
||||
DECLARE
|
||||
book_id integer := -1;
|
||||
author_id integer := -1;
|
||||
BEGIN
|
||||
SELECT id INTO book_id FROM books WHERE source = source_ AND remote_id = book_;
|
||||
SELECT id INTO author_id FROM authors WHERE source = source_ AND remote_id = author_;
|
||||
IF EXISTS (SELECT * FROM book_authors WHERE book = book_id AND author = author_id) THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
INSERT INTO book_authors (book, author) VALUES (book_id, author_id);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
"
|
||||
, &[]).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client
|
||||
.execute(
|
||||
"SELECT update_book_author($1, $2, $3);",
|
||||
&[&source_id, &(self.book_id as i32), &(self.author_id as i32)],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Translator {
|
||||
pub book_id: u64,
|
||||
pub author_id: u64,
|
||||
pub position: u64,
|
||||
}
|
||||
|
||||
impl FromVecExpression<Translator> for Translator {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> Translator {
|
||||
Translator {
|
||||
book_id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("Translator.book_id"),
|
||||
},
|
||||
author_id: match &value[1] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("Translator.author_id"),
|
||||
},
|
||||
position: match &value[2] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("Translator.pos"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for Translator {
|
||||
async fn before_update(
|
||||
client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"
|
||||
CREATE OR REPLACE FUNCTION update_translation(source_ smallint, book_ integer, author_ integer, position_ smallint) RETURNS void AS $$
|
||||
DECLARE
|
||||
book_id integer := -1;
|
||||
author_id integer := -1;
|
||||
BEGIN
|
||||
SELECT id INTO book_id FROM books WHERE source = source_ AND remote_id = book_;
|
||||
SELECT id INTO author_id FROM authors WHERE source = source_ AND remote_id = author_;
|
||||
IF EXISTS (SELECT * FROM translations WHERE book = book_id AND author = author_id) THEN
|
||||
UPDATE translations SET position = position_
|
||||
WHERE book = book_id AND author = author_id;
|
||||
RETURN;
|
||||
END IF;
|
||||
INSERT INTO translations (book, author, position) VALUES (book_id, author_id, position_);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
"
|
||||
, &[]).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client
|
||||
.execute(
|
||||
"SELECT update_translation($1, $2, $3, $4);",
|
||||
&[
|
||||
&source_id,
|
||||
&(self.book_id as i32),
|
||||
&(self.author_id as i32),
|
||||
&(self.position as i16),
|
||||
],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Sequence {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl FromVecExpression<Sequence> for Sequence {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> Sequence {
|
||||
Sequence {
|
||||
id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("Sequence.id"),
|
||||
},
|
||||
name: match &value[1] {
|
||||
sql_parse::Expression::String(v) => remove_wrong_chars(&v.value),
|
||||
_ => panic!("Sequence.name"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for Sequence {
|
||||
async fn before_update(
|
||||
client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"
|
||||
CREATE OR REPLACE FUNCTION update_sequences(source_ smallint, remote_id_ int, name_ varchar) RETURNS void AS $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT * FROM sequences WHERE source = source_ AND remote_id = remote_id_) THEN
|
||||
UPDATE sequences SET name = name_ WHERE source = source_ AND remote_id = remote_id_;
|
||||
RETURN;
|
||||
END IF;
|
||||
INSERT INTO sequences (source, remote_id, name) VALUES (source_, remote_id_, name_);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
"
|
||||
, &[]).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client
|
||||
.execute(
|
||||
"SELECT update_sequences($1, $2, cast($3 as varchar));",
|
||||
&[&source_id, &(self.id as i32), &self.name],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SequenceInfo {
|
||||
pub book_id: u64,
|
||||
pub sequence_id: u64,
|
||||
pub position: i64,
|
||||
}
|
||||
|
||||
impl FromVecExpression<SequenceInfo> for SequenceInfo {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> SequenceInfo {
|
||||
SequenceInfo {
|
||||
book_id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("SequenceInfo.book_id"),
|
||||
},
|
||||
sequence_id: match &value[1] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("SequenceInfo.sequence_id"),
|
||||
},
|
||||
position: match &value[2] {
|
||||
sql_parse::Expression::Integer(v) => v.0.try_into().unwrap(),
|
||||
sql_parse::Expression::Unary {
|
||||
op,
|
||||
op_span: _,
|
||||
operand,
|
||||
} => match (op, operand.as_ref()) {
|
||||
(sql_parse::UnaryOperator::Minus, Expression::Integer(v)) => {
|
||||
let value: i64 = (v.0).try_into().unwrap();
|
||||
-value
|
||||
}
|
||||
(_, _) => panic!("SequenceInfo.position = {:?}", &value[2]),
|
||||
},
|
||||
_ => panic!("SequenceInfo.position = {:?}", &value[2]),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for SequenceInfo {
|
||||
async fn before_update(
|
||||
client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"
|
||||
CREATE OR REPLACE FUNCTION update_book_sequence(source_ smallint, book_ integer, sequence_ integer, position_ smallint) RETURNS void AS $$
|
||||
DECLARE
|
||||
book_id integer := -1;
|
||||
sequence_id integer := -1;
|
||||
BEGIN
|
||||
SELECT id INTO book_id FROM books WHERE source = source_ AND remote_id = book_;
|
||||
SELECT id INTO sequence_id FROM sequences WHERE source = source_ AND remote_id = sequence_;
|
||||
IF EXISTS (SELECT * FROM book_sequences WHERE book = book_id AND sequence = sequence_id) THEN
|
||||
UPDATE book_sequences SET position = position_ WHERE book = book_id AND sequence = sequence_id;
|
||||
RETURN;
|
||||
END IF;
|
||||
INSERT INTO book_sequences (book, sequence, position) VALUES (book_id, sequence_id, position_);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
"
|
||||
, &[]).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client
|
||||
.execute(
|
||||
"SELECT update_book_sequence($1, $2, $3, $4);",
|
||||
&[
|
||||
&source_id,
|
||||
&(self.book_id as i32),
|
||||
&(self.sequence_id as i32),
|
||||
&(self.position as i16),
|
||||
],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BookAnnotation {
|
||||
pub book_id: u64,
|
||||
pub title: String,
|
||||
pub body: Option<String>,
|
||||
}
|
||||
|
||||
impl FromVecExpression<BookAnnotation> for BookAnnotation {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> BookAnnotation {
|
||||
BookAnnotation {
|
||||
book_id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("BookAnnotation.book_id"),
|
||||
},
|
||||
title: match &value[2] {
|
||||
sql_parse::Expression::String(v) => v.value.to_string(),
|
||||
_ => panic!("BookAnnotation.title"),
|
||||
},
|
||||
body: match &value[3] {
|
||||
sql_parse::Expression::String(v) => Some(fix_annotation_text(&v.value)),
|
||||
sql_parse::Expression::Null(_) => None,
|
||||
_ => panic!("BookAnnotation.body"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for BookAnnotation {
|
||||
async fn before_update(
|
||||
client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"
|
||||
CREATE OR REPLACE FUNCTION update_book_annotation(source_ smallint, book_ integer, title_ varchar, text_ text) RETURNS void AS $$
|
||||
DECLARE
|
||||
book_id integer := -1;
|
||||
BEGIN
|
||||
SELECT id INTO book_id FROM books WHERE source = source_ AND remote_id = book_;
|
||||
IF EXISTS (SELECT * FROM book_annotations WHERE book = book_id) THEN
|
||||
UPDATE book_annotations SET title = title_, text = text_ WHERE book = book_id;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
IF book_id IS NULL THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
INSERT INTO book_annotations (book, title, text) VALUES (book_id, title_, text_);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
"
|
||||
, &[]).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client
|
||||
.execute(
|
||||
"SELECT update_book_annotation($1, $2, cast($3 as varchar), cast($4 as text));",
|
||||
&[&source_id, &(self.book_id as i32), &self.title, &self.body],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BookAnnotationPic {
|
||||
pub book_id: u64,
|
||||
pub file: String,
|
||||
}
|
||||
|
||||
impl FromVecExpression<BookAnnotationPic> for BookAnnotationPic {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> BookAnnotationPic {
|
||||
BookAnnotationPic {
|
||||
book_id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("BookAnnotationPic.book_id"),
|
||||
},
|
||||
file: match &value[2] {
|
||||
sql_parse::Expression::String(v) => v.value.to_string(),
|
||||
_ => panic!("BookAnnotationPic.file"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for BookAnnotationPic {
|
||||
async fn before_update(
|
||||
_client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client
|
||||
.execute(
|
||||
"\
|
||||
UPDATE book_annotations \
|
||||
SET file = cast($3 as varchar) \
|
||||
FROM (SELECT id FROM books WHERE source = $1 AND remote_id = $2) as books \
|
||||
WHERE book = books.id;\
|
||||
",
|
||||
&[&source_id, &(self.book_id as i32), &self.file],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AuthorAnnotation {
|
||||
pub author_id: u64,
|
||||
pub title: String,
|
||||
pub body: Option<String>,
|
||||
}
|
||||
|
||||
impl FromVecExpression<AuthorAnnotation> for AuthorAnnotation {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> AuthorAnnotation {
|
||||
AuthorAnnotation {
|
||||
author_id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("AuthorAnnotation.author_id"),
|
||||
},
|
||||
title: match &value[2] {
|
||||
sql_parse::Expression::String(v) => v.value.to_string(),
|
||||
_ => panic!("AuthorAnnotation.title"),
|
||||
},
|
||||
body: match &value[3] {
|
||||
sql_parse::Expression::String(v) => Some(fix_annotation_text(&v.value)),
|
||||
sql_parse::Expression::Null(_) => None,
|
||||
_ => panic!("AuthorAnnotation.body"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for AuthorAnnotation {
|
||||
async fn before_update(
|
||||
client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"
|
||||
CREATE OR REPLACE FUNCTION update_author_annotation(source_ smallint, author_ integer, title_ varchar, text_ text) RETURNS void AS $$
|
||||
DECLARE
|
||||
author_id integer := -1;
|
||||
BEGIN
|
||||
SELECT id INTO author_id FROM authors WHERE source = source_ AND remote_id = author_;
|
||||
IF EXISTS (SELECT * FROM author_annotations WHERE author = author_id) THEN
|
||||
UPDATE author_annotations SET title = title_, text = text_ WHERE author = author_id;
|
||||
RETURN;
|
||||
END IF;
|
||||
INSERT INTO author_annotations (author, title, text) VALUES (author_id, title_, text_);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
"
|
||||
, &[]).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client
|
||||
.execute(
|
||||
"SELECT update_author_annotation($1, $2, cast($3 as varchar), cast($4 as text));",
|
||||
&[
|
||||
&source_id,
|
||||
&(self.author_id as i32),
|
||||
&self.title,
|
||||
&self.body,
|
||||
],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AuthorAnnotationPic {
|
||||
pub author_id: u64,
|
||||
pub file: String,
|
||||
}
|
||||
|
||||
impl FromVecExpression<AuthorAnnotationPic> for AuthorAnnotationPic {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> AuthorAnnotationPic {
|
||||
AuthorAnnotationPic {
|
||||
author_id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("AuthorAnnotationPic.book_id"),
|
||||
},
|
||||
file: match &value[2] {
|
||||
sql_parse::Expression::String(v) => v.value.to_string(),
|
||||
_ => panic!("AuthorAnnotationPic.file"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for AuthorAnnotationPic {
|
||||
async fn before_update(
|
||||
_client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client
|
||||
.execute(
|
||||
"\
|
||||
UPDATE author_annotations \
|
||||
SET file = cast($3 as varchar) \
|
||||
FROM (SELECT id FROM authors WHERE source = $1 AND remote_id = $2) as authors \
|
||||
WHERE author = authors.id;",
|
||||
&[&source_id, &(self.author_id as i32), &self.file],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Genre {
|
||||
pub id: u64,
|
||||
pub code: String,
|
||||
pub description: String,
|
||||
pub meta: String,
|
||||
}
|
||||
|
||||
impl FromVecExpression<Genre> for Genre {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> Genre {
|
||||
Genre {
|
||||
id: match &value[0] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("Genre.id"),
|
||||
},
|
||||
code: match &value[1] {
|
||||
sql_parse::Expression::String(v) => v.value.to_string(),
|
||||
_ => panic!("Genre.code = {:?}", &value[1]),
|
||||
},
|
||||
description: match &value[2] {
|
||||
sql_parse::Expression::String(v) => v.value.to_string(),
|
||||
_ => panic!("Genre.description = {:?}", &value[2]),
|
||||
},
|
||||
meta: match &value[3] {
|
||||
sql_parse::Expression::String(v) => v.value.to_string(),
|
||||
_ => panic!("Genre.meta"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for Genre {
|
||||
async fn before_update(
|
||||
client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client.execute(
|
||||
"
|
||||
CREATE OR REPLACE FUNCTION update_book_sequence(source_ smallint, book_ integer, genre_ integer) RETURNS void AS $$
|
||||
DECLARE
|
||||
book_id integer := -1;
|
||||
genre_id integer := -1;
|
||||
BEGIN
|
||||
SELECT id INTO book_id FROM books WHERE source = source_ AND remote_id = book_;
|
||||
SELECT id INTO genre_id FROM genres WHERE source = source_ AND remote_id = genre_;
|
||||
IF EXISTS (SELECT * FROM book_genres WHERE book = book_id AND genre = genre_id) THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
INSERT INTO book_genres (book, genre) VALUES (book_id, genre_id);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
"
|
||||
, &[]).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client
|
||||
.execute(
|
||||
"SELECT update_genre($1, $2, cast($3 as varchar), cast($4 as varchar), cast($5 as varchar));",
|
||||
&[&source_id, &(self.id as i32), &self.code, &self.description, &self.meta]
|
||||
).await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BookGenre {
|
||||
pub book_id: u64,
|
||||
pub genre_id: u64,
|
||||
}
|
||||
|
||||
impl FromVecExpression<BookGenre> for BookGenre {
|
||||
fn from_vec_expression(value: &Vec<Expression>) -> BookGenre {
|
||||
BookGenre {
|
||||
book_id: match &value[1] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("BookGenre.book_id"),
|
||||
},
|
||||
genre_id: match &value[2] {
|
||||
sql_parse::Expression::Integer(v) => v.0,
|
||||
_ => panic!("BookGenre.genre_id"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Update for BookGenre {
|
||||
async fn before_update(
|
||||
_client: &Client
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&self,
|
||||
client: &Client,
|
||||
source_id: i16,
|
||||
) -> Result<(), Box<tokio_postgres::Error>> {
|
||||
match client
|
||||
.execute(
|
||||
"SELECT update_book_sequence($1, $2, $3);",
|
||||
&[&source_id, &(self.book_id as i32), &(self.genre_id as i32)],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user