-
Notifications
You must be signed in to change notification settings - Fork 0
Corrección Tp individual #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: base
Are you sure you want to change the base?
Changes from all commits
d959b97
bf01139
0531695
5eb7246
61e9b14
86b1e2d
23ee444
5fbfdfc
ce94067
78d6f22
03ec858
cc6a99c
4ecfd49
a1994d5
238dcbd
b0ea9fb
f73742f
bbc7a86
ae6ea14
1904f6a
c7cd81e
1b8c1e2
2762937
e2bebfc
0440306
c3025a4
0e49beb
c66d2d2
7577dc9
7e2e64b
9b352cb
7aa07bc
efec607
c1852c2
ae523e7
57cdad1
4a59148
c0865d2
838bf69
c82caea
db98cb0
2137d35
a97842d
d98caae
481a71e
935b229
ad93b01
dec9535
1383f09
e5fa8da
6b61bcc
17b2b8c
7d1981b
8c82097
202873e
da45881
b2635a9
692d272
f1d0ced
8c67169
8c35496
a9d3cb3
657da68
7ed40dc
60b03f9
c7a971c
1c9a11e
b4c6a18
08cf019
f62ac46
d48c13b
76f325f
fbac191
1a80e13
dd4325b
729c41c
8048bc4
d75ed5a
be71d78
2d3b856
d1f8f6b
48ad5fa
447fc1c
2229be6
edf1254
cfd342f
4f5b604
5fe0476
8469567
eac9e94
db6368a
b6b3510
3bc7267
caf736c
52ac616
cc2be76
f759d6a
c81ca88
bc07803
5a239ca
a491a1b
d346878
435ce2b
8bbc27a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 |
| 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| /target | ||
| .idea |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| [package] | ||
| name = "rustic-sql" | ||
| version = "0.1.0" | ||
| edition = "2021" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # rustic-sql 🦀  | ||
|
|
||
| > [!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) | ||
| 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(()) | ||
| } |
| 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); | ||
| } | ||
| } |
| 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 { | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. parece que se encarga de eliminar un builderjsjsj
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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")); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
muy lindo quedó!