{"id":38206030,"url":"https://github.com/urban-wombat/gotables","last_synced_at":"2026-01-17T00:34:58.493Z","repository":{"id":168979244,"uuid":"84535783","full_name":"urban-wombat/gotables","owner":"urban-wombat","description":"Simple dynamic type-safe in-memory tables for multi-key sorting, searching and merging","archived":false,"fork":false,"pushed_at":"2024-01-02T00:36:25.000Z","size":1668,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-13T19:05:23.224Z","etag":null,"topics":["dynamic","echo","syntax-checker","tables"],"latest_commit_sha":null,"homepage":"","language":"Go","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/urban-wombat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-03-10T08:10:53.000Z","updated_at":"2024-04-26T03:22:18.000Z","dependencies_parsed_at":"2024-03-28T15:15:44.893Z","dependency_job_id":null,"html_url":"https://github.com/urban-wombat/gotables","commit_stats":null,"previous_names":["urban-wombat/gotables","urban-wombat/gotable"],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/urban-wombat/gotables","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urban-wombat%2Fgotables","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urban-wombat%2Fgotables/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urban-wombat%2Fgotables/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urban-wombat%2Fgotables/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/urban-wombat","download_url":"https://codeload.github.com/urban-wombat/gotables/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urban-wombat%2Fgotables/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28490245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T23:55:29.509Z","status":"ssl_error","status_checked_at":"2026-01-16T23:55:29.108Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["dynamic","echo","syntax-checker","tables"],"created_at":"2026-01-17T00:34:57.996Z","updated_at":"2026-01-17T00:34:58.485Z","avatar_url":"https://github.com/urban-wombat.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/urban-wombat/gotables.svg?branch=master)](https://travis-ci.org/urban-wombat/gotables)\n\nSee [gotables godoc](https://godoc.org/github.com/urban-wombat/gotables)\n\n# Gotables \u0026 FlatBuffers\n\nThe focus of recent work is on support for Google `FlatBuffers`.\nIf you don't want to get into the weeds of the FlatBuffers API, `gotables` will save you a lot of time.\nBut a warning up front: this implementation doesn't support complex data structures such as Monsters. Only rectangular tables.\n\nTo distinguish the `gotables` FlatBuffers support from something that would support Monsters, I have called it `FlatTables`.\n\n* See [FlatBuffers Monster](https://google.github.io/flatbuffers/flatbuffers_guide_tutorial.html) for FlatBuffers Monster documentation\nto see what you may be missing out on. It's suitable for gaming.\n\n* See [The `gotables.FlatTables` implementation of Google FlatBuffers](https://github.com/urban-wombat/flattables).\nIt contains all the installation instructions and how to get started generating FlatBuffers code, and reading and writing FlatTables data.\n\nIn a nutshell, `gotables.FlatTables` does the following:\n* Makes it very easy to create a FlatBuffers schema and associated table-type-specific Go code to access FlatBuffers data.\n* Makes it a piece of cake (rectangular cake) to populate a set of one or more FlatBuffers tables as a []byte array.\n* Gives you easy methods (generated specifically for your table data types) to read from a FlatBuffers []byte array.\n* Provides a worked example (in the form of a main program) specific to your schema that is a tutorial you can use directly in your code.\n* [This particular tutorial](https://github.com/urban-wombat/flattables_sample_main/blob/master/flattables_sample_main.go)\n  is the `flattables_sample_main.go` generated for the `flattables_sample` package I created from\n  [my gotables file of tables](https://github.com/urban-wombat/flattables_sample/blob/master/tables.got).\n  Your own generated code will produce a tutorial main program _specific to **your** own gotables file of tables_.\n  Can you believe it?\n\n* See [https://github.com/urban-wombat/flattables](https://github.com/urban-wombat/flattables) for instructions on how to\n  install `FlatTables` and run the flattables_sample package, or create and run your own.\n\n* [https://urban-wombat.github.io](https://urban-wombat.github.io) has an introduction to `gotables`.\n\n\n# gotables\n\n`gotables` reinvents the wheel as a table.\nGo (golang) Table data format is simple and self-describing.\nOften data and configurations can be expressed best as tables, or can be flattened or normalised into tables.\nAnd events which are simple structs (or records) can be batched into tables for transmission.\n\n\t`go get -u github.com/urban-wombat/gotables`\n\n## Here's the `gotables` API ...\n\n[gotables API](https://godoc.org/github.com/urban-wombat/gotables) - a rich set of helper functions and methods\n\n## Here are the Release Notes ...\n\nhttps://github.com/urban-wombat/gotables/releases\n\n\u003ca id=\"cli\" /\u003e\n## Command line utilities ...\n\n| CLI | Purpose |\n| --- | ------- |\n| [gotecho](https://github.com/urban-wombat/gotables/tree/master/cmd/gotecho)           | echo 1 or all tables from a gotables file\n| [gotsyntax](https://github.com/urban-wombat/gotables/tree/master/cmd/gotsyntax)       | check syntax of 1 or more gotables files\n| [flattablesc](https://github.com/urban-wombat/flattables/tree/master/cmd/flattablesc) | generate Google FlatBuffers code\n\n## Contact:\n\n* _email:_ urban.wombat.burrow@gmail.com\n\n* _Twitter:_ @UrbanWombat\n\n## Why Use gotables?\n\n1. Often enough the data you want to represent is intrinsically tabular, or should be.\n2. You want tables of data to be more readable by human beings. Be able to look at the data and spot any problems.\n3. You want to eliminate repetitive metadata such as tags, and reduce the size of each tabular chunk of data.\n   Data name and type are mentioned only once in a gotables Table.\n4. Sometimes the data you want to represent is intrinsically tabular, and really you don't want any elements to be missing.\n   And if they are, you want it to be obvious.\n5. It feels like overkill to set up a relational database table (or tables) to store (and modify) your software configurations,\n   or to use a database as a conduit for sharing messages or data flows between processes or goroutines.\n6. If you are sending messages between goroutines in Go, you can use a gotables Table or a set of Tables (a TableSet) to send\n   data through your channels. A Table can be sent and received as an object or as a string.\n7. gotables has methods and functions to perform tasks in these broad categories:\n\n   1. Instantiate a gotables.Table or gotables.TableSet from a file, a string, a Go binary object, or a segment of an existing table.\n\n   2. Get and Set values. Most Go types are supported.\n\n   3. Sort and Search a table. Multiple keys and reverse sort and search are supported.\n\n   4. Merge two tables (with shared key(s)) into one. NaN and zero values are handled consistently.\n\n   5. SortUnique to remove NaN and zero values.\n\n8. **gotables Table is _simple_**. For instance, sorting (and searching) a table is probably as easy as it can possibly be.\n   And that can mean multiple sort/search keys, and even reverse keys. It's very simple. And if a wrong column name is\n   used, or you forget to set sort keys before sorting, the gotables error handling system will notice and return to you\n   a meaningful error message.\n\n9. Some advantages are subtle. For instance, **versioning** is easier. Your program can test for the presence of particular\n   columns (and their types) before accessing potentially new columns of data. And sending a table with additional columns\n   will not break downstream code.\n\n10. gotables is written in the Go language, using purely Go libraries. No third-party libraries will be used. If down the track\n\tnon-Go libraries are needed, a separate distribution will be created (to contain any third-party dependency issues) and\n\twill itself use gotables as a third-party library to maintain separation.\n\tThe core gotables library will **not* use third-party libraries.\n\n## Go Doc for gotables\n\nhttps://urban-wombat.github.io\n\n## What is a gotables.Table?\n\nA gotables.Table is a table of data with the following sections:\n1. A table name in square brackets:   **[planets]**\n2. A row of one or more column names: **name      mass**\n3. A row of one or more column types: **string    float64**\n4. Zero or more rows of data:         **\"Mercury\" 0.055**\n5. One or more blank lines before any subsequent table(s)\n\nIt's a bit like a slice of struct.\n\nHere's an example:\n\n    [planets]\n    name         mass distance moons index mnemonic\n    string    float64  float64   int   int string\n    \"Mercury\"   0.055      0.4     0     0 \"my\"\n    \"Venus\"     0.815      0.7     0     1 \"very\"\n    \"Earth\"     1.0        1.0     1     2 \"elegant\"\n    \"Mars\"      0.107      1.5     2     3 \"mother\"\n    \"Jupiter\" 318.0        5.2    79     4 \"just\"\n    \"Saturn\"   95.0        9.5    62     5 \"sat\"\n    \"Uranus\"   15.0       19.2    27     6 \"upon\"\n    \"Neptune\"  17.0       30.6    13     7 \"nine\"\n    \"Pluto\"     0.002     39.4     5     8 \"porcupines\"\n\nMost of the Go builtin data types can be used (except complex64 and complex128).\n\nHere is a simple program that parses the table into a gotables.Table and echoes it back out:\n\n```\n// main_echo.go\n\npackage main\n\nimport (\n    \"github.com/urban-wombat/gotables\"\n    \"fmt\"\n    \"log\"\n)\n\nfunc main() {\n    tableString :=\n    `[planets]\n    name         mass distance moons index mnemonic\n    string    float64  float64   int   int string\n    \"Mercury\"   0.055      0.4     0     0 \"my\"\n    \"Venus\"     0.815      0.7     0     1 \"very\"\n    \"Earth\"     1.0        1.0     1     2 \"elegant\"\n    \"Mars\"      0.107      1.5     2     3 \"mother\"\n    \"Jupiter\" 318.0        5.2    79     4 \"just\"\n    \"Saturn\"   95.0        9.5    62     5 \"sat\"\n    \"Uranus\"   15.0       19.2    27     6 \"upon\"\n    \"Neptune\"  17.0       30.6    13     7 \"nine\"\n    \"Pluto\"     0.002     39.4     5     8 \"porcupines\"\n    `\n    \n    table, err := gotables.NewTableFromString(tableString)\n    if err != nil {\n        log.Println(err)\n    }\n    \n    fmt.Println(\"Default String() padded output\\n\")\n    fmt.Println(table)\n\n    // Notice that the columns of data are padded with spaces, and numeric types are right-aligned.\n    // This reflects the opinion that human readability is important.\n\n    fmt.Println(\"For unpadded output use StringUnpadded()\\n\")\n    fmt.Println(table.StringUnpadded())\n}\n```\n\nHere's the output:\n\n```\nDefault String() padded output\n\n[planets]\nname         mass distance moons index mnemonic\nstring    float64  float64   int   int string\n\"Mercury\"   0.055      0.4     0     0 \"my\"\n\"Venus\"     0.815      0.7     0     1 \"very\"\n\"Earth\"     1.0        1.0     1     2 \"elegant\"\n\"Mars\"      0.107      1.5     2     3 \"mother\"\n\"Jupiter\" 318.0        5.2    79     4 \"just\"\n\"Saturn\"   95.0        9.5    62     5 \"sat\"\n\"Uranus\"   15.0       19.2    27     6 \"upon\"\n\"Neptune\"  17.0       30.6    13     7 \"nine\"\n\"Pluto\"     0.002     39.4     5     8 \"porcupines\"\n\nFor unpadded output use StringUnpadded()\n\n[planets]\nname mass distance moons index mnemonic\nstring float64 float64 int int string\n\"Mercury\" 0.055 0.4 0 0 \"my\"\n\"Venus\" 0.815 0.7 0 1 \"very\"\n\"Earth\" 1 1 1 2 \"elegant\"\n\"Mars\" 0.107 1.5 2 3 \"mother\"\n\"Jupiter\" 318 5.2 79 4 \"just\"\n\"Saturn\" 95 9.5 62 5 \"sat\"\n\"Uranus\" 15 19.2 27 6 \"upon\"\n\"Neptune\" 17 30.6 13 7 \"nine\"\n\"Pluto\" 0.002 39.4 5 8 \"porcupines\"\n\n```\n\n## Can you show me some worked examples?\n\nFor these examples to compile and run for you, you need to go get and import \"github.com/urban-wombat/gotables\"\nand prefix function and method calls with gotables.\n\n```\n// example1.go\n\npackage main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"github.com/urban-wombat/gotables\"\n)\n\n// Copyright (c) 2017 Malcolm Gorman\n\nfunc main() {\n    tableString :=\n    `[planets]\n    name         mass distance moons index mnemonic\n    string    float64  float64   int   int string\n    \"Mercury\"   0.055      0.4     0     0 \"my\"\n    \"Venus\"     0.815      0.7     0     1 \"very\"\n    \"Earth\"     1.0        1.0     1     2 \"elegant\"\n    \"Mars\"      0.107      1.5     2     3 \"mother\"\n    \"Jupiter\" 318.0        5.2    79     4 \"just\"\n    \"Saturn\"   95.0        9.5    62     5 \"sat\"\n    \"Uranus\"   15.0       19.2    27     6 \"upon\"\n    \"Neptune\"  17.0       30.6    13     7 \"nine\"\n    \"Pluto\"     0.002     39.4     5     8 \"porcupines\"\n    `\n\n    var err error\n\n    table, err := gotables.NewTableFromString(tableString)\n    if err != nil {\n    \tlog.Println(err)\n    }\n    fmt.Println(\"Table [planets] already in distance order.\")\n    fmt.Println(\"Distance is in AU: Earth units from the Sun\")\n    fmt.Println(table)\n\n    var rowIndex int\n\n    fmt.Println(\"Get the name and mass of the first planet.\")\n    rowIndex = 0\n    fmt.Printf(\"rowIndex = %d\\n\", rowIndex)\n    name, err := table.GetString(\"name\", rowIndex)\n    if err != nil {\n    \tlog.Println(err)\n    }\n    fmt.Printf(\"name = %s\\n\", name)\n\n    mass, err := table.GetFloat64(\"mass\", rowIndex)\n    if err != nil {\n    \tlog.Println(err)\n    }\n    fmt.Printf(\"mass = %f\\n\", mass)\n    fmt.Println()\n\n    fmt.Println(\"Get and Set the mnemonic of the second planet: index 1\")\n    rowIndex = 1\n    fmt.Printf(\"rowIndex = %d\\n\", rowIndex)\n    name, err = table.GetString(\"name\", rowIndex)\n    if err != nil {\n    \tlog.Println(err)\n    }\n    fmt.Printf(\"name = %s\\n\", name)\n\n    mnemonic, err := table.GetString(\"mnemonic\", rowIndex)\n    if err != nil {\n    \tlog.Println(err)\n    }\n    fmt.Printf(\"mnemonic = %q\\n\", mnemonic)\n\n    err = table.SetString(\"mnemonic\", rowIndex, \"*VERY*\")\n    if err != nil {\n    \tlog.Println(err)\n    }\n\n    mnemonic, err = table.GetString(\"mnemonic\", rowIndex)\n    if err != nil {\n    \tlog.Println(err)\n    }\n    fmt.Printf(\"mnemonic = %q\\n\", mnemonic)\n    fmt.Println()\n\n    fmt.Println(\"Sort and Search.\")\n    sortKey := \"name\"\n    fmt.Printf(\"sortKey = %q\\n\", sortKey)\n    err = table.SetSortKeys(sortKey)\n    if err != nil {\n    \tlog.Println(err)\n    }\n    err = table.Sort()\n    if err != nil {\n    \tlog.Println(err)\n    }\n\n    planet := \"Saturn\"\n    fmt.Printf(\"search value: planet = %q\\n\", planet)\n    rowIndex, err = table.Search(planet)\n    if err != nil {\n    \tlog.Println(err)\n    }\n\n    moons, err := table.GetInt(\"moons\", rowIndex)\n    if err != nil {\n    \tlog.Println(err)\n    }\n\n    fmt.Println(table)\n    fmt.Printf(\"%s has %d moons.\\n\", planet, moons)\n    fmt.Println()\n\n    fmt.Println(\"Sort and Search Range.\")\n    err = table.SetSortKeys(\"moons\")\n    if err != nil {\n    \tlog.Println(err)\n    }\n\n    err = table.Sort()\n    if err != nil {\n    \tlog.Println(err)\n    }\n\n    moons = 2\n    firstRowIndex, lastRowIndex, err := table.SearchRange(moons)\n    if err != nil {\n    \tlog.Println(err)\n    }\n    var planets int\n    if err == nil {\n    \tfmt.Println(\"Found at least 1 row with 2 moons.\")\n    \tplanets = lastRowIndex - firstRowIndex + 1\n    } else {\n    \t// moons = 3: [planets].Search([3]) search values not in table: [3]\n    \tfmt.Println(err)\n    \tplanets = 0\n    }\n    fmt.Println(table)\n    fmt.Printf(\"%d planets have %d moons.\\n\", planets, moons)\n    fmt.Println()\n\n\n    // Sort Unique.\n\n    tableString =\n    `[Unique]\n    key n       s\n    int float32 string\n    2   0       \"two point two\"\n    2   2.2     \"\"\n    1   1.1     \"one point one\"\n    3   3.3     \"three point three\"\n    3   3.3     \"\"\n    3   NaN     \"three point three\"\n    4   0.0     \"neither zero nor same XX\"\n    4   NaN     \"neither zero nor same YY\"\n    4   4.4     \"neither zero nor same ZZ\"\n    4   NaN     \"neither zero nor same AA\"\n    5   NaN     \"minus 5\"\n    5   -0      \"minus 5\"\n    5   -5      \"minus 5\"\n    `\n    table, err = gotables.NewTableFromString(tableString)\n    if err != nil {\n    \tlog.Println(err)\n    }\n\n    fmt.Println(\"Table [Unique] in no particular order, contains duplicate key values and zero and NaN values.\")\n    fmt.Println(table)\n\n    sortKey = \"key\"\n    fmt.Printf(\"sortKey = %q\\n\", sortKey)\n    err = table.SetSortKeys(sortKey)\n    if err != nil {\n    \tlog.Println(err)\n    }\n\n    tableUnique, err := table.SortUnique()\n    if err != nil {\n    \tlog.Println(err)\n    }\n    fmt.Printf(\"table [%s] sorted unique by key %q\\n\", tableUnique.Name(), sortKey)\n    fmt.Println(tableUnique)\n}\n```\n\nOutput:\n\n```\nTable [planets] already in distance order.\nDistance is in AU: Earth units from the Sun\n[planets]\nname         mass distance moons index mnemonic\nstring    float64  float64   int   int string\n\"Mercury\"   0.055      0.4     0     0 \"my\"\n\"Venus\"     0.815      0.7     0     1 \"very\"\n\"Earth\"     1.0        1.0     1     2 \"elegant\"\n\"Mars\"      0.107      1.5     2     3 \"mother\"\n\"Jupiter\" 318.0        5.2    79     4 \"just\"\n\"Saturn\"   95.0        9.5    62     5 \"sat\"\n\"Uranus\"   15.0       19.2    27     6 \"upon\"\n\"Neptune\"  17.0       30.6    13     7 \"nine\"\n\"Pluto\"     0.002     39.4     5     8 \"porcupines\"\n\nGet the name and mass of the first planet.\nrowIndex = 0\nname = Mercury\nmass = 0.055000\n\nGet and Set the mnemonic of the second planet: index 1\nrowIndex = 1\nname = Venus\nmnemonic = \"very\"\nmnemonic = \"*VERY*\"\n\nSort and Search.\nsortKey = \"name\"\nsearch value: planet = \"Saturn\"\n[planets]\nname         mass distance moons index mnemonic\nstring    float64  float64   int   int string\n\"Earth\"     1.0        1.0     1     2 \"elegant\"\n\"Jupiter\" 318.0        5.2    79     4 \"just\"\n\"Mars\"      0.107      1.5     2     3 \"mother\"\n\"Mercury\"   0.055      0.4     0     0 \"my\"\n\"Neptune\"  17.0       30.6    13     7 \"nine\"\n\"Pluto\"     0.002     39.4     5     8 \"porcupines\"\n\"Saturn\"   95.0        9.5    62     5 \"sat\"\n\"Uranus\"   15.0       19.2    27     6 \"upon\"\n\"Venus\"     0.815      0.7     0     1 \"*VERY*\"\n\nSaturn has 62 moons.\n\nSort and Search Range.\nFound at least 1 row with 2 moons.\n[planets]\nname         mass distance moons index mnemonic\nstring    float64  float64   int   int string\n\"Venus\"     0.815      0.7     0     1 \"*VERY*\"\n\"Mercury\"   0.055      0.4     0     0 \"my\"\n\"Earth\"     1.0        1.0     1     2 \"elegant\"\n\"Mars\"      0.107      1.5     2     3 \"mother\"\n\"Pluto\"     0.002     39.4     5     8 \"porcupines\"\n\"Neptune\"  17.0       30.6    13     7 \"nine\"\n\"Uranus\"   15.0       19.2    27     6 \"upon\"\n\"Saturn\"   95.0        9.5    62     5 \"sat\"\n\"Jupiter\" 318.0        5.2    79     4 \"just\"\n\n1 planets have 2 moons.\n\nTable [Unique] in no particular order, contains duplicate key values and zero and NaN values.\n[Unique]\nkey       n s\nint float32 string\n  2     0.0 \"two point two\"\n  2     2.2 \"\"\n  1     1.1 \"one point one\"\n  3     3.3 \"three point three\"\n  3     3.3 \"\"\n  3     NaN \"three point three\"\n  4     0.0 \"neither zero nor same XX\"\n  4     NaN \"neither zero nor same YY\"\n  4     4.4 \"neither zero nor same ZZ\"\n  4     NaN \"neither zero nor same AA\"\n  5     NaN \"minus 5\"\n  5    -0.0 \"minus 5\"\n  5    -5.0 \"minus 5\"\n\nsortKey = \"key\"\ntable [Unique] sorted unique by key \"key\"\n[Unique]\nkey       n s\nint float32 string\n  1     1.1 \"one point one\"\n  2     2.2 \"two point two\"\n  3     3.3 \"three point three\"\n  4     4.4 \"neither zero nor same AA\"\n  5    -5.0 \"minus 5\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furban-wombat%2Fgotables","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Furban-wombat%2Fgotables","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furban-wombat%2Fgotables/lists"}