Upgrade Diesel 1.x to 2.x and move the db to sqlite

master
kirbylife 2025-04-11 00:41:14 -06:00
parent 031abd96ce
commit df669e8b78
14 changed files with 54 additions and 88 deletions
migrations
00000000000000_diesel_initial_setup
2022-12-22-062417_create_posts
2025-04-11-054642_create_db

7
.gitignore vendored
View File

@ -12,4 +12,9 @@ proyectos
Rocket.toml
# Certificates
*.pem
*.pem
# Sqlite database
*.db
*.sqlite
*.sqlite3

View File

@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
rocket = { version = "0.5.0", features = ["secrets"] }
rocket_dyn_templates = { version = "0.1.0", features = ["tera"] }
diesel = { version = "1.0.0", features = ["postgres", "chrono"] }
diesel = { version = "2.0.0", features = ["sqlite", "chrono", "returning_clauses_for_sqlite_3_35"] }
dotenv = "0.15.0"
rand = "0.8.5"
chrono = { version = "0.4.9", features = ["serde"] }

View File

@ -1,6 +0,0 @@
-- This file was automatically created by Diesel to setup helper functions
-- and other internal bookkeeping. This file is safe to edit, any future
-- changes will be added to existing projects as new migrations.
DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
DROP FUNCTION IF EXISTS diesel_set_updated_at();

View File

@ -1,36 +0,0 @@
-- This file was automatically created by Diesel to setup helper functions
-- and other internal bookkeeping. This file is safe to edit, any future
-- changes will be added to existing projects as new migrations.
-- Sets up a trigger for the given table to automatically set a column called
-- `updated_at` whenever the row is modified (unless `updated_at` was included
-- in the modified columns)
--
-- # Example
--
-- ```sql
-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
--
-- SELECT diesel_manage_updated_at('users');
-- ```
CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
BEGIN
EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
BEGIN
IF (
NEW IS DISTINCT FROM OLD AND
NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
) THEN
NEW.updated_at := current_timestamp;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

View File

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

View File

@ -1,10 +0,0 @@
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title VARCHAR NOT NULL,
content TEXT NOT NULL,
published BOOLEAN NOT NULL DEFAULT 'f',
views integer NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
)

View File

@ -0,0 +1 @@
-- This file should undo anything in `up.sql`

View File

@ -0,0 +1,9 @@
CREATE TABLE posts (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL,
published BOOLEAN NOT NULL DEFAULT 0,
views INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

View File

@ -50,7 +50,7 @@ fn login(cookies: &CookieJar<'_>, login: Form<Login>) -> Redirect {
}
#[get("/panel")]
fn panel(cookies: &CookieJar<'_>) -> Result<Template, Redirect> {
fn panel(cookies: &CookieJar<'_>) -> Result<Template, Box<Redirect>> {
let password = env::var("admin_pass").expect("admin_pass not setted");
match cookies.get_private("user") {
@ -62,15 +62,15 @@ fn panel(cookies: &CookieJar<'_>) -> Result<Template, Redirect> {
Ok(Template::render("admin/panel", context))
} else {
Err(Redirect::to("/admin"))
Err(Box::new(Redirect::to("/admin")))
}
}
None => Err(Redirect::to("/admin")),
None => Err(Box::new(Redirect::to("/admin"))),
}
}
#[get("/add_post")]
fn add_post(cookies: &CookieJar<'_>) -> Result<Template, Redirect> {
fn add_post(cookies: &CookieJar<'_>) -> Result<Template, Box<Redirect>> {
let password = env::var("admin_pass").expect("admin_pass not setted");
match cookies.get_private("user") {
@ -80,10 +80,10 @@ fn add_post(cookies: &CookieJar<'_>) -> Result<Template, Redirect> {
Ok(Template::render("admin/add_post", context))
} else {
Err(Redirect::to("/admin"))
Err(Box::new(Redirect::to("/admin")))
}
}
None => Err(Redirect::to("/admin")),
None => Err(Box::new(Redirect::to("/admin"))),
}
}
@ -107,7 +107,7 @@ fn write_add_post(cookies: &CookieJar<'_>, post: Form<NewPost>) -> Redirect {
}
#[get("/edit_post/<id>")]
fn edit_post(cookies: &CookieJar<'_>, id: i32) -> Result<Template, Redirect> {
fn edit_post(cookies: &CookieJar<'_>, id: i32) -> Result<Template, Box<Redirect>> {
let password = env::var("admin_pass").expect("admin_pass not setted");
match cookies.get_private("user") {
@ -119,10 +119,10 @@ fn edit_post(cookies: &CookieJar<'_>, id: i32) -> Result<Template, Redirect> {
Ok(Template::render("admin/edit_post", context))
} else {
Err(Redirect::to("/admin"))
Err(Box::new(Redirect::to("/admin")))
}
}
None => Err(Redirect::to("/admin")),
None => Err(Box::new(Redirect::to("/admin"))),
}
}

View File

@ -1,17 +1,18 @@
use chrono::prelude::Utc;
use diesel::pg::PgConnection;
use diesel::sqlite::SqliteConnection;
use diesel::result::Error;
use diesel::Connection;
use diesel::ExpressionMethods;
use diesel::QueryDsl;
use diesel::RunQueryDsl;
use diesel::SelectableHelper;
use std::env;
use std::vec::Vec;
fn establish_connection() -> PgConnection {
fn establish_connection() -> SqliteConnection {
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL not setted");
PgConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
SqliteConnection::establish(&database_url).unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}
pub mod posts {
@ -23,24 +24,24 @@ pub mod posts {
pub fn get_posts(page: Option<u64>) -> (Vec<Post>, i64) {
use crate::schema::posts::dsl::*;
let connection = establish_connection();
let connection = &mut establish_connection();
let visible_posts = posts.order(created_at.desc());
let visible_posts = match page {
Some(number_page) => visible_posts
.filter(published.eq(true))
.limit(MAX_POSTS_PER_PAGE as i64)
.offset((MAX_POSTS_PER_PAGE * (number_page - 1)) as i64)
.load::<Post>(&connection)
.load::<Post>(connection)
.expect("Error loading posts"),
None => visible_posts
.load::<Post>(&connection)
.load::<Post>(connection)
.expect("Error loading posts"),
};
let number_of_posts: i64 = posts
.filter(published.eq(true))
.count()
.get_result(&connection)
.get_result(connection)
.expect("Error counting the posts");
(visible_posts, number_of_posts)
@ -49,24 +50,25 @@ pub mod posts {
pub fn get_post(id_number: i32) -> Result<Post, Error> {
use crate::schema::posts::dsl::*;
let connection = establish_connection();
let post = posts.find(id_number).first(&connection);
let connection = &mut establish_connection();
posts.find(id_number).first(connection)
post
}
pub fn add_post(new_post: &NewPost) -> Result<Post, Error> {
use crate::schema::posts;
let connection = establish_connection();
let connection = &mut establish_connection();
diesel::insert_into(posts::table)
.values(new_post)
.get_result(&connection)
.returning(Post::as_returning())
.get_result(connection)
}
pub fn edit_post(updated_id: i32, new_post: &NewPost) -> Result<Post, Error> {
use crate::schema::posts::dsl::*;
let connection = establish_connection();
let connection = &mut establish_connection();
let date = Utc::now().naive_utc();
@ -77,16 +79,17 @@ pub mod posts {
published.eq(&new_post.published),
updated_at.eq(&date),
))
.get_result(&connection)
.returning(Post::as_returning())
.get_result(connection)
}
pub fn add_visit(post_id: i32) {
use crate::schema::posts::dsl::*;
let connection = establish_connection();
let connection = &mut establish_connection();
diesel::update(posts.filter(id.eq(post_id)))
.set(views.eq(views + 1))
.execute(&connection)
.execute(connection)
.unwrap();
}
}

View File

@ -1,6 +1,5 @@
mod schema;
#[macro_use]
extern crate diesel;
#[macro_use]
@ -22,7 +21,7 @@ use std::vec::Vec;
static BOTS: OnceCell<Bots> = OnceCell::const_new();
async fn is_bot(ua: &String) -> bool {
async fn is_bot(ua: &str) -> bool {
let bots = BOTS.get_or_init(|| async { Bots::default() }).await;
bots.is_bot(ua)
}

View File

@ -59,7 +59,7 @@ pub fn ascii_table(raw_table: String) -> String {
let index_subrow = index / row.len();
let index_col = index % row.len();
let text = if let Some(col) = row.get(index_col) {
if let Some(&ref text) = col.get(index_subrow) {
if let Some(text) = col.get(index_subrow) {
text
} else {
&String::from("")

View File

@ -3,7 +3,9 @@ use serde::Serialize;
use super::schema::posts;
#[derive(Queryable, Serialize)]
#[derive(Queryable, Selectable, Serialize)]
#[diesel(table_name = posts)]
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
pub struct Post {
pub id: i32,
pub title: String,
@ -15,7 +17,7 @@ pub struct Post {
}
#[derive(FromForm, Insertable, Debug)]
#[table_name = "posts"]
#[diesel(table_name = posts)]
pub struct NewPost {
pub title: String,
pub content: String,

View File

@ -2,11 +2,11 @@
diesel::table! {
posts (id) {
id -> Int4,
title -> Varchar,
id -> Integer,
title -> Text,
content -> Text,
published -> Bool,
views -> Int4,
views -> Integer,
created_at -> Timestamp,
updated_at -> Timestamp,
}