Skip to content

Commit

Permalink
Add mysql delete tests (#155)
Browse files Browse the repository at this point in the history
  • Loading branch information
mjovanc authored Oct 16, 2024
2 parents 7e5c1ac + f81b311 commit 76b7b22
Show file tree
Hide file tree
Showing 14 changed files with 910 additions and 21 deletions.
20 changes: 13 additions & 7 deletions .github/workflows/core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,19 @@ jobs:
- name: Running Integration Tests for SQLite
run: cargo test --test sqlite_tests

# - name: Set up MySQL schema
# env:
# MYSQL_PWD: rootpassword
# run: |
# echo "Injecting schema and data into MySQL..."
# mysql -h 127.0.0.1 -u root njord_db < njord/db/test/mysql.sql
- name: Wait for MySQL to be ready
run: |
until mysqladmin ping -h 127.0.0.1 --silent; do
echo "Waiting for MySQL to be ready..."
sleep 5
done
- name: Set up MySQL schema
env:
MYSQL_PWD: rootpassword
run: |
echo "Injecting schema and data into MySQL..."
mysql -h 127.0.0.1 -u njord_user -pnjord_password njord_db < njord/db/test/mysql.sql
- name: Running Unit Tests for MySQL
run: cargo test mysql
Expand All @@ -82,4 +89,3 @@ jobs:
MYSQL_PASSWORD: njord_password
MYSQL_HOST: 127.0.0.1
run: cargo test --test sqlite_tests

1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ services:
volumes:
- mysql_data:/var/lib/mysql
- ./njord_examples/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
- ./njord/db/test/mysql.sql:/docker-entrypoint-initdb.d/tests.sql

volumes:
mysql_data:
Binary file modified njord/db/insert.db
Binary file not shown.
31 changes: 31 additions & 0 deletions njord/db/test/mysql.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
DROP DATABASE IF EXISTS njord_db;

CREATE DATABASE njord_db;

USE njord_db;

-- Table: users
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY, -- Auto incrementing primary key for the user ID
username VARCHAR(255) NOT NULL, -- Username field
email VARCHAR(255) NOT NULL, -- Email field
address VARCHAR(255) -- Address field
);

-- Table: categories
CREATE TABLE categories (
id INT PRIMARY KEY, -- Primary key for categories
name VARCHAR(255) NOT NULL -- Name of the category
);

-- Table: products
CREATE TABLE products (
id INT PRIMARY KEY, -- Primary key for products
name VARCHAR(255) NOT NULL, -- Product name
description TEXT, -- Product description
price DECIMAL(10, 2) NOT NULL, -- Price with up to two decimal places
stock_quantity INT NOT NULL, -- Stock quantity
category_id INT NOT NULL, -- Foreign key to categories (one-to-one relationship)
discount DECIMAL(5, 2) DEFAULT 0.00, -- Discount field with default value
FOREIGN KEY (category_id) REFERENCES categories(id) -- Foreign key constraint to categories table
);
50 changes: 43 additions & 7 deletions njord/src/mysql/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc};

use log::info;
use mysql::prelude::*;
use mysql::{prelude::FromRow, Error, PooledConn};
use mysql::{Error, PooledConn, Value};

use crate::table::Table;
use crate::util::{Join, JoinType};
Expand All @@ -57,7 +57,7 @@ use crate::util::{Join, JoinType};
/// # Returns
///
/// A `SelectQueryBuilder` instance.
pub fn select<'a, T: Table + Default + FromRow>(
pub fn select<'a, T: Table + Default>(
conn: &'a mut PooledConn,
columns: Vec<Column<'a, T>>,
) -> SelectQueryBuilder<'a, T> {
Expand All @@ -66,7 +66,7 @@ pub fn select<'a, T: Table + Default + FromRow>(

/// A builder for constructing SELECT queries.
#[derive(Clone)]
pub struct SelectQueryBuilder<'a, T: Table + Default + FromRow> {
pub struct SelectQueryBuilder<'a, T: Table + Default> {
conn: Rc<RefCell<&'a mut PooledConn>>,
table: Option<T>,
columns: Vec<Column<'a, T>>,
Expand All @@ -82,7 +82,7 @@ pub struct SelectQueryBuilder<'a, T: Table + Default + FromRow> {
joins: Option<Vec<Join<'a>>>,
}

impl<'a, T: Table + Default + FromRow> SelectQueryBuilder<'a, T> {
impl<'a, T: Table + Default> SelectQueryBuilder<'a, T> {
/// Creates a new `SelectQueryBuilder` instance.
///
/// # Arguments
Expand Down Expand Up @@ -366,10 +366,46 @@ impl<'a, T: Table + Default + FromRow> SelectQueryBuilder<'a, T> {
info!("{}", final_query);
println!("{}", final_query);

// Borrow the connection mutably from the RefCell
let mut conn = self.conn.borrow_mut();
let query_set = conn.query_iter(final_query.as_str()).unwrap();

let mut results: Vec<T> = Vec::new();

for row_result in query_set {
let row = row_result.unwrap(); // Unwrap the row result
let mut instance = T::default();

for column in row.columns_ref() {
// Cells in a row can be indexed by numeric index or by column name
let column_value = &row[column.name_str().as_ref()];

let column_value_str = match column_value {
Value::NULL => "NULL".to_string(),
Value::Bytes(bytes) => String::from_utf8_lossy(bytes).to_string(),
Value::Int(i) => i.to_string(),
Value::UInt(u) => u.to_string(),
Value::Float(f) => f.to_string(),
Value::Double(d) => d.to_string(),
Value::Date(year, month, day, hour, min, sec, micro) => format!(
"{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:06}",
year, month, day, hour, min, sec, micro
),
Value::Time(neg, days, hours, minutes, seconds, micros) => format!(
"{}{:02}:{:02}:{:02}.{:06}",
if *neg { "-" } else { "" },
days * 24 + u32::from(*hours),
minutes,
seconds,
micros
),
};

instance.set_column_value(column.name_str().as_ref(), &column_value_str);
}

let results: Vec<T> = conn.query(final_query.as_str())?;
// Move `instance` to the `results` only after it is fully set up
results.push(instance);
}

Ok(results)
}
Expand All @@ -380,7 +416,7 @@ impl<'a, T: Table + Default + FromRow> SelectQueryBuilder<'a, T> {
/// The where statement ensures the T is long lived
impl<'a, T> QueryBuilder<'a> for SelectQueryBuilder<'a, T>
where
T: Table + Default + Clone + FromRow + 'a, // Added 'a bound here
T: Table + Default + Clone + 'a, // Added 'a bound here
{
fn to_sql(&self) -> String {
self.build_query()
Expand Down
11 changes: 4 additions & 7 deletions njord/src/mysql/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ use crate::{
};

use log::info;
use mysql::{
prelude::{FromRow, Queryable},
PooledConn,
};
use mysql::{prelude::Queryable, PooledConn};

use crate::table::Table;

Expand All @@ -59,15 +56,15 @@ use super::select::SelectQueryBuilder;
/// # Returns
///
/// An `UpdateQueryBuilder` instance.
pub fn update<'a, T: Table + Default + FromRow>(
pub fn update<'a, T: Table + Default>(
conn: &'a mut PooledConn,
table: T,
) -> UpdateQueryBuilder<'a, T> {
UpdateQueryBuilder::new(conn, table)
}

/// A builder for constructing UPDATE queries.
pub struct UpdateQueryBuilder<'a, T: Table + Default + FromRow> {
pub struct UpdateQueryBuilder<'a, T: Table + Default> {
conn: &'a mut PooledConn,
table: Option<T>,
columns: Vec<String>,
Expand All @@ -78,7 +75,7 @@ pub struct UpdateQueryBuilder<'a, T: Table + Default + FromRow> {
offset: Option<usize>,
}

impl<'a, T: Table + Default + FromRow> UpdateQueryBuilder<'a, T> {
impl<'a, T: Table + Default> UpdateQueryBuilder<'a, T> {
/// Creates a new `UpdateQueryBuilder` instance.
///
/// # Arguments
Expand Down
52 changes: 52 additions & 0 deletions njord/tests/mysql/delete_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use super::User;
use njord::condition::{Condition, Value};
use njord::keys::AutoIncrementPrimaryKey;
use njord::mysql;
use std::vec;

#[test]
fn delete_row() {
insert_row();

let url = "mysql://njord_user:njord_password@localhost:3306/njord_db";
let mut conn = mysql::open(url);

match conn {
Ok(ref mut c) => {
let result = mysql::delete(c)
.from(User::default())
.where_clause(Condition::Eq(
"username".to_string(),
Value::Literal("chasewillden2".to_string()),
))
.build();
assert!(result.is_ok());
}
Err(e) => {
panic!("Failed to DELETE: {:?}", e);
}
}
}

/// Helper function to insert a row to be deleted
fn insert_row() {
let url = "mysql://njord_user:njord_password@localhost:3306/njord_db";
let mut conn = mysql::open(url);

let table_row: User = User {
id: AutoIncrementPrimaryKey::default(),
username: "chasewillden2".to_string(),
email: "[email protected]".to_string(),
address: "Some Random Address 1".to_string(),
};

match conn {
Ok(ref mut c) => {
let result = mysql::insert(c, vec![table_row]);
assert!(result.is_ok());
}
Err(e) => {
panic!("Failed to INSERT: {:?}", e);
}
}
}
27 changes: 27 additions & 0 deletions njord/tests/mysql/insert_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use super::User;
use njord::keys::AutoIncrementPrimaryKey;
use njord::mysql;
use std::vec;

#[test]
fn insert_row() {
let url = "mysql://njord_user:njord_password@localhost:3306/njord_db";
let mut conn = mysql::open(url);

let table_row: User = User {
id: AutoIncrementPrimaryKey::default(),
username: "chasewillden".to_string(),
email: "[email protected]".to_string(),
address: "Some Random Address 1".to_string(),
};

match conn {
Ok(ref mut c) => {
let result = mysql::insert(c, vec![table_row]);
assert!(result.is_ok());
}
Err(e) => {
panic!("Failed to INSERT: {:?}", e);
}
}
}
56 changes: 56 additions & 0 deletions njord/tests/mysql/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
mod delete_test;
mod insert_test;
mod open_test;
mod select_joins_test;
mod select_test;
mod update_test;

use njord::keys::{AutoIncrementPrimaryKey, PrimaryKey};
use njord::table::Table;
use njord_derive::Table;

#[derive(Table, Clone)]
#[table_name = "users"]
pub struct User {
pub id: AutoIncrementPrimaryKey<usize>,
pub username: String,
pub email: String,
pub address: String,
}

#[derive(Table)]
#[table_name = "users"]
pub struct UserWithSubQuery {
pub id: AutoIncrementPrimaryKey<usize>,
pub username: String,
pub email: String,
pub address: String,
pub additional_address: String,
}

#[derive(Table)]
#[table_name = "categories"]
pub struct Category {
pub id: PrimaryKey<usize>,
pub name: String,
}

#[derive(Table)]
#[table_name = "products"]
pub struct Product {
pub id: PrimaryKey<usize>,
pub name: String,
pub description: String,
pub price: f64,
pub stock_quantity: usize,
pub category: Category, // one-to-one relationship
pub discount: f64,
}

#[derive(Table)]
#[table_name = "users"]
pub struct UsersWithJoin {
username: String,
price: f64,
name: String,
}
8 changes: 8 additions & 0 deletions njord/tests/mysql/open_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use njord::mysql;

#[test]
fn open_db() {
let url = "mysql://njord_user:njord_password@localhost:3306/njord_db";
let result = mysql::open(url);
assert!(result.is_ok());
}
Loading

0 comments on commit 76b7b22

Please sign in to comment.