Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
d959b97
initial commit
Aug 29, 2024
bf01139
Create README.md
gabokatta Aug 29, 2024
0531695
initialized test folders
Aug 29, 2024
5eb7246
test auth commit
Aug 29, 2024
61e9b14
test auth commit 2
gabokatta Aug 29, 2024
86b1e2d
added validation and began working on errors
gabokatta Aug 31, 2024
23ee444
reworked errors
gabokatta Aug 31, 2024
5fbfdfc
format
gabokatta Aug 31, 2024
ce94067
format
gabokatta Aug 31, 2024
78d6f22
made errors output to stdout instead of stderr per tp requirements
gabokatta Aug 31, 2024
03ec858
slight refactor to string formatting in errored
gabokatta Aug 31, 2024
cc6a99c
added base for finite state machine (really simple implementation)
gabokatta Sep 1, 2024
4ecfd49
slight clippy fix
gabokatta Sep 1, 2024
a1994d5
rollbacked parser approach, will try another route
gabokatta Sep 1, 2024
238dcbd
tokenizer is a work in progress, weird bug with multibyte chars
gabokatta Sep 1, 2024
b0ea9fb
made tokenizer internal count be in bytes to handle accented chars.
gabokatta Sep 2, 2024
f73742f
new modules
gabokatta Sep 2, 2024
bbc7a86
starting builder module
gabokatta Sep 3, 2024
ae6ea14
module refactoring
gabokatta Sep 3, 2024
1904f6a
new error macro and used generics to reduce repetition in tokenizer
gabokatta Sep 3, 2024
c7cd81e
formatting
gabokatta Sep 3, 2024
1b8c1e2
made validate_path simpler
gabokatta Sep 3, 2024
2762937
layed groundwork for query builders
gabokatta Sep 5, 2024
e2bebfc
keyword validation and executor module refactor
gabokatta Sep 5, 2024
0440306
added SET to keywords
gabokatta Sep 5, 2024
c3025a4
began select builder
gabokatta Sep 5, 2024
0e49beb
added parenthesis support for future condition evaluation
gabokatta Sep 5, 2024
c66d2d2
added table and fields parsing for select
gabokatta Sep 5, 2024
7577dc9
added order by parsing
gabokatta Sep 5, 2024
7e2e64b
improved query debugging logs
gabokatta Sep 5, 2024
9b352cb
buggy where parser
gabokatta Sep 6, 2024
7aa07bc
new draft of where parser using recursive descent parser
gabokatta Sep 6, 2024
efec607
refactored ExpressionBuilder to reduce ugly indentation
gabokatta Sep 6, 2024
c1852c2
keeping functions below 30 linebreaks
gabokatta Sep 6, 2024
ae523e7
more refactors
gabokatta Sep 6, 2024
57cdad1
finished implementing rest of query builders.
gabokatta Sep 6, 2024
4a59148
slight refactoring
gabokatta Sep 7, 2024
c0865d2
slight refactoring
gabokatta Sep 7, 2024
838bf69
fixed bug in select
gabokatta Sep 7, 2024
c82caea
handle more edge cases for each query.
gabokatta Sep 7, 2024
db98cb0
slight refactor to parse_leaf
gabokatta Sep 7, 2024
2137d35
more refactors
gabokatta Sep 7, 2024
a97842d
module refactor to match tp requirements
gabokatta Sep 8, 2024
d98caae
error simplification and file utils added
gabokatta Sep 8, 2024
481a71e
added Expression evaluator
gabokatta Sep 8, 2024
935b229
forgot error message
gabokatta Sep 8, 2024
ad93b01
forgot another error message
gabokatta Sep 8, 2024
dec9535
improved select execution
gabokatta Sep 8, 2024
1383f09
removed imports
gabokatta Sep 8, 2024
e5fa8da
finished select ordering and first implementation of select.
gabokatta Sep 8, 2024
6b61bcc
slight refactors to reduce clippy alerts
gabokatta Sep 8, 2024
17b2b8c
refactor and new row methods
gabokatta Sep 8, 2024
7d1981b
allowed for multiple inserts in one query.
gabokatta Sep 8, 2024
8c82097
improved file handling in executor
gabokatta Sep 8, 2024
202873e
first implementation of update
gabokatta Sep 8, 2024
da45881
first implementations of delete and insert
gabokatta Sep 8, 2024
b2635a9
polished insert implementation
gabokatta Sep 8, 2024
692d272
added a LOT of unit tests, (jesus christ im never doing that again)
gabokatta Sep 9, 2024
f1d0ced
Create rust.yml
gabokatta Sep 9, 2024
8c67169
some file changes
gabokatta Sep 9, 2024
8c35496
testing new CI
gabokatta Sep 9, 2024
a9d3cb3
testing new CI pt2
gabokatta Sep 9, 2024
657da68
testing new CI pt3
gabokatta Sep 9, 2024
7ed40dc
removed unused methods in tests
gabokatta Sep 9, 2024
60b03f9
fixed clippy
gabokatta Sep 9, 2024
c7a971c
setup integration tests
gabokatta Sep 9, 2024
1c9a11e
separated run into lib.rs
gabokatta Sep 9, 2024
b4c6a18
new test utils
gabokatta Sep 9, 2024
08cf019
added select integration tests and fixed some bugs
gabokatta Sep 9, 2024
f62ac46
added insert integration tests and fixed some bugs
gabokatta Sep 9, 2024
d48c13b
added update integration tests
gabokatta Sep 9, 2024
76f325f
added delete integration tests
gabokatta Sep 9, 2024
fbac191
added documentation
gabokatta Sep 9, 2024
1a80e13
fix slight doc issue
gabokatta Sep 9, 2024
dd4325b
readme test
gabokatta Sep 9, 2024
729c41c
Update README.md
gabokatta Sep 9, 2024
8048bc4
testing doc workflow
gabokatta Sep 9, 2024
d75ed5a
Update README.md
gabokatta Sep 9, 2024
be71d78
testing doc workflow pt2
gabokatta Sep 9, 2024
2d3b856
testing doc workflow pt3
gabokatta Sep 9, 2024
d1f8f6b
testing doc workflow pt4
gabokatta Sep 9, 2024
48ad5fa
testing doc workflow pt5
gabokatta Sep 9, 2024
447fc1c
testing doc workflow pt6
gabokatta Sep 9, 2024
2229be6
testing doc workflow pt7
gabokatta Sep 9, 2024
edf1254
testing doc workflow pt8
gabokatta Sep 9, 2024
cfd342f
testing doc workflow pt9
gabokatta Sep 9, 2024
4f5b604
testing doc workflow pt10
gabokatta Sep 9, 2024
5fe0476
testing doc workflow pt11
gabokatta Sep 9, 2024
8469567
testing doc workflow pt12
gabokatta Sep 9, 2024
eac9e94
testing doc workflow pt13
gabokatta Sep 9, 2024
db6368a
return workflow to default
gabokatta Sep 9, 2024
b6b3510
removed redirect from workflow
gabokatta Sep 9, 2024
3bc7267
snake case fix, maybe?
gabokatta Sep 9, 2024
caf736c
Update README.md
gabokatta Sep 9, 2024
52ac616
final doc update
gabokatta Sep 9, 2024
cc2be76
document private items (educational-purposes)
gabokatta Sep 9, 2024
f759d6a
clippy
gabokatta Sep 9, 2024
c81ca88
fix select projection bug
gabokatta Sep 9, 2024
bc07803
format
gabokatta Sep 9, 2024
5a239ca
new tests and fixed bug from projection
gabokatta Sep 9, 2024
a491a1b
renamed output_rows into output_projection
gabokatta Sep 9, 2024
d346878
did some more testing, found some bugs with ordering
gabokatta Sep 9, 2024
435ce2b
new select test
gabokatta Sep 9, 2024
8bbc27a
Merge branch 'main' into entrega
noahmasri Sep 18, 2024
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
66 changes: 66 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Docs

on:
push:
branches: [main]

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: deploy
cancel-in-progress: false

jobs:
build:
name: Build
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable

- name: Configure cache
uses: Swatinem/rust-cache@v2

- name: Setup pages
id: pages
uses: actions/configure-pages@v4

- name: Clean docs folder
run: cargo clean --doc

- name: Build docs
run: cargo doc --document-private-items --no-deps

- name: Add redirect
run: echo '<meta http-equiv="refresh" content="0;url=rustic_sql/index.html">' > target/doc/index.html

- name: Remove lock file
run: rm target/doc/.lock

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./target/doc

deploy:
name: Deploy

environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

runs-on: ubuntu-latest

needs: build

steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
22 changes: 22 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Rust
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Format Code
run: cargo fmt -- --check
- name: Build
run: cargo build --verbose
- name: Run Clippy
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Run tests
run: cargo test --verbose
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target
.idea
7 changes: 7 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
name = "rustic-sql"
version = "0.1.0"
edition = "2021"
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# rustic-sql 🦀 ![workflow TP](https://github.com/gabokatta/rustic-sql/actions/workflows/rust.yml/badge.svg)

> [!IMPORTANT]
> ¿Como correr la app?
> - Para las queries de tipo SELECT puedes redirigir la salida de STDOUT a un archivo o simplemente ver la salida por pantalla.
> ```BASH
>cargo run -- ruta/a/tablas "SELECT * FROM table" > output.csv
>```
> - Para las otras queries, simplemente se aplican los cambios sobre los archivos.
> ```BASH
>cargo run -- ruta/a/tablas "INSERT INTO table (id, name) VALUES (1, 'gabriel');"
>```
___
> [!TIP]
> ¿Como testear la app?
>```BASH
>cargo test --all
>```
___
> [!NOTE]
> ¿Como levantar la documentación?
>```BASH
>cargo doc --open
>```
> Alternativamente se puede visualizar por [github!](https://gabokatta.github.io/rustic-sql)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

muy lindo quedó!

63 changes: 63 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//! # RusticSQL 🦀
//!
//! ### Clon de SQL, en Rust.
//!
//! Permite al usuario ejecutar consultas SQL mediante la linea de comandos.
//!
//! Las operaciones se realizan sobre "tablas" (archivos csv).
//!
//!
//! Consultas Permitidas: [SELECT, INSERT, UPDATE, DELETE]
//!
//! Operadores Disponibles: [AND, OR, NOT y comparadores simples (>, <, =, etc..)]
//!
//!
//! Estructura del Proyecto:
//! - Tokenizador: Recibe un String y te devuelve tokens.
//! - Constructor: Recibe tokens y los transforma en consultas validas.
//! - Ejecutor: Recibe consultas y las ejecuta sobre las tablas.
//!
//! # Usar RusticSQL:
//!
//! > ```BASH
//! > cargo run -- ruta/a/tablas "SELECT * FROM table" > output.csv
//! > ```
//!
//! # Testea RusticSQL:
//!
//! >```BASH
//! >cargo test --all
//! >```
//!
//!
#![doc(
html_logo_url = "https://cdn-icons-png.flaticon.com/512/4726/4726022.png",
html_favicon_url = "https://cdn-icons-png.flaticon.com/512/4726/4726022.png"
)]

use crate::query::executor::Executor;
use crate::query::structs::query::Query;
use crate::query::tokenizer::Tokenizer;
use crate::query::validate_query_string;
use crate::utils::files::validate_path;
use std::error::Error;

pub mod query;
pub mod utils;

pub fn run(args: Vec<String>) -> Result<(), Box<dyn Error>> {
if args.len() != 3 {
println!("invalid usage of rustic-sql");
return Err("usage: cargo run -- <path-to-tables> <sql-query>".into());
}

let path: &String = &args[1];
let query: &String = &args[2];
validate_path(path)?;
validate_query_string(query)?;

let tokens = Tokenizer::new().tokenize(query)?;
let query = Query::from(tokens)?;
Executor::run(path, query)?;
Ok(())
}
9 changes: 9 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use rustic_sql::run;
use std::env;

fn main() {
let args = env::args().collect();
if let Err(e) = run(args) {
println!("{}", e);
}
}
146 changes: 146 additions & 0 deletions src/query/builder/delete.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use crate::query::builder::{validate_keywords, Builder};
use crate::query::structs::operation::Operation::Delete;
use crate::query::structs::query::Query;
use crate::query::structs::token::Token;
use crate::query::structs::token::TokenKind::Keyword;
use crate::utils::errors::Errored;
use std::collections::VecDeque;

const ALLOWED_KEYWORDS: &[&str] = &["FROM", "WHERE", "AND", "OR"];

/// Constructor para consultas de eliminación (`DELETE`).
///
/// `DeleteBuilder` se encarga de construir una consulta de eliminación a partir
/// de una lista de tokens que representan la sintaxis de una consulta SQL.
pub struct DeleteBuilder {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parece que se encarga de eliminar un builderjsjsj

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JAJAJA tenes razon, pasa que el IDE me chillaba si el nombre del struct era redundante

Mas claro era DeleteQueryBuilder pero como ya inferia que estaba dentro del modulo Query me molestaba con eso 🤣

tokens: VecDeque<Token>,
}

impl DeleteBuilder {
/// Crea una nueva instancia de `DeleteBuilder`.
///
/// Este constructor inicializa el `DeleteBuilder` con una cola de tokens
/// que representan una consulta SQL.
///
/// # Parámetros
///
/// - `tokens`: Cola de tokens (`VecDeque<Token>`) que se utilizarán para construir la consulta.
pub fn new(tokens: VecDeque<Token>) -> Self {
Self { tokens }
}
}

impl Builder for DeleteBuilder {
/// Construye una consulta `DELETE` a partir de los tokens proporcionados.
///
/// Este método analiza los tokens para construir una consulta de eliminación válida.
/// Verifica palabras clave permitidas, obtiene la tabla objetivo y, opcionalmente,
/// analiza las condiciones de la cláusula `WHERE`.
///
/// # Retorno
///
/// Retorna un objeto `Query` con la operación de eliminación configurada.
///
/// # Errores
///
/// Retorna un error `Errored` si la consulta contiene errores de sintaxis o palabras clave no permitidas.
fn build(&mut self) -> Result<Query, Errored> {
let mut query = Query::default();
self.validate_keywords()?;
query.operation = Delete;
query.table = self.parse_table(Delete)?;
match self.peek_expecting("WHERE", Keyword) {
Ok(_) => {
query.conditions = self.parse_where()?;
}
Err(_) => self.expect_none()?,
}
Ok(query)
}

/// Devuelve una referencia mutable a los tokens de la consulta.
///
/// Este método es utilizado por otros métodos de construcción para acceder y modificar
/// la lista de tokens durante el proceso de análisis.
///
/// # Retorno
///
/// Retorna una referencia mutable a la cola de tokens (`VecDeque<Token>`).
fn tokens(&mut self) -> &mut VecDeque<Token> {
&mut self.tokens
}

/// Valida las palabras clave permitidas en una consulta `DELETE`.
///
/// Este método verifica que solo se utilicen las palabras clave permitidas para una
/// operación de eliminación. Si encuentra alguna palabra clave no permitida, lanza un error.
///
/// Las palabras clave permitidas son: `FROM`, `WHERE`, `AND`, `OR`.
///
/// # Retorno
///
/// Retorna `Ok(())` si todas las palabras clave son válidas.
///
/// # Errores
///
/// Retorna un error `Errored` si se encuentra una palabra clave no válida.
fn validate_keywords(&self) -> Result<(), Errored> {
validate_keywords(ALLOWED_KEYWORDS, &self.tokens, Delete)
}
}

#[cfg(test)]
mod tests {
use crate::query::structs::expression::ExpressionNode::Empty;
use crate::query::structs::operation::Operation::Delete;
use crate::query::structs::query::Query;
use crate::query::structs::token::Token;
use crate::query::tokenizer::Tokenizer;

fn tokenize(sql: &str) -> Vec<Token> {
let mut tokenizer = Tokenizer::new();
tokenizer.tokenize(sql).unwrap()
}

#[test]
fn test_delete_simple() {
let sql = "DELETE FROM ordenes";
let tokens = tokenize(sql);
let query = Query::from(tokens).unwrap();

assert_eq!(query.operation, Delete);
assert_eq!(query.table, "ordenes");
assert_eq!(query.conditions, Empty);
}

#[test]
fn test_delete_with_conditions() {
let sql = "DELETE FROM ordenes WHERE id = 1";
let tokens = tokenize(sql);
let query = Query::from(tokens).unwrap();

assert_eq!(query.operation, Delete);
assert_eq!(query.table, "ordenes");
assert_ne!(query.conditions, Empty);
}

#[test]
fn test_delete_invalid_keyword() {
let sql = "DELETE FROM ordenes ORDER BY id";
let tokens = tokenize(sql);
let result = Query::from(tokens);

assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("ORDER BY"));
}

#[test]
fn test_delete_missing_table() {
let sql = "DELETE WHERE id = 1";
let tokens = tokenize(sql);
let result = Query::from(tokens);

assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("FROM"));
}
}
Loading