Ported the project from sqlite to postgres

This commit is contained in:
Imbus 2023-11-14 08:40:45 +01:00
parent d397b5c1ed
commit 29c1fc8f82
23 changed files with 566 additions and 409 deletions

View file

@ -25,6 +25,9 @@ RUN cargo build --target x86_64-unknown-linux-musl --release
RUN rm src/*.rs RUN rm src/*.rs
ADD server /build-container ADD server /build-container
# Make sure sqlx reads from .sqlx directory
ENV SQLX_OFFLINE true
RUN cargo build --target x86_64-unknown-linux-musl --release RUN cargo build --target x86_64-unknown-linux-musl --release
# Final stage, copy the server binary and the frontend build # Final stage, copy the server binary and the frontend build

View file

@ -22,6 +22,9 @@ RUN cargo build --target x86_64-unknown-linux-musl
RUN rm src/*.rs RUN rm src/*.rs
ADD server /build-container ADD server /build-container
# Make sure sqlx reads from .sqlx directory
ENV SQLX_OFFLINE true
# Note that '--release' is missing here, so we build in debug mode # Note that '--release' is missing here, so we build in debug mode
RUN cargo build --target x86_64-unknown-linux-musl RUN cargo build --target x86_64-unknown-linux-musl

View file

@ -1,76 +1,60 @@
runtime := "podman"
# Builds a debug container and runs it # Builds a debug container and runs it
dev: start-debug dev: start-debug
@echo "Cd into client and run 'npm run dev' to start the client in dev mode." @echo "Cd into client and run 'npm run dev' to start the client in dev mode."
[private]
npm-install directory:
cd {{directory}} && npm install
# Builds the client with npm (result in client/dist)
[private]
npm-build directory: (npm-install directory)
cd {{directory}} && npm run build
@echo "Built client at {{directory}}/dist"
# Builds a debug container # Builds a debug container
[private] [private]
build-container-server-debug: build-container-server-debug:
{{runtime}} build -t fb-server-debug -f container/ContainerfileDebug . podman build -t fb-server-debug -f container/ContainerfileDebug .
# Builds a debug container and runs it # Builds a debug container and runs it
[private] [private]
start-debug: build-container-server-debug remove-podman-containers start-debug: start-postgres-dev clean-podman init-sqlx build-container-server-debug
{{runtime}} run -d -e DATABASE_URL=sqlite:debug.db -p 8080:8080 --name frostbyte-debug fb-server-debug podman network create fb_network --ignore
podman run -d --network fb_network -e DATABASE_URL=postgres://postgres:password@postgres:5432/frostbyte -p 8080:8080 --name frostbyte-debug fb-server-debug
@echo "Debug server started." @echo "Debug server started."
# Builds a release container # Builds a release container
[private] [private]
build-container-release: build-container-release:
{{runtime}} build -t fb-server -f container/Containerfile . podman build -t fb-server -f container/Containerfile .
# Builds a release container and runs it # Builds a release container and runs it
start-release: build-container-release remove-podman-containers start-release: start-postgres-dev clean-podman init-sqlx build-container-release
{{runtime}} network create fb_network --ignore podman network create fb_network --ignore
{{runtime}} run -d --network fb_network -e DATABASE_URL=sqlite:release.db -p 8080:8080 --name frostbyte fb-server podman run -d --network fb_network -e DATABASE_URL=postgres://postgres:password@postgres:5432/frostbyte -p 8080:8080 --name frostbyte fb-server
# Initializes the database, runs migrations and then prepares sqlx
init-sqlx: init-sqlx:
echo "DATABASE_URL=sqlite:debug.db" > server/.env echo "DATABASE_URL=postgres://postgres:password@localhost:5432/frostbyte" > server/.env
cd server && sqlx database create cd server && sqlx database create --connect-timeout 40 # Postgres takes a while to start up
cd server && sqlx migrate run cd server && sqlx migrate run --source migrations_pg
cd server && cargo sqlx prepare cd server && cargo sqlx prepare
# Removes and stops any containers related to the project # Starts a postgres container for development
[private] [private]
remove-podman-containers: start-postgres-dev:
{{runtime}} network rm -f fb_network podman rm -f postgres
{{runtime}} container rm -f frostbyte podman run --network fb_network --name postgres -e POSTGRES_PASSWORD=password -d -p 5432:5432 docker.io/postgres:16.1-alpine
{{runtime}} container rm -f frostbyte-debug
# Deletes everything podman related (even unrelated to the project) # Forcefully stops and removes the frostbyte container
[private] [private]
prune-podman: clean-podman:
{{runtime}} stop -a podman container rm -f frostbyte
{{runtime}} rm -af podman container rm -f frostbyte-debug
{{runtime}} image rm -af
{{runtime}} system prune -af # Forcefully removes the frostbyte images
{{runtime}} system reset --force [private]
clean-images:
podman image rm -f fb-server
podman image rm -f fb-server-debug
# Cleans up everything related to the project # Cleans up everything related to the project
clean: clean: clean-podman clean-images
{{runtime}} container rm -f frostbyte
{{runtime}} container rm -f frostbyte-debug
{{runtime}} image rm -f fb-server
{{runtime}} image rm -f fb-server-debug
rm -rf client/dist rm -rf client/dist
rm -rf client/node_modules rm -rf client/node_modules
rm -rf client-solid/dist rm -rf client-solid/dist
rm -rf client-solid/node_modules rm -rf client-solid/node_modules
rm -rf server/public rm -rf server/public
rm -rf server/target rm -rf server/target
@echo "Cleaned up! Make sure to run 'just nuke' to nuke everything podman related." @echo "Cleaned up! Make sure to clean up podman volumes and networks."
# Nukes everything. No mercy. Leave no trace.
nuke: clean prune-podman
@echo "Nuked everything! You're starting from scratch now."

View file

@ -1,20 +1,22 @@
{ {
"db_name": "SQLite", "db_name": "PostgreSQL",
"query": "SELECT username FROM users WHERE username = ?", "query": "SELECT username FROM users WHERE username = $1",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"name": "username",
"ordinal": 0, "ordinal": 0,
"name": "username",
"type_info": "Text" "type_info": "Text"
} }
], ],
"parameters": { "parameters": {
"Right": 1 "Left": [
"Text"
]
}, },
"nullable": [ "nullable": [
false false
] ]
}, },
"hash": "fdbb1cd2873a5c866faaf3a60185d1f98e14198655aa536c2227ef8d2c6b88e1" "hash": "16e84d577155f3c47fcb736bbad4dcaf05b21c79d47fe008e209191157f5697e"
} }

View file

@ -1,46 +1,46 @@
{ {
"db_name": "SQLite", "db_name": "PostgreSQL",
"query": "SELECT * FROM posts WHERE id = (SELECT MAX(id) FROM posts)", "query": "SELECT * FROM posts WHERE id = (SELECT MAX(id) FROM posts)",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"name": "id",
"ordinal": 0, "ordinal": 0,
"type_info": "Int64" "name": "id",
"type_info": "Int8"
}, },
{ {
"name": "user_id",
"ordinal": 1, "ordinal": 1,
"type_info": "Int64" "name": "user_id",
"type_info": "Int8"
}, },
{ {
"name": "content",
"ordinal": 2, "ordinal": 2,
"name": "content",
"type_info": "Text" "type_info": "Text"
}, },
{ {
"name": "upvotes",
"ordinal": 3, "ordinal": 3,
"type_info": "Int64" "name": "upvotes",
"type_info": "Int4"
}, },
{ {
"name": "downvotes",
"ordinal": 4, "ordinal": 4,
"type_info": "Int64" "name": "downvotes",
"type_info": "Int4"
}, },
{ {
"name": "created_at",
"ordinal": 5, "ordinal": 5,
"type_info": "Datetime" "name": "created_at",
"type_info": "Timestamp"
}, },
{ {
"name": "updated_at",
"ordinal": 6, "ordinal": 6,
"type_info": "Datetime" "name": "updated_at",
"type_info": "Timestamp"
} }
], ],
"parameters": { "parameters": {
"Right": 0 "Left": []
}, },
"nullable": [ "nullable": [
false, false,

View file

@ -1,20 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT id FROM users WHERE username = ?",
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Int64"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "2e61cd30a6cd3e0937dd096b4f94493e8bcb8c10687d0f8c0592fe38ed956fa6"
}

View file

@ -1,36 +1,38 @@
{ {
"db_name": "SQLite", "db_name": "PostgreSQL",
"query": "SELECT * FROM users WHERE username = ?", "query": "SELECT * FROM users WHERE username = $1",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"name": "id",
"ordinal": 0, "ordinal": 0,
"type_info": "Int64" "name": "id",
"type_info": "Int8"
}, },
{ {
"name": "username",
"ordinal": 1, "ordinal": 1,
"name": "username",
"type_info": "Text" "type_info": "Text"
}, },
{ {
"name": "password",
"ordinal": 2, "ordinal": 2,
"name": "password",
"type_info": "Text" "type_info": "Text"
}, },
{ {
"name": "created_at",
"ordinal": 3, "ordinal": 3,
"type_info": "Datetime" "name": "created_at",
"type_info": "Timestamp"
}, },
{ {
"name": "updated_at",
"ordinal": 4, "ordinal": 4,
"type_info": "Datetime" "name": "updated_at",
"type_info": "Timestamp"
} }
], ],
"parameters": { "parameters": {
"Right": 1 "Left": [
"Text"
]
}, },
"nullable": [ "nullable": [
false, false,
@ -40,5 +42,5 @@
false false
] ]
}, },
"hash": "98f4c0bfff04e07f5d0a46d48a31d24655826eebdf09c7f9f45d770df02035d3" "hash": "606364c79e0990deb07dfbe6c32b3d302d083ec5333f3a5ce04113c38a041100"
} }

View file

@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "INSERT INTO users (username, password) VALUES (?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "78ecd3bc5a999dc227a86556f0ce41065974104b735d96b3c5785480023bb60a"
}

View file

@ -1,10 +1,10 @@
{ {
"db_name": "SQLite", "db_name": "PostgreSQL",
"query": "INSERT INTO posts (user_id, content) VALUES (1, 'Hello world! The demo username is user and the password is pass.')", "query": "INSERT INTO posts (user_id, content) VALUES (1, 'Hello world! The demo username is user and the password is pass.')",
"describe": { "describe": {
"columns": [], "columns": [],
"parameters": { "parameters": {
"Right": 0 "Left": []
}, },
"nullable": [] "nullable": []
}, },

View file

@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO posts (user_id, content) VALUES ($1, $2)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Text"
]
},
"nullable": []
},
"hash": "a2835289cba16d38401e5324876508b8397ef7fbb9eb521ac3c5e57206eeecf7"
}

View file

@ -1,46 +1,46 @@
{ {
"db_name": "SQLite", "db_name": "PostgreSQL",
"query": "SELECT * FROM posts WHERE id = 1", "query": "SELECT * FROM posts WHERE id = 1",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"name": "id",
"ordinal": 0, "ordinal": 0,
"type_info": "Int64" "name": "id",
"type_info": "Int8"
}, },
{ {
"name": "user_id",
"ordinal": 1, "ordinal": 1,
"type_info": "Int64" "name": "user_id",
"type_info": "Int8"
}, },
{ {
"name": "content",
"ordinal": 2, "ordinal": 2,
"name": "content",
"type_info": "Text" "type_info": "Text"
}, },
{ {
"name": "upvotes",
"ordinal": 3, "ordinal": 3,
"type_info": "Int64" "name": "upvotes",
"type_info": "Int4"
}, },
{ {
"name": "downvotes",
"ordinal": 4, "ordinal": 4,
"type_info": "Int64" "name": "downvotes",
"type_info": "Int4"
}, },
{ {
"name": "created_at",
"ordinal": 5, "ordinal": 5,
"type_info": "Datetime" "name": "created_at",
"type_info": "Timestamp"
}, },
{ {
"name": "updated_at",
"ordinal": 6, "ordinal": 6,
"type_info": "Datetime" "name": "updated_at",
"type_info": "Timestamp"
} }
], ],
"parameters": { "parameters": {
"Right": 0 "Left": []
}, },
"nullable": [ "nullable": [
false, false,

View file

@ -1,46 +1,48 @@
{ {
"db_name": "SQLite", "db_name": "PostgreSQL",
"query": "SELECT * FROM posts WHERE id = ?", "query": "SELECT * FROM posts WHERE id = $1",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"name": "id",
"ordinal": 0, "ordinal": 0,
"type_info": "Int64" "name": "id",
"type_info": "Int8"
}, },
{ {
"name": "user_id",
"ordinal": 1, "ordinal": 1,
"type_info": "Int64" "name": "user_id",
"type_info": "Int8"
}, },
{ {
"name": "content",
"ordinal": 2, "ordinal": 2,
"name": "content",
"type_info": "Text" "type_info": "Text"
}, },
{ {
"name": "upvotes",
"ordinal": 3, "ordinal": 3,
"type_info": "Int64" "name": "upvotes",
"type_info": "Int4"
}, },
{ {
"name": "downvotes",
"ordinal": 4, "ordinal": 4,
"type_info": "Int64" "name": "downvotes",
"type_info": "Int4"
}, },
{ {
"name": "created_at",
"ordinal": 5, "ordinal": 5,
"type_info": "Datetime" "name": "created_at",
"type_info": "Timestamp"
}, },
{ {
"name": "updated_at",
"ordinal": 6, "ordinal": 6,
"type_info": "Datetime" "name": "updated_at",
"type_info": "Timestamp"
} }
], ],
"parameters": { "parameters": {
"Right": 1 "Left": [
"Int8"
]
}, },
"nullable": [ "nullable": [
false, false,
@ -52,5 +54,5 @@
false false
] ]
}, },
"hash": "da280dfbdfe992918eb4f25ca61c08fc01474c3753a63e05b02051f5c066abc2" "hash": "b6019471ff1989ef2f0658b0b34e683fdc706751e2bb69043544c9a4d08b5ba0"
} }

View file

@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "INSERT INTO posts (user_id, content) VALUES (?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "c2804e9c7bbd92dcddc34dd6f9d95a2598bb69984d6023e38eeea54454887b90"
}

View file

@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO users (username, password) VALUES ($1, $2)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "c936f44864dafe4660a736babd5f93050b7d35c66c0fe0c86f7b2dcdb7a1e3eb"
}

View file

@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id FROM users WHERE username = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "dd99e48b1572e25db38f03da95984fda1072913b29bb6b3753a0d351583dfff6"
}

View file

@ -1,46 +1,49 @@
{ {
"db_name": "SQLite", "db_name": "PostgreSQL",
"query": "SELECT * FROM posts ORDER BY created_at DESC LIMIT ? OFFSET ?", "query": "SELECT * FROM posts ORDER BY created_at DESC LIMIT $1 OFFSET $2",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"name": "id",
"ordinal": 0, "ordinal": 0,
"type_info": "Int64" "name": "id",
"type_info": "Int8"
}, },
{ {
"name": "user_id",
"ordinal": 1, "ordinal": 1,
"type_info": "Int64" "name": "user_id",
"type_info": "Int8"
}, },
{ {
"name": "content",
"ordinal": 2, "ordinal": 2,
"name": "content",
"type_info": "Text" "type_info": "Text"
}, },
{ {
"name": "upvotes",
"ordinal": 3, "ordinal": 3,
"type_info": "Int64" "name": "upvotes",
"type_info": "Int4"
}, },
{ {
"name": "downvotes",
"ordinal": 4, "ordinal": 4,
"type_info": "Int64" "name": "downvotes",
"type_info": "Int4"
}, },
{ {
"name": "created_at",
"ordinal": 5, "ordinal": 5,
"type_info": "Datetime" "name": "created_at",
"type_info": "Timestamp"
}, },
{ {
"name": "updated_at",
"ordinal": 6, "ordinal": 6,
"type_info": "Datetime" "name": "updated_at",
"type_info": "Timestamp"
} }
], ],
"parameters": { "parameters": {
"Right": 2 "Left": [
"Int8",
"Int8"
]
}, },
"nullable": [ "nullable": [
false, false,
@ -52,5 +55,5 @@
false false
] ]
}, },
"hash": "8f5e9d8d0c7c33d31f02a9cbd9886ed945d788caeb704b2ee5f743f7bf5fac88" "hash": "f68cd95363d7da716b14f430118176ed4da34e450fc07b812f6bf77073cc2128"
} }

492
server/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,7 @@ log = "0.4.20"
serde = { version = "1.0.188", features = ["derive"] } serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.107" serde_json = "1.0.107"
sled = { version = "0.34.7" } sled = { version = "0.34.7" }
sqlx = { version = "0.7.2", features = ["sqlite", "runtime-tokio", "chrono", "uuid"] } sqlx = { version = "0.7.2", features = ["runtime-tokio", "chrono", "uuid", "postgres", "tls-rustls"] }
uuid = { version = "1.4.1", features = ["serde", "v4"] } uuid = { version = "1.4.1", features = ["serde", "v4"] }
[profile.dev.package.sqlx-macros] [profile.dev.package.sqlx-macros]

View file

@ -0,0 +1,38 @@
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- Create a function to set created_at and updated_at on INSERT
CREATE OR REPLACE FUNCTION set_timestamps_on_insert() RETURNS TRIGGER AS $$
BEGIN
NEW.created_at = NOW();
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Create a trigger to call the function after INSERT
CREATE TRIGGER set_timestamps_on_insert
BEFORE INSERT ON users
FOR EACH ROW
EXECUTE FUNCTION set_timestamps_on_insert();
-- Create a function to set updated_at on UPDATE
CREATE OR REPLACE FUNCTION set_updated_at() RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Create a trigger to call the function after UPDATE
CREATE TRIGGER set_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION set_updated_at();
CREATE INDEX users_username_index ON users (username);

View file

@ -0,0 +1,43 @@
CREATE TABLE IF NOT EXISTS posts (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
content TEXT NOT NULL,
upvotes INTEGER NOT NULL DEFAULT 0,
downvotes INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users (id)
);
-- Create a function to set created_at and updated_at on INSERT
CREATE OR REPLACE FUNCTION set_timestamps_on_insert() RETURNS TRIGGER AS $$
BEGIN
NEW.created_at = NOW();
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Create a trigger to call the function after INSERT
CREATE TRIGGER set_timestamps_on_insert
BEFORE INSERT ON posts
FOR EACH ROW
EXECUTE FUNCTION set_timestamps_on_insert();
-- Create a function to set updated_at on UPDATE
CREATE OR REPLACE FUNCTION set_updated_at() RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Create a trigger to call the function after UPDATE
CREATE TRIGGER set_updated_at
BEFORE UPDATE ON posts
FOR EACH ROW
EXECUTE FUNCTION set_updated_at();
CREATE INDEX posts_user_id_index ON posts (user_id);
CREATE INDEX posts_id_index ON posts (id);
CREATE INDEX idx_created_at_desc ON posts (created_at DESC);

View file

@ -4,13 +4,13 @@ use argon2::{
Argon2, PasswordHasher, PasswordVerifier, Argon2, PasswordHasher, PasswordVerifier,
}; };
use log::{info, warn}; use log::{info, warn};
use sqlx::SqlitePool; use sqlx::PgPool;
// Gets the latest posts from the database, ordered by created_at // Gets the latest posts from the database, ordered by created_at
pub async fn db_get_latest_posts(pool: &SqlitePool, limit: i64, offset: i64) -> Vec<Post> { pub async fn db_get_latest_posts(pool: &PgPool, limit: i64, offset: i64) -> Vec<Post> {
sqlx::query_as!( sqlx::query_as!(
Post, Post,
"SELECT * FROM posts ORDER BY created_at DESC LIMIT ? OFFSET ?", "SELECT * FROM posts ORDER BY created_at DESC LIMIT $1 OFFSET $2",
limit, limit,
offset offset
) )
@ -20,19 +20,19 @@ pub async fn db_get_latest_posts(pool: &SqlitePool, limit: i64, offset: i64) ->
} }
// Gets the post with id from the database // Gets the post with id from the database
pub async fn db_get_post(id: i64, pool: &SqlitePool) -> Option<Post> { pub async fn db_get_post(id: i64, pool: &PgPool) -> Option<Post> {
sqlx::query_as!(Post, "SELECT * FROM posts WHERE id = ?", id) sqlx::query_as!(Post, "SELECT * FROM posts WHERE id = $1", id)
.fetch_one(pool) .fetch_one(pool)
.await .await
.ok() .ok()
} }
// Inserts a new post to the database // Inserts a new post to the database
pub async fn db_new_post(userid: i64, content: &str, pool: &SqlitePool) -> Option<Post> { pub async fn db_new_post(userid: i64, content: &str, pool: &PgPool) -> Option<Post> {
info!("User with id {} submitted a post", userid); info!("User with id {} submitted a post", userid);
let insert_query = sqlx::query!( let insert_query = sqlx::query!(
"INSERT INTO posts (user_id, content) VALUES (?, ?)", "INSERT INTO posts (user_id, content) VALUES ($1, $2)",
userid, userid,
content content
) )
@ -57,8 +57,8 @@ pub async fn db_new_post(userid: i64, content: &str, pool: &SqlitePool) -> Optio
Some(post) Some(post)
} }
pub async fn db_user_exists(username: String, pool: &SqlitePool) -> bool { pub async fn db_user_exists(username: String, pool: &PgPool) -> bool {
let exists = sqlx::query!("SELECT username FROM users WHERE username = ?", username) let exists = sqlx::query!("SELECT username FROM users WHERE username = $1", username)
.fetch_one(pool) .fetch_one(pool)
.await .await
.ok() .ok()
@ -67,9 +67,9 @@ pub async fn db_user_exists(username: String, pool: &SqlitePool) -> bool {
exists.is_some() exists.is_some()
} }
pub async fn db_user_login(username: String, password: String, pool: &SqlitePool) -> Option<User> { pub async fn db_user_login(username: String, password: String, pool: &PgPool) -> Option<User> {
let username = username.clone(); let username = username.clone();
let user = sqlx::query_as!(User, "SELECT * FROM users WHERE username = ?", username) let user = sqlx::query_as!(User, "SELECT * FROM users WHERE username = $1", username)
.fetch_one(pool) .fetch_one(pool)
.await .await
.ok()?; .ok()?;
@ -95,7 +95,7 @@ pub async fn db_user_login(username: String, password: String, pool: &SqlitePool
} }
} }
pub async fn db_new_user(username: String, password: String, pool: &SqlitePool) -> Option<User> { pub async fn db_new_user(username: String, password: String, pool: &PgPool) -> Option<User> {
// First check if the user already exists // First check if the user already exists
match db_user_exists(username.clone(), pool).await { match db_user_exists(username.clone(), pool).await {
true => { true => {
@ -113,7 +113,7 @@ pub async fn db_new_user(username: String, password: String, pool: &SqlitePool)
// Insert our new user into the database // Insert our new user into the database
let insert_query = sqlx::query!( let insert_query = sqlx::query!(
"INSERT INTO users (username, password) VALUES (?, ?)", "INSERT INTO users (username, password) VALUES ($1, $2)",
username, username,
phc_hash phc_hash
) )
@ -123,7 +123,7 @@ pub async fn db_new_user(username: String, password: String, pool: &SqlitePool)
match insert_query { match insert_query {
Ok(_) => { Ok(_) => {
info!("User: {} registered", username); info!("User: {} registered", username);
let user = sqlx::query_as!(User, "SELECT * FROM users WHERE username = ?", username) let user = sqlx::query_as!(User, "SELECT * FROM users WHERE username = $1", username)
.fetch_one(pool) .fetch_one(pool)
.await .await
.ok()?; .ok()?;

View file

@ -79,7 +79,7 @@ pub async fn new_post(new_post: Json<NewPost>, state: Data<ServerState>) -> Resu
let username = claims.sub.clone(); let username = claims.sub.clone();
// This one is avoidable if we just store the user id in the token // This one is avoidable if we just store the user id in the token
let userid = sqlx::query!("SELECT id FROM users WHERE username = ?", username) let userid = sqlx::query!("SELECT id FROM users WHERE username = $1", username)
.fetch_one(&state.pool) .fetch_one(&state.pool)
.await .await
.unwrap() .unwrap()

View file

@ -4,10 +4,8 @@ use std::sync::Mutex;
use log::error; use log::error;
use log::info; use log::info;
use sqlx::migrate::MigrateDatabase; use sqlx::postgres::PgPoolOptions;
use sqlx::Pool; use sqlx::PgPool;
use sqlx::Sqlite;
use sqlx::{self, sqlite};
#[derive(Clone)] #[derive(Clone)]
pub struct CaptchaState { pub struct CaptchaState {
@ -24,7 +22,7 @@ impl CaptchaState {
#[derive(Clone)] #[derive(Clone)]
pub struct ServerState { pub struct ServerState {
pub pool: Pool<Sqlite>, pub pool: PgPool,
} }
impl ServerState { impl ServerState {
@ -38,17 +36,13 @@ impl ServerState {
info!("Using db_url: {}", &db_url); info!("Using db_url: {}", &db_url);
if !sqlx::Sqlite::database_exists(&db_url).await.unwrap() { let pool = PgPoolOptions::new()
sqlx::Sqlite::create_database(&db_url).await.unwrap();
}
let pool = sqlite::SqlitePoolOptions::new()
.max_connections(5) .max_connections(5)
.connect(&db_url) .connect(&db_url)
.await .await
.unwrap(); .unwrap();
sqlx::migrate!("./migrations").run(&pool).await.unwrap(); sqlx::migrate!("./migrations_pg").run(&pool).await.unwrap();
match crate::db::db_new_user("imbus".to_string(), "kartellen1234".to_string(), &pool).await match crate::db::db_new_user("imbus".to_string(), "kartellen1234".to_string(), &pool).await
{ {
@ -63,13 +57,10 @@ impl ServerState {
} }
} }
#[cfg(debug_assertions)]
use sqlx::SqlitePool;
// Inserts a bunch of dummy data into the database // Inserts a bunch of dummy data into the database
// Mostly useful for debugging new posts, as we need to satisfy foreign key constraints. // Mostly useful for debugging new posts, as we need to satisfy foreign key constraints.
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
async fn debug_setup(pool: &SqlitePool) -> Result<(), sqlx::Error> { async fn debug_setup(pool: &PgPool) -> Result<(), sqlx::Error> {
use sqlx::query; use sqlx::query;
use crate::db::db_new_user; use crate::db::db_new_user;