Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<div align="center">
<img src="https://img.shields.io/badge/Rust-dea584?style=for-the-badge&logo=rust&logoColor=white" alt="Rust" />
<img src="https://img.shields.io/badge/Tauri-ffc130?style=for-the-badge&logo=tauri&logoColor=white" alt="Tauri" />
<img src="https://img.shields.io/badge/Version-1.0.1-7073f6?style=for-the-badge" alt="Version" />
<img src="https://img.shields.io/badge/Version-1.0.3-7073f6?style=for-the-badge" alt="Version" />
</div>
</div>

Expand Down
48 changes: 24 additions & 24 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,45 @@
"tauri": "tauri"
},
"dependencies": {
"@radix-ui/react-checkbox": "^1.1.5",
"@radix-ui/react-dialog": "^1.1.7",
"@radix-ui/react-dropdown-menu": "^2.1.7",
"@radix-ui/react-checkbox": "^1.3.2",
"@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-dropdown-menu": "^2.1.15",
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.3",
"@radix-ui/react-menubar": "^1.1.7",
"@radix-ui/react-popover": "^1.1.7",
"@radix-ui/react-radio-group": "^1.2.4",
"@radix-ui/react-select": "^2.1.7",
"@radix-ui/react-separator": "^1.1.3",
"@radix-ui/react-slot": "^1.2.0",
"@radix-ui/react-switch": "^1.1.4",
"@radix-ui/react-tabs": "^1.1.4",
"@radix-ui/react-tooltip": "^1.2.0",
"@tauri-apps/api": "^2.4.1",
"@tauri-apps/plugin-dialog": "~2.2.1",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-menubar": "^1.1.15",
"@radix-ui/react-popover": "^1.1.14",
"@radix-ui/react-radio-group": "^1.3.7",
"@radix-ui/react-select": "^2.2.5",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.5",
"@radix-ui/react-tabs": "^1.1.12",
"@radix-ui/react-tooltip": "^1.2.7",
"@tauri-apps/api": "^2.5.0",
"@tauri-apps/plugin-dialog": "~2.2.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "1.0.0",
"framer-motion": "^12.6.5",
"framer-motion": "^12.17.0",
"lucide-react": "^0.441.0",
"next-themes": "^0.4.6",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.30.0",
"react-router-dom": "^6.30.1",
"sonner": "^1.7.4",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@tauri-apps/cli": "^2.4.1",
"@types/node": "^22.14.1",
"@types/react": "^18.3.20",
"@types/react-dom": "^18.3.6",
"@vitejs/plugin-react": "^4.3.4",
"@tauri-apps/cli": "^2.5.0",
"@types/node": "^22.15.31",
"@types/react": "^18.3.23",
"@types/react-dom": "^18.3.7",
"@vitejs/plugin-react": "^4.5.2",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.3",
"postcss": "^8.5.4",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^5.4.18"
"vite": "^5.4.19"
}
}
1,660 changes: 838 additions & 822 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "FileFlow"
version = "1.0.2"
version = "1.0.3"
description = "An app to manipulate DBMS tables"
authors = ["Maxime-Cllt"]
edition = "2021"
Expand Down
6 changes: 3 additions & 3 deletions src-tauri/src/fileflow/action/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use crate::fileflow::database::connection::Connection;
use crate::fileflow::enumeration::insertion_type::InsertionType;
use crate::fileflow::stuct::insert_config::InsertConfig;
use crate::fileflow::stuct::save_config::SaveConfig;
use crate::fileflow::stuct::string_formater::StringFormatter;
use crate::fileflow::utils::constants::DATABASE_CONFIG_FILE;
use crate::fileflow::utils::csv_utils::{find_separator, read_first_line};
use crate::fileflow::utils::fileflowlib::{get_all_saved_configs, save_config};
use crate::fileflow::utils::string_formater::{get_formated_column_names, sanitize_column};
use csv::{Reader, ReaderBuilder};
use std::fs::{File, Metadata};
use std::sync::Arc;
Expand Down Expand Up @@ -35,10 +35,10 @@ pub async fn insert_csv_data(
let first_line: String = read_first_line(&csv.file_path).expect("Failed to read first line"); // Read the first line of the file to detect the separator
let separator: char = find_separator(&first_line).expect("Failed to find separator"); // Separator detection of the file

let final_columns_name: Vec<String> = get_formated_column_names(
let final_columns_name: Vec<String> = StringFormatter::get_formated_column_names(
&first_line
.split(separator)
.map(|s| sanitize_column(s))
.map(|s| StringFormatter::sanitize_column(s))
.collect::<Vec<String>>(),
);

Expand Down
6 changes: 3 additions & 3 deletions src-tauri/src/fileflow/action/database_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::fileflow::enumeration::database_engine::DatabaseEngine;
use crate::fileflow::stuct::combo_item::ComboItem;
use crate::fileflow::stuct::db_config::DbConfig;
use crate::fileflow::stuct::download_config::DownloadConfig;
use crate::fileflow::utils::string_formater::{escaped_record, sanitize_value};
use csv::{Reader, StringRecord};
use serde_json::{json, Value};
use sqlx::Row;
Expand All @@ -20,6 +19,7 @@ use std::fs::File;
use std::sync::Arc;
use std::time::Instant;
use tauri::{command, State};
use crate::fileflow::stuct::string_formater::StringFormatter;

#[command]
pub async fn connect_to_database(
Expand Down Expand Up @@ -215,7 +215,7 @@ pub async fn fast_insert(

for result in reader.records() {
let values: String = match result {
Ok(record) => escaped_record(record),
Ok(record) => StringFormatter::escaped_record(record),
Err(_) => continue,
};

Expand Down Expand Up @@ -284,7 +284,7 @@ pub async fn optimized_insert(
let mut values: Vec<String> = Vec::with_capacity(record.len());

for (i, value) in record.iter().enumerate() {
let sanitized_value: String = sanitize_value(value);
let sanitized_value: String = StringFormatter::sanitize_value(value);
let max_length: &mut usize = columns_size_map
.get_mut(final_columns_name[i].as_str())
.ok_or("Column name mismatch")
Expand Down
12 changes: 2 additions & 10 deletions src-tauri/src/fileflow/database/database_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::fileflow::database::sql_builder::{
build_copy_table_sql, build_create_with_fixed_size_sql, build_drop_statement_sql,
};
use crate::fileflow::enumeration::database_engine::DatabaseEngine;
use crate::fileflow::enumeration::separator::SeparatorType;
use crate::fileflow::stuct::download_config::DownloadConfig;
use csv::{Writer, WriterBuilder};
use sqlx::{Column, Row};
Expand All @@ -16,20 +15,13 @@ pub async fn export_table(
download_config: &DownloadConfig,
table_name: &str,
) -> Result<(), Box<dyn std::error::Error>> {
const LIMIT: i32 = 5000;
const LIMIT: i32 = 5_000;
let mut offset: i32 = 0;
let mut header_written: bool = false;
let file_path: String = format!("{}/{table_name}_export.csv", download_config.location);

let separator: u8 = match download_config.separator {
SeparatorType::Comma => b',',
SeparatorType::Semicolon => b';',
SeparatorType::Pipe => b'|',
SeparatorType::Space => b' ',
};

let mut wtr: Writer<File> = WriterBuilder::new()
.delimiter(separator)
.delimiter(download_config.separator.as_u8())
.from_path(&file_path)
.expect("Failed to create CSV writer");

Expand Down
11 changes: 0 additions & 11 deletions src-tauri/src/fileflow/enumeration/database_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,3 @@ pub enum DatabaseEngine {
Postgres,
SQLite,
}

// impl DatabaseEngine {
// pub fn as_str(&self) -> &'static str {
// match self {
// DatabaseEngine::MariaDB => "mariadb",
// DatabaseEngine::MySQL => "mysql",
// DatabaseEngine::Postgres => "postgres",
// DatabaseEngine::SQLite => "sqlite",
// }
// }
// }
13 changes: 13 additions & 0 deletions src-tauri/src/fileflow/enumeration/separator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,16 @@ pub enum SeparatorType {
Space,
Pipe,
}

impl SeparatorType {

/// Returns the separator as a u8.
pub const fn as_u8(&self) -> u8 {
match self {
SeparatorType::Comma => b',',
SeparatorType::Semicolon => b';',
SeparatorType::Space => b' ',
SeparatorType::Pipe => b'|',
}
}
}
1 change: 1 addition & 0 deletions src-tauri/src/fileflow/stuct/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pub mod db_config;
pub mod download_config;
pub mod insert_config;
pub mod save_config;
pub mod string_formater;
74 changes: 74 additions & 0 deletions src-tauri/src/fileflow/stuct/string_formater.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use csv::StringRecord;

pub struct StringFormatter;

impl StringFormatter {
/// This function is used to generate the column names for a CSV file.
pub fn get_formated_column_names(headers: &[String]) -> Vec<String> {
const COLUMN_PREFIX: &str = "column_";
let mut safe_headers: Vec<String> = Vec::with_capacity(headers.len());

for (index, item) in headers.iter().enumerate() {
let trimmed_column_name: &str = item.trim();
if trimmed_column_name.is_empty() {
safe_headers.push(format!("{COLUMN_PREFIX}{}", index + 1));
} else {
safe_headers.push(Self::sanitize_column(trimmed_column_name));
}
}
safe_headers
}

/// Sanitize a value for safe insertion into the database
pub fn sanitize_value(value: &str) -> String {
let mut sanitized: String = String::with_capacity(value.len());

for c in value.trim().chars() {
match c {
'\'' => sanitized.push_str("''"), // Escape single quotes
'\\' => sanitized.push_str("\\\\"), // Escape backslashes
'\"' | '\0' => {} // Remove double quotes and null characters
'\r' | '\n' => sanitized.push(' '), // Normalize newlines
_ => sanitized.push(c),
}
}

sanitized
}

/// Sanitize a column name for safe insertion into the database
pub fn sanitize_column(value: &str) -> String {
let trimmed = value.trim();
let mut result = String::with_capacity(trimmed.len()); // Pre-allocate

for c in trimmed.chars() {
// Filter out unwanted characters first (early return)
if (c.is_control() && c != '\n' && c != '\t')
|| c == '\u{feff}' // BOM
|| c == '\u{200b}' // Zero-width space
|| c == '\u{200c}' // Zero-width non-joiner
|| c == '\u{200d}'
// Zero-width joiner
{
continue;
}

match c {
'\'' | '\\' | '\"' => continue, // Skip these
' ' => result.push('_'),
_ => result.push(c.to_ascii_lowercase()),
}
}

result
}

/// Escape values for SQL insert statement to avoid SQL injection attacks and other issues with special characters in values.
pub fn escaped_record(values: StringRecord) -> String {
let vec: Vec<String> = values
.iter()
.map(|v| format!("'{}'", Self::sanitize_value(v)))
.collect();
vec.join(", ")
}
}
1 change: 0 additions & 1 deletion src-tauri/src/fileflow/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
pub mod constants;
pub mod csv_utils;
pub mod fileflowlib;
pub mod string_formater;
56 changes: 0 additions & 56 deletions src-tauri/src/fileflow/utils/string_formater.rs

This file was deleted.

Loading
Loading