{"id":15908011,"url":"https://github.com/jomy10/simple_tables","last_synced_at":"2025-03-21T21:31:55.604Z","repository":{"id":45059783,"uuid":"446977973","full_name":"Jomy10/simple_tables","owner":"Jomy10","description":"An easy to use rust crate for creating table structures. Including macros for easily creating these table structures.","archived":false,"fork":false,"pushed_at":"2022-01-18T19:12:34.000Z","size":4980,"stargazers_count":3,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-17T11:52:04.780Z","etag":null,"topics":["crate","crates-io","macros","proc-macro","rust","rust-crate","rust-lang","rust-library","struct","table","tables","trait"],"latest_commit_sha":null,"homepage":"https://jomy10.github.io/simple_tables/simple_tables/index.html","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Jomy10.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":["https://paypal.me/JonasEveraert?country.x=BE\u0026locale.x=nl_NL"]}},"created_at":"2022-01-11T20:54:30.000Z","updated_at":"2024-03-06T01:42:01.000Z","dependencies_parsed_at":"2022-08-26T10:12:03.638Z","dependency_job_id":null,"html_url":"https://github.com/Jomy10/simple_tables","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jomy10%2Fsimple_tables","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jomy10%2Fsimple_tables/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jomy10%2Fsimple_tables/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jomy10%2Fsimple_tables/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Jomy10","download_url":"https://codeload.github.com/Jomy10/simple_tables/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244874390,"owners_count":20524577,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crate","crates-io","macros","proc-macro","rust","rust-crate","rust-lang","rust-library","struct","table","tables","trait"],"created_at":"2024-10-06T14:08:51.005Z","updated_at":"2025-03-21T21:31:53.665Z","avatar_url":"https://github.com/Jomy10.png","language":"Rust","readme":"\u003cimg src=\"res/logo.png\" style=\"display:block; margin-left:auto; margin-right:auto; width:500px; \" /\u003e\n\n[![CirlceCI](https://img.shields.io/circleci/build/github/Jomy10/simple_tables)](https://app.circleci.com/pipelines/github/Jomy10/simple_tables?branch=master)\n![Language](https://img.shields.io/badge/lang-Rust-B7410E)\n[![Licenses](https://img.shields.io/crates/l/simple_tables)](#license)\n[![Crates.io](https://img.shields.io/crates/v/simple_tables)](https://crates.io/crates/simple_tables)\n[![Docs.rs](https://img.shields.io/docsrs/simple_tables)](https://docs.rs/simple_tables/latest/simple_tables/)\n\nSimple Tables is a rust crate for easily creating table structures. This is made easy using macros.\n\nThis crate is actively maintained and everything is well documented.\n\n## Table of Contents\n\n- [Overview](#overview)\n  - [Creating tables](#creating-tables)\n  - [Functions](#functions)\n    - [ToString](#tostring)\n    - [Creating a new table instance](#creating-a-new-table-instance)\n    - [Get rows](#get-rows)\n    - [Get columns](#get-columns)\n    - [Inserting rows](#inserting-rows)\n    - [Removing rows](#removing-rows)\n    - [Column and row count](#column-and-row-count)\n  - [Tables with UID's](#tables-with-uids)\n    - [Getting a row based on the uid](#getting-a-row-based-on-the-uid)\n- [Adding derive attributes](#adding-derive-attributes)\n- [Installing](#installing)\n- [Contributing](#contributing)\n- [Documentation](#documentation)\n- [Use cases](#use-cases)\n- [Questions](#questions)\n- [License](#license)\n\n## Overview\n### Creating tables\nTo create a table, you use the macros `table_row` to indicate the structure of a row and `table` to use a struct as a \ntable for that row.\n\n**Example**\n```rust\nuse simple_tables::macros::{table_row, table};\n\n#[table_row]\nstruct MyTableRow {\n  id: u32,\n  name: String,\n  email: String,\n  address: String\n}\n\n#[table(rows = MyTableRow)]\nstruct MyTable {}\n```\n\nThese macros will implement the `TableRow` and `Table` trait respectively. You could also implement these manually.\n\n**NOTE**: If you use **IntelliJ**, I highly encourage you to enable the `org.rust.cargo.evaluate.build.scripts` and `org.rust.macros.proc`\nexperimental features. You can accomplish this by pressing `⇧⌘A` (macOs) or `⌃⇧A` (Linux/Windows) and searching\nfor `Experimental Features`, then enabling the two before-mentioned features.\n\nI don't know if rust-analyzer has this feature enabled by default, so I don't know what the state is in other IDE's.\n\n### Functions\nThe traits `TableRow` and `Table` define a collection a functions, most of them with default implementations. Using the\n`table_row` and `table` macros will implement these traits and their respective functions for the struct you are targetting.\nThe macros also provide some additional functions.\n\n#### ToString\nThe macros also implement the `ToString` trait for tables, so you can use the `to_string` function.\n\n**Example**\n```rust\nuse simple_tables::Table;\n\nlet rows: Vec\u003cMyTableRow\u003e = vec![\n  MyTableRow{ id: 0, name: \"David Bowie\".to_string(), email: \"david@bowie.com\".to_string(), address: \"England\".to_string()},\n  MyTableRow{ id: 1, name: \"David Gilmour\".to_string(), email: \"david@gilmour.com\".to_string(), address: \"England\".to_string()},\n  MyTableRow{ id: 2, name: \"Opeth\".to_string(), email: \"info@opeth.com\".to_string(), address: \"Sweden\".to_string()},\n  MyTableRow{ id: 3, name: \"The Beatles\".to_string(), email: \"info@beatles.com\".to_string(), address: \"England\".to_string()}\n];\n\nlet table = MyTable::from_vec(\u0026rows);\nlet s = table.to_string();\nprintln!(\"{}\", s);\n```\n\nThe output will be:\n```\n+----+---------------+-------------------+---------+\n| id | name          | email             | address |\n+====+===============+===================+=========+\n| 0  | David Bowie   | david@bowie.com   | England |\n+----+---------------+-------------------+---------+\n| 1  | David Gilmour | david@gilmour.com | England |\n+----+---------------+-------------------+---------+\n| 2  | Opeth         | info@opeth.com    | Sweden  |\n+----+---------------+-------------------+---------+\n| 3  | The Beatles   | info@beatles.com  | England |\n+----+---------------+-------------------+---------+\n```\n\n#### Creating a new table instance\n```rust\nlet empty_table = MyTable::new();\nlet populated_table = MyTable::from_vec(\u0026vec);\n```\n\n#### Get rows\nYou can get the rows using one of the getters:\n- `table.get_rows()`\n- `table.get_rows_mut()`\n- `table.get_row_at(index)`\n\n#### Get columns\nYou can get all values of a column using the `get_column` function. This function takes in a closure to get the value\nof each entry.\n\n**Example**\n```rust\n#[table_row]\nstruct MyTableRow2 {\n  id: u32,\n  name: String\n}\n\n#[table(rows = TableRow)]\nstruct MyTable2 {}\n\nlet vec: Vec\u003cMyTableRow2\u003e = vec![\n  MyTableRow2{id: 1, name: String::from(\"Metallica\")}, \n  MyTableRow2{id: 2, name: String::from(\"Slipknot\")}\n];\nlet table2 = MyTable2::from_vec(\u0026vec);\nlet ids: Vec\u003cu32\u003e = table2.get_column(|row| row.id); // The function takes in a closure\nassert_eq!(vec![1,2], ids);\n```\n\n#### Inserting rows\n\n**Example**\n```rust\nlet row = MyTableRow { id: 4, name: \"Pink Floyd\", email: \"pink@floyd.com\", address: \"England\"};\n// Appending the row to the end of the table\ntable.push(row);\n// Inserting a row at the top of the table\ntable.insert_top(row);\n// Inserting a row in the second position \ntable.insert(2, row);\n```\n\n#### Removing rows\nYou can use the `rm_row_at(index)` method to remove the row with the specified index, or use the `rm_row(id)` to remove\na row for a table with a [uid](#tables-with-uids).\n\n**Examples**\n```rust\nlet row = MyTableRow { id: 4, name: \"Pink Floyd\", email: \"pink@floyd.com\", address: \"England\"};\n// assume table was empty before this\ntable.push(row);\ntable.rm_row_at(0);\nassert_eq!(vec![], table.get_rows());\n```\n\nAnd for a table with a uid:\n```rust\nlet row = MyTableRow { id: 4, name: \"Pink Floyd\", email: \"pink@floyd.com\", address: \"England\"};\n// assume table was empty before this\ntable.push(row);\ntable.rm_row(4);\nassert_eq!(vec![], table.get_rows());\n```\n\n#### Column and row count\nYou can get the amount of columns using the `column_count()` function on your table. You can also get the amount of rows\nusing the `row_count()`.\n\n### Tables with UID's\nWe can specify a table with a unique identifier. The following example shows how to do this:\n\n```rust\nuse simple_tables::IdTable;\n\n#[table_row]\nstruct MyTableRow {\n  id: u32,\n  name: String\n}\n\n#[table(rows = MyTableRow)]\nstruct MyTable {}\n\n// When you need a table with rows containing uid's, you will have to manually implement the \n// `get_id_from_row` function\n// The `IdTable` takes in 2 type parameters, one for the id's type and one for the rows's type\nimpl IdTable\u003cu32, MyTableRow\u003e for MyTable {\n  // This function will simply return the id field from the row\n  fn get_id_from_row(row: \u0026MyTableRow) -\u003e u32 { \n    row.id \n  }\n}\n```\n\n**NOTE**: If your IDE complains saying `the trait bound MyTable: Table\u003cMyTableRow\u003e is not satisfied`, you can simply \nignore this. The `Table` trait is implemented in the `table` macro, but your IDE just doesn't know this.\n\nTo get rid of these warnings, you will have to enable the `org.rust.cargo.evaluate.build.scripts` and `org.rust.macros.proc`\nexperimental features. In IntelliJ, you can accomplish this by pressing `⇧⌘A` (macOs) or `⌃⇧A` (Linux/Windows) and searching\nfor `Experimental Features`, then enabling the two before-mentioned features.\n\n#### Getting a row based on the uid\n\nYou can get a row that matches the uid using the `get_row()` function.\n\n**Example**\n```rust\nlet vec = vec![ \n  MyTableRow { id: 1, name: \"Jimmy Page\".to_string() }, \n  MyTableRow { id: 2, name: \"Slayer\".to_string() }, \n  MyTableRow { id: 3, name: \"MGMT\".to_string() } \n];\n\nlet table = MyTable::from_vec(\u0026vec);\nlet table_row = table.get_row(2).unwrap();\n\nassert_eq!(vec[1], table_row.clone());\n```\n\nYou can also get a row mutably using its uid using the `get_row_mut(id)` method.\n\n**Example**\n```rust\nlet vec = vec![\n    MyTableRow { id: 1, name: \"Swedish House Mafia\".to_string() },\n    MyTableRow { id: 2, name: \"Pink Floyd\".to_string() },\n    MyTableRow { id: 3, name: \"Nick Cave \u0026 The Bad Seeds\".to_string() }\n];\nlet vec_unedited = vec![\n    MyTableRow { id: 1, name: \"Swedish House Mafia\".to_string() },\n    MyTableRow { id: 2, name: \"Pink Floyd\".to_string() },\n    MyTableRow { id: 3, name: \"Nick Cave\".to_string() }\n];\n\nlet table = MyTable::from_vec(\u0026vec);\nlet mut table2 = MyTable::from_vec(\u0026vec_unedited);\nlet row = table2.get_row_mut(3).unwrap();\nrow.name =  format!(\"{} {}\", row.name, \"\u0026 The Bad Seeds\");\nassert_eq!(table2.get_rows(), table.get_rows());\n```\n\nYou can get a row's index using `get_row_index(id)`.\n\nYou can remove a row with a uid using `rm_row(id)`.\n\n## Adding derive attributes\nYou can add derive attributes to your table, but you should put them beneath the `#[table]`.\n\n**Example**\n```rust\n#[table(MyTableRow)\n#[derive(PartialEq)]\nstruct MyTable {}\n```\n\n## Installing\nSimply add the crate to your `cargo.toml`.\n\n```toml\n[dependencies]\nsimple_tables = \"0.3.0\"\n```\n\nYou can see the crate on [crates.io](https://crates.io/crates/simple_tables)\n\n## Contributing\nContributions and suggestions are always welcome. \n\nIf you know how to improve the crate just let me know.\n\nYou can also claim one of the issues in the issues tab.\n\nWhen you contribute, make sure your commit passes the tests. You can run the tests by going into the tables directory\n`cd tables` and then running the tests with `cargo test`. I also have a CircleCI set up for this\nrepository that will test all commits. If you add a new feature, make sure to also write a test for this feature.\n\n## Documentation\nThe documentation can be found [here](https://jomy10.github.io/simple_tables/simple_tables/index.html).\n\nIt is also available on [docs.rs](https://docs.rs/simple_tables/latest/simple_tables/), here you can also find \ndocumentation of previous versions.\n\n## Use cases\nThis project started because I was working on an application that retrieved data from an SQL database. After making a\ndebug representation of my table, I thought that it might be a good idea to make this more generic, and so I started\nworking on this crate.\n\nHere's a snippet if you are interested:\n```rust\nuse mysql::PooledConn;\nuse mysql::prelude::Queryable;\nuse simple_tables::{IdTable, Table};\nuse simple_tables::macros::*;\n\n#[table_row]\npub struct DatabaseEntry {\n    id: u32,\n    name: String,\n    year: u32,\n    ban_id: u32,\n    ban: String,\n    emails: Emails\n}\n\n#[table(rows = DatabaseEntry)]\npub struct Database {}\n\nimpl IdTable\u003cu32, DatabaseEntry\u003e for Database {\n  fn get_id_from_row(row: \u0026DatabaseEntry) -\u003e u32 {\n    row.id\n  }\n}\n\nimpl Database {\n  pub fn fetch(conn: \u0026mut PooledConn) -\u003e Database {\n    let mut database: Database = Database::new();\n\n    let query = \"\\\n        SELECT Users.User_Id as id, Users.Name as name, Years.Year_Id as year, Bannen.Ban_Id as ban_id, Bannen.Naam as ban, Emails.Email as email FROM Users \\\n        INNER JOIN Years ON Users.Year_Id = Years.Year_Id \\\n        INNER JOIN Bannen ON Years.Ban_Id = Bannen.Ban_Id \\\n        LEFT JOIN Emails ON Emails.Email_Id = Users.User_Id\\\n        \";\n\n    conn.query_iter(query)\n            .unwrap()\n            .for_each(|row| {\n              let (user_id, name, years_id, ban_id, ban_naam, email):\n                      (u32, String, u32, u32, String, Option\u003cString\u003e)\n                      = mysql::from_row(row.unwrap());\n              if let Some(email) = email {\n                if let Some(entry) = database.get_row_mut(user_id) {\n                  entry.emails.push(email);\n                } else {\n                  // Create new entry\n                  database.push(\n                    DatabaseEntry {\n                      id: user_id,\n                      name,\n                      year: years_id,\n                      ban_id,\n                      ban: ban_naam,\n                      emails: Emails { emails: Some(vec![email]) }\n                    }\n                  );\n                }\n              } else {\n                // Create new entry\n                database.push(\n                  DatabaseEntry {\n                    id: user_id,\n                    name,\n                    year: years_id,\n                    ban_id,\n                    ban: ban_naam,\n                    emails: if email.is_some() { Emails { emails: Some(vec![email.unwrap()]) } } else { Emails { emails: None } }\n                  }\n                );\n              }\n\n            });\n\n    database\n  }\n}\n\n#[derive(Clone, Debug)]\npub struct Emails {\n  emails: Option\u003cVec\u003cString\u003e\u003e\n}\n\nimpl Emails {\n  fn push(\u0026mut self, s: String) {\n    if let Some(ref mut v) = self.emails {\n      v.push(s);\n    }\n  }\n}\n\nimpl ToString for Emails {\n  fn to_string(\u0026self) -\u003e String {\n    let mut s = String::new();\n    if self.emails.is_some() {\n      let len = self.emails.as_ref().unwrap().len();\n      for (i, email) in self.emails.as_ref().unwrap().iter().enumerate() {\n        if i != len - 1 {\n          s.push_str(format!(\"{}{}\", email, \", \").as_str());\n        } else {\n          s.push_str(email);\n        }\n      }\n    } else {\n      s.push_str(\"None\");\n    }\n    s\n  }\n}\n```\n\nIf you end up building something with this crate, let me know!\n\n## Questions?\nFeel free to open an issue or contact me directly with any questions.\n\n## License\nThis crate is licensed under the **MIT License**. Details in the [LICENSE](LICENSE) file.\n\nAlternatively, this crate can also be licensed under the [Apache 2.0-license](ALT_LICENSE).","funding_links":["https://paypal.me/JonasEveraert?country.x=BE\u0026locale.x=nl_NL"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjomy10%2Fsimple_tables","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjomy10%2Fsimple_tables","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjomy10%2Fsimple_tables/lists"}