[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".gitignore",
    "content": "tests/*.txt\ntests/test.cpp\ntests/test\ntests/queries/*\n.vscode/*\nexample\n.DS_STORE\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Michael Kitzan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Constexpr SQL\n\nA light weight single header alternative to DBMS\n\nThis library was developed during my honors project at the [University of Victoria](https://www.uvic.ca/engineering/computerscience/index.php) under the supervision of [Bill Bird](https://github.com/billbird). The original development occurred in this [Metaprogramming Optimization](https://github.com/mkitzan/metaprogramming-optimization) repository, but was moved into a new, dedicated, home repository. The project was inspired and influenced by [Hana Dusíková](https://github.com/hanickadot)'s great [Compile Time Regular Expressions](https://github.com/hanickadot/compile-time-regular-expressions) library (CTRE).\n\nMaintenance may slow in the near future due to my employer's open source software policy. I will be looking into getting approval to continue maintaining this project.\n\n## Library Features and Compiler Support\n\nSupported features:\n\n- SQL query syntax for data processing\n- `SELECT` data querying\n- `AS` column renaming\n- `CROSS JOIN` (note: all column names of each relation must be unique)\n- `NATURAL JOIN` (note: natural join will attempt to join on the first column of each relation)\n- `WHERE` clause predicates on numeric and `std::string` types\n- Wildcard selection with `*`\n- Nested queries\n- Uppercase and lowercase SQL keywords\n- Modern `!=` and legacy `<>` not-equal operator\n- Standard SQL operator precedence in `WHERE` clause\n- Schemas support all default constructable types\n- Indexes for schemas (used for sorting the data)\n- Range loop and structured binding declaration support\n- [Loading data](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L180) from files (no header row)\n- [Storing data](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L210) from `sql::schema` and `sql::query` objects to files\n- Element querying from `sql::row` objects with [`sql::get<\"column-name\">`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L81)\n\nUnsupported features (future work):\n\n- `INNER JOIN`, `OUTER JOIN`, `LEFT JOIN`, and `RIGHT JOIN`\n- `GROUP BY`, `HAVING`, and `ORDER BY` (using indexes can simulate some of these features)\n- `IN` operation within `WHERE` clause\n- Template argument error detection\n\nAs of April 2020, Constexpr SQL is only supported by **`GCC 9.0+`**. The compiler support is constrained because of the widespread use of the new `C++20` feature [\"Class Types in Non-Type Template Parameters\"](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0732r2.pdf) (proposal `P0732R2`) which is only implemented by `GCC 9.0+`. Library users specify SQL queries and column labels with string literals which are converted into `constexpr` objects all of which relies on functionality from `P0732R2`.\n\n## Example\n\nThe following example shows usage of all class templates a user is expected to define to use the library.\n\n```c++\n#include <iostream>\n#include <string>\n\n#include \"sql.hpp\"\n\nusing books =\n\tsql::schema<\n\t\t\"books\", sql::index<\"title\">,\n\t\tsql::column<\"title\", std::string>,\n\t\tsql::column<\"genre\", std::string>,\n\t\tsql::column<\"year\", unsigned>,\n\t\tsql::column<\"pages\", unsigned>\n\t>;\n\nusing authored =\n\tsql::schema<\n\t\t\"authored\", sql::index<>,\n\t\tsql::column<\"title\", std::string>,\n\t\tsql::column<\"name\", std::string>\n\t>;\n\nusing query =\n\tsql::query<\n\t\t\"SELECT title AS book, name AS author, year, pages \"\n\t\t\"FROM books NATURAL JOIN (SELECT * FROM authored WHERE name = \\\"Harlan Ellison\\\") \"\n\t\t\"WHERE year = 1967 OR year >= 1972 AND genre = \\\"science fiction\\\"\",\n\t\tbooks, authored\n\t>;\n\nint main()\n{\n\tauthored a{ sql::load<authored>(\"tests/data/authored.tsv\", '\\t') };\n\tbooks b{ sql::load<books>(\"tests/data/books.tsv\", '\\t') };\n\n\tfor (query q{ b, a }; auto const& [book, author, year, pages] : q)\n\t{\n\t\tstd::cout << book << '\\t' << author << '\\t' << year << '\\t' << pages << '\\n';\n\t}\n\n\treturn 0;\n}\n```\n\n[`sql::schema`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp) defines a relation used in a query. [`sql::index`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/index.hpp) defines how an `sql::schema` sorts its data (unsorted if unspecified). [`sql::column`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/column.hpp) types are used to define the rows in an `sql::schema`. [`sql::query`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp) wraps a query statement and the `sql::schema` types the query will operate on. [`sql::load`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L180) can be used to load data from a file into an `sql::schema`.\n\nThe example is from [`example.cpp`](https://github.com/mkitzan/constexpr-sql/blob/master/example.cpp) in the root of the repository, and can be compiled and executed with the following command:\n\n```shell\ng++ -std=c++2a -pedantic -Wall -Wextra -Werror -O3 -Isingle-header/ -o example example.cpp && ./example\n```\n\nIt is strongly recommended to compile with optimizations enabled, otherwise expect template bloat. Use of multiple objects of the same `sql::query` type is considered **undefined behavior** (due to issues involving static members). Instantiating `sql::query` objects should be performed within a guarded scope, like in the example. However, there are no use restrictions to `sql::schema` types. `sql::schema` types may be used multiple times within a single query or in many queries at once. There are more examples and information in [`presentation.pdf`](https://github.com/mkitzan/constexpr-sql/blob/master/presentation.pdf) at the root of the repository.\n\n## Correctness and Performance Testing\n\nThe library has a significant testing system which is composed of two script pipelines. All tests use the data from another project of mine called [`Terminus`](https://github.com/mkitzan/terminus) which is a library database shell. The correctness testing pipeline generates nearly 1.5 million test queries, then Constexpr SQL's output is compared against the output of `SQLite3` performing the same queries. The performance testing pipeline executes six different SQL queries implemented using Constexpr SQL and hand coded SQL. The queries are executed over 65 thousand times (256 for `CROSS JOIN` due to computational complexity), and the execution timing is captured using the Linux `time` tool.\n\nThe [`runner.sh`](https://github.com/mkitzan/constexpr-sql/blob/master/tests/runner.sh) script in the `tests` directory will execute correctness testing, and the [`runner.sh`](https://github.com/mkitzan/constexpr-sql/tree/master/tests/perf/runner.sh) script in `tests/perf` will execute performance testing.\n\n## Important Class Templates and Implementation Details\n\nThe following sections provide a high-level description about how the library is implemented. Hopefully, the sections will provide useful code and document references to others looking to write similar libraries.\n\n### Class Template: `sql::schema`\n\nThe `sql::schema` class template represents relational schemas and, when instantiated, SQL tables. The class template is parameterized on three template parameters: `Name`, `Index`, and `Col` template parameter pack. `Name` defines the SQL table name which is matched against table names in a query's `FROM` statement. The `Index` template argument is used to support `GROUP BY` statements by using [**SFINAE**](https://en.cppreference.com/w/cpp/language/sfinae) to select the [underlying column data container](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L25) (`std::vector` or `std::multiset`). The `Index` template argument, when fully specified, provides the [comparator functor](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/index.hpp#L15) used by the `std::multiset` container. The `Cols` template parameter pack is expanded into the `sql::row` type for the schema. `sql::schema` objects support [**structured binding declarations**](https://en.cppreference.com/w/cpp/language/structured_binding) which is facilitated partly through the `sql::schema` API and partly through [`std` namespace injections from `sql::row`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L131) helping to satisfy the [argument dependant lookup](https://en.cppreference.com/w/cpp/language/adl) of the [`get<i>` function](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L97).\n\nReference the example [earlier](https://github.com/mkitzan/constexpr-sql#example) for proper usage of `sql::schema`. Notice in the example the string literal as a template argument. String literals are lvalue reference types which are passed as `const` pointers. Normally, pointers can not be used as template arguments. With the new C++20 feature mentioned [earlier](https://github.com/mkitzan/constexpr-sql#library-features-and-compiler-support), a [`cexpr::string`](https://github.com/mkitzan/constexpr-sql/blob/master/include/cexpr/string.hpp) constructor template can be [deduced](https://en.cppreference.com/w/cpp/language/class_template_argument_deduction) to turn the string literal into a `constexpr` object. The deduction is enabled through [`cexpr::string`'s class template argument deduction guide](https://github.com/mkitzan/constexpr-sql/blob/master/include/cexpr/string.hpp#L144) which provides a mapping of constructor arguments to template parameters.\n\n### Class Template: `sql::query`\n\nThe [`sql::query`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp) class template is the user interface to the SQL query parser. The class is templated on a `cexpr::string` object (the SQL query) and a template parameter pack of `sql::schema` types. At compile time, the SQL query string is parsed into the relational algebra expression tree representing the query's computation. The constructor to a fully specified `sql::query` class takes a variadic pack of `sql::schema` objects which it uses to seed the relational algebra expression tree with iterators to data. The `sql::query` object can then be used in a range loop with structured binding declarations like in the example.\n\nThe relational algebra expression tree uses static members to hold data, so only one object of a single fully specified `sql::query` class can exist at once in the program. To ensure this the object should be constructed within a guarded scope like in the example. It's worth noting that even though this class template's source file is the largest among the code base, nearly all of it is only live during compilation to parse the SQL query. In fact, the [runtime interface](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp#L666) is deliberately insubstantial, merely providing an wrapper to support range loops and structured binding declarations.\n\nIn compliance with range loop syntax, `sql::query` has an associated iterator class [`sql::query_iterator`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp#L189). `sql::query_iterator` wraps the type representing the relational algebra expression and handles all of the idiosyncrasies of its usage in favor of the familiar [`forward iterator`](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) interface. When an [`sql::query_iterator` is dereferenced](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp#L211), it returns a constant reference to an `sql::row` object representing the current row of output from the query stream.\n\n### Class Template: `sql::row`\n\nThe [`sql::row`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp) class template is a template recursive linked-list (similar to [`std::tuple`](https://en.cppreference.com/w/cpp/utility/tuple)). A template recursive linked-list is a template metaprogramming pattern which expresses a type analogous to a traditional linked-list. `sql::row` implements this pattern with two template parameters `Col` and `Next`. `Col` represents the [`sql::column`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/column.hpp) which the node in list holds a data element from. `Next` represents the type of the next node in the list, which is either another `sql::row` type or [`sql::void_row`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L12). Because the next node is expressed as a type the template linked-list does not incur the overhead of holding a next pointer nor the run time cost of dereferencing a pointer to iterate (also makes better use of the cache). A quirk to this pattern is that the node data type need not be homogenous across the list, instead the list may be composed of heterogenous data types. Also, template linked-list access is computed at compile time, so the run time cost is constant.\n\nThe example does not demonstrate the [`sql::get<cexpr::string>`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L81) helper function. This helper function allows the user to query a specific element from an `sql::row` object by column name. Additionally, `sql::row` has [**ML**-like](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L81) functions for getting the `head` and `tail` of the object.\n\n### Relational Algebra Expression Nodes\n\nAt the moment, [`ra::projection`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/projection.hpp), [`ra::rename`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/rename.hpp), [`ra::cross`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/cross.hpp), [`ra::natural`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/natural.hpp), [`ra::selection`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/selection.hpp), and [`ra::relation`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/relation.hpp) are the only relational algebra nodes implemented. `ra::projection` and `ra::rename` are unary operators which take a single `sql::row` from their `Input` relational algebra operator and fold their operation over the row before propagating the transformed row to their `Output`. The `fold` is implemented as a template recursive function. `ra::cross` outputs the cross product of two relations. `ra::natural` implements a natural join between two relations using a hash table buffer of the right relation for performance. `ra::selection` uses a predicate function constructed from a `WHERE` clause to filter rows in a query. `ra::relation` is the only terminal node in the expression tree which is used for retrieving the next input in the stream. These operators are composable types and are used to serialize the relational algebra expression tree. Individual objects of each type are not instantiated to compose the expression tree. Instead to ensure the expression tree is a zero overhead abstraction, the types implement a `static` member function `next` used to request data from its input type. The actual `constexpr` template recursive recursive descent SQL parser will serialize these individual nodes together into the appropriate expression tree.\n\n### Constexpr Parsing\n\nAs a proof of concept for `constexpr` parsing, two math expression parsers were implemented in old repository: [`cexpr::prefix`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp) and [`cexpr::infix`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/infix.hpp). `cexpr::prefix` demonstrates the fundamental method of `constexpr` parsing an expression tree into a class template. `cexpr::infix` extends this to perform `constepxr` recursive descent parsing. `cexpr::infix` and the SQL query parser are a whole order of magnitude more complex, because there's recursive function template instantiations to many different function templates. The explanation of `constexpr` parsing is illustrated through `cexpr::prefix` for simplicity.\n\nThe expression tree created while parsing is a template recursive tree which shares similar properties to the template linked-list (discussed [earlier](https://github.com/mkitzan/constexpr-sql#class-template-sqlrow)). A notable benefit to this data structure is that because the tree is composed of types rather than data values, the tree can be used to express computation models (expression trees) rather than just a tree based container.\n\nFundamentally, the parsing is accomplished by calling a template recursive `static constexpr` parsing function member parameterized on the token position which the parser's \"cursor\" is standing on ([`Pos`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp#L39) template parameter). At each \"cursor\" position, the function uses the token to decide the how to proceed. If the token indicates the start of an operation, the parser recurses the immediate left subexpression (\"cursor\" + 1). On return, the left subexpression will report the depth in the token stream it recursed at which point the right subexpression will pick up at this position. This control flow is expressed in [this line](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp#L47) of [`cexpr::prefix::parse`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp#L40). Once both left and right subexpressions are parsed, the new node's type is formed ([`decltype`](https://en.cppreference.com/w/cpp/language/decltype) left and right subexpressions) which is then propagated to the caller. Otherwise, if the token indicates a terminal, then an appropriate terminal node is constructed. It is necessary that the \"cursor\" position is unique across template instantiations, otherwise template memoization will lead to \"infinite\" recursion.\n\nThe few ancillary class templates used to support this parsing and the math node `struct` templates can be found in the [`templ` namespace](https://github.com/mkitzan/metaprogramming-optimization/tree/master/include/templ) of the old repository. There is also a [driver program](https://github.com/mkitzan/metaprogramming-optimization/blob/master/resources/parser/equation.cpp) using the parsers in the old repository. In the Constexpr SQL parser, all of the entities in the `templ` namespace were replaced for more template metaprogramming idiomatic structures.\n"
  },
  {
    "path": "example.cpp",
    "content": "#include <iostream>\n#include <string>\n\n#include \"sql.hpp\"\n\nusing books =\n\tsql::schema<\n\t\t\"books\", sql::index<\"title\">,\n\t\tsql::column<\"title\", std::string>,\n\t\tsql::column<\"genre\", std::string>,\n\t\tsql::column<\"year\", unsigned>,\n\t\tsql::column<\"pages\", unsigned>\n\t>;\n\nusing authored =\n\tsql::schema<\n\t\t\"authored\", sql::index<>,\n\t\tsql::column<\"title\", std::string>,\n\t\tsql::column<\"name\", std::string>\n\t>;\n\nusing query =\n\tsql::query<\n\t\t\"SELECT title AS book, name AS author, year, pages \"\n\t\t\"FROM books NATURAL JOIN (SELECT * FROM authored WHERE name = \\\"Harlan Ellison\\\") \"\n\t\t\"WHERE year = 1967 OR year >= 1972 AND genre = \\\"science fiction\\\"\",\n\t\tbooks, authored\n\t>;\n\nint main()\n{\n\tauthored a{ sql::load<authored>(\"tests/data/authored.tsv\", '\\t') };\n\tbooks b{ sql::load<books>(\"tests/data/books.tsv\", '\\t') };\n\n\tfor (query q{ b, a }; auto const& [book, author, year, pages] : q)\n\t{\n\t\tstd::cout << book << '\\t' << author << '\\t' << year << '\\t' << pages << '\\n';\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "generator.py",
    "content": "import os\n\ndef include(header, incs, root, included):\n\tfile = open(\"include/\" + root, \"r\")\n\n\tfor line in file:\n\t\tif line == \"#pragma once\\n\" or line == \"\\n\":\n\t\t\tpass\n\t\telif line[:10] == \"#include \\\"\":\n\t\t\tif not line in included:\n\t\t\t\tincluded += [line]\n\t\t\t\tinclude(header, incs, line[10:-2], included)\n\t\telif line[:10] == \"#include <\":\n\t\t\tincs += [line]\n\t\telse:\n\t\t\theader.write(line)\n\t\t\tbreak\n\t\n\tfor line in file:\n\t\theader.write(line)\n\theader.write(\"\\n\")\n\n\treturn included, incs\n\ndef main():\n\theader = open(\"temp\", \"w\")\n\tincluded, incs = include(header, [], \"sql/schema.hpp\", [])\n\tincluded, incs = include(header, incs, \"sql/query.hpp\", included)\n\theader.close()\n\theader = open(\"single-header/sql.hpp\", \"w\")\n\theader.write(\"#pragma once\\n\\n\")\n\n\tfor line in sorted(set(incs)):\n\t\theader.write(line)\n\theader.write(\"\\n\")\n\n\tfor line in open(\"temp\"):\n\t\theader.write(line)\n\n\tos.remove(\"temp\")\n\nif __name__ == \"__main__\":\n\tmain()\n"
  },
  {
    "path": "include/cexpr/string.hpp",
    "content": "#pragma once\n\n#include <cstddef>\n#include <string>\n#include <string_view>\n\nnamespace cexpr\n{\n\n\ttemplate <typename Char, std::size_t N>\n\tclass string\n\t{\n\tpublic:\n\t\tusing char_type = Char;\n\n\t\tconstexpr string() noexcept : size_{ 0 }, string_{ 0 }\n\t\t{}\n\n\t\tconstexpr string(const Char(&s)[N]) noexcept : string{}\n\t\t{\n\t\t\tfor(; s[size_]; ++size_)\n\t\t\t{\n\t\t\t\tstring_[size_] = s[size_];\n\t\t\t}\n\t\t}\n\n\t\tconstexpr string(cexpr::string<Char, N> const& s) noexcept : string{}\n\t\t{\n\t\t\tfor (; s[size_]; ++size_)\n\t\t\t{\n\t\t\t\tstring_[size_] = s[size_];\n\t\t\t}\n\t\t}\n\n\t\tconstexpr string(std::basic_string_view<Char> const& s) noexcept : string{}\n\t\t{\n\t\t\tif (s.length() < N)\n\t\t\t{\n\t\t\t\tfor (; size_ < s.length(); ++size_)\n\t\t\t\t{\n\t\t\t\t\tstring_[size_] = s[size_];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconstexpr void fill(const Char* begin, const Char* end) noexcept\n\t\t{\n\t\t\tfill_from(begin, end, begin());\n\t\t}\n\n\t\tconstexpr void fill_from(const Char* begin, const Char* end, Char* start) noexcept\n\t\t{\n\t\t\tif (end - begin < N)\n\t\t\t{\n\t\t\t\tfor (auto curr{ start }; begin != end; ++begin, ++curr)\n\t\t\t\t{\n\t\t\t\t\t*curr = *begin;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tinline constexpr std::size_t capacity() const noexcept\n\t\t{ \n\t\t\treturn N - 1;\n\t\t}\n\n\t\tinline constexpr std::size_t size() const noexcept\n\t\t{\n\t\t\treturn size_;\n\t\t}\n\n\t\tinline constexpr Char* begin() noexcept\n\t\t{\n\t\t\treturn string_;\n\t\t}\n\t\tinline constexpr const Char* cbegin() const noexcept\n\t\t{\n\t\t\treturn string_;\n\t\t}\n\n\t\tinline constexpr Char* end() noexcept\n\t\t{\n\t\t\treturn &string_[size_];\n\t\t}\n\t\tinline constexpr const Char* cend() const noexcept\n\t\t{\n\t\t\treturn &string_[size_];\n\t\t}\n\n\t\tinline constexpr Char& operator[](std::size_t i)\n\t\t{\n\t\t\treturn string_[i];\n\t\t}\n\t\tinline constexpr Char const& operator[](std::size_t i) const\n\t\t{\n\t\t\treturn string_[i];\n\t\t}\n\n\t\ttemplate <typename OtherChar, std::size_t OtherN>\n\t\tconstexpr bool operator==(string<OtherChar, OtherN> const& other) const noexcept\n\t\t{\n\t\t\tif constexpr (N != OtherN)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tstd::size_t i{};\n\t\t\tfor (; i < N && string_[i] == other[i]; ++i);\n\n\t\t\treturn i == N;\n\t\t}\n\n\t\ttemplate <typename OtherChar, std::size_t OtherN>\n\t\tconstexpr bool operator==(const OtherChar(&other)[OtherN]) const noexcept\n\t\t{\n\t\t\tif constexpr (N != OtherN)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tstd::size_t i{};\n\t\t\tfor (; i < N && string_[i] == other[i]; ++i);\n\n\t\t\treturn i == N;\n\t\t}\n\n\t\ttemplate <typename OtherChar>\n\t\tinline bool operator==(std::basic_string<OtherChar> const& other) const noexcept\n\t\t{\n\t\t\treturn other == string_;\n\t\t}\n\n\t\ttemplate <typename OtherChar>\n\t\tinline bool operator!=(std::basic_string<OtherChar> const& other) const noexcept\n\t\t{\n\t\t\treturn !(other == string_);\n\t\t}\n\n\tprivate:\n\t\tstd::size_t size_;\n\t\tChar string_[N];\n\t};\n\n\ttemplate <typename Char, std::size_t N>\n\tstring(const Char[N]) -> string<Char, N>;\n\n\ttemplate <typename Char, std::size_t N>\n\tinline bool operator==(std::basic_string<Char> const& str, string<Char, N> const& cstr) noexcept\n\t{\n\t\treturn cstr == str;\n\t}\n\n\ttemplate <typename Char, std::size_t N>\n\tinline bool operator!=(std::basic_string<Char> const& str, string<Char, N> const& cstr) noexcept\n\t{\n\t\treturn cstr != str;\n\t}\n\n} // namespace cexpr\n"
  },
  {
    "path": "include/ra/cross.hpp",
    "content": "#pragma once\n\n#include \"ra/join.hpp\"\n#include \"ra/relation.hpp\"\n\nnamespace ra\n{\n\n\ttemplate <typename LeftInput, typename RightInput>\n\tclass cross : public ra::join<LeftInput, RightInput>\n\t{\n\t\tusing join_type = ra::join<LeftInput, RightInput>;\n\tpublic:\n\t\tusing output_type = join_type::output_type;\n\n\t\tstatic auto&& next()\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tcopy(join_type::output_row, RightInput::next());\n\t\t\t}\n\t\t\tcatch(ra::data_end const& e)\n\t\t\t{\n\t\t\t\tcopy(join_type::output_row, LeftInput::next());\n\t\t\t\tRightInput::reset();\n\t\t\t\tcopy(join_type::output_row, RightInput::next());\n\t\t\t}\n\n\t\t\treturn std::move(join_type::output_row);\n\t\t}\n\t};\n\n} // namespace ra\n"
  },
  {
    "path": "include/ra/join.hpp",
    "content": "#pragma once\n\n#include <type_traits>\n\n#include \"ra/operation.hpp\"\n\n#include \"sql/row.hpp\"\n\nnamespace ra\n{\n\n\tnamespace\n\t{\n\n\t\ttemplate <typename Left, typename Right>\n\t\tconstexpr auto recr_merge()\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Left, sql::void_row>)\n\t\t\t{\n\t\t\t\treturn Right{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tusing next = decltype(recr_merge<typename Left::next, Right>());\n\n\t\t\t\treturn sql::row<typename Left::column, next>{};\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Left, typename Right>\n\t\tinline constexpr auto merge()\n\t\t{\n\t\t\tif constexpr (Left::column::name == Right::column::name)\n\t\t\t{\n\t\t\t\treturn recr_merge<Left, typename Right::next>();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn recr_merge<Left, Right>();\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Dest, typename Row>\n\t\tconstexpr void recr_copy(Dest& dest, Row const& src)\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Row, sql::void_row>)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdest.head() = src.head();\n\t\t\t\trecr_copy(dest.tail(), src.tail());\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Dest, typename Row>\n\t\tinline constexpr void copy(Dest& dest, Row const& src)\n\t\t{\n\t\t\tif constexpr (Dest::column::name == Row::column::name)\n\t\t\t{\n\t\t\t\trecr_copy(dest, src);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcopy(dest.tail(), src);\n\t\t\t}\n\t\t}\n\n\t} // namespace\n\n\ttemplate <typename LeftInput, typename RightInput>\n\tclass join : public ra::binary<LeftInput, RightInput>\n\t{\n\t\tusing binary_type = ra::binary<LeftInput, RightInput>;\n\t\tusing left_type = typename binary_type::left_type;\n\t\tusing right_type = typename binary_type::right_type;\n\tpublic:\n\t\tusing output_type = decltype(merge<left_type, right_type>());\n\n\t\ttemplate <typename... Inputs>\n\t\tstatic inline void seed(Inputs const&... rs)\n\t\t{\n\t\t\tbinary_type::seed(rs...);\n\t\t\tcopy(output_row, LeftInput::next());\n\t\t}\n\n\t\tstatic inline void reset()\n\t\t{\n\t\t\tbinary_type::reset();\n\t\t\tcopy(output_row, LeftInput::next());\n\t\t}\n\n\t\tstatic output_type output_row;\n\t};\n\n\ttemplate <typename LeftInput, typename RightInput>\n\ttypename join<LeftInput, RightInput>::output_type join<LeftInput, RightInput>::output_row{};\n\n} // namespace ra\n"
  },
  {
    "path": "include/ra/natural.hpp",
    "content": "#pragma once\n\n#include <type_traits>\n#include <vector>\n#include <unordered_map>\n\n#include \"ra/join.hpp\"\n#include \"ra/relation.hpp\"\n\nnamespace ra\n{\n\n\ttemplate <typename LeftInput, typename RightInput>\n\tclass natural : public ra::join<LeftInput, RightInput>\n\t{\n\t\tusing join_type = ra::join<LeftInput, RightInput>;\n\t\tusing key_type = std::remove_cvref_t<decltype(LeftInput::next().head())>;\n\t\tusing value_type = std::vector<std::remove_cvref_t<decltype(RightInput::next().tail())>>;\n\t\tusing map_type = std::unordered_map<key_type, value_type>;\n\tpublic:\n\t\tusing output_type = join_type::output_type;\n\n\t\ttemplate <typename... Inputs>\n\t\tstatic void seed(Inputs const&... rs)\n\t\t{\n\t\t\tjoin_type::seed(rs...);\n\t\t\t\n\t\t\tif (row_cache.empty())\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tfor (;;)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto const& row{ RightInput::next() };\n\t\t\t\t\t\trow_cache[row.head()].push_back(row.tail());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch(ra::data_end const& e)\n\t\t\t\t{\n\t\t\t\t\tRightInput::reset();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tauto const& active{ row_cache[join_type::output_row.head()] };\n\t\t\tcurr = active.cbegin();\n\t\t\tend = active.cend();\n\t\t}\n\n\t\tstatic auto&& next()\n\t\t{\n\t\t\twhile (curr == end)\n\t\t\t{\n\t\t\t\tcopy(join_type::output_row, LeftInput::next());\n\t\t\t\tauto const& active{ row_cache[join_type::output_row.head()] };\n\t\t\t\tcurr = active.cbegin();\n\t\t\t\tend = active.cend();\n\t\t\t}\n\n\t\t\tcopy(join_type::output_row, *curr++);\n\t\t\t\n\t\t\treturn std::move(join_type::output_row);\n\t\t}\n\n\tprivate:\n\t\tstatic map_type row_cache;\n\t\tstatic value_type::const_iterator curr;\n\t\tstatic value_type::const_iterator end;\n\t};\n\n\ttemplate <typename LeftInput, typename RightInput>\n\ttypename natural<LeftInput, RightInput>::map_type natural<LeftInput, RightInput>::row_cache{};\n\n\ttemplate <typename LeftInput, typename RightInput>\n\ttypename natural<LeftInput, RightInput>::value_type::const_iterator natural<LeftInput, RightInput>::curr;\n\n\ttemplate <typename LeftInput, typename RightInput>\n\ttypename natural<LeftInput, RightInput>::value_type::const_iterator natural<LeftInput, RightInput>::end;\n\n} // namespace ra\n"
  },
  {
    "path": "include/ra/operation.hpp",
    "content": "#pragma once\n\n#include <type_traits>\n\nnamespace ra\n{\n\n\ttemplate <typename Input>\n\tclass unary\n\t{\n\tpublic:\n\t\tusing input_type = std::remove_cvref_t<decltype(Input::next())>;\n\n\t\ttemplate <typename... Inputs>\n\t\tstatic inline void seed(Inputs const&... rs)\n\t\t{\n\t\t\tInput::seed(rs...);\n\t\t}\n\n\t\tstatic inline void reset()\n\t\t{\n\t\t\tInput::reset();\n\t\t}\n\t};\n\n\ttemplate <typename LeftInput, typename RightInput>\n\tclass binary\n\t{\n\tpublic:\n\t\tusing left_type = std::remove_cvref_t<decltype(LeftInput::next())>;\n\t\tusing right_type = std::remove_cvref_t<decltype(RightInput::next())>;\n\n\t\ttemplate <typename... Inputs>\n\t\tstatic inline void seed(Inputs const&... rs)\n\t\t{\n\t\t\tLeftInput::seed(rs...);\n\t\t\tRightInput::seed(rs...);\n\t\t}\n\n\t\tstatic inline void reset()\n\t\t{\n\t\t\tLeftInput::reset();\n\t\t\tRightInput::reset();\n\t\t}\n\t};\n\n} // namespace ra\n"
  },
  {
    "path": "include/ra/projection.hpp",
    "content": "#pragma once\n\n#include \"ra/operation.hpp\"\n\n#include \"sql/row.hpp\"\n\nnamespace ra\n{\n\n\ttemplate <typename Output, typename Input>\n\tclass projection : public ra::unary<Input>\n\t{\n\t\tusing input_type =  typename ra::unary<Input>::input_type;\n\tpublic:\n\t\tusing output_type = Output;\n\n\t\tstatic auto&& next()\n\t\t{\n\t\t\tfold<output_type>(output_row, Input::next());\n\t\t\t\n\t\t\treturn std::move(output_row);\n\t\t}\n\n\tprivate:\n\t\ttemplate <typename Dest>\n\t\tstatic inline constexpr void fold(Dest& dest, input_type const& src)\n\t\t{\n\t\t\tif constexpr (Dest::depth == 0)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdest.head() = sql::get<Dest::column::name>(src);\n\t\t\t\tfold<typename Dest::next>(dest.tail(), src);\t\n\t\t\t}\n\t\t}\n\n\t\tstatic output_type output_row;\n\t};\n\n\ttemplate <typename Output, typename Input>\n\ttypename projection<Output, Input>::output_type projection<Output, Input>::output_row{};\n\n} // namespace ra\n"
  },
  {
    "path": "include/ra/relation.hpp",
    "content": "#pragma once\n\n#include <exception>\n#include <type_traits>\n\nnamespace ra\n{\n\n\tstruct data_end : std::exception\n\t{};\n\n\t// Id template parameter allows unique ra::relation types to be instantiated from\n\t//\ta single sql::schema type (for queries referencing a schema multiple times).\n\ttemplate <typename Schema, std::size_t Id>\n\tclass relation\n\t{\n\tpublic:\n\t\tusing output_type = Schema::row_type&;\n\n\t\tstatic auto& next()\n\t\t{\n\t\t\tif (curr != end)\n\t\t\t{\n\t\t\t\treturn *curr++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthrow ra::data_end{};\n\t\t\t}\n\t\t}\n\t\t\n\t\ttemplate <typename Input, typename... Inputs>\n\t\tstatic void seed(Input const& r, Inputs const&... rs) noexcept\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Input, Schema>)\n\t\t\t{\n\t\t\t\tcurr = r.begin();\n\t\t\t\tbegin = r.begin();\n\t\t\t\tend = r.end();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tseed(rs...);\n\t\t\t}\n\t\t}\n\n\t\tstatic inline void reset() noexcept\n\t\t{\n\t\t\tcurr = begin;\n\t\t}\n\n\tprivate:\n\t\tstatic Schema::const_iterator curr;\n\t\tstatic Schema::const_iterator begin;\n\t\tstatic Schema::const_iterator end;\n\t};\n\n\ttemplate <typename Schema, std::size_t Id>\n\tSchema::const_iterator relation<Schema, Id>::curr{};\n\n\ttemplate <typename Schema, std::size_t Id>\n\tSchema::const_iterator relation<Schema, Id>::begin{};\n\n\ttemplate <typename Schema, std::size_t Id>\n\tSchema::const_iterator relation<Schema, Id>::end{};\n\n} // namespace ra\n"
  },
  {
    "path": "include/ra/rename.hpp",
    "content": "#pragma once\n\n#include \"ra/operation.hpp\"\n\n#include \"sql/row.hpp\"\n\nnamespace ra\n{\n\n\ttemplate <typename Output, typename Input>\n\tclass rename : public ra::unary<Input>\n\t{\n\t\tusing input_type = typename ra::unary<Input>::input_type;\n\tpublic:\n\t\tusing output_type = Output;\n\n\t\tstatic auto&& next()\n\t\t{\n\t\t\tfold<output_type, input_type>(output_row, Input::next());\n\t\t\t\n\t\t\treturn std::move(output_row);\n\t\t}\n\n\tprivate:\n\t\ttemplate <typename Dest, typename Src>\n\t\tstatic inline constexpr void fold(Dest& dest, Src const& src)\n\t\t{\n\t\t\tif constexpr (Dest::depth == 0)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdest.head() = src.head();\n\t\t\t\tfold<typename Dest::next, typename Src::next>(dest.tail(), src.tail());\n\t\t\t}\n\t\t}\n\n\t\tstatic output_type output_row;\n\t};\n\n\ttemplate <typename Output, typename Input>\n\ttypename rename<Output, Input>::output_type rename<Output, Input>::output_row{};\n\t\n} // namespace ra\n"
  },
  {
    "path": "include/ra/selection.hpp",
    "content": "#pragma once\n\n#include \"ra/operation.hpp\"\n\nnamespace ra\n{\n\n\ttemplate <typename Predicate, typename Input>\n\tclass selection : public ra::unary<Input>\n\t{\n\t\tusing input_type = typename ra::unary<Input>::input_type;\n\tpublic:\n\t\tusing output_type = input_type;\t\t\n\n\t\tstatic auto&& next()\n\t\t{\n\t\t\toutput_row = Input::next();\n\n\t\t\twhile(!Predicate::eval(output_row))\n\t\t\t{\n\t\t\t\toutput_row = Input::next();\n\t\t\t}\n\n\t\t\treturn std::move(output_row);\n\t\t}\n\n\tprivate:\n\t\tstatic output_type output_row;\n\t};\n\n\ttemplate <typename Output, typename Input>\n\ttypename selection<Output, Input>::output_type selection<Output, Input>::output_row{};\n\n} // namespace ra\n"
  },
  {
    "path": "include/sql/column.hpp",
    "content": "#pragma once\n\n#include \"cexpr/string.hpp\"\n\nnamespace sql\n{\n\n\ttemplate <cexpr::string Name, typename Type>\n\tstruct column\n\t{\n\t\tstatic constexpr auto name{ Name };\n\t\t\n\t\tusing type = Type;\n\t};\n\n} // namespace sql\n"
  },
  {
    "path": "include/sql/index.hpp",
    "content": "#pragma once\n\n#include <type_traits>\n\n#include \"cexpr/string.hpp\"\n\n#include \"sql/row.hpp\"\n\nnamespace sql\n{\n\n\ttemplate <cexpr::string... Columns>\n\tstruct index\n\t{\n\t\ttemplate <typename Row>\n\t\tstruct comparator\n\t\t{\n\t\t\tbool operator()(Row const& left, Row const& right) const noexcept\n\t\t\t{\n\t\t\t\treturn compare<Columns...>(left, right);\n\t\t\t}\n\t\t\n\t\tprivate:\n\t\t\ttemplate <cexpr::string Col, cexpr::string... Cols>\n\t\t\tbool compare(Row const& left, Row const& right) const noexcept\n\t\t\t{\n\t\t\t\tauto const& l{ sql::get<Col>(left) };\n\t\t\t\tauto const& r{ sql::get<Col>(right) };\n\n\t\t\t\tif constexpr (sizeof...(Cols) != 0)\n\t\t\t\t{\n\t\t\t\t\tif (l == r)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn compare<Cols...>(left, right);\n\t\t\t\t\t}\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn l < r;\n\t\t\t}\n\t\t};\n\t};\n\n} // namespace sql\n"
  },
  {
    "path": "include/sql/predicate.hpp",
    "content": "#pragma once\n\n#include <cstddef>\n\n#include \"cexpr/string.hpp\"\n\nnamespace sql\n{\n\n\tnamespace\n\t{\n\n\t\t// shim to allow all value types like double or float to be used as non-type template parameters.\n\t\ttemplate <typename Type>\n\t\tstruct value\n\t\t{\n\t\t\tconstexpr value(Type v) : val{ v }\n\t\t\t{}\n\n\t\t\tType val;\n\t\t};\n\n\t} // namespace\n\n\ttemplate <cexpr::string Op, typename Row, typename Left, typename Right=void>\n\tstruct operation\n\t{\n\t\tstatic constexpr bool eval(Row const& row) noexcept\n\t\t{\n\t\t\tif constexpr (Op == \"=\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) == Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr (Op == \">\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) > Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"<\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) < Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \">=\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) >= Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"<=\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) <= Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"!=\" || Op == \"<>\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) != Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"AND\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) && Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"OR\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) || Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"NOT\")\n\t\t\t{\n\t\t\t\treturn !Left::eval(row);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <cexpr::string Column, typename Row>\n\tstruct variable\n\t{\n\t\tstatic constexpr auto eval(Row const& row) noexcept\n\t\t{\n\t\t\treturn sql::get<Column>(row);\n\t\t}\n\t};\n\n\ttemplate <auto Const, typename Row>\n\tstruct constant\n\t{\n\t\tstatic constexpr auto eval([[maybe_unused]] Row const& row) noexcept\n\t\t{\n\t\t\treturn Const.val;\n\t\t}\n\t};\n\n} // namespace sql\n"
  },
  {
    "path": "include/sql/query.hpp",
    "content": "#pragma once\n\n#include <array>\n#include <string>\n#include <string_view>\n#include <type_traits>\n\n#include \"cexpr/string.hpp\"\n\n#include \"ra/cross.hpp\"\n#include \"ra/join.hpp\"\n#include \"ra/natural.hpp\"\n#include \"ra/projection.hpp\"\n#include \"ra/relation.hpp\"\n#include \"ra/rename.hpp\"\n#include \"ra/selection.hpp\"\n\n#include \"sql/column.hpp\"\n#include \"sql/tokens.hpp\"\n#include \"sql/predicate.hpp\"\n#include \"sql/row.hpp\"\n\nnamespace sql\n{\n\n\t// anonymous namespace to hold helper data structures and functions\n\tnamespace\n\t{\n\n\t\ttemplate <std::size_t Pos, typename Node>\n\t\tstruct context\n\t\t{\n\t\t\tusing node = Node;\n\t\t\tstatic constexpr std::size_t pos = Pos;\n\t\t};\n\n\t\ttemplate <typename Type, std::size_t Name, std::size_t Next>\n\t\tstruct colinfo\n\t\t{\n\t\t\tusing type = Type;\n\t\t\tstatic constexpr std::size_t name = Name;\n\t\t\tstatic constexpr std::size_t next = Next;\n\t\t};\n\n\t\ttemplate <cexpr::string Name, typename Row>\n\t\tconstexpr bool exists() noexcept\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Row, sql::void_row>)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif constexpr (Row::column::name == Name)\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn exists<Name, typename Row::next>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Type, typename Char, std::size_t N>\n\t\tconstexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept\n\t\t{\n\t\t\tauto curr{ str.cbegin() }, end{ str.cend() };\n\t\t\tconstexpr Char dot{ '.' }, zro{ '0' }, min{ '-' };\n\t\t\tType acc{}, sign{ 1 }, scalar{ 10 };\n\n\t\t\tif (*curr == min)\n\t\t\t{\n\t\t\t\tsign = -1;\n\t\t\t\t++curr;\n\t\t\t}\n\n\t\t\twhile (curr != end && *curr != dot)\n\t\t\t{\n\t\t\t\tacc = (acc * scalar) + (*curr - zro);\n\t\t\t\t++curr;\n\t\t\t}\n\n\t\t\tif (curr != end && *curr == dot)\n\t\t\t{\n\t\t\t\tscalar = 1;\n\t\t\t\t++curr;\n\n\t\t\t\twhile(curr != end)\n\t\t\t\t{\n\t\t\t\t\tacc += (*curr - zro) * (scalar /= Type{ 10 });\n\t\t\t\t\t++curr;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn value<Type>{ acc * sign };\n\t\t}\n\n\t\tinline constexpr bool isquote(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"\\\"\" || tv == \"'\";\n\t\t}\n\n\t\tinline constexpr bool isor(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"OR\" || tv == \"or\";\n\t\t}\n\n\t\tinline constexpr bool isand(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"AND\" || tv == \"and\";\n\t\t}\n\n\t\tinline constexpr bool isnot(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"NOT\" || tv == \"not\";\n\t\t}\n\n\t\tinline constexpr bool isnatural(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"NATURAL\" || tv == \"natural\";\n\t\t}\n\n\t\tinline constexpr bool isjoin(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"JOIN\" || tv == \"join\";\n\t\t}\n\n\t\tinline constexpr bool iswhere(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"WHERE\" || tv == \"where\";\n\t\t}\n\n\t\tinline constexpr bool isfrom(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"FROM\" || tv == \"from\";\n\t\t}\n\n\t\tinline constexpr bool isas(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"AS\" || tv == \"as\";\n\t\t}\n\n\t\tinline constexpr bool isselect(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"SELECT\" || tv == \"select\";\n\t\t}\n\n\t\tinline constexpr bool iscomma(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \",\";\n\t\t}\n\n\t\tconstexpr bool isintegral(std::string_view const& tv) noexcept\n\t\t{\n\t\t\tbool result{ false };\n\n\t\t\tfor (auto c : tv)\n\t\t\t{\n\t\t\t\tresult |= (c == '.');\n\t\t\t}\n\n\t\t\treturn !result;\n\t\t}\n\n\t\tconstexpr bool isdigit(char c) noexcept\n\t\t{\n\t\t\treturn (c >= '0' && c <= '9') || c == '-' || c == '.';\n\t\t}\n\n\t\tconstexpr bool iscomp(char c) noexcept\n\t\t{\n\t\t\treturn c == '=' || c == '!' || c == '<' || c == '>';\n\t\t}\n\n\t\tconstexpr bool iscolumn(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn !iscomma(tv) && !isas(tv) && !isfrom(tv);\n\t\t}\n\n\t\tconstexpr bool isseparator(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn iscomma(tv) || isfrom(tv);\n\t\t}\n\n\t} // namespace\n\n\t// structured binding compliant iterator for query objects\n\ttemplate <typename Expr>\n\tclass query_iterator\n\t{\n\tpublic:\n\t\tusing row_type = std::remove_cvref_t<typename Expr::output_type>;\n\n\t\t// seeds row datamember for first dereference\n\t\tquery_iterator(bool end) : end_{ end }, row_{}\n\t\t{\n\t\t\toperator++();\n\t\t}\n\n\t\tinline bool operator==(query_iterator const& it) const noexcept\n\t\t{\n\t\t\treturn end_ == it.end_;\n\t\t}\n\n\t\tinline bool operator!=(query_iterator const& it) const noexcept\n\t\t{\n\t\t\treturn !(*this == it);\n\t\t}\n\n\t\tinline row_type const& operator*() const noexcept\n\t\t{\n\t\t\treturn row_;\n\t\t}\n\n\t\tquery_iterator& operator++()\n\t\t{\n\t\t\tif (!end_)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\trow_ = Expr::next();\n\t\t\t\t}\n\t\t\t\tcatch (ra::data_end const& e)\n\t\t\t\t{\n\t\t\t\t\tend_ = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn *this;\n\t\t}\n\n\tprivate:\n\t\tbool end_{};\n\t\trow_type row_{};\n\t};\n\n\ttemplate <cexpr::string Str, typename... Schemas>\n\tclass query\n\t{\n\tprivate:\n\t\t// where predicate terminal parsing \n\t\ttemplate <std::size_t Pos, typename Row>\n\t\tstatic constexpr auto parse_terms()\n\t\t{\n\t\t\tif constexpr (tokens_[Pos] == \"(\")\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_or<Pos + 1, Row>() };\n\n\t\t\t\tusing node = typename decltype(next)::node;\n\n\t\t\t\tstatic_assert(tokens_[next.pos] == \")\", \"No closing paranthesis found.\");\n\n\t\t\t\treturn context<next.pos + 1, node>{};\n\t\t\t}\n\t\t\telse if constexpr (isquote(tokens_[Pos]))\n\t\t\t{\n\t\t\t\tconstexpr cexpr::string<char, tokens_[Pos + 1].length() + 1> name{ tokens_[Pos + 1] };\n\n\t\t\t\tusing str = decltype(name);\n\t\t\t\tusing node = sql::constant<value<str>{ name }, Row>;\n\n\t\t\t\tstatic_assert(isquote(tokens_[Pos + 2]), \"No closing quote found.\");\n\n\t\t\t\treturn context<Pos + 3, node>{};\n\t\t\t}\n\t\t\telse if constexpr (isdigit(tokens_[Pos][0]))\n\t\t\t{\n\t\t\t\tconstexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };\n\t\t\t\t\n\t\t\t\tusing val = decltype(isintegral(tokens_[Pos]) ? std::int64_t{} : double{});\n\t\t\t\tusing node = sql::constant<sql::convert<val>(name), Row>;\n\n\t\t\t\treturn context<Pos + 1, node>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };\n\n\t\t\t\tusing node = sql::variable<name, Row>;\n\n\t\t\t\treturn context<Pos + 1, node>{};\n\t\t\t}\n\t\t}\n\n\t\t// parses a single compare operation\n\t\ttemplate <typename Left, typename Row>\n\t\tstatic constexpr auto recurse_comparison()\n\t\t{\n\t\t\tif constexpr (!iscomp(tokens_[Left::pos][0]))\n\t\t\t{\n\t\t\t\treturn Left{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_terms<Left::pos + 1, Row>() };\n\t\t\t\tconstexpr cexpr::string<char, tokens_[Left::pos].length() + 1> name{ tokens_[Left::pos] };\n\n\t\t\t\tusing ranode = typename decltype(next)::node;\n\t\t\t\tusing node = sql::operation<name, Row, typename Left::node, ranode>;\n\n\t\t\t\treturn context<next.pos, node>{};\n\t\t\t}\t\t\t\n\t\t}\n\n\t\t// descend further and attempt to parse a compare operation\n\t\ttemplate <std::size_t Pos, typename Row>\n\t\tstatic constexpr auto parse_comparison()\n\t\t{\n\t\t\tusing left = decltype(parse_terms<Pos, Row>());\n\t\t\t\n\t\t\treturn recurse_comparison<left, Row>();\n\t\t}\n\n\t\t// attempt to parse a negation operation then descend further\n\t\ttemplate <std::size_t Pos, typename Row>\n\t\tstatic constexpr auto parse_negation()\n\t\t{\n\t\t\tif constexpr (isnot(tokens_[Pos]))\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_comparison<Pos + 1, Row>() };\n\n\t\t\t\tusing ranode = typename decltype(next)::node;\n\t\t\t\tusing node = sql::operation<\"NOT\", Row, ranode>;\n\n\t\t\t\treturn context<next.pos, node>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn parse_comparison<Pos, Row>();\n\t\t\t}\n\t\t}\n\n\t\t// recursively parse chained AND operations\n\t\ttemplate <typename Left, typename Row>\n\t\tstatic constexpr auto recurse_and()\n\t\t{\n\t\t\tif constexpr (!isand(tokens_[Left::pos]))\n\t\t\t{\n\t\t\t\treturn Left{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_negation<Left::pos + 1, Row>() };\n\n\t\t\t\tusing ranode = typename decltype(next)::node;\n\t\t\t\tusing node = sql::operation<\"AND\", Row, typename Left::node, ranode>;\n\n\t\t\t\treturn recurse_and<context<next.pos, node>, Row>();\n\t\t\t}\n\t\t}\n\n\t\t// descend further then attempt to parse AND operations\n\t\ttemplate <std::size_t Pos, typename Row>\n\t\tstatic constexpr auto parse_and()\n\t\t{\n\t\t\tusing left = decltype(parse_negation<Pos, Row>());\n\t\t\t\n\t\t\treturn recurse_and<left, Row>();\n\t\t}\n\t\t\n\t\t// recursively parse chained OR operations\n\t\ttemplate <typename Left, typename Row>\n\t\tstatic constexpr auto recurse_or()\n\t\t{\n\t\t\tif constexpr (!isor(tokens_[Left::pos]))\n\t\t\t{\n\t\t\t\treturn Left{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_and<Left::pos + 1, Row>() };\n\t\t\t\t\n\t\t\t\tusing ranode = typename decltype(next)::node;\n\t\t\t\tusing node = sql::operation<\"OR\", Row, typename Left::node, ranode>;\n\n\t\t\t\treturn recurse_or<context<next.pos, node>, Row>();\n\t\t\t}\n\t\t}\n\n\t\t// descend further then attempt to parse OR operations\n\t\ttemplate <std::size_t Pos, typename Row>\n\t\tstatic constexpr auto parse_or()\n\t\t{\n\t\t\tusing left = decltype(parse_and<Pos, Row>());\n\t\t\t\n\t\t\treturn recurse_or<left, Row>();\n\t\t}\n\n\t\t// find correct schema for terminal relation\n\t\ttemplate <cexpr::string Name, std::size_t Id, typename Schema, typename... Others>\n\t\tstatic constexpr auto recurse_schemas()\n\t\t{\n\t\t\tif constexpr (Name == Schema::name)\n\t\t\t{\n\t\t\t\treturn ra::relation<Schema, Id>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstatic_assert(sizeof...(Others) != 0, \"Schema name used in JOIN was not provided.\");\n\n\t\t\t\treturn recurse_schemas<Name, Id, Others...>();\n\t\t\t}\n\t\t}\n\n\t\t// wrapper function to determine terminal relation\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_schema()\n\t\t{\n\t\t\tif constexpr (tokens_[Pos] == \"(\")\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_root<Pos + 1>() };\n\t\t\t\t\n\t\t\t\tusing node = typename decltype(next)::node;\n\n\t\t\t\tstatic_assert(tokens_[next.pos] == \")\", \"No closing paranthesis found.\");\n\n\t\t\t\treturn context<next.pos + 1, node>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };\n\n\t\t\t\tusing node = decltype(recurse_schemas<name, Pos, Schemas...>());\n\n\t\t\t\treturn context<Pos + 1, node>{};\n\t\t\t}\n\t\t}\n\n\t\t// stub which will choose the specific join RA node\n\t\ttemplate <std::size_t Pos, typename Left, typename Right>\n\t\tstatic constexpr auto choose_join()\n\t\t{\n\t\t\tif constexpr (isnatural(tokens_[Pos]))\n\t\t\t{\n\t\t\t\treturn ra::natural<Left, Right>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn ra::cross<Left, Right>{};\t\n\t\t\t}\n\t\t}\n\n\t\t// parses join colinfo if a join is present else returns the single relation terminal\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_join()\n\t\t{\n\t\t\tconstexpr auto lnext{ parse_schema<Pos>() };\n\n\t\t\tusing lnode = typename decltype(lnext)::node;\n\n\t\t\tif constexpr (lnext.pos + 2 < tokens_.count() && isjoin(tokens_[lnext.pos + 1]))\n\t\t\t{\n\t\t\t\tconstexpr auto rnext{ parse_schema<lnext.pos + 2>() };\n\n\t\t\t\tusing rnode = typename decltype(rnext)::node;\n\t\t\t\tusing join = decltype(choose_join<lnext.pos, lnode, rnode>());\n\n\t\t\t\treturn context<rnext.pos, join>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn context<lnext.pos, lnode>{};\n\t\t\t}\n\t\t}\n\n\t\t// starting point to parse everything after the from keyword\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_from()\n\t\t{\n\t\t\tstatic_assert(isfrom(tokens_[Pos]), \"Expected 'FROM' token not found.\");\n\n\t\t\tconstexpr auto next{ parse_join<Pos + 1>() };\n\n\t\t\tusing node = typename decltype(next)::node;\n\n\t\t\tif constexpr (next.pos < tokens_.count() && iswhere(tokens_[next.pos]))\n\t\t\t{\n\t\t\t\tusing output = std::remove_cvref_t<typename node::output_type>;\n\n\t\t\t\tconstexpr auto predicate{ parse_or<next.pos + 1, output>() };\n\n\t\t\t\tusing pnext = typename decltype(predicate)::node;\n\t\t\t\tusing snode = ra::selection<pnext, node>;\n\n\t\t\t\treturn context<predicate.pos, snode>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn context<next.pos, node>{};\t\n\t\t\t}\n\t\t}\n\n\t\t// recursively searches all schemas for the a matching column\n\t\ttemplate <cexpr::string Name, typename Schema, typename... Others>\n\t\tstatic constexpr auto recurse_types()\n\t\t{\n\t\t\tif constexpr (sql::exists<Name, typename Schema::row_type>())\n\t\t\t{\n\t\t\t\treturn decltype(sql::get<Name>(typename Schema::row_type{})){};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstatic_assert(sizeof...(Others) != 0, \"Column name was not present in any schema.\");\n\n\t\t\t\treturn recurse_types<Name, Others...>();\n\t\t\t}\n\t\t}\n\n\t\t// wrapper to determine the type for the the column\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto column_type()\n\t\t{\n\t\t\tconstexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };\n\n\t\t\treturn recurse_types<name, Schemas...>();\n\t\t}\n\n\t\t// asserts token is column separator, and if comma returns one past the comma else start position\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr std::size_t next_column()\n\t\t{\n\t\t\tstatic_assert(isseparator(tokens_[Pos]), \"Expected ',' or 'FROM' token following column.\");\n\n\t\t\tif constexpr (iscomma(tokens_[Pos]))\n\t\t\t{\n\t\t\t\treturn Pos + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn Pos;\n\t\t\t}\n\t\t}\n\n\t\ttemplate <std::size_t Pos, bool Rename>\n\t\tstatic constexpr auto parse_colinfo()\n\t\t{\n\t\t\tstatic_assert(iscolumn(tokens_[Pos]), \"Invalid token starting column delcaration.\");\n\n\t\t\tconstexpr bool rename{ isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]) };\n\n\t\t\tusing col = decltype(column_type<Pos>());\n\n\t\t\tif constexpr (Rename && rename)\n\t\t\t{\n\t\t\t\tconstexpr auto next{ next_column<Pos + 3>() };\n\n\t\t\t\treturn colinfo<col, Pos + 2, next>{};\n\t\t\t}\n\t\t\telse if constexpr (rename)\n\t\t\t{\n\t\t\t\tconstexpr auto next{ next_column<Pos + 3>() };\n\n\t\t\t\treturn colinfo<col, Pos, next>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr auto next{ next_column<Pos + 1>() };\n\n\t\t\t\treturn colinfo<col, Pos, next>{};\n\t\t\t}\n\t\t}\n\n\t\t// recursively parse all columns projected/renamed in the query\n\t\ttemplate <std::size_t Pos, bool Rename>\n\t\tstatic constexpr auto recurse_columns()\n\t\t{\n\t\t\tif constexpr (isfrom(tokens_[Pos]))\n\t\t\t{\n\t\t\t\treturn context<Pos, sql::void_row>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr auto info{ parse_colinfo<Pos, Rename>() };\n\t\t\t\tconstexpr cexpr::string<char, tokens_[info.name].length() + 1> name{ tokens_[info.name] };\n\t\t\t\tconstexpr auto child{ recurse_columns<info.next, Rename>() };\n\n\t\t\t\tusing next = std::remove_const_t<typename decltype(child)::node>;\n\t\t\t\tusing col = std::remove_const_t<decltype(sql::column<name, typename decltype(info)::type>{})>;\n\t\t\t\tusing node = sql::row<col, next>;\n\n\t\t\t\treturn context<child.pos, node>{};\n\t\t\t}\n\t\t}\n\n\t\t// wrapper to parse columns as a projection RA node\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_projection()\n\t\t{\n\t\t\tconstexpr auto proj{ recurse_columns<Pos, false>() };\n\t\t\tconstexpr auto next{ parse_from<proj.pos>() };\n\n\t\t\tusing ranode = typename decltype(proj)::node;\n\t\t\tusing node = ra::projection<ranode, typename decltype(next)::node>;\n\n\t\t\treturn context<next.pos, node>{};\n\t\t}\n\n\t\t// wrapper to parse columns as a rename RA node\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_rename()\n\t\t{\n\t\t\tconstexpr auto next = parse_projection<Pos>();\n\n\t\t\tusing ranode = typename decltype(recurse_columns<Pos, true>())::node;\n\t\t\tusing node = ra::rename<ranode, typename decltype(next)::node>;\n\n\t\t\treturn context<next.pos, node>{};\n\t\t}\n\n\t\t// attempts to match column rename operation pattern on a column\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr bool has_rename()\n\t\t{\n\t\t\tif constexpr (isfrom(tokens_[Pos]) || isfrom(tokens_[Pos + 2]))\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse if constexpr (iscolumn(tokens_[Pos]) && isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]))\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr bool comma{ iscomma(tokens_[Pos + 1]) };\n\n\t\t\t\tstatic_assert(comma || isfrom(tokens_[Pos + 1]), \"Expected ',' or 'FROM' token following column.\");\n\n\t\t\t\tif constexpr (comma)\n\t\t\t\t{\n\t\t\t\t\treturn has_rename<Pos + 2>();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn has_rename<Pos + 1>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// decide RA node to root the expression tree\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_root()\n\t\t{\n\t\t\tstatic_assert(isselect(tokens_[Pos]), \"Expected 'SELECT' token not found.\");\n\n\t\t\tif constexpr (tokens_[Pos + 1] == \"*\")\n\t\t\t{\n\t\t\t\treturn parse_from<Pos + 2>();\n\t\t\t}\n\t\t\telse if constexpr (has_rename<Pos + 1>())\n\t\t\t{\n\t\t\t\treturn parse_rename<Pos + 1>();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn parse_projection<Pos + 1>();\n\t\t\t}\n\t\t}\n\n\t\tstatic constexpr sql::tokens<char, sql::preprocess(Str)> tokens_{ Str };\n\n\t\tusing expression = typename decltype(parse_root<0>())::node;\n\n\t\tbool empty_;\n\t\n\tpublic:\n\t\tusing iterator = query_iterator<expression>;\n\t\tusing row_type = expression::output_type;\n\n\t\tquery(Schemas const&... tables)\n\t\t{\n\t\t\ttry \n\t\t\t{\n\t\t\t\texpression::seed(tables...);\n\t\t\t\tempty_ = false;\n\t\t\t}\n\t\t\tcatch(ra::data_end const& e)\n\t\t\t{\n\t\t\t\tempty_ = true;\n\t\t\t}\n\t\t}\n\n\t\t~query()\n\t\t{\n\t\t\texpression::reset();\n\t\t}\n\n\t\tinline iterator begin() const\n\t\t{\n\t\t\treturn iterator{ empty_ };\n\t\t}\n\n\t\tinline iterator end() const\n\t\t{\n\t\t\treturn iterator{ true };\n\t\t}\n\t};\n\n} // namespace sql\n"
  },
  {
    "path": "include/sql/row.hpp",
    "content": "#pragma once\n\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#include \"cexpr/string.hpp\"\n\nnamespace sql\n{\n\n\tstruct void_row\n\t{\n\t\tstatic constexpr std::size_t depth{ 0 };\n\t};\n\n\ttemplate <typename Col, typename Next>\n\tclass row\n\t{\n\tpublic:\n\t\tusing column = Col;\n\t\tusing next = Next;\n\n\t\tstatic constexpr std::size_t depth{ 1 + next::depth };\n\n\t\trow() = default;\n\n\t\ttemplate <typename... ColTs>\n\t\trow(column::type const& val, ColTs const&... vals) : value_{ val }, next_{ vals... }\n\t\t{}\n\n\t\ttemplate <typename... ColTs>\n\t\trow(column::type&& val, ColTs&&... vals) : value_{ std::forward<column::type>(val) }, next_{ std::forward<ColTs>(vals)... }\n\t\t{}\n\n\t\tinline constexpr next const& tail() const noexcept\n\t\t{\n\t\t\treturn next_;\n\t\t}\n\n\t\tinline constexpr next& tail() noexcept\n\t\t{\n\t\t\treturn next_;\n\t\t}\n\n\t\tinline constexpr column::type const& head() const noexcept\n\t\t{\n\t\t\treturn value_;\n\t\t}\n\n\t\tinline constexpr column::type& head() noexcept\n\t\t{\n\t\t\treturn value_;\n\t\t}\n\t\n\tprivate:\n\t\tcolumn::type value_;\n\t\tnext next_;\n\t};\n\n\ttemplate <typename Col, typename... Cols>\n\tstruct variadic_row\n\t{\n\tprivate:\n\t\tstatic inline constexpr auto resolve() noexcept\n\t\t{\n\t\t\tif constexpr (sizeof...(Cols) != 0)\n\t\t\t{\n\t\t\t\treturn typename variadic_row<Cols...>::row_type{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn void_row{};\n\t\t\t}\n\t\t}\n\n\tpublic:\n\t\tusing row_type = row<Col, decltype(resolve())>;\n\t};\n\n\t// user function to query row elements by column name\n\ttemplate <cexpr::string Name, typename Row>\n\tconstexpr auto const& get(Row const& r) noexcept\n\t{\n\t\tstatic_assert(!std::is_same_v<Row, sql::void_row>, \"Name does not match a column name.\");\n\n\t\tif constexpr (Row::column::name == Name)\n\t\t{\n\t\t\treturn r.head();\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn get<Name>(r.tail());\n\t\t}\n\t}\n\n\t// compiler function used by structured binding declaration\n\ttemplate <std::size_t Pos, typename Row>\n\tconstexpr auto const& get(Row const& r) noexcept\n\t{\n\t\tstatic_assert(Pos < Row::depth, \"Position is larger than number of row columns.\");\n\n\t\tif constexpr (Pos == 0)\n\t\t{\n\t\t\treturn r.head();\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn get<Pos - 1>(r.tail());\n\t\t}\n\t}\n\n\t// function to assign a value to a column's value in a row\n\ttemplate <cexpr::string Name, typename Row, typename Type>\n\tconstexpr void set(Row& r, Type const& value)\n\t{\n\t\tstatic_assert(!std::is_same_v<Row, sql::void_row>, \"Name does not match a column name.\");\n\n\t\tif constexpr (Row::column::name == Name)\n\t\t{\n\t\t\tr.head() = value;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tset<Name>(r.tail(), value);\n\t\t}\n\t}\n\n} // namespace sql\n\n// STL injections to allow row to be used in structured binding declarations\nnamespace std\n{\n\n\ttemplate <typename Col, typename Next>\n\tclass tuple_size<sql::row<Col, Next>> : public integral_constant<size_t, sql::row<Col, Next>::depth>\n\t{};\n\n\ttemplate <size_t Index, typename Col, typename Next>\n\tstruct tuple_element<Index, sql::row<Col, Next>>\n\t{\n\t\tusing type = decltype(sql::get<Index>(sql::row<Col, Next>{}));\n\t};\n\n} // namespace std\n"
  },
  {
    "path": "include/sql/schema.hpp",
    "content": "#pragma once\n\n#include <fstream>\n#include <set>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#include \"cexpr/string.hpp\"\n\n#include \"sql/column.hpp\"\n#include \"sql/index.hpp\"\n#include \"sql/row.hpp\"\n\nnamespace sql\n{\n\n\ttemplate <cexpr::string Name, typename Index, typename... Cols>\n\tclass schema\n\t{\n\tpublic:\n\t\tstatic constexpr auto name{ Name };\n\n\t\tusing row_type = sql::variadic_row<Cols...>::row_type;\n\t\tusing container = typename\n\t\t\tstd::conditional_t<\n\t\t\t\tstd::is_same_v<Index, sql::index<>>,\n\t\t\t\tstd::vector<row_type>,\n\t\t\t\tstd::multiset<row_type, typename Index::template comparator<row_type>>\n\t\t\t>;\n\t\tusing const_iterator = typename container::const_iterator;\n\t\t\n\t\tschema() = default;\n\n\t\ttemplate <typename Type, typename... Types>\n\t\tschema(std::vector<Type> const& col, Types const&... cols) : schema{}\n\t\t{\n\t\t\tinsert(col, cols...);\n\t\t}\n\n\t\ttemplate <typename Type, typename... Types>\n\t\tschema(std::vector<Type>&& col, Types&&... cols) : schema{}\n\t\t{\n\t\t\tinsert(std::forward<Type>(col), std::forward<Types>(cols)...);\n\t\t}\n\n\t\ttemplate <typename... Types>\n\t\tinline void emplace(Types const&... vals)\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Index, sql::index<>>)\n\t\t\t{\n\t\t\t\ttable_.emplace_back(vals...);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttable_.emplace(vals...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename... Types>\n\t\tinline void emplace(Types&&... vals)\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Index, sql::index<>>)\n\t\t\t{\n\t\t\t\ttable_.emplace_back(vals...);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttable_.emplace(vals...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Type, typename... Types>\n\t\tvoid insert(std::vector<Type> const& col, Types const&... cols)\n\t\t{\n\t\t\tfor (std::size_t i{}; i < col.size(); ++i)\n\t\t\t{\n\t\t\t\templace(col[i], cols[i]...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Type, typename... Types>\n\t\tvoid insert(std::vector<Type>&& col, Types&&... cols)\n\t\t{\n\t\t\tfor (std::size_t i{}; i < col.size(); ++i)\n\t\t\t{\n\t\t\t\templace(std::forward<Type>(col[i]), std::forward<Types>(cols[i])...);\n\t\t\t}\n\t\t}\n\n\t\tvoid insert(row_type const& row)\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Index, sql::index<>>)\n\t\t\t{\n\t\t\t\ttable_.push_back(row);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttable_.insert(row);\n\t\t\t}\n\t\t}\n\n\t\tvoid insert(row_type&& row)\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Index, sql::index<>>)\n\t\t\t{\n\t\t\t\ttable_.push_back(std::forward<row_type>(row));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttable_.insert(std::forward<row_type>(row));\n\t\t\t}\n\t\t}\n\n\t\tinline const_iterator begin() const noexcept\n\t\t{\n\t\t\treturn table_.begin();\n\t\t}\n\n\t\tinline const_iterator end() const noexcept\n\t\t{\n\t\t\treturn table_.end();\n\t\t}\n\n\tprivate:\n\t\tcontainer table_;\n\t};\n\n\tnamespace\n\t{\n\n\t\ttemplate <typename Row>\n\t\tvoid fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)\n\t\t{\n\t\t\tif constexpr (!std::is_same_v<Row, sql::void_row>)\n\t\t\t{\n\t\t\t\tif constexpr (std::is_same_v<typename Row::column::type, std::string>)\n\t\t\t\t{\n\t\t\t\t\tif constexpr (std::is_same_v<typename Row::next, sql::void_row>)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::getline(fstr, row.head());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::getline(fstr, row.head(), delim);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfstr >> row.head();\n\t\t\t\t}\n\n\t\t\t\tfill<typename Row::next>(fstr, row.tail(), delim);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Row>\n\t\tvoid fill(std::fstream& fstr, Row const& row, char delim)\n\t\t{\n\t\t\tif constexpr (!std::is_same_v<Row, sql::void_row>)\n\t\t\t{\n\t\t\t\tfstr << row.head();\n\n\t\t\t\tif constexpr (std::is_same_v<typename Row::next, sql::void_row>)\n\t\t\t\t{\n\t\t\t\t\tfstr << '\\n';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfstr << delim;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfill<typename Row::next>(fstr, row.tail(), delim);\n\t\t\t}\n\t\t}\n\n\t} // namespace\n\n\t// helper function for users to load a data into a schema from a file\n\ttemplate <typename Schema>\n\tSchema load(std::string const& file, char delim)\n\t{\n\t\tauto fstr{ std::fstream(file, fstr.in) };\n\t\tSchema table{};\n\t\ttypename Schema::row_type row{};\n\n\t\twhile (fstr)\n\t\t{\n\t\t\tfill<typename Schema::row_type>(fstr, row, delim);\n\t\t\ttable.insert(std::move(row));\n\n\t\t\t// in case last stream extraction did not remove newline\n\t\t\tif (fstr.get() != '\\n')\n\t\t\t{\n\t\t\t\tfstr.unget();\n\t\t\t}\n\t\t}\n\n\t\treturn table;\n\t}\n\n\t// for compat with previous versions\n\ttemplate <typename Schema, char Delim>\n\tinline Schema load(std::string const& file)\n\t{\n\t\treturn load<Schema>(file, Delim);\n\t}\n\n\t// will work with schema and query objects\n\ttemplate <typename Type>\n\tvoid store(Type const& data, std::string const& file, char delim)\n\t{\n\t\tauto fstr{ std::fstream(file, fstr.out) };\n\n\t\tfor (auto const& row : data)\n\t\t{\n\t\t\tfill<typename Type::row_type>(fstr, row, delim);\n\t\t}\n\t}\n\n\t// for devs who want to use the previous format\n\ttemplate <typename Type, char Delim>\n\tinline void store(Type const& data, std::string const& file)\n\t{\n\t\tstore<Type>(data, file, Delim);\n\t}\n\n} // namespace sql\n"
  },
  {
    "path": "include/sql/tokens.hpp",
    "content": "#pragma once\n\n#include <array>\n#include <cstddef>\n#include <locale>\n#include <string_view>\n\n#include \"cexpr/string.hpp\"\n\nnamespace sql\n{\n\tnamespace\n\t{\n\t\t\n\t\ttemplate <typename Char>\n\t\tconstexpr bool whitespace(Char curr)\n\t\t{\n\t\t\treturn curr == Char{ ' ' } || curr == Char{ '\\t' } || curr == Char{ '\\n' };\n\t\t}\n\n\t\ttemplate <typename Char>\n\t\tconstexpr bool syntax(Char curr)\n\t\t{\n\t\t\treturn curr == Char{ ',' } || curr == Char{ '(' } || curr == Char{ ')' } ||\n\t\t\t\tcurr == Char{ '\\'' } || curr == Char{ '\\\"' } || curr == Char{ '=' };\n\t\t}\n\n\t\ttemplate <typename Char>\n\t\tconstexpr const Char* skip(const Char *curr, const Char *end)\n\t\t{\n\t\t\tfor (; curr != end && whitespace(*curr); ++curr);\n\t\t\treturn curr;\n\t\t}\n\n\t\ttemplate <typename Char>\n\t\tconstexpr const Char* next(const Char *curr, const Char *end)\n\t\t{\n\t\t\tChar c{ *curr };\n\n\t\t\tif (c == Char{ '>' } || c == Char{ '<' } || c == Char{ '!' })\n\t\t\t{\n\t\t\t\t++curr;\n\n\t\t\t\tif (*curr == Char{ '=' } || (c == Char{ '<' } && *curr == Char{ '>' }))\n\t\t\t\t{\n\t\t\t\t\t++curr;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (syntax(c))\n\t\t\t{\n\t\t\t\t++curr;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (; curr != end && !whitespace(*curr) && !syntax(*curr); ++curr);\n\t\t\t}\n\t\t\t\n\t\t\treturn curr;\n\t\t}\n\t\n\t} // namespace\n\n\ttemplate <typename Char, std::size_t Count>\n\tclass tokens\n\t{\n\tpublic:\n\t\tusing token_view = std::basic_string_view<Char>;\n\n\t\tconstexpr tokens() = default;\n\n\t\ttemplate<std::size_t N>\n\t\tconstexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}\n\t\t{\n\t\t\tauto curr{ cs.cbegin() }, last{ cs.cbegin() };\n\t\t\tconst auto end{ cs.cend() };\n\t\t\tstd::size_t i{};\n\n\t\t\twhile (curr < end)\n\t\t\t{\n\t\t\t\tcurr = skip(curr, end);\n\t\t\t\tlast = curr;\n\t\t\t\tlast = next(last, end);\n\n\t\t\t\tif (*curr == Char{ '\\\"' } || *curr == Char{ '\\'' })\n\t\t\t\t{\n\t\t\t\t\ttokens_[i++] = token_view{ curr, 1 };\n\t\t\t\t\tfor (char c{ *curr++ }; last != end && *last != c; ++last);\n\t\t\t\t}\n\n\t\t\t\tauto len{ reinterpret_cast<std::size_t>(last) - reinterpret_cast<std::size_t>(curr) };\n\t\t\t\ttokens_[i++] = token_view{ curr, len };\n\n\t\t\t\tif (*last == Char{ '\\\"' } || *last == Char{ '\\'' })\n\t\t\t\t{\n\t\t\t\t\ttokens_[i++] = token_view{ last, 1 };\n\t\t\t\t\t++last;\n\t\t\t\t}\n\n\t\t\t\tcurr = last;\n\t\t\t}\n\t\t}\n\n\t\tconstexpr std::size_t count() const noexcept\n\t\t{\n\t\t\treturn Count;\n\t\t}\n\n\t\tconstexpr token_view* begin() noexcept\n\t\t{\n\t\t\treturn tokens_.begin();\n\t\t}\n\t\tconstexpr const token_view* cbegin() const noexcept\n\t\t{\n\t\t\treturn tokens_.cbegin();\n\t\t}\n\n\t\tconstexpr token_view* end() noexcept\n\t\t{\n\t\t\treturn tokens_.end();\n\t\t}\n\t\tconstexpr const token_view* cend() const noexcept\n\t\t{\n\t\t\treturn tokens_.cend();\n\t\t}\n\n\t\tconstexpr token_view& operator[](std::size_t i)\n\t\t{\n\t\t\treturn tokens_[i];\n\t\t}\n\t\tconstexpr token_view const& operator[](std::size_t i) const\n\t\t{\n\t\t\treturn tokens_[i];\n\t\t}\n\n\tprivate:\n\t\tstd::array<token_view, Count> tokens_;\n\t};\n\n\ttemplate<typename Char, std::size_t N>\n\tconstexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noexcept\n\t{\n\t\tauto begin{ cs.cbegin() };\n\t\tconst auto end{ cs.cend() };\n\t\tstd::size_t count{ 1 };\n\n\t\twhile (begin < end)\n\t\t{\n\t\t\tbegin = skip(begin, end);\n\t\t\tbegin = next(begin, end);\n\t\t\t++count;\n\t\t}\n\n\t\treturn count;\n\t}\n\n} // namespace sql\n"
  },
  {
    "path": "single-header/sql.hpp",
    "content": "#pragma once\n\n#include <array>\n#include <cstddef>\n#include <exception>\n#include <fstream>\n#include <locale>\n#include <set>\n#include <string>\n#include <string_view>\n#include <type_traits>\n#include <unordered_map>\n#include <utility>\n#include <vector>\n\nnamespace cexpr\n{\n\n\ttemplate <typename Char, std::size_t N>\n\tclass string\n\t{\n\tpublic:\n\t\tusing char_type = Char;\n\n\t\tconstexpr string() noexcept : size_{ 0 }, string_{ 0 }\n\t\t{}\n\n\t\tconstexpr string(const Char(&s)[N]) noexcept : string{}\n\t\t{\n\t\t\tfor(; s[size_]; ++size_)\n\t\t\t{\n\t\t\t\tstring_[size_] = s[size_];\n\t\t\t}\n\t\t}\n\n\t\tconstexpr string(cexpr::string<Char, N> const& s) noexcept : string{}\n\t\t{\n\t\t\tfor (; s[size_]; ++size_)\n\t\t\t{\n\t\t\t\tstring_[size_] = s[size_];\n\t\t\t}\n\t\t}\n\n\t\tconstexpr string(std::basic_string_view<Char> const& s) noexcept : string{}\n\t\t{\n\t\t\tif (s.length() < N)\n\t\t\t{\n\t\t\t\tfor (; size_ < s.length(); ++size_)\n\t\t\t\t{\n\t\t\t\t\tstring_[size_] = s[size_];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconstexpr void fill(const Char* begin, const Char* end) noexcept\n\t\t{\n\t\t\tfill_from(begin, end, begin());\n\t\t}\n\n\t\tconstexpr void fill_from(const Char* begin, const Char* end, Char* start) noexcept\n\t\t{\n\t\t\tif (end - begin < N)\n\t\t\t{\n\t\t\t\tfor (auto curr{ start }; begin != end; ++begin, ++curr)\n\t\t\t\t{\n\t\t\t\t\t*curr = *begin;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tinline constexpr std::size_t capacity() const noexcept\n\t\t{ \n\t\t\treturn N - 1;\n\t\t}\n\n\t\tinline constexpr std::size_t size() const noexcept\n\t\t{\n\t\t\treturn size_;\n\t\t}\n\n\t\tinline constexpr Char* begin() noexcept\n\t\t{\n\t\t\treturn string_;\n\t\t}\n\t\tinline constexpr const Char* cbegin() const noexcept\n\t\t{\n\t\t\treturn string_;\n\t\t}\n\n\t\tinline constexpr Char* end() noexcept\n\t\t{\n\t\t\treturn &string_[size_];\n\t\t}\n\t\tinline constexpr const Char* cend() const noexcept\n\t\t{\n\t\t\treturn &string_[size_];\n\t\t}\n\n\t\tinline constexpr Char& operator[](std::size_t i)\n\t\t{\n\t\t\treturn string_[i];\n\t\t}\n\t\tinline constexpr Char const& operator[](std::size_t i) const\n\t\t{\n\t\t\treturn string_[i];\n\t\t}\n\n\t\ttemplate <typename OtherChar, std::size_t OtherN>\n\t\tconstexpr bool operator==(string<OtherChar, OtherN> const& other) const noexcept\n\t\t{\n\t\t\tif constexpr (N != OtherN)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tstd::size_t i{};\n\t\t\tfor (; i < N && string_[i] == other[i]; ++i);\n\n\t\t\treturn i == N;\n\t\t}\n\n\t\ttemplate <typename OtherChar, std::size_t OtherN>\n\t\tconstexpr bool operator==(const OtherChar(&other)[OtherN]) const noexcept\n\t\t{\n\t\t\tif constexpr (N != OtherN)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tstd::size_t i{};\n\t\t\tfor (; i < N && string_[i] == other[i]; ++i);\n\n\t\t\treturn i == N;\n\t\t}\n\n\t\ttemplate <typename OtherChar>\n\t\tinline bool operator==(std::basic_string<OtherChar> const& other) const noexcept\n\t\t{\n\t\t\treturn other == string_;\n\t\t}\n\n\t\ttemplate <typename OtherChar>\n\t\tinline bool operator!=(std::basic_string<OtherChar> const& other) const noexcept\n\t\t{\n\t\t\treturn !(other == string_);\n\t\t}\n\n\tprivate:\n\t\tstd::size_t size_;\n\t\tChar string_[N];\n\t};\n\n\ttemplate <typename Char, std::size_t N>\n\tstring(const Char[N]) -> string<Char, N>;\n\n\ttemplate <typename Char, std::size_t N>\n\tinline bool operator==(std::basic_string<Char> const& str, string<Char, N> const& cstr) noexcept\n\t{\n\t\treturn cstr == str;\n\t}\n\n\ttemplate <typename Char, std::size_t N>\n\tinline bool operator!=(std::basic_string<Char> const& str, string<Char, N> const& cstr) noexcept\n\t{\n\t\treturn cstr != str;\n\t}\n\n} // namespace cexpr\n\nnamespace sql\n{\n\n\ttemplate <cexpr::string Name, typename Type>\n\tstruct column\n\t{\n\t\tstatic constexpr auto name{ Name };\n\t\t\n\t\tusing type = Type;\n\t};\n\n} // namespace sql\n\nnamespace sql\n{\n\n\tstruct void_row\n\t{\n\t\tstatic constexpr std::size_t depth{ 0 };\n\t};\n\n\ttemplate <typename Col, typename Next>\n\tclass row\n\t{\n\tpublic:\n\t\tusing column = Col;\n\t\tusing next = Next;\n\n\t\tstatic constexpr std::size_t depth{ 1 + next::depth };\n\n\t\trow() = default;\n\n\t\ttemplate <typename... ColTs>\n\t\trow(column::type const& val, ColTs const&... vals) : value_{ val }, next_{ vals... }\n\t\t{}\n\n\t\ttemplate <typename... ColTs>\n\t\trow(column::type&& val, ColTs&&... vals) : value_{ std::forward<column::type>(val) }, next_{ std::forward<ColTs>(vals)... }\n\t\t{}\n\n\t\tinline constexpr next const& tail() const noexcept\n\t\t{\n\t\t\treturn next_;\n\t\t}\n\n\t\tinline constexpr next& tail() noexcept\n\t\t{\n\t\t\treturn next_;\n\t\t}\n\n\t\tinline constexpr column::type const& head() const noexcept\n\t\t{\n\t\t\treturn value_;\n\t\t}\n\n\t\tinline constexpr column::type& head() noexcept\n\t\t{\n\t\t\treturn value_;\n\t\t}\n\t\n\tprivate:\n\t\tcolumn::type value_;\n\t\tnext next_;\n\t};\n\n\ttemplate <typename Col, typename... Cols>\n\tstruct variadic_row\n\t{\n\tprivate:\n\t\tstatic inline constexpr auto resolve() noexcept\n\t\t{\n\t\t\tif constexpr (sizeof...(Cols) != 0)\n\t\t\t{\n\t\t\t\treturn typename variadic_row<Cols...>::row_type{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn void_row{};\n\t\t\t}\n\t\t}\n\n\tpublic:\n\t\tusing row_type = row<Col, decltype(resolve())>;\n\t};\n\n\t// user function to query row elements by column name\n\ttemplate <cexpr::string Name, typename Row>\n\tconstexpr auto const& get(Row const& r) noexcept\n\t{\n\t\tstatic_assert(!std::is_same_v<Row, sql::void_row>, \"Name does not match a column name.\");\n\n\t\tif constexpr (Row::column::name == Name)\n\t\t{\n\t\t\treturn r.head();\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn get<Name>(r.tail());\n\t\t}\n\t}\n\n\t// compiler function used by structured binding declaration\n\ttemplate <std::size_t Pos, typename Row>\n\tconstexpr auto const& get(Row const& r) noexcept\n\t{\n\t\tstatic_assert(Pos < Row::depth, \"Position is larger than number of row columns.\");\n\n\t\tif constexpr (Pos == 0)\n\t\t{\n\t\t\treturn r.head();\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn get<Pos - 1>(r.tail());\n\t\t}\n\t}\n\n\t// function to assign a value to a column's value in a row\n\ttemplate <cexpr::string Name, typename Row, typename Type>\n\tconstexpr void set(Row& r, Type const& value)\n\t{\n\t\tstatic_assert(!std::is_same_v<Row, sql::void_row>, \"Name does not match a column name.\");\n\n\t\tif constexpr (Row::column::name == Name)\n\t\t{\n\t\t\tr.head() = value;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tset<Name>(r.tail(), value);\n\t\t}\n\t}\n\n} // namespace sql\n\n// STL injections to allow row to be used in structured binding declarations\nnamespace std\n{\n\n\ttemplate <typename Col, typename Next>\n\tclass tuple_size<sql::row<Col, Next>> : public integral_constant<size_t, sql::row<Col, Next>::depth>\n\t{};\n\n\ttemplate <size_t Index, typename Col, typename Next>\n\tstruct tuple_element<Index, sql::row<Col, Next>>\n\t{\n\t\tusing type = decltype(sql::get<Index>(sql::row<Col, Next>{}));\n\t};\n\n} // namespace std\n\nnamespace sql\n{\n\n\ttemplate <cexpr::string... Columns>\n\tstruct index\n\t{\n\t\ttemplate <typename Row>\n\t\tstruct comparator\n\t\t{\n\t\t\tbool operator()(Row const& left, Row const& right) const noexcept\n\t\t\t{\n\t\t\t\treturn compare<Columns...>(left, right);\n\t\t\t}\n\t\t\n\t\tprivate:\n\t\t\ttemplate <cexpr::string Col, cexpr::string... Cols>\n\t\t\tbool compare(Row const& left, Row const& right) const noexcept\n\t\t\t{\n\t\t\t\tauto const& l{ sql::get<Col>(left) };\n\t\t\t\tauto const& r{ sql::get<Col>(right) };\n\n\t\t\t\tif constexpr (sizeof...(Cols) != 0)\n\t\t\t\t{\n\t\t\t\t\tif (l == r)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn compare<Cols...>(left, right);\n\t\t\t\t\t}\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn l < r;\n\t\t\t}\n\t\t};\n\t};\n\n} // namespace sql\n\nnamespace sql\n{\n\n\ttemplate <cexpr::string Name, typename Index, typename... Cols>\n\tclass schema\n\t{\n\tpublic:\n\t\tstatic constexpr auto name{ Name };\n\n\t\tusing row_type = sql::variadic_row<Cols...>::row_type;\n\t\tusing container = typename\n\t\t\tstd::conditional_t<\n\t\t\t\tstd::is_same_v<Index, sql::index<>>,\n\t\t\t\tstd::vector<row_type>,\n\t\t\t\tstd::multiset<row_type, typename Index::template comparator<row_type>>\n\t\t\t>;\n\t\tusing const_iterator = typename container::const_iterator;\n\t\t\n\t\tschema() = default;\n\n\t\ttemplate <typename Type, typename... Types>\n\t\tschema(std::vector<Type> const& col, Types const&... cols) : schema{}\n\t\t{\n\t\t\tinsert(col, cols...);\n\t\t}\n\n\t\ttemplate <typename Type, typename... Types>\n\t\tschema(std::vector<Type>&& col, Types&&... cols) : schema{}\n\t\t{\n\t\t\tinsert(std::forward<Type>(col), std::forward<Types>(cols)...);\n\t\t}\n\n\t\ttemplate <typename... Types>\n\t\tinline void emplace(Types const&... vals)\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Index, sql::index<>>)\n\t\t\t{\n\t\t\t\ttable_.emplace_back(vals...);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttable_.emplace(vals...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename... Types>\n\t\tinline void emplace(Types&&... vals)\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Index, sql::index<>>)\n\t\t\t{\n\t\t\t\ttable_.emplace_back(vals...);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttable_.emplace(vals...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Type, typename... Types>\n\t\tvoid insert(std::vector<Type> const& col, Types const&... cols)\n\t\t{\n\t\t\tfor (std::size_t i{}; i < col.size(); ++i)\n\t\t\t{\n\t\t\t\templace(col[i], cols[i]...);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Type, typename... Types>\n\t\tvoid insert(std::vector<Type>&& col, Types&&... cols)\n\t\t{\n\t\t\tfor (std::size_t i{}; i < col.size(); ++i)\n\t\t\t{\n\t\t\t\templace(std::forward<Type>(col[i]), std::forward<Types>(cols[i])...);\n\t\t\t}\n\t\t}\n\n\t\tvoid insert(row_type const& row)\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Index, sql::index<>>)\n\t\t\t{\n\t\t\t\ttable_.push_back(row);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttable_.insert(row);\n\t\t\t}\n\t\t}\n\n\t\tvoid insert(row_type&& row)\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Index, sql::index<>>)\n\t\t\t{\n\t\t\t\ttable_.push_back(std::forward<row_type>(row));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttable_.insert(std::forward<row_type>(row));\n\t\t\t}\n\t\t}\n\n\t\tinline const_iterator begin() const noexcept\n\t\t{\n\t\t\treturn table_.begin();\n\t\t}\n\n\t\tinline const_iterator end() const noexcept\n\t\t{\n\t\t\treturn table_.end();\n\t\t}\n\n\tprivate:\n\t\tcontainer table_;\n\t};\n\n\tnamespace\n\t{\n\n\t\ttemplate <typename Row>\n\t\tvoid fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)\n\t\t{\n\t\t\tif constexpr (!std::is_same_v<Row, sql::void_row>)\n\t\t\t{\n\t\t\t\tif constexpr (std::is_same_v<typename Row::column::type, std::string>)\n\t\t\t\t{\n\t\t\t\t\tif constexpr (std::is_same_v<typename Row::next, sql::void_row>)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::getline(fstr, row.head());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::getline(fstr, row.head(), delim);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfstr >> row.head();\n\t\t\t\t}\n\n\t\t\t\tfill<typename Row::next>(fstr, row.tail(), delim);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Row>\n\t\tvoid fill(std::fstream& fstr, Row const& row, char delim)\n\t\t{\n\t\t\tif constexpr (!std::is_same_v<Row, sql::void_row>)\n\t\t\t{\n\t\t\t\tfstr << row.head();\n\n\t\t\t\tif constexpr (std::is_same_v<typename Row::next, sql::void_row>)\n\t\t\t\t{\n\t\t\t\t\tfstr << '\\n';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfstr << delim;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfill<typename Row::next>(fstr, row.tail(), delim);\n\t\t\t}\n\t\t}\n\n\t} // namespace\n\n\t// helper function for users to load a data into a schema from a file\n\ttemplate <typename Schema>\n\tSchema load(std::string const& file, char delim)\n\t{\n\t\tauto fstr{ std::fstream(file, fstr.in) };\n\t\tSchema table{};\n\t\ttypename Schema::row_type row{};\n\n\t\twhile (fstr)\n\t\t{\n\t\t\tfill<typename Schema::row_type>(fstr, row, delim);\n\t\t\ttable.insert(std::move(row));\n\n\t\t\t// in case last stream extraction did not remove newline\n\t\t\tif (fstr.get() != '\\n')\n\t\t\t{\n\t\t\t\tfstr.unget();\n\t\t\t}\n\t\t}\n\n\t\treturn table;\n\t}\n\n\t// for compat with previous versions\n\ttemplate <typename Schema, char Delim>\n\tinline Schema load(std::string const& file)\n\t{\n\t\treturn load<Schema>(file, Delim);\n\t}\n\n\t// will work with schema and query objects\n\ttemplate <typename Type>\n\tvoid store(Type const& data, std::string const& file, char delim)\n\t{\n\t\tauto fstr{ std::fstream(file, fstr.out) };\n\n\t\tfor (auto const& row : data)\n\t\t{\n\t\t\tfill<typename Type::row_type>(fstr, row, delim);\n\t\t}\n\t}\n\n\t// for devs who want to use the previous format\n\ttemplate <typename Type, char Delim>\n\tinline void store(Type const& data, std::string const& file)\n\t{\n\t\tstore<Type>(data, file, Delim);\n\t}\n\n} // namespace sql\n\nnamespace ra\n{\n\n\ttemplate <typename Input>\n\tclass unary\n\t{\n\tpublic:\n\t\tusing input_type = std::remove_cvref_t<decltype(Input::next())>;\n\n\t\ttemplate <typename... Inputs>\n\t\tstatic inline void seed(Inputs const&... rs)\n\t\t{\n\t\t\tInput::seed(rs...);\n\t\t}\n\n\t\tstatic inline void reset()\n\t\t{\n\t\t\tInput::reset();\n\t\t}\n\t};\n\n\ttemplate <typename LeftInput, typename RightInput>\n\tclass binary\n\t{\n\tpublic:\n\t\tusing left_type = std::remove_cvref_t<decltype(LeftInput::next())>;\n\t\tusing right_type = std::remove_cvref_t<decltype(RightInput::next())>;\n\n\t\ttemplate <typename... Inputs>\n\t\tstatic inline void seed(Inputs const&... rs)\n\t\t{\n\t\t\tLeftInput::seed(rs...);\n\t\t\tRightInput::seed(rs...);\n\t\t}\n\n\t\tstatic inline void reset()\n\t\t{\n\t\t\tLeftInput::reset();\n\t\t\tRightInput::reset();\n\t\t}\n\t};\n\n} // namespace ra\n\nnamespace ra\n{\n\n\tnamespace\n\t{\n\n\t\ttemplate <typename Left, typename Right>\n\t\tconstexpr auto recr_merge()\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Left, sql::void_row>)\n\t\t\t{\n\t\t\t\treturn Right{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tusing next = decltype(recr_merge<typename Left::next, Right>());\n\n\t\t\t\treturn sql::row<typename Left::column, next>{};\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Left, typename Right>\n\t\tinline constexpr auto merge()\n\t\t{\n\t\t\tif constexpr (Left::column::name == Right::column::name)\n\t\t\t{\n\t\t\t\treturn recr_merge<Left, typename Right::next>();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn recr_merge<Left, Right>();\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Dest, typename Row>\n\t\tconstexpr void recr_copy(Dest& dest, Row const& src)\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Row, sql::void_row>)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdest.head() = src.head();\n\t\t\t\trecr_copy(dest.tail(), src.tail());\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Dest, typename Row>\n\t\tinline constexpr void copy(Dest& dest, Row const& src)\n\t\t{\n\t\t\tif constexpr (Dest::column::name == Row::column::name)\n\t\t\t{\n\t\t\t\trecr_copy(dest, src);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcopy(dest.tail(), src);\n\t\t\t}\n\t\t}\n\n\t} // namespace\n\n\ttemplate <typename LeftInput, typename RightInput>\n\tclass join : public ra::binary<LeftInput, RightInput>\n\t{\n\t\tusing binary_type = ra::binary<LeftInput, RightInput>;\n\t\tusing left_type = typename binary_type::left_type;\n\t\tusing right_type = typename binary_type::right_type;\n\tpublic:\n\t\tusing output_type = decltype(merge<left_type, right_type>());\n\n\t\ttemplate <typename... Inputs>\n\t\tstatic inline void seed(Inputs const&... rs)\n\t\t{\n\t\t\tbinary_type::seed(rs...);\n\t\t\tcopy(output_row, LeftInput::next());\n\t\t}\n\n\t\tstatic inline void reset()\n\t\t{\n\t\t\tbinary_type::reset();\n\t\t\tcopy(output_row, LeftInput::next());\n\t\t}\n\n\t\tstatic output_type output_row;\n\t};\n\n\ttemplate <typename LeftInput, typename RightInput>\n\ttypename join<LeftInput, RightInput>::output_type join<LeftInput, RightInput>::output_row{};\n\n} // namespace ra\n\nnamespace ra\n{\n\n\tstruct data_end : std::exception\n\t{};\n\n\t// Id template parameter allows unique ra::relation types to be instantiated from\n\t//\ta single sql::schema type (for queries referencing a schema multiple times).\n\ttemplate <typename Schema, std::size_t Id>\n\tclass relation\n\t{\n\tpublic:\n\t\tusing output_type = Schema::row_type&;\n\n\t\tstatic auto& next()\n\t\t{\n\t\t\tif (curr != end)\n\t\t\t{\n\t\t\t\treturn *curr++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthrow ra::data_end{};\n\t\t\t}\n\t\t}\n\t\t\n\t\ttemplate <typename Input, typename... Inputs>\n\t\tstatic void seed(Input const& r, Inputs const&... rs) noexcept\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Input, Schema>)\n\t\t\t{\n\t\t\t\tcurr = r.begin();\n\t\t\t\tbegin = r.begin();\n\t\t\t\tend = r.end();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tseed(rs...);\n\t\t\t}\n\t\t}\n\n\t\tstatic inline void reset() noexcept\n\t\t{\n\t\t\tcurr = begin;\n\t\t}\n\n\tprivate:\n\t\tstatic Schema::const_iterator curr;\n\t\tstatic Schema::const_iterator begin;\n\t\tstatic Schema::const_iterator end;\n\t};\n\n\ttemplate <typename Schema, std::size_t Id>\n\tSchema::const_iterator relation<Schema, Id>::curr{};\n\n\ttemplate <typename Schema, std::size_t Id>\n\tSchema::const_iterator relation<Schema, Id>::begin{};\n\n\ttemplate <typename Schema, std::size_t Id>\n\tSchema::const_iterator relation<Schema, Id>::end{};\n\n} // namespace ra\n\nnamespace ra\n{\n\n\ttemplate <typename LeftInput, typename RightInput>\n\tclass cross : public ra::join<LeftInput, RightInput>\n\t{\n\t\tusing join_type = ra::join<LeftInput, RightInput>;\n\tpublic:\n\t\tusing output_type = join_type::output_type;\n\n\t\tstatic auto&& next()\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tcopy(join_type::output_row, RightInput::next());\n\t\t\t}\n\t\t\tcatch(ra::data_end const& e)\n\t\t\t{\n\t\t\t\tcopy(join_type::output_row, LeftInput::next());\n\t\t\t\tRightInput::reset();\n\t\t\t\tcopy(join_type::output_row, RightInput::next());\n\t\t\t}\n\n\t\t\treturn std::move(join_type::output_row);\n\t\t}\n\t};\n\n} // namespace ra\n\nnamespace ra\n{\n\n\ttemplate <typename LeftInput, typename RightInput>\n\tclass natural : public ra::join<LeftInput, RightInput>\n\t{\n\t\tusing join_type = ra::join<LeftInput, RightInput>;\n\t\tusing key_type = std::remove_cvref_t<decltype(LeftInput::next().head())>;\n\t\tusing value_type = std::vector<std::remove_cvref_t<decltype(RightInput::next().tail())>>;\n\t\tusing map_type = std::unordered_map<key_type, value_type>;\n\tpublic:\n\t\tusing output_type = join_type::output_type;\n\n\t\ttemplate <typename... Inputs>\n\t\tstatic void seed(Inputs const&... rs)\n\t\t{\n\t\t\tjoin_type::seed(rs...);\n\t\t\t\n\t\t\tif (row_cache.empty())\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tfor (;;)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto const& row{ RightInput::next() };\n\t\t\t\t\t\trow_cache[row.head()].push_back(row.tail());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch(ra::data_end const& e)\n\t\t\t\t{\n\t\t\t\t\tRightInput::reset();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tauto const& active{ row_cache[join_type::output_row.head()] };\n\t\t\tcurr = active.cbegin();\n\t\t\tend = active.cend();\n\t\t}\n\n\t\tstatic auto&& next()\n\t\t{\n\t\t\twhile (curr == end)\n\t\t\t{\n\t\t\t\tcopy(join_type::output_row, LeftInput::next());\n\t\t\t\tauto const& active{ row_cache[join_type::output_row.head()] };\n\t\t\t\tcurr = active.cbegin();\n\t\t\t\tend = active.cend();\n\t\t\t}\n\n\t\t\tcopy(join_type::output_row, *curr++);\n\t\t\t\n\t\t\treturn std::move(join_type::output_row);\n\t\t}\n\n\tprivate:\n\t\tstatic map_type row_cache;\n\t\tstatic value_type::const_iterator curr;\n\t\tstatic value_type::const_iterator end;\n\t};\n\n\ttemplate <typename LeftInput, typename RightInput>\n\ttypename natural<LeftInput, RightInput>::map_type natural<LeftInput, RightInput>::row_cache{};\n\n\ttemplate <typename LeftInput, typename RightInput>\n\ttypename natural<LeftInput, RightInput>::value_type::const_iterator natural<LeftInput, RightInput>::curr;\n\n\ttemplate <typename LeftInput, typename RightInput>\n\ttypename natural<LeftInput, RightInput>::value_type::const_iterator natural<LeftInput, RightInput>::end;\n\n} // namespace ra\n\nnamespace ra\n{\n\n\ttemplate <typename Output, typename Input>\n\tclass projection : public ra::unary<Input>\n\t{\n\t\tusing input_type =  typename ra::unary<Input>::input_type;\n\tpublic:\n\t\tusing output_type = Output;\n\n\t\tstatic auto&& next()\n\t\t{\n\t\t\tfold<output_type>(output_row, Input::next());\n\t\t\t\n\t\t\treturn std::move(output_row);\n\t\t}\n\n\tprivate:\n\t\ttemplate <typename Dest>\n\t\tstatic inline constexpr void fold(Dest& dest, input_type const& src)\n\t\t{\n\t\t\tif constexpr (Dest::depth == 0)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdest.head() = sql::get<Dest::column::name>(src);\n\t\t\t\tfold<typename Dest::next>(dest.tail(), src);\t\n\t\t\t}\n\t\t}\n\n\t\tstatic output_type output_row;\n\t};\n\n\ttemplate <typename Output, typename Input>\n\ttypename projection<Output, Input>::output_type projection<Output, Input>::output_row{};\n\n} // namespace ra\n\nnamespace ra\n{\n\n\ttemplate <typename Output, typename Input>\n\tclass rename : public ra::unary<Input>\n\t{\n\t\tusing input_type = typename ra::unary<Input>::input_type;\n\tpublic:\n\t\tusing output_type = Output;\n\n\t\tstatic auto&& next()\n\t\t{\n\t\t\tfold<output_type, input_type>(output_row, Input::next());\n\t\t\t\n\t\t\treturn std::move(output_row);\n\t\t}\n\n\tprivate:\n\t\ttemplate <typename Dest, typename Src>\n\t\tstatic inline constexpr void fold(Dest& dest, Src const& src)\n\t\t{\n\t\t\tif constexpr (Dest::depth == 0)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdest.head() = src.head();\n\t\t\t\tfold<typename Dest::next, typename Src::next>(dest.tail(), src.tail());\n\t\t\t}\n\t\t}\n\n\t\tstatic output_type output_row;\n\t};\n\n\ttemplate <typename Output, typename Input>\n\ttypename rename<Output, Input>::output_type rename<Output, Input>::output_row{};\n\t\n} // namespace ra\n\nnamespace ra\n{\n\n\ttemplate <typename Predicate, typename Input>\n\tclass selection : public ra::unary<Input>\n\t{\n\t\tusing input_type = typename ra::unary<Input>::input_type;\n\tpublic:\n\t\tusing output_type = input_type;\t\t\n\n\t\tstatic auto&& next()\n\t\t{\n\t\t\toutput_row = Input::next();\n\n\t\t\twhile(!Predicate::eval(output_row))\n\t\t\t{\n\t\t\t\toutput_row = Input::next();\n\t\t\t}\n\n\t\t\treturn std::move(output_row);\n\t\t}\n\n\tprivate:\n\t\tstatic output_type output_row;\n\t};\n\n\ttemplate <typename Output, typename Input>\n\ttypename selection<Output, Input>::output_type selection<Output, Input>::output_row{};\n\n} // namespace ra\n\nnamespace sql\n{\n\tnamespace\n\t{\n\t\t\n\t\ttemplate <typename Char>\n\t\tconstexpr bool whitespace(Char curr)\n\t\t{\n\t\t\treturn curr == Char{ ' ' } || curr == Char{ '\\t' } || curr == Char{ '\\n' };\n\t\t}\n\n\t\ttemplate <typename Char>\n\t\tconstexpr bool syntax(Char curr)\n\t\t{\n\t\t\treturn curr == Char{ ',' } || curr == Char{ '(' } || curr == Char{ ')' } ||\n\t\t\t\tcurr == Char{ '\\'' } || curr == Char{ '\\\"' } || curr == Char{ '=' };\n\t\t}\n\n\t\ttemplate <typename Char>\n\t\tconstexpr const Char* skip(const Char *curr, const Char *end)\n\t\t{\n\t\t\tfor (; curr != end && whitespace(*curr); ++curr);\n\t\t\treturn curr;\n\t\t}\n\n\t\ttemplate <typename Char>\n\t\tconstexpr const Char* next(const Char *curr, const Char *end)\n\t\t{\n\t\t\tChar c{ *curr };\n\n\t\t\tif (c == Char{ '>' } || c == Char{ '<' } || c == Char{ '!' })\n\t\t\t{\n\t\t\t\t++curr;\n\n\t\t\t\tif (*curr == Char{ '=' } || (c == Char{ '<' } && *curr == Char{ '>' }))\n\t\t\t\t{\n\t\t\t\t\t++curr;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (syntax(c))\n\t\t\t{\n\t\t\t\t++curr;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (; curr != end && !whitespace(*curr) && !syntax(*curr); ++curr);\n\t\t\t}\n\t\t\t\n\t\t\treturn curr;\n\t\t}\n\t\n\t} // namespace\n\n\ttemplate <typename Char, std::size_t Count>\n\tclass tokens\n\t{\n\tpublic:\n\t\tusing token_view = std::basic_string_view<Char>;\n\n\t\tconstexpr tokens() = default;\n\n\t\ttemplate<std::size_t N>\n\t\tconstexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}\n\t\t{\n\t\t\tauto curr{ cs.cbegin() }, last{ cs.cbegin() };\n\t\t\tconst auto end{ cs.cend() };\n\t\t\tstd::size_t i{};\n\n\t\t\twhile (curr < end)\n\t\t\t{\n\t\t\t\tcurr = skip(curr, end);\n\t\t\t\tlast = curr;\n\t\t\t\tlast = next(last, end);\n\n\t\t\t\tif (*curr == Char{ '\\\"' } || *curr == Char{ '\\'' })\n\t\t\t\t{\n\t\t\t\t\ttokens_[i++] = token_view{ curr, 1 };\n\t\t\t\t\tfor (char c{ *curr++ }; last != end && *last != c; ++last);\n\t\t\t\t}\n\n\t\t\t\tauto len{ reinterpret_cast<std::size_t>(last) - reinterpret_cast<std::size_t>(curr) };\n\t\t\t\ttokens_[i++] = token_view{ curr, len };\n\n\t\t\t\tif (*last == Char{ '\\\"' } || *last == Char{ '\\'' })\n\t\t\t\t{\n\t\t\t\t\ttokens_[i++] = token_view{ last, 1 };\n\t\t\t\t\t++last;\n\t\t\t\t}\n\n\t\t\t\tcurr = last;\n\t\t\t}\n\t\t}\n\n\t\tconstexpr std::size_t count() const noexcept\n\t\t{\n\t\t\treturn Count;\n\t\t}\n\n\t\tconstexpr token_view* begin() noexcept\n\t\t{\n\t\t\treturn tokens_.begin();\n\t\t}\n\t\tconstexpr const token_view* cbegin() const noexcept\n\t\t{\n\t\t\treturn tokens_.cbegin();\n\t\t}\n\n\t\tconstexpr token_view* end() noexcept\n\t\t{\n\t\t\treturn tokens_.end();\n\t\t}\n\t\tconstexpr const token_view* cend() const noexcept\n\t\t{\n\t\t\treturn tokens_.cend();\n\t\t}\n\n\t\tconstexpr token_view& operator[](std::size_t i)\n\t\t{\n\t\t\treturn tokens_[i];\n\t\t}\n\t\tconstexpr token_view const& operator[](std::size_t i) const\n\t\t{\n\t\t\treturn tokens_[i];\n\t\t}\n\n\tprivate:\n\t\tstd::array<token_view, Count> tokens_;\n\t};\n\n\ttemplate<typename Char, std::size_t N>\n\tconstexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noexcept\n\t{\n\t\tauto begin{ cs.cbegin() };\n\t\tconst auto end{ cs.cend() };\n\t\tstd::size_t count{ 1 };\n\n\t\twhile (begin < end)\n\t\t{\n\t\t\tbegin = skip(begin, end);\n\t\t\tbegin = next(begin, end);\n\t\t\t++count;\n\t\t}\n\n\t\treturn count;\n\t}\n\n} // namespace sql\n\nnamespace sql\n{\n\n\tnamespace\n\t{\n\n\t\t// shim to allow all value types like double or float to be used as non-type template parameters.\n\t\ttemplate <typename Type>\n\t\tstruct value\n\t\t{\n\t\t\tconstexpr value(Type v) : val{ v }\n\t\t\t{}\n\n\t\t\tType val;\n\t\t};\n\n\t} // namespace\n\n\ttemplate <cexpr::string Op, typename Row, typename Left, typename Right=void>\n\tstruct operation\n\t{\n\t\tstatic constexpr bool eval(Row const& row) noexcept\n\t\t{\n\t\t\tif constexpr (Op == \"=\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) == Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr (Op == \">\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) > Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"<\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) < Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \">=\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) >= Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"<=\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) <= Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"!=\" || Op == \"<>\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) != Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"AND\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) && Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"OR\")\n\t\t\t{\n\t\t\t\treturn Left::eval(row) || Right::eval(row);\n\t\t\t}\n\t\t\telse if constexpr(Op == \"NOT\")\n\t\t\t{\n\t\t\t\treturn !Left::eval(row);\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <cexpr::string Column, typename Row>\n\tstruct variable\n\t{\n\t\tstatic constexpr auto eval(Row const& row) noexcept\n\t\t{\n\t\t\treturn sql::get<Column>(row);\n\t\t}\n\t};\n\n\ttemplate <auto Const, typename Row>\n\tstruct constant\n\t{\n\t\tstatic constexpr auto eval([[maybe_unused]] Row const& row) noexcept\n\t\t{\n\t\t\treturn Const.val;\n\t\t}\n\t};\n\n} // namespace sql\n\nnamespace sql\n{\n\n\t// anonymous namespace to hold helper data structures and functions\n\tnamespace\n\t{\n\n\t\ttemplate <std::size_t Pos, typename Node>\n\t\tstruct context\n\t\t{\n\t\t\tusing node = Node;\n\t\t\tstatic constexpr std::size_t pos = Pos;\n\t\t};\n\n\t\ttemplate <typename Type, std::size_t Name, std::size_t Next>\n\t\tstruct colinfo\n\t\t{\n\t\t\tusing type = Type;\n\t\t\tstatic constexpr std::size_t name = Name;\n\t\t\tstatic constexpr std::size_t next = Next;\n\t\t};\n\n\t\ttemplate <cexpr::string Name, typename Row>\n\t\tconstexpr bool exists() noexcept\n\t\t{\n\t\t\tif constexpr (std::is_same_v<Row, sql::void_row>)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif constexpr (Row::column::name == Name)\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn exists<Name, typename Row::next>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename Type, typename Char, std::size_t N>\n\t\tconstexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept\n\t\t{\n\t\t\tauto curr{ str.cbegin() }, end{ str.cend() };\n\t\t\tconstexpr Char dot{ '.' }, zro{ '0' }, min{ '-' };\n\t\t\tType acc{}, sign{ 1 }, scalar{ 10 };\n\n\t\t\tif (*curr == min)\n\t\t\t{\n\t\t\t\tsign = -1;\n\t\t\t\t++curr;\n\t\t\t}\n\n\t\t\twhile (curr != end && *curr != dot)\n\t\t\t{\n\t\t\t\tacc = (acc * scalar) + (*curr - zro);\n\t\t\t\t++curr;\n\t\t\t}\n\n\t\t\tif (curr != end && *curr == dot)\n\t\t\t{\n\t\t\t\tscalar = 1;\n\t\t\t\t++curr;\n\n\t\t\t\twhile(curr != end)\n\t\t\t\t{\n\t\t\t\t\tacc += (*curr - zro) * (scalar /= Type{ 10 });\n\t\t\t\t\t++curr;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn value<Type>{ acc * sign };\n\t\t}\n\n\t\tinline constexpr bool isquote(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"\\\"\" || tv == \"'\";\n\t\t}\n\n\t\tinline constexpr bool isor(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"OR\" || tv == \"or\";\n\t\t}\n\n\t\tinline constexpr bool isand(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"AND\" || tv == \"and\";\n\t\t}\n\n\t\tinline constexpr bool isnot(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"NOT\" || tv == \"not\";\n\t\t}\n\n\t\tinline constexpr bool isnatural(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"NATURAL\" || tv == \"natural\";\n\t\t}\n\n\t\tinline constexpr bool isjoin(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"JOIN\" || tv == \"join\";\n\t\t}\n\n\t\tinline constexpr bool iswhere(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"WHERE\" || tv == \"where\";\n\t\t}\n\n\t\tinline constexpr bool isfrom(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"FROM\" || tv == \"from\";\n\t\t}\n\n\t\tinline constexpr bool isas(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"AS\" || tv == \"as\";\n\t\t}\n\n\t\tinline constexpr bool isselect(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \"SELECT\" || tv == \"select\";\n\t\t}\n\n\t\tinline constexpr bool iscomma(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn tv == \",\";\n\t\t}\n\n\t\tconstexpr bool isintegral(std::string_view const& tv) noexcept\n\t\t{\n\t\t\tbool result{ false };\n\n\t\t\tfor (auto c : tv)\n\t\t\t{\n\t\t\t\tresult |= (c == '.');\n\t\t\t}\n\n\t\t\treturn !result;\n\t\t}\n\n\t\tconstexpr bool isdigit(char c) noexcept\n\t\t{\n\t\t\treturn (c >= '0' && c <= '9') || c == '-' || c == '.';\n\t\t}\n\n\t\tconstexpr bool iscomp(char c) noexcept\n\t\t{\n\t\t\treturn c == '=' || c == '!' || c == '<' || c == '>';\n\t\t}\n\n\t\tconstexpr bool iscolumn(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn !iscomma(tv) && !isas(tv) && !isfrom(tv);\n\t\t}\n\n\t\tconstexpr bool isseparator(std::string_view const& tv) noexcept\n\t\t{\n\t\t\treturn iscomma(tv) || isfrom(tv);\n\t\t}\n\n\t} // namespace\n\n\t// structured binding compliant iterator for query objects\n\ttemplate <typename Expr>\n\tclass query_iterator\n\t{\n\tpublic:\n\t\tusing row_type = std::remove_cvref_t<typename Expr::output_type>;\n\n\t\t// seeds row datamember for first dereference\n\t\tquery_iterator(bool end) : end_{ end }, row_{}\n\t\t{\n\t\t\toperator++();\n\t\t}\n\n\t\tinline bool operator==(query_iterator const& it) const noexcept\n\t\t{\n\t\t\treturn end_ == it.end_;\n\t\t}\n\n\t\tinline bool operator!=(query_iterator const& it) const noexcept\n\t\t{\n\t\t\treturn !(*this == it);\n\t\t}\n\n\t\tinline row_type const& operator*() const noexcept\n\t\t{\n\t\t\treturn row_;\n\t\t}\n\n\t\tquery_iterator& operator++()\n\t\t{\n\t\t\tif (!end_)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\trow_ = Expr::next();\n\t\t\t\t}\n\t\t\t\tcatch (ra::data_end const& e)\n\t\t\t\t{\n\t\t\t\t\tend_ = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn *this;\n\t\t}\n\n\tprivate:\n\t\tbool end_{};\n\t\trow_type row_{};\n\t};\n\n\ttemplate <cexpr::string Str, typename... Schemas>\n\tclass query\n\t{\n\tprivate:\n\t\t// where predicate terminal parsing \n\t\ttemplate <std::size_t Pos, typename Row>\n\t\tstatic constexpr auto parse_terms()\n\t\t{\n\t\t\tif constexpr (tokens_[Pos] == \"(\")\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_or<Pos + 1, Row>() };\n\n\t\t\t\tusing node = typename decltype(next)::node;\n\n\t\t\t\tstatic_assert(tokens_[next.pos] == \")\", \"No closing paranthesis found.\");\n\n\t\t\t\treturn context<next.pos + 1, node>{};\n\t\t\t}\n\t\t\telse if constexpr (isquote(tokens_[Pos]))\n\t\t\t{\n\t\t\t\tconstexpr cexpr::string<char, tokens_[Pos + 1].length() + 1> name{ tokens_[Pos + 1] };\n\n\t\t\t\tusing str = decltype(name);\n\t\t\t\tusing node = sql::constant<value<str>{ name }, Row>;\n\n\t\t\t\tstatic_assert(isquote(tokens_[Pos + 2]), \"No closing quote found.\");\n\n\t\t\t\treturn context<Pos + 3, node>{};\n\t\t\t}\n\t\t\telse if constexpr (isdigit(tokens_[Pos][0]))\n\t\t\t{\n\t\t\t\tconstexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };\n\t\t\t\t\n\t\t\t\tusing val = decltype(isintegral(tokens_[Pos]) ? std::int64_t{} : double{});\n\t\t\t\tusing node = sql::constant<sql::convert<val>(name), Row>;\n\n\t\t\t\treturn context<Pos + 1, node>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };\n\n\t\t\t\tusing node = sql::variable<name, Row>;\n\n\t\t\t\treturn context<Pos + 1, node>{};\n\t\t\t}\n\t\t}\n\n\t\t// parses a single compare operation\n\t\ttemplate <typename Left, typename Row>\n\t\tstatic constexpr auto recurse_comparison()\n\t\t{\n\t\t\tif constexpr (!iscomp(tokens_[Left::pos][0]))\n\t\t\t{\n\t\t\t\treturn Left{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_terms<Left::pos + 1, Row>() };\n\t\t\t\tconstexpr cexpr::string<char, tokens_[Left::pos].length() + 1> name{ tokens_[Left::pos] };\n\n\t\t\t\tusing ranode = typename decltype(next)::node;\n\t\t\t\tusing node = sql::operation<name, Row, typename Left::node, ranode>;\n\n\t\t\t\treturn context<next.pos, node>{};\n\t\t\t}\t\t\t\n\t\t}\n\n\t\t// descend further and attempt to parse a compare operation\n\t\ttemplate <std::size_t Pos, typename Row>\n\t\tstatic constexpr auto parse_comparison()\n\t\t{\n\t\t\tusing left = decltype(parse_terms<Pos, Row>());\n\t\t\t\n\t\t\treturn recurse_comparison<left, Row>();\n\t\t}\n\n\t\t// attempt to parse a negation operation then descend further\n\t\ttemplate <std::size_t Pos, typename Row>\n\t\tstatic constexpr auto parse_negation()\n\t\t{\n\t\t\tif constexpr (isnot(tokens_[Pos]))\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_comparison<Pos + 1, Row>() };\n\n\t\t\t\tusing ranode = typename decltype(next)::node;\n\t\t\t\tusing node = sql::operation<\"NOT\", Row, ranode>;\n\n\t\t\t\treturn context<next.pos, node>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn parse_comparison<Pos, Row>();\n\t\t\t}\n\t\t}\n\n\t\t// recursively parse chained AND operations\n\t\ttemplate <typename Left, typename Row>\n\t\tstatic constexpr auto recurse_and()\n\t\t{\n\t\t\tif constexpr (!isand(tokens_[Left::pos]))\n\t\t\t{\n\t\t\t\treturn Left{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_negation<Left::pos + 1, Row>() };\n\n\t\t\t\tusing ranode = typename decltype(next)::node;\n\t\t\t\tusing node = sql::operation<\"AND\", Row, typename Left::node, ranode>;\n\n\t\t\t\treturn recurse_and<context<next.pos, node>, Row>();\n\t\t\t}\n\t\t}\n\n\t\t// descend further then attempt to parse AND operations\n\t\ttemplate <std::size_t Pos, typename Row>\n\t\tstatic constexpr auto parse_and()\n\t\t{\n\t\t\tusing left = decltype(parse_negation<Pos, Row>());\n\t\t\t\n\t\t\treturn recurse_and<left, Row>();\n\t\t}\n\t\t\n\t\t// recursively parse chained OR operations\n\t\ttemplate <typename Left, typename Row>\n\t\tstatic constexpr auto recurse_or()\n\t\t{\n\t\t\tif constexpr (!isor(tokens_[Left::pos]))\n\t\t\t{\n\t\t\t\treturn Left{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_and<Left::pos + 1, Row>() };\n\t\t\t\t\n\t\t\t\tusing ranode = typename decltype(next)::node;\n\t\t\t\tusing node = sql::operation<\"OR\", Row, typename Left::node, ranode>;\n\n\t\t\t\treturn recurse_or<context<next.pos, node>, Row>();\n\t\t\t}\n\t\t}\n\n\t\t// descend further then attempt to parse OR operations\n\t\ttemplate <std::size_t Pos, typename Row>\n\t\tstatic constexpr auto parse_or()\n\t\t{\n\t\t\tusing left = decltype(parse_and<Pos, Row>());\n\t\t\t\n\t\t\treturn recurse_or<left, Row>();\n\t\t}\n\n\t\t// find correct schema for terminal relation\n\t\ttemplate <cexpr::string Name, std::size_t Id, typename Schema, typename... Others>\n\t\tstatic constexpr auto recurse_schemas()\n\t\t{\n\t\t\tif constexpr (Name == Schema::name)\n\t\t\t{\n\t\t\t\treturn ra::relation<Schema, Id>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstatic_assert(sizeof...(Others) != 0, \"Schema name used in JOIN was not provided.\");\n\n\t\t\t\treturn recurse_schemas<Name, Id, Others...>();\n\t\t\t}\n\t\t}\n\n\t\t// wrapper function to determine terminal relation\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_schema()\n\t\t{\n\t\t\tif constexpr (tokens_[Pos] == \"(\")\n\t\t\t{\n\t\t\t\tconstexpr auto next{ parse_root<Pos + 1>() };\n\t\t\t\t\n\t\t\t\tusing node = typename decltype(next)::node;\n\n\t\t\t\tstatic_assert(tokens_[next.pos] == \")\", \"No closing paranthesis found.\");\n\n\t\t\t\treturn context<next.pos + 1, node>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };\n\n\t\t\t\tusing node = decltype(recurse_schemas<name, Pos, Schemas...>());\n\n\t\t\t\treturn context<Pos + 1, node>{};\n\t\t\t}\n\t\t}\n\n\t\t// stub which will choose the specific join RA node\n\t\ttemplate <std::size_t Pos, typename Left, typename Right>\n\t\tstatic constexpr auto choose_join()\n\t\t{\n\t\t\tif constexpr (isnatural(tokens_[Pos]))\n\t\t\t{\n\t\t\t\treturn ra::natural<Left, Right>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn ra::cross<Left, Right>{};\t\n\t\t\t}\n\t\t}\n\n\t\t// parses join colinfo if a join is present else returns the single relation terminal\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_join()\n\t\t{\n\t\t\tconstexpr auto lnext{ parse_schema<Pos>() };\n\n\t\t\tusing lnode = typename decltype(lnext)::node;\n\n\t\t\tif constexpr (lnext.pos + 2 < tokens_.count() && isjoin(tokens_[lnext.pos + 1]))\n\t\t\t{\n\t\t\t\tconstexpr auto rnext{ parse_schema<lnext.pos + 2>() };\n\n\t\t\t\tusing rnode = typename decltype(rnext)::node;\n\t\t\t\tusing join = decltype(choose_join<lnext.pos, lnode, rnode>());\n\n\t\t\t\treturn context<rnext.pos, join>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn context<lnext.pos, lnode>{};\n\t\t\t}\n\t\t}\n\n\t\t// starting point to parse everything after the from keyword\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_from()\n\t\t{\n\t\t\tstatic_assert(isfrom(tokens_[Pos]), \"Expected 'FROM' token not found.\");\n\n\t\t\tconstexpr auto next{ parse_join<Pos + 1>() };\n\n\t\t\tusing node = typename decltype(next)::node;\n\n\t\t\tif constexpr (next.pos < tokens_.count() && iswhere(tokens_[next.pos]))\n\t\t\t{\n\t\t\t\tusing output = std::remove_cvref_t<typename node::output_type>;\n\n\t\t\t\tconstexpr auto predicate{ parse_or<next.pos + 1, output>() };\n\n\t\t\t\tusing pnext = typename decltype(predicate)::node;\n\t\t\t\tusing snode = ra::selection<pnext, node>;\n\n\t\t\t\treturn context<predicate.pos, snode>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn context<next.pos, node>{};\t\n\t\t\t}\n\t\t}\n\n\t\t// recursively searches all schemas for the a matching column\n\t\ttemplate <cexpr::string Name, typename Schema, typename... Others>\n\t\tstatic constexpr auto recurse_types()\n\t\t{\n\t\t\tif constexpr (sql::exists<Name, typename Schema::row_type>())\n\t\t\t{\n\t\t\t\treturn decltype(sql::get<Name>(typename Schema::row_type{})){};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstatic_assert(sizeof...(Others) != 0, \"Column name was not present in any schema.\");\n\n\t\t\t\treturn recurse_types<Name, Others...>();\n\t\t\t}\n\t\t}\n\n\t\t// wrapper to determine the type for the the column\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto column_type()\n\t\t{\n\t\t\tconstexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };\n\n\t\t\treturn recurse_types<name, Schemas...>();\n\t\t}\n\n\t\t// asserts token is column separator, and if comma returns one past the comma else start position\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr std::size_t next_column()\n\t\t{\n\t\t\tstatic_assert(isseparator(tokens_[Pos]), \"Expected ',' or 'FROM' token following column.\");\n\n\t\t\tif constexpr (iscomma(tokens_[Pos]))\n\t\t\t{\n\t\t\t\treturn Pos + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn Pos;\n\t\t\t}\n\t\t}\n\n\t\ttemplate <std::size_t Pos, bool Rename>\n\t\tstatic constexpr auto parse_colinfo()\n\t\t{\n\t\t\tstatic_assert(iscolumn(tokens_[Pos]), \"Invalid token starting column delcaration.\");\n\n\t\t\tconstexpr bool rename{ isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]) };\n\n\t\t\tusing col = decltype(column_type<Pos>());\n\n\t\t\tif constexpr (Rename && rename)\n\t\t\t{\n\t\t\t\tconstexpr auto next{ next_column<Pos + 3>() };\n\n\t\t\t\treturn colinfo<col, Pos + 2, next>{};\n\t\t\t}\n\t\t\telse if constexpr (rename)\n\t\t\t{\n\t\t\t\tconstexpr auto next{ next_column<Pos + 3>() };\n\n\t\t\t\treturn colinfo<col, Pos, next>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr auto next{ next_column<Pos + 1>() };\n\n\t\t\t\treturn colinfo<col, Pos, next>{};\n\t\t\t}\n\t\t}\n\n\t\t// recursively parse all columns projected/renamed in the query\n\t\ttemplate <std::size_t Pos, bool Rename>\n\t\tstatic constexpr auto recurse_columns()\n\t\t{\n\t\t\tif constexpr (isfrom(tokens_[Pos]))\n\t\t\t{\n\t\t\t\treturn context<Pos, sql::void_row>{};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr auto info{ parse_colinfo<Pos, Rename>() };\n\t\t\t\tconstexpr cexpr::string<char, tokens_[info.name].length() + 1> name{ tokens_[info.name] };\n\t\t\t\tconstexpr auto child{ recurse_columns<info.next, Rename>() };\n\n\t\t\t\tusing next = std::remove_const_t<typename decltype(child)::node>;\n\t\t\t\tusing col = std::remove_const_t<decltype(sql::column<name, typename decltype(info)::type>{})>;\n\t\t\t\tusing node = sql::row<col, next>;\n\n\t\t\t\treturn context<child.pos, node>{};\n\t\t\t}\n\t\t}\n\n\t\t// wrapper to parse columns as a projection RA node\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_projection()\n\t\t{\n\t\t\tconstexpr auto proj{ recurse_columns<Pos, false>() };\n\t\t\tconstexpr auto next{ parse_from<proj.pos>() };\n\n\t\t\tusing ranode = typename decltype(proj)::node;\n\t\t\tusing node = ra::projection<ranode, typename decltype(next)::node>;\n\n\t\t\treturn context<next.pos, node>{};\n\t\t}\n\n\t\t// wrapper to parse columns as a rename RA node\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_rename()\n\t\t{\n\t\t\tconstexpr auto next = parse_projection<Pos>();\n\n\t\t\tusing ranode = typename decltype(recurse_columns<Pos, true>())::node;\n\t\t\tusing node = ra::rename<ranode, typename decltype(next)::node>;\n\n\t\t\treturn context<next.pos, node>{};\n\t\t}\n\n\t\t// attempts to match column rename operation pattern on a column\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr bool has_rename()\n\t\t{\n\t\t\tif constexpr (isfrom(tokens_[Pos]) || isfrom(tokens_[Pos + 2]))\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse if constexpr (iscolumn(tokens_[Pos]) && isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]))\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconstexpr bool comma{ iscomma(tokens_[Pos + 1]) };\n\n\t\t\t\tstatic_assert(comma || isfrom(tokens_[Pos + 1]), \"Expected ',' or 'FROM' token following column.\");\n\n\t\t\t\tif constexpr (comma)\n\t\t\t\t{\n\t\t\t\t\treturn has_rename<Pos + 2>();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn has_rename<Pos + 1>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// decide RA node to root the expression tree\n\t\ttemplate <std::size_t Pos>\n\t\tstatic constexpr auto parse_root()\n\t\t{\n\t\t\tstatic_assert(isselect(tokens_[Pos]), \"Expected 'SELECT' token not found.\");\n\n\t\t\tif constexpr (tokens_[Pos + 1] == \"*\")\n\t\t\t{\n\t\t\t\treturn parse_from<Pos + 2>();\n\t\t\t}\n\t\t\telse if constexpr (has_rename<Pos + 1>())\n\t\t\t{\n\t\t\t\treturn parse_rename<Pos + 1>();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn parse_projection<Pos + 1>();\n\t\t\t}\n\t\t}\n\n\t\tstatic constexpr sql::tokens<char, sql::preprocess(Str)> tokens_{ Str };\n\n\t\tusing expression = typename decltype(parse_root<0>())::node;\n\n\t\tbool empty_;\n\t\n\tpublic:\n\t\tusing iterator = query_iterator<expression>;\n\t\tusing row_type = expression::output_type;\n\n\t\tquery(Schemas const&... tables)\n\t\t{\n\t\t\ttry \n\t\t\t{\n\t\t\t\texpression::seed(tables...);\n\t\t\t\tempty_ = false;\n\t\t\t}\n\t\t\tcatch(ra::data_end const& e)\n\t\t\t{\n\t\t\t\tempty_ = true;\n\t\t\t}\n\t\t}\n\n\t\t~query()\n\t\t{\n\t\t\texpression::reset();\n\t\t}\n\n\t\tinline iterator begin() const\n\t\t{\n\t\t\treturn iterator{ empty_ };\n\t\t}\n\n\t\tinline iterator end() const\n\t\t{\n\t\t\treturn iterator{ true };\n\t\t}\n\t};\n\n} // namespace sql\n\n"
  },
  {
    "path": "tests/data/authored.tsv",
    "content": "1984\tGeorge Orwell\n!!!The!!Teddy!Crazy!!Show!!!\tHarlan Ellison\n(Learning About) Machine Sex\tCandas Jane Dorsey\n...the World, as we Know 't\tHoward Waldrop\n2001: A Space Odyssey\tArthur C. Clarke\n2004, or Thereabouts\tDavid R. Bunch\n20th Century Boys vol.1\tNaoki Urasawa\n20th Century Boys vol.2\tNaoki Urasawa\n20th Century Boys vol.3\tNaoki Urasawa\n20th Century Boys vol.4\tNaoki Urasawa\n20th Century Boys vol.5\tNaoki Urasawa\n20th Century Boys vol.6\tNaoki Urasawa\nA Biography of Tadeo Isidoro Cruz (1829-1874)\tJorge Luis Borges\nA Brief History of the Trans-Pacific Tunnel\tKen Liu\nA Canticle for Leibowitz\tWalter M. Miller, Jr.\nA Case of Conscience\tJames Blish\nA Case of Identity\tArthur Conan Doyle\nA Clash of Cymbals\tJames Blish\nA Clockwork Orange\tAnthony Burgess\nA Day at Harmenz\tTadeusz Borowski\nA Deskful of Girls\tFritz Leiber\nA Dialog About A Dialog\tJorge Luis Borges\nA Dialog Between Dead Men\tJorge Luis Borges\nA Farewell to Arms\tErnest Hemingway\nA Feast of Demons\tWilliam Morrison\nA Few Things I Know About While Away\tJoanna Russ\nA Hundred Ghosts Parade Tonight\tXia Jia\nA is for Automation\tKate Wilhelm\nA Life for the Stars\tJames Blish\nA Midwinter's Tale\tMichael Swanwick\nA Momentary Taste of Being\tJames Tiptree, Jr.\nA Mouse in the Walls of the Global Village\tDean R. Koontz\nA New Refutation of Time\tJorge Luis Borges\nA Note on (toward) Bernard Shaw\tJorge Luis Borges\nA Path Through the Darkness\tHarlan Ellison\nA Prayer for No One's Enemies\tHarlan Ellison\nA Problem\tJorge Luis Borges\nA Scandal in Bohemia\tArthur Conan Doyle\nA Scanner Darkly\tPhilip K. Dick\nA Time of Changes\tRobert Silverberg\nA Tour of C++ 2nd\tBjarne Stroustrup\nA Toy for Juliette\tRobert Bloch\nA True Story\tTadeusz Borowski\nA Visit\tTadeusz Borowski\nA Way of Thinking\tTheodore Sturgeon\nAbsalom, Absalom!\tWilliam Faulkner\nAdrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W\tHarlan Ellison\nAdrift on the Policy Level\tChandler Davis\nAesop\tClifford D. Simak\nAfter the Days of Dead-Eye 'Dee\tPat Cadigan\nAgain, Dangerous Visions\tHarlan Ellison\nAkira vol.1\tKatsuhiro Otomo\nAkira vol.2\tKatsuhiro Otomo\nAkira vol.3\tKatsuhiro Otomo\nAkira vol.4\tKatsuhiro Otomo\nAkira vol.5\tKatsuhiro Otomo\nAkira vol.6\tKatsuhiro Otomo\nAlgorithms 4th\tKevin Wayne\nAlgorithms 4th\tRobert Sedgewick\nAll in Good Time\tMiram Allen deFord\nAll the Birds Come Home to Roost\tHarlan Ellison\nAll the Flavors\tKen Liu\nAll the Lies Lies That Are My Life\tHarlan Ellison\nAll The People\tR. A. Lafferty\nAll the Sound of Fear\tHarlan Ellison\nAll Tomorrow's Parties\tWilliam Gibson\nAlong the Scenic Route\tHarlan Ellison\nAlpha Ralpha Boulevard\tCordwainer Smith\nAmateur in Chancery\tGeorge O. Smith\nAmerica\tOrson Scott Card\nAn Advanced Readers' Picture Book of Comparative Cognition\tKen Liu\nAn Examination of the Work of Herbert Quain\tJorge Luis Borges\nAnd Chaos Died\tJoanna Russ\nAnd the Angels Sing\tKate Wilhelm\nAnd the Moon be Still as Bright\tRay Bradbury\nAnd the Sea Like Mirrors\tGregory Benford\nAndover and the Android\tKate Wilhelm\nAngry Candy\tHarlan Ellison\nAnimal Farm\tGeorge Orwell\nAnybody Else Like Me?\tWalter M. Miller, Jr.\nAnywhere But Here, With Anybody But You\tHarlan Ellison\nApproaching Oblivion\tHarlan Ellison\nApril Fools' Day Forever\tKate Wilhelm\nArgumentum Ornithologicum\tJorge Luis Borges\nArmy of None\tPaul Scharre\nAs Simple As That\tZenna Henderson\nAt the End of the Orbit\tArthur C. Clarke\nAt the Mouse Circus\tHarlan Ellison\nAunt Parnetta's Electric Blisters\tDiane Glancy\nAuschwitz, Our Home (A Letter)\tTadeusz Borowski\nAuto-De-Fe\tRoger Zelazny\nAvatars of the Tortoise\tJorge Luis Borges\nAverroes' Search\tJorge Luis Borges\nAye, and Gomorrah...\tSamuel R. Delany\nBalanced Ecology\tJames H. Schmitz\nBasilisk\tHarlan Ellison\nBattle for the Mind\tWilliam Sargant\nBattle Without Banners\tHarlan Ellison\nBattlefield\tHarlan Ellison\nBeachhead\tClifford D. Simak\nBeauty's Beast\tRobert Bloch\nBed Sheets are White\tEvelyn Lief\nBeowulf\tAnonymous\nBettyann\tKris Neville\nBeyond the Blue Event Horizon\tFrederik Pohl\nBianca's Hands\tTheodore Sturgeon\nBible and Sword\tBarbara W. Tuchman\nBig Joe and the Nth Generation\tWalter M. Miller, Jr.\nBlabbermouth\tTheodore Sturgeon\nBlack Bargain\tRobert Bloch\nBlame! vol.1\tTsumotu Nihei\nBlame! vol.2\tTsumotu Nihei\nBlame! vol.3\tTsumotu Nihei\nBlame! vol.4\tTsumotu Nihei\nBlame! vol.5\tTsumotu Nihei\nBlame! vol.6\tTsumotu Nihei\nBlank?\tHarlan Ellison\nBleeding Stones\tHarlan Ellison\nBlind Bird, Blind Bird, Go Away From Me!\tHarlan Ellison\nBlood Bank\tWalter M. Miller, Jr.\nBlot\tGahan Wilson\nBlowups Happen\tRobert A. Heilein\nBlue Spring\tTaiyo Matsumoto\nBorges and I\tJorge Luis Borges\nBounty\tT. L. Sherred\nBrain Wave\tPoul Anderson\nBrass and Gold (or Horse and Zeppelin in Beverly Hills)\tPhilip Jose Farmer\nBrave New World\tAldous Huxley\nBright Eyes\tHarlan Ellison\nBright Segment\tTheodore Sturgeon\nBroken Glass\tHarlan Ellison\nBrownshoes\tTheodore Sturgeon\nBurning Chrome\tWilliam Gibson\nBy His Bootstraps\tRobert A. Heinlein\nC Primer Plus 5th\tStephen Prata\nC++ Primer 5th\tBarbara E. Moo\nC++ Primer 5th\tJosee Lajoie\nC++ Primer 5th\tStanley B. Lippman\nCall Girl\tTang Fei\nCamps\tJack Dann\nCapitalism Without Capital\tJonathan Haskel\nCapitalism Without Capital\tStian Westlake\nCaptain Harlock: The Classic Collection vol.1\tLeiji Matsumoto\nCaptain Harlock: The Classic Collection vol.2\tLeiji Matsumoto\nCaptain Harlock: The Classic Collection vol.3\tLeiji Matusmoto\nCarcinoma Angels\tNorman Spinard\nCatch That Rabbit\tIsaac Asimov\nCatch-22\tJoseph Heller\nCatman\tHarlan Ellison\nCaviar\tTheodore Sturgeon\nCensus\tClifford D. Simak\nChain Reaction\tBoyd Ellanby\nChained to the Fast Lane in the Red Queen's Race\tHarlan Ellison\nChangewar\tFritz Leiber\nChapterhouse: Dune\tFrank Herbert\nChatting with Anubis\tHarlan Ellison\nChildhood's End\tArthur C. Clarke\nChildren of Dune\tFrank Herbert\nChildren of the Sea vol.1\tDaisuke Igarashi\nChildren of the Sea vol.2\tDaisuke Igarashi\nChildren of the Sea vol.3\tDaisuke Igarashi\nChildren of the Sea vol.4\tDaisuke Igarashi\nChildren of the Sea vol.5\tDaisuke Igarashi\nChing Witch!\tRoss Rocklynne\nChrist, Old Student in a New School\tRay Bradbury\nChuck Berry, Won't You Please Come Home\tKen McCullough\nCity\tClifford D. Simak\nCold Friend\tHarlan Ellison\nCollecting Team\tRobert Silverberg\nColossus\tB. Jack Copeland\nColumbus Was a Dope\tRobert A. Heinlein\nCome to the Party\tF. M. Busby\nComes Now the Power\tRoger Zelazny\nCommuter's Problem\tHarlan Ellison\nConversations With Jorge Luis Borges\tRichard Burgin\nCorpse\tHarlan Ellison\nCount the Clock That Tells the Time\tHarlan Ellison\nCount Zero\tWilliam Gibson\nCovered Mirrors\tJorge Luis Borges\nCrate\tTheodore Sturgeon\nCrazy as a Soup Sandwich\tHarlan Ellison\nCroatoan\tHarlan Ellison\nCrome Yellow\tAldous Huxley\nCrucifixus Etiam\tWalter M. Miller, Jr.\nCurse 5.0\tLiu Cixin\nDamnation Morning\tFritz Leiber\nDandelion Wine\tRay Bradbury\nDangerous Visions\tHarlan Ellison\nDanger-Human!\tGordon R. Dickson\nDaniel White for the Greater Good\tHarlan Ellison\nDarkness Upon the Face of the Deep\tHarlan Ellison\nDay Million\tFrederik Pohl\nDeal From the Bottom\tHarlan Ellison\nDeath and the Compass\tJorge Luis Borges\nDeath and the Penguin\tAndrey Kurkov\nDeathbird Stories\tHarlan Ellison\nDeath's End\tLiu Cixin\nDeeper than the Darkness\tHarlan Ellison\nDelia Elena San Marco\tJorge Luis Borges\nDelusion for a Dragon Slayer\tHarlan Ellison\nDesign Patterns\tErich Gamma\nDesign Patterns\tJohn Vlissides\nDesign Patterns\tRalph Johnson\nDesign Patterns\tRichard Helm\nDestined for War\tGraham Allison\nDeutsches Requiem\tJorge Luis Borges\nDevourer\tLiu Cixin\nDirk Gently's Holistic Detective Agency\tDouglas Adams\nDistant Signals\tAndrew Weiner\nDistrust That Particular Flavor\tWilliam Gibson\nDivision by Zero\tTed Chiang\nDjango\tHarlan Ellison\nDjinn, No Chaser\tHarlan Ellison\nDo Androids Dream of Electric Sheep?\tPhilip K. Dick\nDoctor Zhivago\tBoris Pasternak\nDogfight\tMichael Swanwick\nDogfight\tWilliam Gibson\nDo-It-Yourself\tHarlan Ellison\nDon Quixote\tMiguel de Cervantes Saavedra\nDouble Star\tRobert A. Heinlein\nDownward to the Earth\tRobert Silverberg\nDr. Bloodmoney\tPhilip K. Dick\nDreamtigers\tJorge Luis Borges\nDumb Waiter\tWalter M. Miller, Jr.\nDune\tFrank Herbert\nDune Messiah\tFrank Herbert\nDying Inside\tRobert Silverberg\nEach an Explorer\tIsaac Asimov\nEarthman, Come Home\tJames Blish\nEarthman, Go Home!\tHarlan Ellison\nEcowarewness\tHarlan Ellison\nEidolons\tHarlan Ellison\nElbow Room\tMarion Zimmer Bradley\nElegy\tJorge Luis Borges\nElouise and the Doctors of the Planet Pergamon\tJosephine Saxton\nEmanon vol.1: Memories of Emanon\tKenji Tsuruta\nEmanon vol.2: Emanon Wanderer pt.1\tKenji Tsuruta\nEmanon vol.3: Emanon Wanderer pt.2\tKenji Tsuruta\nEmissary from Hamelin\tHarlan Ellison\nEmma Zunz\tJorge Luis Borges\nEmpire of the Sun\tAndrew Weiner\nEmpire Star\tSamuel R. Delany\nEncounter With A Hick\tJonathan Brand\nEnder's Game\tOrson Scott Card\nEndless Frontier\tG. Pascal Zachary\nEndymion\tDan Simmons\nEnemy Mine\tBarry B. Longyear\nEniac\tScott McCartney\nEpilogue\tClifford D. Simak\nEpiphany for Aliens\tDavid Kerr\nErnest and the Machine God\tHarlan Ellison\nErotophobia\tHarlan Ellison\nErsatz\tHenry Slesar\nEscape!\tIsaac Asimov\nEscapegoat\tHarlan Ellison\nEutopia\tPoul Anderson\nEvensong\tLester del Rey\nEverything and Nothing\tJorge Luis Borges\nEvidence\tIsaac Asimov\nExploration Team\tMurray Leinster\nExplorers of Space\tRobert Silverberg\nExposures\tGregory Benford\nEye of the Beholder\tBurt K. Filer\nFahrenheit 451\tRay Bradbury\nFaith of our Fathers\tPhilip K. Dick\nFault-Tolerant Computer System Designs\tDhiraj K. Pradhan\nFear is a Cold Black\tKate Wilhelm\nFeather Tigers\tGene Wolfe\nFeatherbed on Chlyntha\tMiram Allen deFord\nFiasco\tStanislaw Lem\nFicciones\tJorge Luis Borges\nFinal Trophy\tHarlan Ellison\nFlies\tRobert Silverberg\nFlop Sweat\tHarlan Ellison\nFlow My Tears, the Policeman Said\tPhilip K. Dick\nFlowers for Algernon\tDaniel Keyes\nFolding Beijing\tHao Jingfang\nFootsteps\tHarlan Ellison\nFor the Sake of Grace\tSuzette Haden Elgin\nFor Value Received\tAndrew J. Ouffutt\nFor Whom the Bell Tolls\tErnest Hemingway\nForward the Foundation\tIsaac Asimov\nFoundation\tIsaac Asimov\nFoundation and Earth\tIsaac Asimov\nFoundation and Empire\tIsaac Asimov\nFoundation's Edge\tIsaac Asimov\nFragments of a Hologram Rose\tWilliam Gibson\nFrank Herbert\tNebula Winners Fifteen\nFrederik Pohl\tThe Expert Dreamers\nFrom A to Z, In The Chocolate Alphabet\tHarlan Ellison\nFrom the Government Printing Office\tKris Neville\nFrozen Journey\tPhilip K. Dick\nFunes the Memorious\tJorge Luis Borges\nG. B. K.-A Many-Flavored Bird\tHarlan Ellison\nGateway\tFrederik Pohl\nGather Blue Roses\tPamela Sargent\nGathi\tMiram Allen deFord\nGetting Along\tJames Blish\nGhost in the Shell\tShirow Masamune\nGhost in the Shell vol.1.5: Human-Error Processor\tShirow Masamune\nGhost in the Shell vol.2: Man-Machine Interface\tShirow Masamune\nGhost of a Chance\tTheodore Sturgeon\ngiANTS\tEdward Bryant\nGift from the Stars\tKate Wilhelm\nGiganto Maxia\tKentaro Miura\nGnomebody\tHarlan Ellison\nGo Toward the Light\tHarlan Ellison\nGo, Go, Go, Said the Bird\tSonya Dorman\nGod Emperor of Dune\tFrank Herbert\nGoldfish Bowl\tRobert A. Heinlein\nGonna Roll the Bones\tFritz Leiber\nGood Hunting\tKen Liu\nGood News from the Vatican\tRobert Silverberg\nGopher in the Gilly\tHarlan Ellison\nGrail\tHarlan Ellison\nGrave of the Fireflies\tCheng Jingbo\nGutter Gang\tHarlan Ellison\nHadj\tHarlan Ellison\nHalf-Life\tPaul Preuss\nHamlet\tWilliam Shakespeare\nHarry the Hare\tJames B. Hemesath\nHawksbill Station\tRobert Silverberg\nHeart of Darkness\tJoseph Conrad\nHeavyplanet\tLee Gregor\nHeechee Rendezvous\tFrederik Pohl\nHeechee Treasures\tFrederik Pohl\nHell Is the Absence of God\tTed Chiang\nHeretics of Dune\tFrank Herbert\nHigh Weir\tSamuel R. Delany\nHindsight: 480 Seconds\tHarlan Ellison\nHinterlands\tWilliam Gibson\nHis Vegetable\tPat Murphy\nHitler Painted Roses\tHarlan Ellison\nHobbies\tClifford D. Simak\nHomecoming\tRay Bradbury\nHomelanding\tMargaret Atwood\nHouston, Houston, Do You Read?\tJames Tiptree, Jr.\nHow Beautiful with Banners\tJames Blish\nHow's the Night Life on Cassalda?\tHarlan Ellison\nHuddling Place\tClifford D. Simak\nHumpty Dumpty had a Great Fall\tFrank Belknap\nHyperion\tDan Simmons\nI Curse the Lesson and Bless the Knowledge\tHarlan Ellison\nI Will Fear No Evil\tRobert A. Heinlein\nI, Dreamer\tWalter M. Miller, Jr.\nI, Robot\tIsaac Asimov\nIbn-Hakam al-Bokhari, Murdered in His Labyrinth\tJorge Luis Borges\nIchi-F\tKazuto Tatsuta\nIdoru\tWilliam Gibson\nIf All Men Were Brothers, Would You Let One Marry Your Sister?\tTheodore Sturgeon\nI'm Looking for Kadak\tHarlan Ellison\nIn Fear of K\tHarlan Ellison\nIn Lonely Islands\tHarlan Ellison\nIn Memoriam, J. F. K.\tJorge Luis Borges\nIn re Glover\tLeonard Tushnet\nIn the Barn\tPiers Anthony\nIn the Core\tFrederik Pohl\nIn the Fourth Year of the War\tHarlan Ellison\nIncident in Moderan\tDavid R. Bunch\nInferno, I, 32\tJorge Luis Borges\nInferno: The World at War, 1939-1945\tMax Hastings\nInterim\tRay Bradbury\nInterlocking Pieces\tMolly Gloss\nInto the Wild\tJon Krakauer\nInto Thin Air\tJon Krakauer\nInvaders\tJohn Kessel\nInvasion Footnote\tHarlan Ellison\nInvisible Man\tRalph Ellison\nInvisible Planets\tHao Jingfang\nIt\tTheodore Sturgeon\nIt was Nothing-Really\tTheodore Sturgeon\nIt's You!\tTheodore Sturgeon\nJ. C. on the Dude Ranch\tPhilip Jose Farmer\nJack-in-the-Box\tRay Bradbury\nJane Doe #112\tHarlan Ellison\nJeffty is Five\tHarlan Ellison\nJenny with Wings\tKate Wilhelm\nJohnny Mnemonic\tWilliam Gibson\nJorry's Gap\tTheodore Sturgeon\nJudas\tJohn Brunner\nJulius Caesar\tWilliam Shakespeare\nJupiter Five\tArthur C. Clarke\nJurassic Park\tMichael Crichton\nKafka and His Precursors\tJorge Luis Borges\nInvisible Planets\tKen Liu\nKeyboard\tHarlan Ellison\nKilldozer!\tTheodore Sturgeon\nKilling Bernstein\tHarlan Ellison\nKing of the Hill\tChad Oliver\nKirinyaga\tMike Resnick\nKiss of Fire\tHarlan Ellison\nKnights to Move\tFritz Leiber\nKnox\tHarlan Ellison\nKyrie\tPoul Anderson\nLabyrinths\tJorge Luis Borges\nLadies and Gentlemen, This Is Your Crisis\tKate Wilhelm\nLamia Mutable\tM. John Harrison\nLand of the Great Horses\tR. A. Lafferty\nLast Train to Kankakee\tRobin Scott\nLaugh Track\tHarlan Ellison\nLeadership in Turbulent Times\tDoris Kearns Goodwin\nLenny\tIsaac Asimov\nLet There Be Light\tRobert A. Heilein\nLiar!\tIsaac Asimov\nLife in Our Time\tRobert Bloch\nLife, the Universe and Everything\tDouglas Adams\nLife-Line\tRobert A. Heilein\nLiking What You See: A Documentary\tTed Chiang\nLittle Lost Robot\tIsaac Asimov\nLollipop and the Tar Baby\tJohn Varley\nLonley Women Are the Vessels of Time\tHarlan Ellison\nLooking for Company\tFrederik Pohl\nLord of Light\tRoger Zelazny\nLord of the Flies\tWilliam Golding\nLord Randy, My Son\tJoe L. Hensley\nLove Ain't Nothing but Sex Misspelled\tHarlan Ellison\nLucy Comes To Stay\tRobert Bloch\nMadame Curie\tEve Curie\nMaking It All the Way into the Future on Gaxton Falls of the Red Planet\tBarry N. Malzberg\nMan of Letters\tKate Wilhelm\nMan Plus\tFrederik Pohl\nMartin Fierro\tJorge Luis Borges\nMartin the Warrior\tBrian Jacques\nMaster and Commander\tPatrick O'Brian\nMathoms from the Time Closet\tGene Wolfe\nMattimeo\tBrian Jacques\nMealtime\tHarlan Ellison\nMedusa\tTheodore Sturgeon\nMefisto in Onyx\tHarlan Ellison\nMicrocosmic God\tTheodore Sturgeon\nMidnight in the Sunken Cathedral\tHarlan Ellison\nMidnight News\tLisa Goldstein\nMom\tHarlan Ellison\nMona at Her Windows\tHarlan Ellison\nMona Lisa Overdrive\tWilliam Gibson\nMonitored Dreams & Strategic Cremations\tBernard Wolfe\nMono no Aware\tKen Liu\nMonolog\tPhilip Jose Farmer\nMonster vol.1\tNaoki Urasawa\nMonster vol.2\tNaoki Urasawa\nMonster vol.3\tNaoki Urasawa\nMonster vol.4\tNaoki Urasawa\nMonster vol.5\tNaoki Urasawa\nMonster vol.6\tNaoki Urasawa\nMonster vol.7\tNaoki Urasawa\nMonster vol.8\tNaoki Urasawa\nMonster vol.9\tNaoki Urasawa\nMore Than Human\tTheodore Sturgeon\nMoth Race\tRichard Hill\nMountain\tLiu Cixin\nMr. Costello, Hero\tTheodore Sturgeon\nMrs. Bagley Goes to Mars\tKate Wilhelm\nMutations\tJorge Luis Borges\nNackles vr.1\tDonald E. Westlake\nNackles vr.2\tDonald E. Westlake\nNackles vr.2\tHarlan Ellison\nNausicaa of the Valley of the Wind vol.1\tHayao Miyazaki\nNausicaa of the Valley of the Wind vol.2\tHayao Miyazaki\nNeither Your Jenny Nor Mine\tHarlan Ellison\nNeon\tHarlan Ellison\nNeuromancer\tWilliam Gibson\nNew Rose Hotel\tWilliam Gibson\nNight Journey of the Dragon-Horse\tXia Jia\nNight Meeting\tRay Bradbury\nNight of Black Glass\tHarlan Ellison\nNightfall\tIsaac Asimov\nNightfall\tRobert Silverberg\nNight-Rise\tKatherine MacLean\nNijigagara Holograph\tInio Asano\nNine Hundred Grandmothers\tR. A. Lafferty\nNo Game for Children\tHarlan Ellison\nNo Great Magic\tFritz Leiber\nNo Light in the Windows\tKate Wilhelm\nNothing for My Noon Meal\tHarlan Ellison\nNova\tSamuel R. Delany\nO Ye of Little Faith\tHarlan Ellison\nOddy and Id\tAlfred Bester\nOf Ants and Dinosaurs\tLiu Cixin\nOn Exactitude and Science\tJorge Luis Borges\nOn the Downhill Slide\tHarlan Ellison\nOn the Feasibility of Coal-Driven Power Stations\tO. R. Frisch\nOn the Slab\tHarlan Ellison\nOne Day in the Life of Ivan Denisovich\tAleksandr Solzhenitsyn\nOne for the Road\tKate Wilhelm\nOne Life, Furnished in Early Poverty\tHarlan Ellison\nOne-Way Journey\tMiram Allen deFord\nOperating Systems in Depth\tThomas W. Doeppner\nOperation Cassandra\tMiram Allen deFord\nOpium\tHarlan Ellison\nOther Worlds\tFrederik Pohl\nOut of All Them Bright Stars\tNancy Kress\nOver the River and Through the Woods\tClifford D. Simak\nOverlord\tMax Hastings\nOzymandias\tTerry Car\nPaingod\tHarlan Ellison\nPaingod and Other Delusions\tHarlan Ellison\nPaladin of the Last Hour\tHarlan Ellison\nParable of Cervantes and the Quixote\tJorge Luis Borges\nParable of the Palace\tJorge Luis Borges\nParadise\tClifford D. Simak\nParadiso, XXXI, 108\tJorge Luis Borges\nPartial Magic in the Quixote\tJorge Luis Borges\nPattern Recognition\tWilliam Gibson\nPaulie Charmed the Sleeping Woman\tHarlan Ellison\nPermanent Record\tEdward Snowden\nPersona 3: Official Design Works\tShigenori Soejima\nPersona 4 Arena: Official Design Works\tShigenori Soejima\nPersona 4: Official Design Works\tShigenori Soejima\nPhiltre Tip\tRobert Bloch\nPicnic on Paradise\tJoanna Russ\nPierre Menrad, Author of Don Quixote\tJorge Luis Borges\nPlanet Story\tKate Wilhelm\nPlanetes vol.1\tMakoto Yukimura\nPlanetes vol.2\tMakoto Yukimura\nPlayer Piano\tKurt Vonnegut\nPrecession\tEdward Bryant\nPrelude to Foundation\tIsaac Asimov\nPresidents of War\tMichael Beschloss\nPretty Maggie Moneyeyes\tHarlan Ellison\nPrince Myshkin, and Hold the Relish\tHarlan Ellison\nProdigy\tTheodore Sturgeon\nProject Nightmare\tRobert A. Heinlein\nPulling Hard Time\tHarlan Ellison\nPunky & The Yale Men\tHarlan Ellison\nQueen Emeraldas vol.1\tLeiji Matsumoto\nQueen Emeraldas vol.2\tLeiji Matsumoto\nQuick to Haste\tMiram Allen deFord\nQuicktime\tHarlan Ellison\nRadio Free Albemuth\tPhilip K. Dick\nRagnarok\tJorge Luis Borges\nRain, Rain, Go Away\tHarlan Ellison\nRat\tJames Patrick Kelly\nReason\tIsaac Asimov\nRed Star, Winter Orbit\tBruce Sterling\nRed Star, Winter Orbit\tWilliam Gibson\nRedwall\tBrian Jacques\nRendezvous with Rama\tArthur C. Clarke\nRepent, Harlequin! Said the Ticktockman\tHarlan Ellison\nRequiem\tRobert A. Heilein\nRiders of the Purple Wage\tPhilip Jose Farmer\nRiding the Dark Train Out\tHarlan Ellison\nRingworld\tLarry Niven\nRiverworld\tPhilip Jose Farmer\nRiverworld and Other Stories\tPhilip Jose Farmer\nRoadside Picnic\tArkady Strugatsky\nRoadside Picnic\tBoris Strugatsky\nRobbie\tIsaac Asimov\nRock God\tHarlan Ellison\nRocket Summer\tRay Bradbury\nRunaround\tIsaac Asimov\nSandkings\tGeorge R. R. Martin\nSaturn, November 11th\tHarlan Ellison\nScartaris, June 28th\tHarlan Ellison\nSchrodinger's Plague\tGreg Bear\nSchwarzschild Radius\tConnie Willis\nSecond Foundation\tIsaac Asimov\nSeeing\tHarlan Ellison\nSelected Poems\tT. S. Eliot\nSelected Stories\tTheodore Sturgeon\nSensible City\tHarlan Ellison\nSeraphim: 266613336 Wings\tSatoshi Kon\nSeventy-Two Letters\tTed Chiang\nSex and/or Mr. Morrison\tCarol Emshwiller\nShadow, Shadow on the Wall\tTheodore Sturgeon\nShall the Dust Praise Thee?\tDamon Knight\nShatterday\tHarlan Ellison\nShattered Like a Glass Goblin\tHarlan Ellison\nShe's a Young Thing and Cannot Leaver Her Mother\tHarlan Ellison\nShin Megami Tensei 4: Official Artworks\tMasayuki Doi\nShoppe Keeper\tHarlan Ellison\nSilence\tTadeusz Borowski\nSilent in Gehenna\tHarlan Ellison\nSilhouette\tGene Wolfe\nSimulacrum\tKen Liu\nSir Gawain and the Green Knight\tJ. R. R. Tolkien\nSkeleton\tRay Bradbury\nSkunk Works\tBen R. Rich\nSkunk Works\tLeo Janos\nSky Lift\tRobert A. Heinlein\nSlippage\tHarlan Ellison\nSlow Sculpture\tTheodore Sturgeon\nSnow\tJohn Crowley\nSo Long, and Thanks for All the Fish\tDouglas Adams\nSoft Monkey\tHarlan Ellison\nSolanin\tInio Asano\nSolaris\tStanislaw Lem\nSome Assembly Required\tTimothy S. Margush\nSomehow, I Don't Think We're in Kansas, Toto\tHarlan Ellison\nSomerset Dreams\tKate Wilhelm\nSomerset Dreams and Other Fictions\tKate Wilhelm\nSouls\tJoanna Russ\nSoundless Evening\tLee Hoffman\nSpeech Sound\tOctavia E. Butler\nSpook Country\tWilliam Gibson\nStable Strategies for Middle Management\tEileen Gunn\nStalingrad\tAntony Beevor\nStalking the Nightmare\tHarlan Ellison\nStand Still and Die\tHarlan Ellison\nStarship Troopers\tRobert A. Heinlein\nState Change\tKen Liu\nState of Grace\tKate Wilhelm\nStill-Life\tK. M. O'Donnell\nStillwell and the American Experience in China 1911-1945\tBarbara W. Tuchman\nStoned Counsel\tH. H. Hollis\nStories of Your Life and Others\tTed Chiang\nStory of the Warrior and the Captive Maiden\tJorge Luis Borges\nStory of Your Life\tTed Chiang\nStrange Gifts\tRobert Silverberg\nStrange Wine\tHarlan Ellison\nStranger in a Strange Land\tRobert A. Heinlein\nStuffing\tHarlan Ellison\nSturgeon is Alive and Well...\tTheodore Sturgeon\nSuicide\tTheodore Sturgeon\nSun of China\tLiu Cixin\nSymbiosis\tKate Wilhelm\nTake Care of Joey\tTheodore Sturgeon\nTaking Care of God\tLiu Cixin\nTandy's Story\tTheodore Sturgeon\nTauf Aleph\tPhysillis Gotlieb\nTeam of Rivals\tDoris Kearns Goodwin\nTekkonkinkreet: Black and White\tTaiyo Matsumoto\nTell Your Fortune\tRobert Bloch\nTest to Destruction\tKeith Laummer\nThat Girl Who Knew What They Meant\tTheodore Sturgeon\nThe [Widget], the [Wadget], and Boff\tTheodore Sturgeon\nThe 10:00 Report is Brought to You By...\tEdward Bryant\nThe 3 Most Important Things in Life\tHarlan Ellison\nThe Absolutely Perfect Murder\tMiram Allen deFord\nThe Adventure of Black Peter\tArthur Conan Doyle\nThe Adventure of Charles Augustus Milverton\tArthur Conan Doyle\nThe Adventure of the Gloria Scott\tArthur Conan Doyle\nThe Adventure of the Abbey Grange\tArthur Conan Doyle\nThe Adventure of the Beryl Coronet\tArthur Conan Doyle\nThe Adventure of the Blue Carbuncle\tArthur Conan Doyle\nThe Adventure of the Cardboard Box\tArthur Conan Doyle\nThe Adventure of the Copper Beeches\tArthur Conan Doyle\nThe Adventure of the Crooked Man\tArthur Conan Doyle\nThe Adventure of the Dancing Men\tArthur Conan Doyle\nThe Adventure of the Empty House\tArthur Conan Doyle\nThe Adventure of the Engineer's Thumb\tArthur Conan Doyle\nThe Adventure of the Final Problem\tArthur Conan Doyle\nThe Adventure of the Golden Pince-Nez\tArthur Conan Doyle\nThe Adventure of the Greek Interpreter\tArthur Conan Doyle\nThe Adventure of the Missing Three-Quarter\tArthur Conan Doyle\nThe Adventure of the Musgrave Ritual\tArthur Conan Doyle\nThe Adventure of the Naval Treaty\tArthur Conan Doyle\nThe Adventure of the Noble Bachelor\tArthur Conan Doyle\nThe Adventure of the Norwood Builder\tArthur Conan Doyle\nThe Adventure of the Priory School\tArthur Conan Doyle\nThe Adventure of the Reigate Squires\tArthur Conan Doyle\nThe Adventure of the Resident Patient\tArthur Conan Doyle\nThe Adventure of the Second Stain\tArthur Conan Doyle\nThe Adventure of the Silver Blaze\tArthur Conan Doyle\nThe Adventure of the Six Napoleons\tArthur Conan Doyle\nThe Adventure of the Solitary Cyclist\tArthur Conan Doyle\nThe Adventure of the Speckled Band\tArthur Conan Doyle\nThe Adventure of the Stockbroker's Clerk\tArthur Conan Doyle\nThe Adventure of the Yellow Face\tArthur Conan Doyle\nThe Age of Gold\tFrederik Pohl\nThe Ajeri Diary\tMiram Allen deFord\nThe Aleph\tJorge Luis Borges\nThe Aleph and Other Stories\tJorge Luis Borges\nThe Annals of the Heechee\tFrederik Pohl\nThe Approach to Al-Mu'tasim\tJorge Luis Borges\nThe Argentine Writer and Tradition\tJorge Luis Borges\nThe Art of Computer Programming vol.1\tDonald E. Knuth\nThe Art of Nausicaa of the Valley of the Wind\tHayao Miyazaki\nThe Art of Persona 5\tShigenori Soejima\nThe Art of Space\tRon Miller\nThe Avenger of Death\tHarlan Ellison\nThe Babylon Lottery\tJorge Luis Borges\nThe Beast of Barsac\tRobert Bloch\nThe Belonging Kind\tJohn Shirley\nThe Belonging Kind\tWilliam Gibson\nThe Big Hunger\tWalter M. Miller, Jr.\nThe Big Space Fuck\tKurt Vonnegut, Jr.\nThe Big Time\tFritz Leiber\nThe Black Cloud\tFred Hoyle\nThe Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd.\tMichael Bishop\nThe Book of Skulls\tRobert Silverberg\nThe Bookmaking Habits of Select Species\tKen Liu\nThe Boscombe Valley Mystery\tArthur Conan Doyle\nThe Boulevard of Broken Dreams\tHarlan Ellison\nThe Boy Who Would Live Forever\tFrederik Pohl\nThe Brains of Rats\tMichael Blumlein\nThe Byrds\tMichael G. Coney\nThe Captive\tJorge Luis Borges\nThe Cat Who Walks Through Walls\tRobert A. Heinlein\nThe Catcher in the Rye\tJ. D. Salinger\nThe Cheese Stands Alone\tHarlan Ellison\nThe Children\tMiram Allen deFord\nThe Chrysalids\tJohn Wyndham\nThe Circle\tLiu Cixin\nThe Circular Ruins\tJorge Luis Borges\nThe Cistern\tRay Bradbury\nThe City of Silence\tMa Boyong\nThe Classic Horror Stories\tH. P. Lovecraft\nThe Crackpots\tHarlan Ellison\nThe Crowd\tRay Bradbury\nThe Dark Design\tPhilip Jose Farmer\nThe Dark Forest\tLiu Cixin\nThe Daughter of the Tree\tMiram Allen deFord\nThe Day After the Day the Martians Came\tFrederik Pohl\nThe Day I Died\tHarlan Ellison\nThe Day of the Triffids\tJohn Wyndham\nThe Dead Man\tJorge Luis Borges\nThe Death of Schillinger\tTadeusz Borowski\nThe Deathbird\tHarlan Ellison\nThe Demolished Man\tAlfred Bester\nThe Diagnosis of Dr. Darqueangel\tHarlan Ellison\nThe Difference Engine\tBruce Sterling\nThe Difference Engine\tWilliam Gibson\nThe Discarded\tHarlan Ellison\nThe Dispossessed\tUrsula K. Le Guin\nThe Divine Invasion\tPhilip K. Dick\nThe Doll-House\tJames Cross\nThe Dragon on the Bookshelf\tHarlan Ellison\nThe Dragon on the Bookshelf\tRobert Silverberg\nThe Dreaming Jewels\tTheodore Sturgeon\nThe Dreams a Nightmare Dreams\tHarlan Ellison\nThe Dune Encyclopedia\tDr. Willis E. McNelly\nThe Dwarf\tRay Bradbury\nThe Earth Men\tRay Bradbury\nThe Electric Kool-Aid Acid Test\tTom Wolfe\nThe Emissary\tRay Bradbury\nThe Encounter\tKate Wilhelm\nThe End\tJorge Luis Borges\nThe Evitable Conflict\tIsaac Asimov\nThe Evolution of Human Science\tTed Chiang\nThe Executioner of the Malformed Children\tHarlan Ellison\nThe Extraordinary Voyages of Amelie Bertrand\tJoanna Russ\nThe Eyes of Heisenberg\tFrank Herbert\nThe Face of Helene Bournouw\tHarlan Ellison\nThe Fall of Hyperion\tDan Simmons\nThe Fearful Sphere of Pascal\tJorge Luis Borges\nThe Fellowship of the Ring\tJ. R. R. Tolkien\nThe Few, the Proud\tHarlan Ellison\nThe Fish of Lijiang\tChen Qiufan\nThe Five Orange Pips\tArthur Conan Doyle\nThe Flower of Shazui\tChen Qiufan\nThe Forces that Crush\tHarlan Ellison\nThe Forever War\tJoe Haldeman\nThe Form of the Sword\tJorge Luis Borges\nThe Fountains of Paradise\tArthur C. Clarke\nThe Function of Dream Sleep\tHarlan Ellison\nThe Funeral\tKate Wilhelm\nThe Fusion Bomb\tKate Wilhelm\nThe Garden of Forking Paths\tJorge Luis Borges\nThe Gateway Asteroid\tFrederik Pohl\nThe Gateway Trip\tFrederik Pohl\nThe Gernsback Continum\tWilliam Gibson\nThe Girl From Mars\tRobert Bloch\nThe Goddess in the Ice\tHarlan Ellison\nThe Godmakers\tFrank Herbert\nThe Gods Lie.\tKaori Ozaki\nThe God's Script\tJorge Luis Borges\nThe Gods Themselves\tIsaac Asimov\nThe Golden Helix\tTheodore Sturgeon\nThe Golden Man\tPhilip K. Dick\nThe Great Gatsby\tF. Scott Fitzgerald\nThe Green Morning\tRay Bradbury\nThe Guns of August\tBarbara W. Tuchman\nThe Handler\tDamon Knight\nThe Happy Breed\tJohn T. Sladek\nThe Heart of the Other Side\tGeorge Gamow\nThe Henry Miller Dawn Patrol\tPhilip Jose Farmer\nThe Hitchhiker's Guide to the Galaxy\tDouglas Adams\nThe Hobbit\tJ. R. R. Tolkien\nThe Home Planet\tFrederik Pohl\nThe Hounds\tKate Wilhelm\nThe Hour That Stretches\tHarlan Ellison\nThe House of Asterion\tJorge Luis Borges\nThe House the Blakeneys Built\tAvram Davidson\nThe Immortal\tJorge Luis Borges\nThe Incredible Voyage\tTristan Jones\nThe Indian Spirit Guide\tRobert Bloch\nThe Infinity Box\tKate Wilhelm\nThe Invasion\tRobert Willey\nThe January Offensive\tTadeusz Borowski\nThe Jar\tRay Bradbury\nThe Jigsaw Man\tLarry Niven\nThe Jungle Rot Kid on the Nod\tPhilip Jose Farmer\nThe Korean War\tMax Hastings\nThe Lake\tRay Bradbury\nThe Lake Was Full of Artificial Things\tKaren Joy Fowler\nThe Last Days of the Captain\tKate Wilhelm\nThe Last Generation?\tMiram Allen deFord\nThe Lathe of Heaven\tUrsula K. Le Guin\nThe Leaser of Two Evils\tPhilip Jose Farmer\nThe Library of Babel\tJorge Luis Borges\nThe Life of Anybody\tRobert Sheckley\nThe Lingering Scent of Woodsmoke\tHarlan Ellison\nThe Literomancer\tKen Liu\nThe Litigation Master and the Monkey King\tKen Liu\nThe Living Demons\tRobert Bloch\nThe Locusts\tRay Bradbury\nThe Long Dark Tea-Time of the Soul\tDouglas Adams\nThe Long Space Age\tAlexander MacDonald\nThe Long Years\tRay Bradbury\nThe Longest Fall\tLiu Cixin\nThe Lost World\tMichael Crichton\nThe Lottery in Babylon\tJorge Luis Borges\nThe Lucky Strike\tKim Stanley Robinson\nThe Luggage Store\tRay Bradbury\nThe Maker\tJorge Luis Borges\nThe Malley System\tMiriam Allen deFord\nThe Man in the High Castle\tPhilip K. Dick\nThe Man on the Threshold\tJorge Luis Borges\nThe Man Upstairs\tRay Bradbury\nThe Man Who Ended History: A Documentary\tKen Liu\nThe Man Who Lost the Sea\tTheodore Sturgeon\nThe Man Who Rowed Christopher Columbus Ashore\tHarlan Ellison\nThe Man Who Sold the Moon\tRobert A. Heinlein\nThe Man Who Was Heavily into Revenge\tHarlan Ellison\nThe Man Who Went to the Moon-Twice\tHoward Rodman\nThe Man With English\tHorace L. Gold\nThe Man with the Package\tTadeusz Borowski\nThe Man With the Twisted Lips\tArthur Conan Doyle\nThe Man without a Planet\tKate Wilhelm\nThe Manhattan Project\tAl Cimino\nThe March of Folly\tBarbara W. Tuchman\nThe Mark Gable Foundation\tLeo Szilard\nThe Martian\tRay Bradbury\nThe Martian Chronicles\tRay Bradbury\nThe Menace from Earth\tRobert A. Heinlein\nThe Merchants of Venus\tFrederik Pohl\nThe Micro-Age\tLiu Cixin\nThe Mile-Long Spaceship\tKate Wilhelm\nThe Milk of Paradise\tJames Tiptree, Jr.\nThe Million-Year Picnic\tRay Bradbury\nThe Miracle of the Broom Closet\tW. Norbert\nThe Mirrors of Enigmas\tJorge Luis Borges\nThe Moon is a Harsh Mistress\tRobert A. Heinlein\nThe Mountains of Sunset, the Mountains of Dawn\tVonda N. McIntyre\nThe Mountebank\tJorge Luis Borges\nThe Museum on Cyclops Avenue\tHarlan Ellison\nThe Musicians\tRay Bradbury\nThe Naming of Names\tRay Bradbury\nThe New Atlantis\tRobert Silverberg\nThe New Atlantis\tUrsula K. Le Guin\nThe New York Review of Bird\tHarlan Ellison\nThe Next in Line\tRay Bradbury\nThe Night That All Time Broke Out\tBrian W. Aldiss\nThe Norton Book of Science Fiction\tBrian Attebery\nThe Norton Book of Science Fiction\tUrsula K. Le Guin\nThe October Country\tRay Bradbury\nThe Off Season\tRay Bradbury\nThe Old Man and the Sea\tErnest Hemingway\nThe Old Ones\tRay Bradbury\nThe Oldest Soldier\tFritz Leiber\nThe Original Hitchhiker Radio Scripts\tDouglas Adams\nThe Original Illustrated Sherlock Holmes\tArthur Conan Doyle\nThe Other Death\tJorge Luis Borges\nThe Other Eye of Polyphemus\tHarlan Ellison\nThe Outcast of Redwall\tBrian Jacques\nThe Outpost Undiscovered by Tourists\tHarlan Ellison\nThe Oxford Book of English Verse\tChristopher Ricks\nThe Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1\tHarlan Ellison\nThe Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2\tHarlan Ellison\nThe Paper Menagerie\tKen Liu\nThe Patterns of Drone\tTheodore Sturgeon\nThe People Who Walked On\tTadeusz Borowski\nThe Perfect Match\tKen Liu\nThe Peripheral\tWilliam Gibson\nThe Phantom of the Sewers\tPhilip Jose Farmer\nThe Place with No Name\tHarlan Ellison\nThe Plot\tJorge Luis Borges\nThe Plot Is the Thing\tRobert Bloch\nThe Private War of Private Jacob\tJoe Haldeman\nThe Problem of the Sore Bridge-Among Others\tPhilip Jose Farmer\nThe Proud Tower\tBarbara W. Tuchman\nThe Prowler in the City on the Edge of Forever\tHarlan Ellison\nThe Recognition\tJ. G. Ballard\nThe Red Canary\tKate Wilhelm\nThe Red-Headed League\tArthur Conan Doyle\nThe Region Between\tHarlan Ellison\nThe Regular\tKen Liu\nThe Resurgence of Miss Ankle-Strap Wedgie\tHarlan Ellison\nThe Return of the King\tJ. R. R. Tolkien\nThe Right Stuff\tTom Wolfe\nThe Rise of Endymion\tDan Simmons\nThe Road\tCormac McCarthy\nThe Roads Must Roll\tRobert A. Heilein\nThe Salmon of Doubt\tDouglas Adams\nThe Season of Babies\tMiram Allen deFord\nThe Secret Miracle\tJorge Luis Borges\nThe Sect of Phoenix\tJorge Luis Borges\nThe Settlers\tRay Bradbury\nThe Sex Opposite\tTheodore Sturgeon\nThe Shape of the Sword\tJorge Luis Borges\nThe Shore\tRay Bradbury\nThe Silent Towns\tRay Bradbury\nThe Silver Corridor\tHarlan Ellison\nThe Simple Way\tClifford D. Simak\nThe Singers\tW. Grey Walter\nThe Sirens of Titan\tKurt Vonnegut\nThe Skills of Xanadu\tTheodore Sturgeon\nThe Sky is Burning\tHarlan Ellison\nThe Small Assaassin\tRay Bradbury\nThe Smiling Future\tMiram Allen deFord\nThe Sound and the Fury\tWilliam Faulkner\nThe South\tJorge Luis Borges\nThe Space Merchants\tC. M. Kornbluth\nThe Space Merchants\tFrederik Pohl\nThe Stars My Destination\tAlfred Bester\nThe Starseekers\tFrederik Pohl\nThe Start of the End of It All\tCarol Emshwiller\nThe Stochastic Man\tRobert Silverberg\nThe Summer Night\tRay Bradbury\nThe Sun also Rises\tErnest Hemingway\nThe Superior Sex\tMiram Allen deFord\nThe Supper\tTadeusz Borowski\nThe Sycthe\tRay Bradbury\nThe Taxpayer\tRay Bradbury\nThe Tell-Tale Heart and Other Writings\tEdgar Allan Poe\nThe Tempest\tWilliam Shakespeare\nThe Test Stand\tLee Corey\nThe Test-Tube Creature, Afterward\tJoan Bernott\nThe Theologians\tJorge Luis Borges\nThe Third Ear\tCurt Siodmak\nThe Third Expedition\tRay Bradbury\nThe Three Stigmata of Palmer Eldritch\tPhilip K. Dick\nThe Three-Body Problem\tLiu Cixin\nThe Tides of the Mind\tDavid Gelernter\nThe Time Piece\tKate Wilhelm\nThe Transit of Venus\tMiram Allen deFord\nThe Transmigration of Timothy Archer\tPhilip K. Dick\nThe Tree Lord of Imeten\tTom Purdom\nThe Trial\tFranz Kafka\nThe Two Kings and the Two Labyrinths\tJorge Luis Borges\nThe Two Towers\tJ. R. R. Tolkien\nThe Ultimate Hitchhiker's Guide\tDouglas Adams\nThe Universe of Robert Blake\tHarlan Ellison\nThe Unspeakable Betrothal\tRobert Bloch\nThe Very Last Day of a Good Woman\tHarlan Ellison\nThe View from the Stars\tWalter M. Miller, Jr.\nThe Village\tKate Wilhelm\nThe Visit\tFrederik Pohl\nThe Voice of the Sonar in My Veriform Appendix\tPhilip Jose Farmer\nThe Volcano\tPhilip Jose Farmer\nThe Wages of Humanity\tLiu Cixin\nThe Waiting\tJorge Luis Borges\nThe Wall and the Books\tJorge Luis Borges\nThe Wandering Earth\tLiu Cixin\nThe War at Home\tLewis Shiner\nThe Warlord of Saturn's Moon\tEleanor Aranason\nThe Watchers\tRay Bradbury\nThe Watchful Poker Chip of H. Matisse\tRay Bradbury\nThe Waves\tKen Liu\nThe Westing Game\tEllen Raskin\nThe Whimper of Whipped Dogs\tHarlan Ellison\nThe Will\tWalter M. Miller, Jr.\nThe Wind\tRay Bradbury\nThe Wind Beyond the Mountains\tHarlan Ellison\nThe Windup Girl\tPaolo Bacigalupi\nThe Wine Has Been Left Open Too Long and the Memory Has Gone Flat\tHarlan Ellison\nThe Winter Flies\tFritz Leiber\nThe Winter Market\tWilliam Gibson\nThe Witness\tJorge Luis Borges\nThe Women Men Don't See\tJames Tiptree, Jr.\nThe Wonderful Death of Dudley Stone\tRay Bradbury\nThe Word for World is Forrest\tUrsula K. Le Guin\nThe World Inside\tRobert Silverberg\nThe World of Professor Layton\tJun Suzuki\nThe World of Stone\tTadeusz Borowski\nThe Writing of the God\tJorge Luis Borges\nThe Year of the Jackpot\tRobert A. Heinlein\nThe Year of the Rat\tChen Qiufan\nThe Yellow Rose\tJorge Luis Borges\nThe Zahir\tJorge Luis Borges\nThe Zimmermann Telegram\tBarbara W. Tuchman\nTheme of the Traitor and Hero\tJorge Luis Borges\nThere Was an Old Woman\tRay Bradbury\nThere Will Come Soft Rains\tRay Bradbury\nThey Shall Have Stars\tJames Blish\nThings Lost\tThomas M. Disch\nThis Immortal\tRoger Zelazny\nThis Way for the Gas, Ladies and Gentlemen\tTadeusz Borowski\nThorns\tRobert Silverberg\nThousand Cranes\tYasunari Kawabata\nThree Versions of Judas\tJorge Luis Borges\nThrowback\tMiram Allen deFord\nThunder and Roses\tTheodore Sturgeon\nTime Travel for Pedestrians\tRay Nelson\nTiny Ally\tHarlan Ellison\nTissue\tJames Sallis\nTlon, Uqbar, Orbis Teritus\tJorge Luis Borges\nTo Be Continued\tRobert Silverberg\nTo Explain to Mrs. Thompson\tPhillip Latham\nTo Here and the Easel\tTheodore Sturgeon\nTo Kill a Mockingbird\tHarper Lee\nTo Open the Sky\tRobert Silverberg\nToenails\tJorge Luis Borges\nTongtong's Summer\tXia Jia\nTotenbuch\tA. Parra (y Figuerado)\nTouched With Fire\tRay Bradbury\nTower of Babylon\tTed Chiang\nTower of Glass\tRobert Silverberg\nTracking Level\tHarlan Ellison\nTranscending Destiny\tHarlan Ellison\nTreasure Island\tRobert Lewis Stevenson\nTrigun Omnibus\tYasuhiro Nightow\nTriss\tBrian Jacques\nTrouble With Ants\tClifford D. Simak\nTry and Change the Past\tFritz Leiber\nTwink\tTheodore Sturgeon\nUbik\tPhilip K. Dick\nUnaccompanied Sonata\tOrson Scott Card\nUncle Einar\tRay Bradbury\nUncle Fremmis\tTheodore Sturgeon\nUnderground\tRobert Bloch\nUnderstand\tTed Chiang\nUnlocking the Air\tUrsula K. Le Guin\nUsher II\tRay Bradbury\nValerie\tHarlan Ellison\nValery as Symbol\tJorge Luis Borges\nVALIS\tPhilip K. Dick\nVaster than Empires and More Slow\tUrsula K. Le Guin\nVenus Plus X\tTheodore Sturgeon\nVietnam: An Epic Tragedy, 1945-1975\tMax Hastings\nVirtual Light\tWilliam Gibson\nVisionary\tHarlan Ellison\nWalden; or, Life in the Woods\tHenry David Thoreau\nWandering Island vol.1\tKenji Tsuruta\nWandering Island vol.2\tKenji Tsuruta\nWanted in Surgery\tHarlan Ellison\nWatchmen\tAlan Moore\nWater Is for Washing\tRobert A. Heinlein\nWatership Down\tRichard Adams\nWay in the Middle of the Air\tRay Bradbury\nWay Station\tClifford D. Simak\nWe\tYevgeny Zamyatin\nWe See Things Differently\tBruce Sterling\nWeb of the City\tHarlan Ellison\nWhat Happened to Auguste Clarot?\tLarry Eisenberg\nWhat I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27\tHarlan Ellison\nWhat's It Like Out There?\tEdmond Hamilton\nWhen Auld's Acquaintance is Forgot\tHarlan Ellison\nWhen I was a Hired Gun\tHarlan Ellison\nWhen I Was Miss Dow\tSonya Dorman\nWhen it Changed\tJoanna Russ\nWhen the Bentfin Boomer Boys on Old New Alabama\tRichard A. Lupoff\nWhen the Change-Winds Blow\tFritz Leiber\nWhere Have You Been, Billy Boy, Billy Boy?\tKate Wilhelm\nWhere I Shall Dwell in the Next World\tHarlan Ellison\nWhere Late the Sweet Birds Sang\tKate Wilhelm\nWith a Finger in My I\tDavid Gerrold\nWith Her Eyes\tLiu Cixin\nWith Virgin Oddum at the East Pole\tHarlan Ellison\nWorking with the Little People\tHarlan Ellison\nWould You Do It for a Penny\tHarlan Ellison\nXenogenesis\tMiriam Allen deFord\nYeager\tChuck Yeager\nYeager\tLeo Janos\nYlla\tRay Bradbury\nYou Triflin' Skunk\tWalter M. Miller, Jr.\nZero Gee\tBen Bova\nZero History\tWilliam Gibson"
  },
  {
    "path": "tests/data/books.tsv",
    "content": "1984\tscience fiction\t1950\t328\n2001: A Space Odyssey\tscience fiction\t1968\t221\n20th Century Boys vol.1\tscience fiction\t2018\t413\n20th Century Boys vol.2\tscience fiction\t2018\t412\n20th Century Boys vol.3\tscience fiction\t2019\t410\n20th Century Boys vol.4\tscience fiction\t2019\t416\n20th Century Boys vol.5\tscience fiction\t2019\t422\n20th Century Boys vol.6\tscience fiction\t2019\t456\nA Canticle for Leibowitz\tscience fiction\t1959\t338\nA Case of Conscience\tscience fiction\t1958\t188\nA Clash of Cymbals\tscience fiction\t1959\t199\nA Clockwork Orange\tscience fiction\t1962\t139\nA Farewell to Arms\tamerican lit\t1929\t332\nA Life for the Stars\tscience fiction\t1962\t147\nA Scanner Darkly\tscience fiction\t1977\t217\nA Time of Changes\tscience fiction\t1975\t205\nA Tour of C++ 2nd\ttextbook\t2018\t238\nAbsalom, Absalom!\tamerican lit\t1936\t303\nAgain, Dangerous Visions\tscience fiction\t1972\t830\nAkira vol.1\tscience fiction\t2010\t363\nAkira vol.2\tscience fiction\t2010\t301\nAkira vol.3\tscience fiction\t2010\t282\nAkira vol.4\tscience fiction\t2010\t394\nAkira vol.5\tscience fiction\t2011\t413\nAkira vol.6\tscience fiction\t2011\t434\nAlgorithms 4th\ttextbook\t2011\t959\nAll Tomorrow's Parties\tscience fiction\t1999\t339\nAnd Chaos Died\tscience fiction\t1970\t189\nAngry Candy\tscience fiction\t1988\t324\nAnimal Farm\tbritish lit\t1956\t139\nApproaching Oblivion\tscience fiction\t1974\t164\nArmy of None\thistory\t2018\t436\nBattle for the Mind\tinformative\t1954\t350\nBeowulf\tfantasy\t1994\t92\nBeyond the Blue Event Horizon\tscience fiction\t1980\t309\nBible and Sword\thistory\t1984\t346\nBlame! vol.1\tscience fiction\t2016\t348\nBlame! vol.2\tscience fiction\t2016\t374\nBlame! vol.3\tscience fiction\t2017\t352\nBlame! vol.4\tscience fiction\t2017\t367\nBlame! vol.5\tscience fiction\t2017\t334\nBlame! vol.6\tscience fiction\t2017\t326\nBlue Spring\tfiction\t2004\t213\nBrain Wave\tscience fiction\t1954\t166\nBrave New World\tscience fiction\t1932\t259\nBurning Chrome\tscience fiction\t1986\t191\nC Primer Plus 5th\ttextbook\t2005\t959\nC++ Primer 5th\ttextbook\t2013\t938\nCapitalism Without Capital\teconomics\t2018\t278\nCaptain Harlock: The Classic Collection vol.1\tscience fiction\t2018\t396\nCaptain Harlock: The Classic Collection vol.2\tscience fiction\t2018\t397\nCaptain Harlock: The Classic Collection vol.3\tscience fiction\t2019\t392\nCatch-22\tamerican lit\t1955\t453\nCaviar\tscience fiction\t1955\t182\nChangewar\tscience fiction\t1983\t198\nChapterhouse: Dune\tscience fiction\t1985\t436\nChildhood's End\tscience fiction\t1953\t212\nChildren of Dune\tscience fiction\t1976\t408\nChildren of the Sea vol.1\tfiction\t2013\t316\nChildren of the Sea vol.2\tfiction\t2013\t315\nChildren of the Sea vol.3\tfiction\t2013\t334\nChildren of the Sea vol.4\tfiction\t2013\t324\nChildren of the Sea vol.5\tfiction\t2013\t329\nCity\tscience fiction\t1952\t267\nColossus\thistory\t2006\t462\nConversations With Jorge Luis Borges\tinterviews\t1968\t144\nCount Zero\tscience fiction\t1986\t246\nCrome Yellow\tbritish lit\t1921\t174\nDandelion Wine\tamerican lit\t1957\t239\nDangerous Visions\tscience fiction\t1967\t598\nDeath and the Penguin\tmystery\t1996\t228\nDeathbird Stories\tscience fiction\t1975\t347\nDeath's End\tscience fiction\t2016\t604\nDestined for War\thistory\t2017\t364\nDirk Gently's Holistic Detective Agency\tscience fiction\t1987\t306\nDistrust That Particular Flavor\tessays\t2012\t255\nDo Androids Dream of Electric Sheep?\tscience fiction\t1968\t244\nDoctor Zhivago\teast euro lit\t1957\t456\nDon Quixote\tadventure\t1950\t940\nDouble Star\tscience fiction\t1956\t243\nDownward to the Earth\tscience fiction\t1970\t181\nDr. Bloodmoney\tscience fiction\t1965\t298\nDune\tscience fiction\t1965\t883\nDune Messiah\tscience fiction\t1969\t279\nDying Inside\tscience fiction\t1972\t200\nEarthman, Come Home\tscience fiction\t1955\t256\nEarthman, Go Home!\tscience fiction\t1962\t191\nEmanon vol.1: Memories of Emanon\tscience fiction\t2019\t190\nEmanon vol.2: Emanon Wanderer pt.1\tscience fiction\t2019\t213\nEmanon vol.3: Emanon Wanderer pt.2\tscience fiction\t2019\t233\nEmpire Star\tscience fiction\t1966\t102\nEnder's Game\tscience fiction\t1977\t324\nEndless Frontier\thistory\t1997\t527\nEndymion\tscience fiction\t1995\t563\nEniac\thistory\t1999\t262\nExplorers of Space\tscience fiction\t1975\t253\nFahrenheit 451\tscience fiction\t1953\t190\nFault-Tolerant Computer System Designs\ttextbook\t1996\t550\nFiasco\tscience fiction\t1987\t322\nFicciones\tfiction\t1956\t174\nFlow My Tears, the Policeman Said\tscience fiction\t1974\t231\nFlowers for Algernon\tscience fiction\t1966\t216\nFor Whom the Bell Tolls\tamerican lit\t1940\t507\nForward the Foundation\tscience fiction\t1993\t435\nFoundation\tscience fiction\t1951\t296\nFoundation and Earth\tscience fiction\t1986\t494\nFoundation and Empire\tscience fiction\t1952\t282\nFoundation's Edge\tscience fiction\t1982\t426\nGateway\tscience fiction\t1977\t313\nGhost in the Shell\tscience fiction\t2009\t348\nGhost in the Shell vol.2: Man-Machine Interface\tscience fiction\t2010\t306\nGhost in the Shell vol.1.5: Human-Error Processor\tscience fiction\t2007\t176\nGiganto Maxia\tfantasy\t2016\t232\nGod Emperor of Dune\tscience fiction\t1981\t423\nHamlet\ttragedy\t1599\t287\nHawksbill Station\tscience fiction\t1968\t185\nHeart of Darkness\teast euro lit\t1899\t166\nHeechee Rendezvous\tscience fiction\t1984\t331\nHeretics of Dune\tscience fiction\t1984\t480\nHouston, Houston, Do You Read?\tscience fiction\t1976\t92\nHyperion\tscience fiction\t1989\t482\nI Will Fear No Evil\tscience fiction\t1970\t512\nI, Robot\tscience fiction\t1950\t192\nIchi-F\tnonfiction\t2017\t550\nIdoru\tscience fiction\t1996\t383\nInferno: The World at War, 1939-1945\tinformative\t2012\t729\nInto the Wild\tnonfiction\t1996\t207\nInto Thin Air\tnonfiction\t1997\t404\nInvisible Man\tamerican lit\t1952\t581\nInvisible Planets\tscience fiction\t2016\t393\nJulius Caesar\ttragedy\t1599\t209\nJurassic Park\tscience fiction\t1990\t399\nLabyrinths\tfiction\t2007\t256\nLeadership in Turbulent Times\thistory\t2018\t473\nLife, the Universe and Everything\tscience fiction\t1982\t162\nLord of Light\tscience fiction\t1967\t296\nLord of the Flies\tbritish lit\t1954\t208\nLove Ain't Nothing but Sex Misspelled\tscience fiction\t1968\t380\nMadame Curie\thistory\t1939\t390\nMan Plus\tscience fiction\t1976\t277\nMartin the Warrior\tfantasy\t1994\t376\nMaster and Commander\tadventure\t1970\t408\nMattimeo\tfantasy\t1990\t432\nMona Lisa Overdrive\tscience fiction\t1988\t308\nMonster vol.1\tthriller\t2014\t422\nMonster vol.2\tthriller\t2014\t398\nMonster vol.3\tthriller\t2015\t430\nMonster vol.4\tthriller\t2015\t412\nMonster vol.5\tthriller\t2015\t404\nMonster vol.6\tthriller\t2015\t400\nMonster vol.7\tthriller\t2016\t410\nMonster vol.8\tthriller\t2016\t424\nMonster vol.9\tthriller\t2016\t470\nMore Than Human\tscience fiction\t1953\t188\nNausicaa of the Valley of the Wind vol.1\tfantasy\t2012\t548\nNausicaa of the Valley of the Wind vol.2\tfantasy\t2012\t533\nNebula Winners Fifteen\tscience fiction\t1981\t223\nNeuromancer\tscience fiction\t1984\t271\nNightfall\tscience fiction\t1990\t339\nNijigagara Holograph\tfiction\t2015\t200\nNova\tscience fiction\t1968\t215\nOne Day in the Life of Ivan Denisovich\teast euro lit\t1962\t210\nOperating Systems in Depth\ttextbook\t2011\t444\nOverlord\thistory\t1984\t462\nPaingod and Other Delusions\tscience fiction\t1965\t157\nPattern Recognition\tscience fiction\t2003\t356\nPermanent Record\thistory\t2019\t340\nPersona 3: Official Design Works\tart\t2006\t141\nPersona 4 Arena: Official Design Works\tart\t2012\t176\nPersona 4: Official Design Works\tart\t2008\t191\nPicnic on Paradise\tscience fiction\t1968\t157\nPlanetes vol.1\tscience fiction\t2015\t524\nPlanetes vol.2\tscience fiction\t2016\t524\nPlayer Piano\tscience fiction\t1952\t320\nPrelude to Foundation\tscience fiction\t1988\t434\nPresidents of War\thistory\t2018\t740\nQueen Emeraldas vol.1\tscience fiction\t2016\t415\nQueen Emeraldas vol.2\tscience fiction\t2017\t423\nRadio Free Albemuth\tscience fiction\t1985\t214\nRedwall\tfantasy\t1986\t333\nRendezvous with Rama\tscience fiction\t1973\t243\nRiders of the Purple Wage\tscience fiction\t1992\t216\nRingworld\tscience fiction\t1970\t288\nRiverworld and Other Stories\tscience fiction\t1979\t264\nRoadside Picnic\tscience fiction\t1972\t209\nSecond Foundation\tscience fiction\t1953\t279\nSelected Poems\tamerican lit\t1954\t114\nSelected Stories\tscience fiction\t2000\t439\nSeraphim: 266613336 Wings\tscience fiction\t2015\t268\nShatterday\tscience fiction\t1980\t332\nShin Megami Tensei 4: Official Artworks\tart\t2013\t208\nSir Gawain and the Green Knight\tfantasy\t1975\t212\nSkunk Works\thistory\t1994\t372\nSlippage\tscience fiction\t1997\t359\nSo Long, and Thanks for All the Fish\tscience fiction\t1984\t214\nSolanin\tfiction\t2008\t432\nSolaris\tscience fiction\t1961\t223\nSome Assembly Required\tinformative\t2012\t611\nSomerset Dreams and Other Fictions\tscience fiction\t1979\t174\nSouls\tfantasy\t1982\t84\nSpook Country\tscience fiction\t2007\t480\nStalingrad\thistory\t1998\t493\nStalking the Nightmare\tscience fiction\t1982\t301\nStarship Troopers\tscience fiction\t1959\t335\nStillwell and the American Experience in China 1911-1945\thistory\t1971\t794\nStories of Your Life and Others\tscience fiction\t2002\t281\nStrange Gifts\tscience fiction\t1975\t191\nStrange Wine\tscience fiction\t1979\t316\nStranger in a Strange Land\tscience fiction\t1961\t438\nSturgeon is Alive and Well...\tscience fiction\t1971\t207\nTeam of Rivals\thistory\t2005\t757\nTekkonkinkreet: Black and White\tfiction\t2007\t614\nThe Aleph and Other Stories\tfiction\t1998\t210\nThe Annals of the Heechee\tscience fiction\t1987\t341\nThe Art of Computer Programming vol.1\ttextbook\t1997\t652\nThe Art of Nausicaa of the Valley of the Wind\tart\t2007\t207\nThe Art of Persona 5\tart\t2017\t447\nThe Art of Space\tart\t2014\t224\nThe Big Time\tscience fiction\t1958\t184\nThe Book of Skulls\tscience fiction\t1972\t222\nThe Boy Who Would Live Forever\tscience fiction\t2004\t452\nThe Cat Who Walks Through Walls\tscience fiction\t1985\t388\nThe Catcher in the Rye\tamerican lit\t1945\t214\nThe Chrysalids\tscience fiction\t1955\t200\nThe Classic Horror Stories\thorror\t2013\t487\nThe Dark Forest\tscience fiction\t2015\t512\nThe Day of the Triffids\tscience fiction\t1951\t191\nThe Demolished Man\tscience fiction\t1954\t175\nThe Difference Engine\tscience fiction\t1991\t429\nThe Dispossessed\tscience fiction\t1974\t311\nThe Divine Invasion\tscience fiction\t1981\t260\nThe Dreaming Jewels\tscience fiction\t1950\t174\nThe Dune Encyclopedia\tencyclopedia\t1985\t526\nThe Electric Kool-Aid Acid Test\tinformative\t1968\t416\nThe Expert Dreamers\tscience fiction\t1962\t248\nThe Eyes of Heisenberg\tscience fiction\t1966\t158\nThe Fall of Hyperion\tscience fiction\t1990\t518\nThe Fellowship of the Ring\tfantasy\t1954\t458\nThe Forever War\tscience fiction\t1974\t254\nThe Fountains of Paradise\tscience fiction\t1980\t305\nThe Gateway Trip\tscience fiction\t1990\t245\nThe Godmakers\tscience fiction\t1972\t221\nThe Gods Lie.\tfiction\t2016\t216\nThe Gods Themselves\tscience fiction\t1972\t288\nThe Great Gatsby\tamerican lit\t1952\t180\nThe Guns of August\thistory\t1962\t606\nThe Hitchhiker's Guide to the Galaxy\tscience fiction\t1979\t215\nThe Hobbit\tfantasy\t1937\t305\nThe Incredible Voyage\tnonfiction\t1977\t390\nThe Infinity Box\tscience fiction\t1975\t272\nThe Korean War\thistory\t1987\t389\nThe Lathe of Heaven\tscience fiction\t1971\t175\nThe Living Demons\thorror\t1967\t156\nThe Long Dark Tea-Time of the Soul\tscience fiction\t1988\t307\nThe Long Space Age\thistory\t2017\t258\nThe Lost World\tscience fiction\t1995\t430\nThe Man in the High Castle\tscience fiction\t1962\t259\nThe Man Who Sold the Moon\tscience fiction\t1951\t267\nThe Manhattan Project\thistory\t2016\t187\nThe March of Folly\thistory\t1984\t447\nThe Martian Chronicles\tscience fiction\t1950\t181\nThe Menace from Earth\tscience fiction\t1962\t189\nThe Mile-Long Spaceship\tscience fiction\t1963\t160\nThe Moon is a Harsh Mistress\tscience fiction\t1966\t382\nThe New Atlantis\tscience fiction\t1975\t182\nThe Norton Book of Science Fiction\tscience fiction\t1993\t861\nThe October Country\tscience fiction\t1956\t306\nThe Old Man and the Sea\tamerican lit\t1952\t127\nThe Original Hitchhiker Radio Scripts\tscience fiction\t1985\t248\nThe Original Illustrated Sherlock Holmes\tmystery\t1976\t636\nThe Outcast of Redwall\tfantasy\t1995\t367\nThe Oxford Book of English Verse\tbritish lit\t1999\t668\nThe Paper Menagerie\tscience fiction\t2016\t450\nThe Peripheral\tscience fiction\t2014\t486\nThe Proud Tower\thistory\t1966\t615\nThe Return of the King\tfantasy\t1955\t466\nThe Right Stuff\tnonfiction\t1970\t352\nThe Rise of Endymion\tscience fiction\t1997\t709\nThe Road\tthriller\t2006\t287\nThe Salmon of Doubt\tfiction\t2002\t299\nThe Sirens of Titan\tscience fiction\t1959\t224\nThe Sound and the Fury\tamerican lit\t1929\t326\nThe Space Merchants\tscience fiction\t1953\t216\nThe Stars My Destination\tscience fiction\t1956\t234\nThe Stochastic Man\tscience fiction\t1976\t240\nThe Sun also Rises\tamerican lit\t1926\t251\nThe Tell-Tale Heart and Other Writings\thorror\t1982\t419\nThe Tempest\ttragedy\t1599\t177\nThe Third Ear\tscience fiction\t1971\t254\nThe Three Stigmata of Palmer Eldritch\tscience fiction\t1964\t230\nThe Three-Body Problem\tscience fiction\t2014\t399\nThe Tides of the Mind\tnonfiction\t2016\t267\nThe Transmigration of Timothy Archer\tscience fiction\t1991\t255\nThe Tree Lord of Imeten\tscience fiction\t1966\t152\nThe Trial\teast euro lit\t1925\t271\nThe Two Towers\tfantasy\t1954\t398\nThe Ultimate Hitchhiker's Guide\tscience fiction\t2005\t815\nThe View from the Stars\tscience fiction\t1965\t192\nThe Wandering Earth\tscience fiction\t2013\t478\nThe Westing Game\tmystery\t1978\t182\nThe Windup Girl\tscience fiction\t2015\t466\nThe World Inside\tscience fiction\t1970\t167\nThe World of Professor Layton\tart\t2015\t191\nThe Zimmermann Telegram\thistory\t1966\t225\nThey Shall Have Stars\tscience fiction\t1956\t181\nThis Immortal\tscience fiction\t1966\t184\nThis Way for the Gas, Ladies and Gentlemen\teast euro lit\t1959\t180\nThorns\tscience fiction\t1967\t222\nThousand Cranes\tasian lit\t1965\t144\nTo Kill a Mockingbird\tamerican lit\t1960\t376\nTo Open the Sky\tscience fiction\t1967\t222\nTower of Glass\tscience fiction\t1971\t184\nTreasure Island\tadventure\t1882\t202\nTrigun Omnibus\tscience fiction\t2013\t691\nTriss\tfantasy\t2002\t389\nUbik\tscience fiction\t1969\t216\nVALIS\tscience fiction\t1991\t241\nVenus Plus X\tscience fiction\t1960\t160\nVietnam: An Epic Tragedy, 1945-1975\thistory\t2018\t857\nVirtual Light\tscience fiction\t1993\t352\nWalden; or, Life in the Woods\tessays\t1854\t216\nWandering Island vol.1\tfiction\t2016\t198\nWandering Island vol.2\tfiction\t2018\t190\nWatchmen\tscience fiction\t1986\t414\nWatership Down\tfantasy\t1973\t478\nWay Station\tscience fiction\t1963\t190\nWe\tscience fiction\t1924\t226\nWeb of the City\tthriller\t1958\t284\nWhat's It Like Out There?\tscience fiction\t1974\t320\nWhere Late the Sweet Birds Sang\tscience fiction\t1976\t207\nXenogenesis\tscience fiction\t1969\t231\nYeager\thistory\t1985\t331\nZero History\tscience fiction\t2010\t529"
  },
  {
    "path": "tests/data/collected.tsv",
    "content": "!!!The!!Teddy!Crazy!!Show!!!\tStalking the Nightmare\t14\n(Learning About) Machine Sex\tThe Norton Book of Science Fiction\t16\n...the World, as we Know 't\tThe Norton Book of Science Fiction\t16\n2004, or Thereabouts\tThe Norton Book of Science Fiction\t5\nA Biography of Tadeo Isidoro Cruz (1829-1874)\tThe Aleph and Other Stories\t4\nA Brief History of the Trans-Pacific Tunnel\tThe Paper Menagerie and Other Stories\t19\nA Case of Identity\tThe Original Illustrated Sherlock Holmes\t12\nA Day at Harmenz\tThis Way for the Gas, Ladies and Gentlemen\t32\nA Deskful of Girls\tChangewar\t44\nA Dialog About A Dialog\tThe Aleph and Other Stories\t1\nA Dialog Between Dead Men\tThe Aleph and Other Stories\t3\nA Feast of Demons\tThe Expert Dreamers\t26\nA Few Things I Know About While Away\tThe Norton Book of Science Fiction\t13\nA Hundred Ghosts Parade Tonight\tInvisible Planets\t20\nA is for Automation\tThe Mile-Long Spaceship\t17\nA Midwinter's Tale\tThe Norton Book of Science Fiction\t13\nA Momentary Taste of Being\tThe New Atlantis\t174\nA Mouse in the Walls of the Global Village\tAgain, Dangerous Visions\t15\nA New Refutation of Time\tLabyrinths\t20\nA Note on (toward) Bernard Shaw\tLabyrinths\t4\nA Path Through the Darkness\tLove Ain't Nothing but Sex Misspelled\t14\nA Prayer for No One's Enemies\tLove Ain't Nothing but Sex Misspelled\t21\nA Problem\tLabyrinths\t2\nA Problem\tThe Aleph and Other Stories\t2\nA Scandal in Bohemia\tThe Original Illustrated Sherlock Holmes\t15\nA Toy for Juliette\tDangerous Visions\t15\nA True Story\tThis Way for the Gas, Ladies and Gentlemen\t4\nA Visit\tThis Way for the Gas, Ladies and Gentlemen\t3\nA Way of Thinking\tSelected Stories\t29\nAdrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W\tDeathbird Stories\t40\nAdrift on the Policy Level\tThe Expert Dreamers\t24\nAesop\tCity\t42\nAfter the Days of Dead-Eye 'Dee\tThe Norton Book of Science Fiction\t11\nAll in Good Time\tXenogensis\t10\nAll the Birds Come Home to Roost\tShatterday\t18\nAll the Flavors\tThe Paper Menagerie and Other Stories\t89\nAll the Lies Lies That Are My Life\tShatterday\t58\nAll The People\tStrange Gifts\t12\nAll the Sound of Fear\tEarthman, Go Home!\t12\nAlong the Scenic Route\tDeathbird Stories\t14\nAlpha Ralpha Boulevard\tThe Norton Book of Science Fiction\t25\nAmateur in Chancery\tThe Expert Dreamers\t18\nAmerica\tThe Norton Book of Science Fiction\t24\nAn Advanced Readers' Picture Book of Comparative Cognition\tThe Paper Menagerie and Other Stories\t15\nAn Examination of the Work of Herbert Quain\tFicciones\t6\nAnd the Angels Sing\tThe Norton Book of Science Fiction\t17\nAnd the Sea Like Mirrors\tAgain, Dangerous Visions\t20\nAndover and the Android\tThe Mile-Long Spaceship\t13\nAnybody Else Like Me?\tThe View from the Stars\t17\nAnywhere But Here, With Anybody But You\tSlippage\t8\nApril Fools' Day Forever\tThe Infinity Box\t58\nArgumentum Ornithologicum\tThe Aleph and Other Stories\t1\nAs Simple As That\tThe Norton Book of Science Fiction\t11\nAt the End of the Orbit\tThe Expert Dreamers\t20\nAt the Mouse Circus\tDeathbird Stories\t10\nAunt Parnetta's Electric Blisters\tThe Norton Book of Science Fiction\t5\nAuschwitz, Our Home (A Letter)\tThis Way for the Gas, Ladies and Gentlemen\t45\nAuto-De-Fe\tDangerous Visions\t10\nAvatars of the Tortoise\tLabyrinths\t7\nAverroes' Search\tLabyrinths\t8\nAverroes' Search\tThe Aleph and Other Stories\t10\nAye, and Gomorrah...\tDangerous Visions\t14\nBalanced Ecology\tThe Norton Book of Science Fiction\t17\nBasilisk\tDeathbird Stories\t22\nBattle Without Banners\tLove Ain't Nothing but Sex Misspelled\t14\nBattlefield\tEarthman, Go Home!\t12\nBeachhead\tExplorers of Space\t25\nBeauty's Beast\tThe Living Demons\t17\nBed Sheets are White\tAgain, Dangerous Visions\t8\nBettyann\tStrange Gifts\t44\nBianca's Hands\tSelected Stories\t9\nBig Joe and the Nth Generation\tThe View from the Stars\t19\nBlabbermouth\tCaviar\t28\nBlack Bargain\tThe Living Demons\t16\nBlank?\tStalking the Nightmare\t8\nBleeding Stones\tDeathbird Stories\t8\nBlind Bird, Blind Bird, Go Away From Me!\tLove Ain't Nothing but Sex Misspelled\t22\nBlood Bank\tThe View from the Stars\t46\nBlot\tAgain, Dangerous Visions\t15\nBlowups Happen\tThe Man Who Sold the Moon\t54\nBorges and I\tLabyrinths\t2\nBorges and I\tThe Aleph and Other Stories\t2\nBounty\tAgain, Dangerous Visions\t7\nBrass and Gold (or Horse and Zeppelin in Beverly Hills)\tRiverworld and Other Stories\t18\nBright Eyes\tPaingod and Other Delusions\t12\nBright Segment\tCaviar\t28\nBright Segment\tSelected Stories\t25\nBroken Glass\tAngry Candy\t12\nBrownshoes\tSturgeon is Alive and Well...\t12\nBurning Chrome\tBurning Chrome\t23\nBy His Bootstraps\tThe Menace from Earth\t49\nCall Girl\tInvisible Planets\t12\nCamps\tNebula Winners Fifteen\t29\nCarcinoma Angels\tDangerous Visions\t15\nCatch That Rabbit\tI, Robot\t15\nCatman\tApproaching Oblivion\t34\nCensus\tCity\t35\nChain Reaction\tThe Expert Dreamers\t16\nChained to the Fast Lane in the Red Queen's Race\tAngry Candy\t16\nChatting with Anubis\tSlippage\t8\nChing Witch!\tAgain, Dangerous Visions\t24\nChrist, Old Student in a New School\tAgain, Dangerous Visions\t9\nChuck Berry, Won't You Please Come Home\tAgain, Dangerous Visions\t12\nCity\tCity\t34\nCold Friend\tApproaching Oblivion\t11\nCollecting Team\tExplorers of Space\t18\nColumbus Was a Dope\tThe Menace from Earth\t4\nCome to the Party\tThe Collected Stories of Frank Herbert\t21\nComes Now the Power\tThe Norton Book of Science Fiction\t5\nCommuter's Problem\tEarthman, Go Home!\t22\nCorpse\tDeathbird Stories\t12\nCount the Clock That Tells the Time\tShatterday\t22\nCovered Mirrors\tThe Aleph and Other Stories\t2\nCrate\tSturgeon is Alive and Well...\t14\nCrazy as a Soup Sandwich\tSlippage\t48\nCroatoan\tStrange Wine\t18\nCrucifixus Etiam\tThe View from the Stars\t18\nCurse 5.0\tThe Wandering Earth\t23\nDamnation Morning\tChangewar\t19\nDanger-Human!\tStrange Gifts\t21\nDaniel White for the Greater Good\tLove Ain't Nothing but Sex Misspelled\t13\nDarkness Upon the Face of the Deep\tSlippage\t16\nDay Million\tThe Norton Book of Science Fiction\t5\nDeal From the Bottom\tEarthman, Go Home!\t7\nDeath and the Compass\tFicciones\t14\nDeath and the Compass\tLabyrinths\t12\nDeeper than the Darkness\tPaingod and Other Delusions\t20\nDelia Elena San Marco\tThe Aleph and Other Stories\t1\nDelusion for a Dragon Slayer\tDeathbird Stories\t18\nDeutsches Requiem\tLabyrinths\t7\nDeutsches Requiem\tThe Aleph and Other Stories\t7\nDevourer\tThe Wandering Earth\t46\nDistant Signals\tThe Norton Book of Science Fiction\t13\nDivision by Zero\tStories of Your Life and Others\t20\nDjango\tShatterday\t12\nDjinn, No Chaser\tStalking the Nightmare\t22\nDogfight\tBurning Chrome\t24\nDo-It-Yourself\tEarthman, Go Home!\t14\nDreamtigers\tThe Aleph and Other Stories\t1\nDumb Waiter\tThe View from the Stars\t34\nEach an Explorer\tExplorers of Space\t18\nEcowarewness\tApproaching Oblivion\t2\nEidolons\tAngry Candy\t18\nElbow Room\tThe Norton Book of Science Fiction\t15\nElegy\tLabyrinths\t2\nElouise and the Doctors of the Planet Pergamon\tAgain, Dangerous Visions\t19\nEmissary from Hamelin\tStrange Wine\t13\nEmma Zunz\tLabyrinths\t6\nEmma Zunz\tThe Aleph and Other Stories\t7\nEmpire of the Sun\tAgain, Dangerous Visions\t8\nEncounter With A Hick\tDangerous Visions\t7\nEnemy Mine\tNebula Winners Fifteen\t64\nEpilogue\tCity\t13\nEpiphany for Aliens\tAgain, Dangerous Visions\t11\nErnest and the Machine God\tDeathbird Stories\t20\nErotophobia\tApproaching Oblivion\t7\nErsatz\tDangerous Visions\t9\nEscape!\tI, Robot\t21\nEscapegoat\tAngry Candy\t4\nEutopia\tDangerous Visions\t23\nEvensong\tDangerous Visions\t10\nEverything and Nothing\tLabyrinths\t3\nEverything and Nothing\tThe Aleph and Other Stories\t3\nEvidence\tI, Robot\t23\nExploration Team\tExplorers of Space\t58\nExposures\tThe Norton Book of Science Fiction\t12\nEye of the Beholder\tAgain, Dangerous Visions\t15\nFaith of our Fathers\tDangerous Visions\t38\nFear is a Cold Black\tThe Mile-Long Spaceship\t25\nFeather Tigers\tThe Norton Book of Science Fiction\t7\nFeatherbed on Chlyntha\tXenogensis\t17\nFinal Trophy\tStalking the Nightmare\t12\nFlies\tDangerous Visions\t13\nFlop Sweat\tShatterday\t18\nFolding Beijing\tInvisible Planets\t44\nFootsteps\tAngry Candy\t14\nFor the Sake of Grace\tThe Norton Book of Science Fiction\t20\nFor Value Received\tAgain, Dangerous Visions\t18\nFragments of a Hologram Rose\tBurning Chrome\t7\nFrom A to Z, In The Chocolate Alphabet\tStrange Wine\t24\nFrom the Government Printing Office\tDangerous Visions\t9\nFrozen Journey\tThe Norton Book of Science Fiction\t16\nFunes the Memorious\tLabyrinths\t8\nFunes the Memorious\tFicciones\t10\nG. B. K.-A Many-Flavored Bird\tLove Ain't Nothing but Sex Misspelled\t11\nGather Blue Roses\tThe Norton Book of Science Fiction\t5\nGathi\tXenogensis\t7\nGetting Along\tAgain, Dangerous Visions\t32\nGhost of a Chance\tCaviar\t20\ngiANTS\tNebula Winners Fifteen\t20\nGift from the Stars\tThe Mile-Long Spaceship\t17\nGnomebody\tEarthman, Go Home!\t7\nGo Toward the Light\tSlippage\t10\nGo, Go, Go, Said the Bird\tDangerous Visions\t9\nGoldfish Bowl\tThe Menace from Earth\t29\nGonna Roll the Bones\tDangerous Visions\t26\nGood Hunting\tThe Paper Menagerie and Other Stories\t23\nGood News from the Vatican\tThe Norton Book of Science Fiction\t8\nGopher in the Gilly\tStalking the Nightmare\t6\nGrail\tStalking the Nightmare\t28\nGrave of the Fireflies\tInvisible Planets\t18\nGutter Gang\tWeb of the City\t25\nHadj\tEarthman, Go Home!\t5\nHalf-Life\tThe Norton Book of Science Fiction\t14\nHarry the Hare\tAgain, Dangerous Visions\t5\nHeavyplanet\tThe Expert Dreamers\t13\nHeechee Treasures\tThe Gateway Trip\t19\nHell Is the Absence of God\tStories of Your Life and Others\t32\nHigh Weir\tThe Norton Book of Science Fiction\t18\nHindsight: 480 Seconds\tApproaching Oblivion\t6\nHinterlands\tBurning Chrome\t22\nHis Vegetable\tThe Norton Book of Science Fiction\t5\nHitler Painted Roses\tStrange Wine\t18\nHobbies\tCity\t28\nHomecoming\tThe October Country\t17\nHomelanding\tThe Norton Book of Science Fiction\t3\nHow Beautiful with Banners\tThe Norton Book of Science Fiction\t9\nHow's the Night Life on Cassalda?\tShatterday\t18\nHuddling Place\tCity\t23\nHumpty Dumpty had a Great Fall\tStrange Gifts\t27\nI Curse the Lesson and Bless the Knowledge\tLove Ain't Nothing but Sex Misspelled\t14\nI, Dreamer\tThe View from the Stars\t12\nIbn-Hakam al-Bokhari, Murdered in His Labyrinth\tThe Aleph and Other Stories\t10\nIf All Men Were Brothers, Would You Let One Marry Your Sister?\tDangerous Visions\t49\nI'm Looking for Kadak\tApproaching Oblivion\t27\nIn Fear of K\tStrange Wine\t16\nIn Lonely Islands\tEarthman, Go Home!\t5\nIn Memoriam, J. F. K.\tThe Aleph and Other Stories\t1\nIn re Glover\tAgain, Dangerous Visions\t13\nIn the Barn\tAgain, Dangerous Visions\t37\nIn the Core\tThe Gateway Trip\t9\nIn the Fourth Year of the War\tShatterday\t14\nIncident in Moderan\tDangerous Visions\t6\nInferno, I, 32\tLabyrinths\t1\nInferno, I, 32\tThe Aleph and Other Stories\t1\nInterim\tThe Martian Chronicles\t1\nInterlocking Pieces\tThe Norton Book of Science Fiction\t6\nInvaders\tThe Norton Book of Science Fiction\t20\nInvasion Footnote\tStalking the Nightmare\t8\nInvisible Planets\tInvisible Planets\t20\nIt\tSelected Stories\t25\nIt was Nothing-Really\tSturgeon is Alive and Well...\t15\nIt's You!\tSturgeon is Alive and Well...\t10\nJ. C. on the Dude Ranch\tRiverworld and Other Stories\t16\nJack-in-the-Box\tThe October Country\t20\nJane Doe #112\tSlippage\t12\nJeffty is Five\tShatterday\t28\nJenny with Wings\tThe Mile-Long Spaceship\t13\nJohnny Mnemonic\tBurning Chrome\t22\nJorry's Gap\tSturgeon is Alive and Well...\t12\nJudas\tDangerous Visions\t12\nJupiter Five\tExplorers of Space\t38\nKafka and His Precursors\tLabyrinths\t3\nKeyboard\tSlippage\t7\nKilldozer!\tSelected Stories\t70\nKilling Bernstein\tStrange Wine\t18\nKing of the Hill\tAgain, Dangerous Visions\t20\nKirinyaga\tThe Norton Book of Science Fiction\t17\nKiss of Fire\tApproaching Oblivion\t11\nKnights to Move\tChangewar\t13\nKnox\tApproaching Oblivion\t15\nKyrie\tExplorers of Space\t15\nKyrie\tThe Norton Book of Science Fiction\t10\nLadies and Gentlemen, This Is Your Crisis\tSomerset Dreams and Other Fictions\t16\nLamia Mutable\tAgain, Dangerous Visions\t10\nLand of the Great Horses\tDangerous Visions\t12\nLast Train to Kankakee\tAgain, Dangerous Visions\t11\nLaugh Track\tAngry Candy\t22\nLenny\tThe Expert Dreamers\t18\nLet There Be Light\tThe Man Who Sold the Moon\t19\nLiar!\tI, Robot\t16\nLife in Our Time\tThe Living Demons\t9\nLife-Line\tThe Man Who Sold the Moon\t22\nLiking What You See: A Documentary\tStories of Your Life and Others\t38\nLittle Lost Robot\tI, Robot\t26\nLollipop and the Tar Baby\tThe Norton Book of Science Fiction\t19\nLonley Women Are the Vessels of Time\tStrange Wine\t8\nLooking for Company\tThe Gateway Trip\t13\nLord Randy, My Son\tDangerous Visions\t18\nLucy Comes To Stay\tThe Living Demons\t6\nMaking It All the Way into the Future on Gaxton Falls of the Red Planet\tThe Norton Book of Science Fiction\t4\nMan of Letters\tThe Infinity Box\t19\nMartin Fierro\tThe Aleph and Other Stories\t2\nMathoms from the Time Closet\tAgain, Dangerous Visions\t12\nMealtime\tEarthman, Go Home!\t11\nMedusa\tCaviar\t26\nMefisto in Onyx\tSlippage\t46\nMicrocosmic God\tCaviar\t34\nMidnight in the Sunken Cathedral\tSlippage\t10\nMidnight News\tThe Norton Book of Science Fiction\t11\nMom\tStrange Wine\t22\nMona at Her Windows\tLove Ain't Nothing but Sex Misspelled\t5\nMonitored Dreams & Strategic Cremations\tAgain, Dangerous Visions\t67\nMono no Aware\tThe Paper Menagerie and Other Stories\t21\nMonolog\tRiverworld and Other Stories\t8\nMoth Race\tAgain, Dangerous Visions\t13\nMountain\tThe Wandering Earth\t48\nMr. Costello, Hero\tSelected Stories\t26\nMrs. Bagley Goes to Mars\tSomerset Dreams and Other Fictions\t10\nMutations\tThe Aleph and Other Stories\t1\nNackles vr.1\tSlippage\t8\nNackles vr.2\tSlippage\t31\nNeither Your Jenny Nor Mine\tLove Ain't Nothing but Sex Misspelled\t44\nNeon\tDeathbird Stories\t12\nNew Rose Hotel\tBurning Chrome\t14\nNight Journey of the Dragon-Horse\tInvisible Planets\t20\nNight Meeting\tThe Martian Chronicles\t9\nNight of Black Glass\tStalking the Nightmare\t16\nNight-Rise\tThe Norton Book of Science Fiction\t10\nNine Hundred Grandmothers\tThe Norton Book of Science Fiction\t9\nNo Game for Children\tWeb of the City\t51\nNo Great Magic\tChangewar\t68\nNo Light in the Windows\tThe Mile-Long Spaceship\t11\nNothing for My Noon Meal\tEarthman, Go Home!\t15\nO Ye of Little Faith\tDeathbird Stories\t10\nOddy and Id\tStrange Gifts\t17\nOf Ants and Dinosaurs\tThe Wandering Earth\t57\nOn Exactitude and Science\tThe Aleph and Other Stories\t1\nOn the Downhill Slide\tDeathbird Stories\t18\nOn the Feasibility of Coal-Driven Power Stations\tThe Expert Dreamers\t4\nOn the Slab\tAngry Candy\t12\nOne for the Road\tThe Mile-Long Spaceship\t16\nOne Life, Furnished in Early Poverty\tApproaching Oblivion\t14\nOne-Way Journey\tXenogensis\t11\nOperation Cassandra\tXenogensis\t27\nOpium\tShatterday\t8\nOther Worlds\tThe Gateway Trip\t19\nOut of All Them Bright Stars\tThe Norton Book of Science Fiction\t7\nOver the River and Through the Woods\tThe Norton Book of Science Fiction\t8\nOzymandias\tAgain, Dangerous Visions\t21\nPaingod\tDeathbird Stories\t12\nPaingod\tPaingod and Other Delusions\t12\nPaladin of the Last Hour\tAngry Candy\t26\nParable of Cervantes and the Quixote\tLabyrinths\t1\nParable of the Palace\tThe Aleph and Other Stories\t2\nParadise\tCity\t16\nParadiso, XXXI, 108\tLabyrinths\t2\nParadiso, XXXI, 108\tThe Aleph and Other Stories\t2\nPartial Magic in the Quixote\tLabyrinths\t4\nPaulie Charmed the Sleeping Woman\tApproaching Oblivion\t4\nPhiltre Tip\tThe Living Demons\t5\nPierre Menrad, Author of Don Quixote\tFicciones\t12\nPierre Menrad, Author of Don Quixote\tLabyrinths\t9\nPlanet Story\tSomerset Dreams and Other Fictions\t16\nPrecession\tThe Norton Book of Science Fiction\t10\nPretty Maggie Moneyeyes\tDeathbird Stories\t24\nPrince Myshkin, and Hold the Relish\tAngry Candy\t10\nProdigy\tCaviar\t14\nProject Nightmare\tThe Menace from Earth\t21\nPulling Hard Time\tSlippage\t6\nPunky & The Yale Men\tLove Ain't Nothing but Sex Misspelled\t30\nQuick to Haste\tXenogensis\t12\nQuicktime\tAngry Candy\t10\nRagnarok\tLabyrinths\t2\nRagnarok\tThe Aleph and Other Stories\t2\nRain, Rain, Go Away\tEarthman, Go Home!\t9\nRat\tThe Norton Book of Science Fiction\t11\nReason\tI, Robot\t18\nRed Star, Winter Orbit\tBurning Chrome\t23\nRepent, Harlequin! Said the Ticktockman\tPaingod and Other Delusions\t14\nRequiem\tThe Man Who Sold the Moon\t20\nRiders of the Purple Wage\tDangerous Visions\t80\nRiding the Dark Train Out\tLove Ain't Nothing but Sex Misspelled\t10\nRiverworld\tRiverworld and Other Stories\t86\nRobbie\tI, Robot\t19\nRock God\tDeathbird Stories\t14\nRocket Summer\tThe Martian Chronicles\t1\nRunaround\tI, Robot\t17\nSandkings\tNebula Winners Fifteen\t43\nSaturn, November 11th\tStalking the Nightmare\t16\nScartaris, June 28th\tSlippage\t22\nSchrodinger's Plague\tThe Norton Book of Science Fiction\t8\nSchwarzschild Radius\tThe Norton Book of Science Fiction\t16\nSeeing\tStrange Wine\t34\nSensible City\tSlippage\t10\nSeventy-Two Letters\tStories of Your Life and Others\t54\nSex and/or Mr. Morrison\tDangerous Visions\t14\nShadow, Shadow on the Wall\tCaviar\t12\nShall the Dust Praise Thee?\tDangerous Visions\t7\nShatterday\tShatterday\t17\nShattered Like a Glass Goblin\tDeathbird Stories\t14\nShe's a Young Thing and Cannot Leaver Her Mother\tSlippage\t16\nShoppe Keeper\tShatterday\t24\nSilence\tThis Way for the Gas, Ladies and Gentlemen\t3\nSilent in Gehenna\tApproaching Oblivion\t16\nSilhouette\tThe New Atlantis\t56\nSimulacrum\tThe Paper Menagerie and Other Stories\t11\nSkeleton\tThe October Country\t20\nSky Lift\tThe Menace from Earth\t14\nSlow Sculpture\tSelected Stories\t20\nSlow Sculpture\tSturgeon is Alive and Well...\t22\nSnow\tThe Norton Book of Science Fiction\t14\nSoft Monkey\tAngry Candy\t16\nSomehow, I Don't Think We're in Kansas, Toto\tStalking the Nightmare\t10\nSomerset Dreams\tSomerset Dreams and Other Fictions\t46\nSoundless Evening\tAgain, Dangerous Visions\t8\nSpeech Sound\tThe Norton Book of Science Fiction\t12\nStable Strategies for Middle Management\tThe Norton Book of Science Fiction\t11\nStand Still and Die\tWeb of the City\t203\nState Change\tThe Paper Menagerie and Other Stories\t16\nState of Grace\tSomerset Dreams and Other Fictions\t9\nStill-Life\tAgain, Dangerous Visions\t15\nStoned Counsel\tAgain, Dangerous Visions\t16\nStory of the Warrior and the Captive Maiden\tLabyrinths\t5\nStory of the Warrior and the Captive Maiden\tThe Aleph and Other Stories\t5\nStory of Your Life\tStories of Your Life and Others\t56\nStrange Wine\tStrange Wine\t12\nStrange Wine\tThe Norton Book of Science Fiction\t7\nStuffing\tAngry Candy\t8\nSuicide\tSturgeon is Alive and Well...\t8\nSun of China\tThe Wandering Earth\t49\nSymbiosis\tSomerset Dreams and Other Fictions\t20\nTake Care of Joey\tSturgeon is Alive and Well...\t12\nTaking Care of God\tInvisible Planets\t40\nTaking Care of God\tThe Wandering Earth\t41\nTandy's Story\tThe Norton Book of Science Fiction\t19\nTauf Aleph\tThe Norton Book of Science Fiction\t18\nTell Your Fortune\tThe Living Demons\t25\nTest to Destruction\tDangerous Visions\t29\nThat Girl Who Knew What They Meant\tSturgeon is Alive and Well...\t10\nThe [Widget], the [Wadget], and Boff\tSelected Stories\t84\nThe 10:00 Report is Brought to You By...\tAgain, Dangerous Visions\t16\nThe 3 Most Important Things in Life\tStalking the Nightmare\t20\nThe Absolutely Perfect Murder\tXenogensis\t11\nThe Adventure of Black Peter\tThe Original Illustrated Sherlock Holmes\t13\nThe Adventure of Charles Augustus Milverton\tThe Original Illustrated Sherlock Holmes\t12\nThe Adventure of the Gloria Scott\tThe Original Illustrated Sherlock Holmes\t12\nThe Adventure of the Abbey Grange\tThe Original Illustrated Sherlock Holmes\t15\nThe Adventure of the Beryl Coronet\tThe Original Illustrated Sherlock Holmes\t15\nThe Adventure of the Blue Carbuncle\tThe Original Illustrated Sherlock Holmes\t13\nThe Adventure of the Cardboard Box\tThe Original Illustrated Sherlock Holmes\t13\nThe Adventure of the Copper Beeches\tThe Original Illustrated Sherlock Holmes\t17\nThe Adventure of the Crooked Man\tThe Original Illustrated Sherlock Holmes\t11\nThe Adventure of the Dancing Men\tThe Original Illustrated Sherlock Holmes\t16\nThe Adventure of the Empty House\tThe Original Illustrated Sherlock Holmes\t15\nThe Adventure of the Engineer's Thumb\tThe Original Illustrated Sherlock Holmes\t13\nThe Adventure of the Final Problem\tThe Original Illustrated Sherlock Holmes\t14\nThe Adventure of the Golden Pince-Nez\tThe Original Illustrated Sherlock Holmes\t15\nThe Adventure of the Greek Interpreter\tThe Original Illustrated Sherlock Holmes\t12\nThe Adventure of the Missing Three-Quarter\tThe Original Illustrated Sherlock Holmes\t14\nThe Adventure of the Musgrave Ritual\tThe Original Illustrated Sherlock Holmes\t11\nThe Adventure of the Naval Treaty\tThe Original Illustrated Sherlock Holmes\t22\nThe Adventure of the Noble Bachelor\tThe Original Illustrated Sherlock Holmes\t14\nThe Adventure of the Norwood Builder\tThe Original Illustrated Sherlock Holmes\t15\nThe Adventure of the Priory School\tThe Original Illustrated Sherlock Holmes\t19\nThe Adventure of the Reigate Squires\tThe Original Illustrated Sherlock Holmes\t12\nThe Adventure of the Resident Patient\tThe Original Illustrated Sherlock Holmes\t11\nThe Adventure of the Second Stain\tThe Original Illustrated Sherlock Holmes\t14\nThe Adventure of the Silver Blaze\tThe Original Illustrated Sherlock Holmes\t16\nThe Adventure of the Six Napoleons\tThe Original Illustrated Sherlock Holmes\t14\nThe Adventure of the Solitary Cyclist\tThe Original Illustrated Sherlock Holmes\t13\nThe Adventure of the Speckled Band\tThe Original Illustrated Sherlock Holmes\t16\nThe Adventure of the Stockbroker's Clerk\tThe Original Illustrated Sherlock Holmes\t11\nThe Adventure of the Yellow Face\tThe Original Illustrated Sherlock Holmes\t11\nThe Age of Gold\tThe Gateway Trip\t16\nThe Ajeri Diary\tXenogensis\t20\nThe Aleph\tThe Aleph and Other Stories\t16\nThe Approach to Al-Mu'tasim\tFicciones\t8\nThe Argentine Writer and Tradition\tLabyrinths\t9\nThe Avenger of Death\tAngry Candy\t14\nThe Babylon Lottery\tFicciones\t8\nThe Beast of Barsac\tThe Living Demons\t19\nThe Belonging Kind\tBurning Chrome\t15\nThe Big Hunger\tThe View from the Stars\t14\nThe Big Space Fuck\tAgain, Dangerous Visions\t11\nThe Black Cloud\tThe Expert Dreamers\t18\nThe Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd.\tThe Norton Book of Science Fiction\t12\nThe Bookmaking Habits of Select Species\tThe Paper Menagerie and Other Stories\t9\nThe Boscombe Valley Mystery\tThe Original Illustrated Sherlock Holmes\t16\nThe Boulevard of Broken Dreams\tStrange Wine\t6\nThe Brains of Rats\tThe Norton Book of Science Fiction\t14\nThe Byrds\tThe Norton Book of Science Fiction\t12\nThe Captive\tThe Aleph and Other Stories\t2\nThe Cheese Stands Alone\tStalking the Nightmare\t14\nThe Children\tXenogensis\t29\nThe Circle\tInvisible Planets\t22\nThe Circular Ruins\tFicciones\t8\nThe Circular Ruins\tLabyrinths\t6\nThe Cistern\tThe October Country\t10\nThe City of Silence\tInvisible Planets\t44\nThe Crackpots\tPaingod and Other Delusions\t40\nThe Crowd\tThe October Country\t12\nThe Daughter of the Tree\tXenogensis\t12\nThe Day After the Day the Martians Came\tDangerous Visions\t10\nThe Day I Died\tStalking the Nightmare\t10\nThe Dead Man\tThe Aleph and Other Stories\t6\nThe Death of Schillinger\tThis Way for the Gas, Ladies and Gentlemen\t4\nThe Deathbird\tDeathbird Stories\t32\nThe Diagnosis of Dr. Darqueangel\tStrange Wine\t17\nThe Discarded\tPaingod and Other Delusions\t14\nThe Doll-House\tDangerous Visions\t24\nThe Dragon on the Bookshelf\tSlippage\t12\nThe Dreams a Nightmare Dreams\tSlippage\t4\nThe Dwarf\tThe October Country\t15\nThe Earth Men\tThe Martian Chronicles\t15\nThe Emissary\tThe October Country\t10\nThe Encounter\tSomerset Dreams and Other Fictions\t28\nThe End\tFicciones\t4\nThe Evitable Conflict\tI, Robot\t22\nThe Evolution of Human Science\tStories of Your Life and Others\t4\nThe Executioner of the Malformed Children\tShatterday\t16\nThe Extraordinary Voyages of Amelie Bertrand\tNebula Winners Fifteen\t15\nThe Face of Helene Bournouw\tDeathbird Stories\t12\nThe Fearful Sphere of Pascal\tLabyrinths\t4\nThe Few, the Proud\tSlippage\t10\nThe Fish of Lijiang\tInvisible Planets\t18\nThe Five Orange Pips\tThe Original Illustrated Sherlock Holmes\t11\nThe Flower of Shazui\tInvisible Planets\t20\nThe Forces that Crush\tEarthman, Go Home!\t15\nThe Form of the Sword\tFicciones\t6\nThe Function of Dream Sleep\tAngry Candy\t23\nThe Funeral\tAgain, Dangerous Visions\t28\nThe Funeral\tThe Infinity Box\t27\nThe Fusion Bomb\tThe Infinity Box\t39\nThe Garden of Forking Paths\tFicciones\t14\nThe Garden of Forking Paths\tLabyrinths\t11\nThe Gateway Asteroid\tThe Gateway Trip\t9\nThe Gernsback Continuum\tThe Norton Book of Science Fiction\t9\nThe Gernsback Continuum\tBurning Chrome\t13\nThe Girl From Mars\tThe Living Demons\t7\nThe Goddess in the Ice\tStalking the Nightmare\t6\nThe God's Script\tLabyrinths\t8\nThe Golden Helix\tSelected Stories\t56\nThe Golden Man\tStrange Gifts\t33\nThe Green Morning\tThe Martian Chronicles\t5\nThe Handler\tThe Norton Book of Science Fiction\t4\nThe Happy Breed\tDangerous Visions\t22\nThe Heart of the Other Side\tThe Expert Dreamers\t11\nThe Henry Miller Dawn Patrol\tRiverworld and Other Stories\t16\nThe Home Planet\tThe Gateway Trip\t9\nThe Hounds\tSomerset Dreams and Other Fictions\t28\nThe Hour That Stretches\tStalking the Nightmare\t22\nThe House of Asterion\tLabyrinths\t3\nThe House of Asterion\tThe Aleph and Other Stories\t3\nThe House the Blakeneys Built\tThe Norton Book of Science Fiction\t10\nThe Immortal\tLabyrinths\t14\nThe Immortal\tThe Aleph and Other Stories\t17\nThe Indian Spirit Guide\tThe Living Demons\t16\nThe Infinity Box\tThe Infinity Box\t65\nThe Invasion\tThe Expert Dreamers\t18\nThe January Offensive\tThis Way for the Gas, Ladies and Gentlemen\t10\nThe Jar\tThe October Country\t17\nThe Jigsaw Man\tDangerous Visions\t17\nThe Jungle Rot Kid on the Nod\tRiverworld and Other Stories\t12\nThe Lake\tThe October Country\t7\nThe Lake Was Full of Artificial Things\tThe Norton Book of Science Fiction\t11\nThe Last Days of the Captain\tThe Mile-Long Spaceship\t15\nThe Last Generation?\tXenogensis\t12\nThe Leaser of Two Evils\tRiverworld and Other Stories\t16\nThe Library of Babel\tFicciones\t10\nThe Library of Babel\tLabyrinths\t8\nThe Life of Anybody\tThe Norton Book of Science Fiction\t2\nThe Lingering Scent of Woodsmoke\tSlippage\t4\nThe Literomancer\tThe Paper Menagerie and Other Stories\t38\nThe Litigation Master and the Monkey King\tThe Paper Menagerie and Other Stories\t26\nThe Locusts\tThe Martian Chronicles\t1\nThe Long Years\tThe Martian Chronicles\t11\nThe Longest Fall\tThe Wandering Earth\t56\nThe Lottery in Babylon\tLabyrinths\t6\nThe Lucky Strike\tThe Norton Book of Science Fiction\t31\nThe Luggage Store\tThe Martian Chronicles\t1\nThe Maker\tThe Aleph and Other Stories\t3\nThe Malley System\tDangerous Visions\t11\nThe Man on the Threshold\tThe Aleph and Other Stories\t6\nThe Man Upstairs\tThe October Country\t16\nThe Man Who Ended History: A Documentary\tThe Paper Menagerie and Other Stories\t61\nThe Man Who Lost the Sea\tSelected Stories\t12\nThe Man Who Rowed Christopher Columbus Ashore\tSlippage\t18\nThe Man Who Sold the Moon\tThe Man Who Sold the Moon\t106\nThe Man Who Was Heavily into Revenge\tShatterday\t8\nThe Man Who Went to the Moon-Twice\tDangerous Visions\t13\nThe Man With English\tStrange Gifts\t10\nThe Man with the Package\tThis Way for the Gas, Ladies and Gentlemen\t5\nThe Man With the Twisted Lips\tThe Original Illustrated Sherlock Holmes\t15\nThe Man without a Planet\tThe Mile-Long Spaceship\t7\nThe Mark Gable Foundation\tThe Expert Dreamers\t13\nThe Martian\tThe Martian Chronicles\t12\nThe Menace from Earth\tThe Menace from Earth\t13\nThe Merchants of Venus\tThe Gateway Trip\t122\nThe Micro-Age\tThe Wandering Earth\t33\nThe Mile-Long Spaceship\tThe Mile-Long Spaceship\t10\nThe Milk of Paradise\tAgain, Dangerous Visions\t13\nThe Million-Year Picnic\tThe Martian Chronicles\t9\nThe Miracle of the Broom Closet\tThe Expert Dreamers\t7\nThe Mirrors of Enigmas\tLabyrinths\t4\nThe Mountains of Sunset, the Mountains of Dawn\tThe Norton Book of Science Fiction\t13\nThe Mountebank\tThe Aleph and Other Stories\t2\nThe Museum on Cyclops Avenue\tSlippage\t12\nThe Musicians\tThe Martian Chronicles\t1\nThe Naming of Names\tThe Martian Chronicles\t1\nThe New Atlantis\tThe New Atlantis\t30\nThe New Atlantis\tThe Norton Book of Science Fiction\t20\nThe New York Review of Bird\tStrange Wine\t44\nThe Next in Line\tThe October Country\t41\nThe Night That All Time Broke Out\tDangerous Visions\t16\nThe Off Season\tThe Martian Chronicles\t12\nThe Old Ones\tThe Martian Chronicles\t1\nThe Oldest Soldier\tChangewar\t27\nThe Other Death\tThe Aleph and Other Stories\t8\nThe Other Eye of Polyphemus\tShatterday\t14\nThe Outpost Undiscovered by Tourists\tStalking the Nightmare\t8\nThe Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1\tSlippage\t6\nThe Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2\tSlippage\t8\nThe Paper Menagerie\tThe Paper Menagerie and Other Stories\t15\nThe Patterns of Drone\tSturgeon is Alive and Well...\t16\nThe People Who Walked On\tThis Way for the Gas, Ladies and Gentlemen\t16\nThe Perfect Match\tThe Paper Menagerie and Other Stories\t25\nThe Phantom of the Sewers\tRiverworld and Other Stories\t25\nThe Place with No Name\tDeathbird Stories\t16\nThe Plot\tThe Aleph and Other Stories\t1\nThe Plot Is the Thing\tThe Living Demons\t7\nThe Private War of Private Jacob\tThe Norton Book of Science Fiction\t5\nThe Problem of the Sore Bridge-Among Others\tRiverworld and Other Stories\t32\nThe Prowler in the City on the Edge of Forever\tDangerous Visions\t20\nThe Recognition\tDangerous Visions\t14\nThe Red Canary\tThe Infinity Box\t18\nThe Red-Headed League\tThe Original Illustrated Sherlock Holmes\t15\nThe Region Between\tAngry Candy\t86\nThe Regular\tThe Paper Menagerie and Other Stories\t25\nThe Resurgence of Miss Ankle-Strap Wedgie\tLove Ain't Nothing but Sex Misspelled\t91\nThe Roads Must Roll\tThe Man Who Sold the Moon\t45\nThe Season of Babies\tXenogensis\t14\nThe Secret Miracle\tFicciones\t8\nThe Secret Miracle\tLabyrinths\t7\nThe Sect of Phoenix\tFicciones\t4\nThe Sect of Phoenix\tLabyrinths\t4\nThe Settlers\tThe Martian Chronicles\t1\nThe Sex Opposite\tSelected Stories\t28\nThe Shape of the Sword\tLabyrinths\t5\nThe Shore\tThe Martian Chronicles\t1\nThe Silent Towns\tThe Martian Chronicles\t10\nThe Silver Corridor\tEarthman, Go Home!\t20\nThe Simple Way\tCity\t25\nThe Singers\tThe Expert Dreamers\t4\nThe Skills of Xanadu\tSelected Stories\t28\nThe Sky is Burning\tEarthman, Go Home!\t9\nThe Small Assaassin\tThe October Country\t21\nThe Smiling Future\tXenogensis\t13\nThe South\tFicciones\t7\nThe Starseekers\tThe Gateway Trip\t19\nThe Start of the End of It All\tThe Norton Book of Science Fiction\t11\nThe Summer Night\tThe Martian Chronicles\t2\nThe Superior Sex\tXenogensis\t11\nThe Supper\tThis Way for the Gas, Ladies and Gentlemen\t5\nThe Sycthe\tThe October Country\t8\nThe Taxpayer\tThe Martian Chronicles\t1\nThe Test Stand\tThe Expert Dreamers\t14\nThe Test-Tube Creature, Afterward\tAgain, Dangerous Visions\t5\nThe Theologians\tLabyrinths\t8\nThe Theologians\tThe Aleph and Other Stories\t9\nThe Third Expedition\tThe Martian Chronicles\t16\nThe Time Piece\tThe Infinity Box\t22\nThe Transit of Venus\tXenogensis\t11\nThe Two Kings and the Two Labyrinths\tThe Aleph and Other Stories\t2\nThe Universe of Robert Blake\tLove Ain't Nothing but Sex Misspelled\t5\nThe Unspeakable Betrothal\tThe Living Demons\t14\nThe Very Last Day of a Good Woman\tEarthman, Go Home!\t9\nThe Village\tThe Infinity Box\t10\nThe Visit\tThe Gateway Trip\t9\nThe Voice of the Sonar in My Veriform Appendix\tRiverworld and Other Stories\t14\nThe Volcano\tRiverworld and Other Stories\t20\nThe Wages of Humanity\tThe Wandering Earth\t44\nThe Waiting\tLabyrinths\t4\nThe Wall and the Books\tLabyrinths\t3\nThe Wandering Earth\tThe Wandering Earth\t46\nThe War at Home\tThe Norton Book of Science Fiction\t3\nThe Warlord of Saturn's Moon\tThe Norton Book of Science Fiction\t8\nThe Watchers\tThe Martian Chronicles\t1\nThe Watchful Poker Chip of H. Matisse\tThe October Country\t12\nThe Waves\tThe Paper Menagerie and Other Stories\t26\nThe Whimper of Whipped Dogs\tDeathbird Stories\t22\nThe Will\tThe View from the Stars\t14\nThe Wind\tThe October Country\t12\nThe Wind Beyond the Mountains\tEarthman, Go Home!\t10\nThe Wine Has Been Left Open Too Long and the Memory Has Gone Flat\tStrange Wine\t16\nThe Winter Flies\tThe Norton Book of Science Fiction\t12\nThe Winter Market\tBurning Chrome\t25\nThe Witness\tLabyrinths\t1\nThe Witness\tThe Aleph and Other Stories\t1\nThe Women Men Don't See\tThe Norton Book of Science Fiction\t25\nThe Wonderful Death of Dudley Stone\tThe October Country\t13\nThe Word for World is Forrest\tAgain, Dangerous Visions\t96\nThe World of Stone\tThis Way for the Gas, Ladies and Gentlemen\t3\nThe Writing of the God\tThe Aleph and Other Stories\t6\nThe Year of the Jackpot\tThe Menace from Earth\t32\nThe Year of the Rat\tInvisible Planets\t30\nThe Yellow Rose\tThe Aleph and Other Stories\t1\nThe Zahir\tLabyrinths\t5\nThe Zahir\tThe Aleph and Other Stories\t10\nTheme of the Traitor and Hero\tFicciones\t6\nTheme of the Traitor and Hero\tLabyrinths\t4\nThere Was an Old Woman\tThe October Country\t16\nThere Will Come Soft Rains\tThe Martian Chronicles\t6\nThings Lost\tAgain, Dangerous Visions\t30\nThis Way for the Gas, Ladies and Gentlemen\tThis Way for the Gas, Ladies and Gentlemen\t21\nThree Versions of Judas\tFicciones\t8\nThree Versions of Judas\tLabyrinths\t6\nThrowback\tXenogensis\t13\nThunder and Roses\tSelected Stories\t24\nTime Travel for Pedestrians\tAgain, Dangerous Visions\t31\nTiny Ally\tStalking the Nightmare\t6\nTissue\tAgain, Dangerous Visions\t16\nTlon, Uqbar, Orbis Teritus\tFicciones\t20\nTlon, Uqbar, Orbis Teritus\tLabyrinths\t16\nTo Be Continued\tStrange Gifts\t14\nTo Explain to Mrs. Thompson\tThe Expert Dreamers\t23\nTo Here and the Easel\tSturgeon is Alive and Well...\t56\nToenails\tThe Aleph and Other Stories\t1\nTongtong's Summer\tInvisible Planets\t20\nTotenbuch\tAgain, Dangerous Visions\t10\nTouched With Fire\tThe October Country\t15\nTower of Babylon\tStories of Your Life and Others\t28\nTracking Level\tStalking the Nightmare\t12\nTranscending Destiny\tStalking the Nightmare\t26\nTrouble With Ants\tCity\t38\nTry and Change the Past\tChangewar\t11\nTwink\tCaviar\t19\nUnaccompanied Sonata\tNebula Winners Fifteen\t20\nUncle Einar\tThe October Country\t10\nUncle Fremmis\tSturgeon is Alive and Well...\t18\nUnderground\tThe Living Demons\t6\nUnderstand\tStories of Your Life and Others\t42\nUnlocking the Air\tThe Unreal and the Real\t26\nUsher II\tThe Martian Chronicles\t15\nValerie\tLove Ain't Nothing but Sex Misspelled\t16\nValery as Symbol\tLabyrinths\t2\nVaster than Empires and More Slow\tExplorers of Space\t57\nVisionary\tStalking the Nightmare\t14\nWanted in Surgery\tPaingod and Other Delusions\t30\nWater Is for Washing\tThe Menace from Earth\t10\nWay in the Middle of the Air\tThe Martian Chronicles\t3\nWe See Things Differently\tThe Norton Book of Science Fiction\t18\nWhat Happened to Auguste Clarot?\tDangerous Visions\t8\nWhat I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27\tLove Ain't Nothing but Sex Misspelled\t19\nWhat's It Like Out There?\tExplorers of Space\t27\nWhen Auld's Acquaintance is Forgot\tAngry Candy\t10\nWhen I was a Hired Gun\tLove Ain't Nothing but Sex Misspelled\t12\nWhen I Was Miss Dow\tThe Norton Book of Science Fiction\t10\nWhen it Changed\tAgain, Dangerous Visions\t16\nWhen the Bentfin Boomer Boys on Old New Alabama\tAgain, Dangerous Visions\t107\nWhen the Change-Winds Blow\tChangewar\t15\nWhere Have You Been, Billy Boy, Billy Boy?\tThe Infinity Box\t13\nWhere I Shall Dwell in the Next World\tSlippage\t12\nWith a Finger in My I\tAgain, Dangerous Visions\t15\nWith Her Eyes\tThe Wandering Earth\t19\nWith Virgin Oddum at the East Pole\tAngry Candy\t20\nWorking with the Little People\tStrange Wine\t18\nWould You Do It for a Penny\tShatterday\t22\nYlla\tThe Martian Chronicles\t12\nYou Triflin' Skunk\tThe View from the Stars\t11\nZero Gee\tAgain, Dangerous Visions\t31\nAnd the Moon be Still as Bright\tThe Martian Chronicles\t24"
  },
  {
    "path": "tests/data/stories.tsv",
    "content": "!!!The!!Teddy!Crazy!!Show!!!\tscience fiction\t1968\n(Learning About) Machine Sex\tscience fiction\t1988\n...the World, as we Know 't\tscience fiction\t1982\n2004, or Thereabouts\tscience fiction\t1964\nA Biography of Tadeo Isidoro Cruz (1829-1874)\tfiction\t1944\nA Brief History of the Trans-Pacific Tunnel\tscience fiction\t2013\nA Case of Identity\tmystery\t1891\nA Day at Harmenz\teast euro lit\t1959\nA Deskful of Girls\tscience fiction\t1958\nA Dialog About A Dialog\tfiction\t1936\nA Dialog Between Dead Men\tfiction\t1957\nA Feast of Demons\tscience fiction\t1958\nA Few Things I Know About While Away\tscience fiction\t1975\nA Hundred Ghosts Parade Tonight\tscience fiction\t2010\nA is for Automation\tscience fiction\t1959\nA Midwinter's Tale\tscience fiction\t1988\nA Momentary Taste of Being\tscience fiction\t1975\nA Mouse in the Walls of the Global Village\tscience fiction\t1972\nA New Refutation of Time\tessay\t1947\nA Note on (toward) Bernard Shaw\tessay\t1962\nA Path Through the Darkness\tscience fiction\t1963\nA Prayer for No One's Enemies\tscience fiction\t1966\nA Problem\tfiction\t1957\nA Scandal in Bohemia\tmystery\t1891\nA Toy for Juliette\tscience fiction\t1967\nA True Story\teast euro lit\t1959\nA Visit\teast euro lit\t1959\nA Way of Thinking\tscience fiction\t1953\nAdrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W\tscience fiction\t1974\nAdrift on the Policy Level\tscience fiction\t1959\nAesop\tscience fiction\t1947\nAfter the Days of Dead-Eye 'Dee\tscience fiction\t1985\nAll in Good Time\tscience fiction\t1960\nAll the Birds Come Home to Roost\tscience fiction\t1978\nAll the Flavors\tscience fiction\t2012\nAll the Lies Lies That Are My Life\tscience fiction\t1980\nAll The People\tscience fiction\t1961\nAll the Sound of Fear\tscience fiction\t1962\nAlong the Scenic Route\tscience fiction\t1969\nAlpha Ralpha Boulevard\tscience fiction\t1961\nAmateur in Chancery\tscience fiction\t1961\nAmerica\tscience fiction\t1987\nAn Advanced Readers' Picture Book of Comparative Cognition\tscience fiction\t2016\nAn Examination of the Work of Herbert Quain\tfiction\t1941\nAnd the Angels Sing\tscience fiction\t1990\nAnd the Sea Like Mirrors\tscience fiction\t1972\nAndover and the Android\tscience fiction\t1963\nAnybody Else Like Me?\tscience fiction\t1952\nAnywhere But Here, With Anybody But You\tscience fiction\t1996\nApril Fools' Day Forever\tscience fiction\t1970\nArgumentum Ornithologicum\tfiction\t1952\nAs Simple As That\tscience fiction\t1971\nAt the End of the Orbit\tscience fiction\t1961\nAt the Mouse Circus\tscience fiction\t1971\nAunt Parnetta's Electric Blisters\tscience fiction\t1990\nAuschwitz, Our Home (A Letter)\teast euro lit\t1959\nAuto-De-Fe\tscience fiction\t1967\nAvatars of the Tortoise\tessay\t1939\nAverroes' Search\tfiction\t1947\nAye, and Gomorrah...\tscience fiction\t1967\nBalanced Ecology\tscience fiction\t1965\nBasilisk\tscience fiction\t1972\nBattle Without Banners\tscience fiction\t1964\nBattlefield\tscience fiction\t1958\nBeachhead\tscience fiction\t1951\nBeauty's Beast\tscience fiction\t1941\nBed Sheets are White\tscience fiction\t1972\nBettyann\tscience fiction\t1951\nBianca's Hands\tscience fiction\t1947\nBig Joe and the Nth Generation\tscience fiction\t1952\nBlabbermouth\tscience fiction\t1945\nBlack Bargain\tscience fiction\t1942\nBlank?\tscience fiction\t1957\nBleeding Stones\tscience fiction\t1973\nBlind Bird, Blind Bird, Go Away From Me!\tscience fiction\t1963\nBlood Bank\tscience fiction\t1952\nBlot\tscience fiction\t1972\nBlowups Happen\tscience fiction\t1940\nBorges and I\tfiction\t1957\nBounty\tscience fiction\t1972\nBrass and Gold (or Horse and Zeppelin in Beverly Hills)\tscience fiction\t1971\nBright Eyes\tscience fiction\t1965\nBright Segment\tscience fiction\t1955\nBroken Glass\tscience fiction\t1981\nBrownshoes\tscience fiction\t1969\nBurning Chrome\tscience fiction\t1982\nBy His Bootstraps\tscience fiction\t1941\nCall Girl\tscience fiction\t2014\nCamps\tscience fiction\t1979\nCarcinoma Angels\tscience fiction\t1967\nCatch That Rabbit\tscience fiction\t1944\nCatman\tscience fiction\t1974\nCensus\tscience fiction\t1944\nChain Reaction\tscience fiction\t1956\nChained to the Fast Lane in the Red Queen's Race\tscience fiction\t1983\nChatting with Anubis\tscience fiction\t1995\nChing Witch!\tscience fiction\t1972\nChrist, Old Student in a New School\tscience fiction\t1972\nChuck Berry, Won't You Please Come Home\tscience fiction\t1972\nCity\tscience fiction\t1944\nCold Friend\tscience fiction\t1973\nCollecting Team\tscience fiction\t1956\nColumbus Was a Dope\tscience fiction\t1947\nCome to the Party\tscience fiction\t1978\nComes Now the Power\tscience fiction\t1966\nCommuter's Problem\tscience fiction\t1957\nCorpse\tscience fiction\t1972\nCount the Clock That Tells the Time\tscience fiction\t1978\nCovered Mirrors\tfiction\t1936\nCrate\tscience fiction\t1970\nCrazy as a Soup Sandwich\tscience fiction\t1989\nCroatoan\tscience fiction\t1975\nCrucifixus Etiam\tscience fiction\t1953\nCurse 5.0\tscience fiction\t2013\nDamnation Morning\tscience fiction\t1959\nDanger-Human!\tscience fiction\t1957\nDaniel White for the Greater Good\tscience fiction\t1961\nDarkness Upon the Face of the Deep\tscience fiction\t1991\nDay Million\tscience fiction\t1966\nDeal From the Bottom\tscience fiction\t1960\nDeath and the Compass\tfiction\t1942\nDeeper than the Darkness\tscience fiction\t1957\nDelia Elena San Marco\tfiction\t1957\nDelusion for a Dragon Slayer\tscience fiction\t1966\nDeutsches Requiem\tfiction\t1946\nDevourer\tscience fiction\t2013\nDistant Signals\tscience fiction\t1984\nDivision by Zero\tscience fiction\t1991\nDjango\tscience fiction\t1978\nDjinn, No Chaser\tscience fiction\t1982\nDogfight\tscience fiction\t1985\nDo-It-Yourself\tscience fiction\t1961\nDreamtigers\tfiction\t1936\nDumb Waiter\tscience fiction\t1952\nEach an Explorer\tscience fiction\t1956\nEcowarewness\tscience fiction\t1974\nEidolons\tscience fiction\t1986\nElbow Room\tscience fiction\t1980\nElegy\tpoem\t1962\nElouise and the Doctors of the Planet Pergamon\tscience fiction\t1972\nEmissary from Hamelin\tscience fiction\t1977\nEmma Zunz\tfiction\t1948\nEmpire of the Sun\tscience fiction\t1972\nEncounter With A Hick\tscience fiction\t1967\nEnemy Mine\tscience fiction\t1979\nEpilogue\tscience fiction\t1952\nEpiphany for Aliens\tscience fiction\t1972\nErnest and the Machine God\tscience fiction\t1968\nErotophobia\tscience fiction\t1971\nErsatz\tscience fiction\t1967\nEscape!\tscience fiction\t1945\nEscapegoat\tscience fiction\t1983\nEutopia\tscience fiction\t1967\nEvensong\tscience fiction\t1967\nEverything and Nothing\tfiction\t1958\nEvidence\tscience fiction\t1946\nExploration Team\tscience fiction\t1956\nExposures\tscience fiction\t1981\nEye of the Beholder\tscience fiction\t1972\nFaith of our Fathers\tscience fiction\t1967\nFear is a Cold Black\tscience fiction\t1963\nFeather Tigers\tscience fiction\t1973\nFeatherbed on Chlyntha\tscience fiction\t1957\nFinal Trophy\tscience fiction\t1957\nFlies\tscience fiction\t1967\nFlop Sweat\tscience fiction\t1977\nFolding Beijing\tscience fiction\t2014\nFootsteps\tscience fiction\t1980\nFor the Sake of Grace\tscience fiction\t1969\nFor Value Received\tscience fiction\t1972\nFragments of a Hologram Rose\tscience fiction\t1977\nFrom A to Z, In The Chocolate Alphabet\tscience fiction\t1979\nFrom the Government Printing Office\tscience fiction\t1967\nFrozen Journey\tscience fiction\t1980\nFunes the Memorious\tfiction\t1942\nG. B. K.-A Many-Flavored Bird\tscience fiction\t1962\nGather Blue Roses\tscience fiction\t1972\nGathi\tscience fiction\t1958\nGetting Along\tscience fiction\t1972\nGhost of a Chance\tscience fiction\t1943\ngiANTS\tscience fiction\t1979\nGift from the Stars\tscience fiction\t1958\nGnomebody\tscience fiction\t1956\nGo Toward the Light\tscience fiction\t1996\nGo, Go, Go, Said the Bird\tscience fiction\t1967\nGoldfish Bowl\tscience fiction\t1942\nGonna Roll the Bones\tscience fiction\t1967\nGood Hunting\tscience fiction\t2012\nGood News from the Vatican\tscience fiction\t1971\nGopher in the Gilly\tscience fiction\t1982\nGrail\tscience fiction\t1981\nGrave of the Fireflies\tscience fiction\t2005\nGutter Gang\tthriller\t1957\nHadj\tscience fiction\t1956\nHalf-Life\tscience fiction\t1989\nHarry the Hare\tscience fiction\t1972\nHeavyplanet\tscience fiction\t1958\nHeechee Treasures\tscience fiction\t1990\nHell Is the Absence of God\tscience fiction\t2001\nHigh Weir\tscience fiction\t1968\nHindsight: 480 Seconds\tscience fiction\t1973\nHinterlands\tscience fiction\t1981\nHis Vegetable\tscience fiction\t1986\nHitler Painted Roses\tscience fiction\t1977\nHobbies\tscience fiction\t1946\nHomecoming\tscience fiction\t1946\nHomelanding\tscience fiction\t1990\nHow Beautiful with Banners\tscience fiction\t1966\nHow's the Night Life on Cassalda?\tscience fiction\t1977\nHuddling Place\tscience fiction\t1944\nHumpty Dumpty had a Great Fall\tscience fiction\t1948\nI Curse the Lesson and Bless the Knowledge\tscience fiction\t1976\nI, Dreamer\tscience fiction\t1953\nIbn-Hakam al-Bokhari, Murdered in His Labyrinth\tfiction\t1951\nIf All Men Were Brothers, Would You Let One Marry Your Sister?\tscience fiction\t1967\nI'm Looking for Kadak\tscience fiction\t1974\nIn Fear of K\tscience fiction\t1975\nIn Lonely Islands\tscience fiction\t1956\nIn Memoriam, J. F. K.\tfiction\t1967\nIn re Glover\tscience fiction\t1972\nIn the Barn\tscience fiction\t1972\nIn the Core\tscience fiction\t1990\nIn the Fourth Year of the War\tscience fiction\t1979\nIncident in Moderan\tscience fiction\t1967\nInferno, I, 32\tfiction\t1955\nInterim\tscience fiction\t1950\nInterlocking Pieces\tscience fiction\t1984\nInvaders\tscience fiction\t1990\nInvasion Footnote\tscience fiction\t1957\nInvisible Planets\tscience fiction\t2010\nIt\tscience fiction\t1940\nIt was Nothing-Really\tscience fiction\t1969\nIt's You!\tscience fiction\t1969\nJ. C. on the Dude Ranch\tscience fiction\t1979\nJack-in-the-Box\tscience fiction\t1947\nJane Doe #112\tscience fiction\t1990\nJeffty is Five\tscience fiction\t1977\nJenny with Wings\tscience fiction\t1963\nJohnny Mnemonic\tscience fiction\t1981\nJorry's Gap\tscience fiction\t1969\nJudas\tscience fiction\t1967\nJupiter Five\tscience fiction\t1953\nKafka and His Precursors\tessay\t1951\nKeyboard\tscience fiction\t1995\nKilldozer!\tscience fiction\t1944\nKilling Bernstein\tscience fiction\t1976\nKing of the Hill\tscience fiction\t1972\nKirinyaga\tscience fiction\t1988\nKiss of Fire\tscience fiction\t1972\nKnights to Move\tscience fiction\t1965\nKnox\tscience fiction\t1974\nKyrie\tscience fiction\t1968\nLadies and Gentlemen, This Is Your Crisis\tscience fiction\t1976\nLamia Mutable\tscience fiction\t1972\nLand of the Great Horses\tscience fiction\t1967\nLast Train to Kankakee\tscience fiction\t1972\nLaugh Track\tscience fiction\t1984\nLenny\tscience fiction\t1957\nLet There Be Light\tscience fiction\t1940\nLiar!\tscience fiction\t1941\nLife in Our Time\tscience fiction\t1966\nLife-Line\tscience fiction\t1939\nLiking What You See: A Documentary\tscience fiction\t2002\nLittle Lost Robot\tscience fiction\t1947\nLollipop and the Tar Baby\tscience fiction\t1977\nLonley Women Are the Vessels of Time\tscience fiction\t1976\nLooking for Company\tscience fiction\t1990\nLord Randy, My Son\tscience fiction\t1967\nLucy Comes To Stay\tscience fiction\t1952\nMaking It All the Way into the Future on Gaxton Falls of the Red Planet\tscience fiction\t1974\nMan of Letters\tscience fiction\t1975\nMartin Fierro\tfiction\t1957\nMathoms from the Time Closet\tscience fiction\t1972\nMealtime\tscience fiction\t1958\nMedusa\tscience fiction\t1942\nMefisto in Onyx\tscience fiction\t1993\nMicrocosmic God\tscience fiction\t1941\nMidnight in the Sunken Cathedral\tscience fiction\t1995\nMidnight News\tscience fiction\t1990\nMom\tscience fiction\t1976\nMona at Her Windows\tscience fiction\t1962\nMonitored Dreams & Strategic Cremations\tscience fiction\t1972\nMono no Aware\tscience fiction\t2012\nMonolog\tscience fiction\t1973\nMoth Race\tscience fiction\t1972\nMountain\tscience fiction\t2013\nMr. Costello, Hero\tscience fiction\t1953\nMrs. Bagley Goes to Mars\tscience fiction\t1975\nMutations\tfiction\t1960\nNackles vr.1\tscience fiction\t1963\nNackles vr.2\tscience fiction\t1987\nNeither Your Jenny Nor Mine\tscience fiction\t1964\nNeon\tscience fiction\t1973\nNew Rose Hotel\tscience fiction\t1984\nNight Journey of the Dragon-Horse\tscience fiction\t2016\nNight Meeting\tscience fiction\t1950\nNight of Black Glass\tscience fiction\t1981\nNight-Rise\tscience fiction\t1978\nNine Hundred Grandmothers\tscience fiction\t1966\nNo Game for Children\tthriller\t1959\nNo Great Magic\tscience fiction\t1960\nNo Light in the Windows\tscience fiction\t1963\nNothing for My Noon Meal\tscience fiction\t1958\nO Ye of Little Faith\tscience fiction\t1968\nOddy and Id\tscience fiction\t1950\nOf Ants and Dinosaurs\tscience fiction\t2013\nOn Exactitude and Science\tfiction\t1946\nOn the Downhill Slide\tscience fiction\t1972\nOn the Feasibility of Coal-Driven Power Stations\tscience fiction\t1956\nOn the Slab\tscience fiction\t1981\nOne for the Road\tscience fiction\t1959\nOne Life, Furnished in Early Poverty\tscience fiction\t1970\nOne-Way Journey\tscience fiction\t1955\nOperation Cassandra\tscience fiction\t1958\nOpium\tscience fiction\t1977\nOther Worlds\tscience fiction\t1990\nOut of All Them Bright Stars\tscience fiction\t1986\nOver the River and Through the Woods\tscience fiction\t1965\nOzymandias\tscience fiction\t1972\nPaingod\tscience fiction\t1964\nPaladin of the Last Hour\tscience fiction\t1985\nParable of Cervantes and the Quixote\tpoem\t1955\nParable of the Palace\tfiction\t1956\nParadise\tscience fiction\t1946\nParadiso, XXXI, 108\tfiction\t1954\nPartial Magic in the Quixote\tessay\t1949\nPaulie Charmed the Sleeping Woman\tscience fiction\t1962\nPhiltre Tip\tscience fiction\t1961\nPierre Menrad, Author of Don Quixote\tfiction\t1939\nPlanet Story\tscience fiction\t1975\nPrecession\tscience fiction\t1980\nPretty Maggie Moneyeyes\tscience fiction\t1967\nPrince Myshkin, and Hold the Relish\tscience fiction\t1982\nProdigy\tscience fiction\t1949\nProject Nightmare\tscience fiction\t1953\nPulling Hard Time\tscience fiction\t1995\nPunky & The Yale Men\tscience fiction\t1966\nQuick to Haste\tscience fiction\t1969\nQuicktime\tscience fiction\t1985\nRagnarok\tfiction\t1959\nRain, Rain, Go Away\tscience fiction\t1956\nRat\tscience fiction\t1986\nReason\tscience fiction\t1941\nRed Star, Winter Orbit\tscience fiction\t1983\nRepent, Harlequin! Said the Ticktockman\tscience fiction\t1965\nRequiem\tscience fiction\t1940\nRiders of the Purple Wage\tscience fiction\t1967\nRiding the Dark Train Out\tscience fiction\t1961\nRiverworld\tscience fiction\t1966\nRobbie\tscience fiction\t1940\nRock God\tscience fiction\t1969\nRocket Summer\tscience fiction\t1950\nRunaround\tscience fiction\t1942\nSandkings\tscience fiction\t1979\nSaturn, November 11th\tscience fiction\t1981\nScartaris, June 28th\tscience fiction\t1990\nSchrodinger's Plague\tscience fiction\t1982\nSchwarzschild Radius\tscience fiction\t1987\nSeeing\tscience fiction\t1976\nSensible City\tscience fiction\t1994\nSeventy-Two Letters\tscience fiction\t2000\nSex and/or Mr. Morrison\tscience fiction\t1967\nShadow, Shadow on the Wall\tscience fiction\t1951\nShall the Dust Praise Thee?\tscience fiction\t1967\nShatterday\tscience fiction\t1975\nShattered Like a Glass Goblin\tscience fiction\t1968\nShe's a Young Thing and Cannot Leaver Her Mother\tscience fiction\t1988\nShoppe Keeper\tscience fiction\t1977\nSilence\teast euro lit\t1959\nSilent in Gehenna\tscience fiction\t1971\nSilhouette\tscience fiction\t1975\nSimulacrum\tscience fiction\t2011\nSkeleton\tscience fiction\t1977\nSky Lift\tscience fiction\t1953\nSlow Sculpture\tscience fiction\t1970\nSnow\tscience fiction\t1985\nSoft Monkey\tscience fiction\t1987\nSomehow, I Don't Think We're in Kansas, Toto\tscience fiction\t1974\nSomerset Dreams\tscience fiction\t1969\nSoundless Evening\tscience fiction\t1972\nSpeech Sound\tscience fiction\t1983\nStable Strategies for Middle Management\tscience fiction\t1988\nStand Still and Die\tthriller\t1956\nState Change\tscience fiction\t2004\nState of Grace\tscience fiction\t1977\nStill-Life\tscience fiction\t1972\nStoned Counsel\tscience fiction\t1972\nStory of the Warrior and the Captive Maiden\tfiction\t1949\nStory of Your Life\tscience fiction\t1998\nStrange Wine\tscience fiction\t1976\nStuffing\tscience fiction\t1982\nSuicide\tscience fiction\t1970\nSun of China\tscience fiction\t2013\nSymbiosis\tscience fiction\t1972\nTake Care of Joey\tscience fiction\t1970\nTaking Care of God\tscience fiction\t2005\nTandy's Story\tscience fiction\t1961\nTauf Aleph\tscience fiction\t1981\nTell Your Fortune\tscience fiction\t1967\nTest to Destruction\tscience fiction\t1967\nThat Girl Who Knew What They Meant\tscience fiction\t1970\nThe [Widget], the [Wadget], and Boff\tscience fiction\t1955\nThe 10:00 Report is Brought to You By...\tscience fiction\t1972\nThe 3 Most Important Things in Life\tscience fiction\t1978\nThe Absolutely Perfect Murder\tscience fiction\t1965\nThe Adventure of Black Peter\tmystery\t1904\nThe Adventure of Charles Augustus Milverton\tmystery\t1904\nThe Adventure of the Gloria Scott\tmystery\t1893\nThe Adventure of the Abbey Grange\tmystery\t1904\nThe Adventure of the Beryl Coronet\tmystery\t1892\nThe Adventure of the Blue Carbuncle\tmystery\t1892\nThe Adventure of the Cardboard Box\tmystery\t1893\nThe Adventure of the Copper Beeches\tmystery\t1892\nThe Adventure of the Crooked Man\tmystery\t1893\nThe Adventure of the Dancing Men\tmystery\t1903\nThe Adventure of the Empty House\tmystery\t1903\nThe Adventure of the Engineer's Thumb\tmystery\t1892\nThe Adventure of the Final Problem\tmystery\t1893\nThe Adventure of the Golden Pince-Nez\tmystery\t1904\nThe Adventure of the Greek Interpreter\tmystery\t1893\nThe Adventure of the Missing Three-Quarter\tmystery\t1904\nThe Adventure of the Musgrave Ritual\tmystery\t1893\nThe Adventure of the Naval Treaty\tmystery\t1893\nThe Adventure of the Noble Bachelor\tmystery\t1892\nThe Adventure of the Norwood Builder\tmystery\t1903\nThe Adventure of the Priory School\tmystery\t1904\nThe Adventure of the Reigate Squires\tmystery\t1893\nThe Adventure of the Resident Patient\tmystery\t1893\nThe Adventure of the Second Stain\tmystery\t1904\nThe Adventure of the Silver Blaze\tmystery\t1892\nThe Adventure of the Six Napoleons\tmystery\t1904\nThe Adventure of the Solitary Cyclist\tmystery\t1903\nThe Adventure of the Speckled Band\tmystery\t1892\nThe Adventure of the Stockbroker's Clerk\tmystery\t1893\nThe Adventure of the Yellow Face\tmystery\t1893\nThe Age of Gold\tscience fiction\t1990\nThe Ajeri Diary\tscience fiction\t1968\nThe Aleph\tfiction\t1949\nThe Approach to Al-Mu'tasim\tfiction\t1936\nThe Argentine Writer and Tradition\tessay\t1951\nThe Avenger of Death\tscience fiction\t1988\nThe Babylon Lottery\tfiction\t1941\nThe Beast of Barsac\tscience fiction\t1944\nThe Belonging Kind\tscience fiction\t1981\nThe Big Hunger\tscience fiction\t1952\nThe Big Space Fuck\tscience fiction\t1972\nThe Black Cloud\tscience fiction\t1957\nThe Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd.\tscience fiction\t1985\nThe Bookmaking Habits of Select Species\tscience fiction\t2012\nThe Boscombe Valley Mystery\tmystery\t1891\nThe Boulevard of Broken Dreams\tscience fiction\t1975\nThe Brains of Rats\tscience fiction\t1986\nThe Byrds\tscience fiction\t1982\nThe Captive\tfiction\t1957\nThe Cheese Stands Alone\tscience fiction\t1981\nThe Children\tscience fiction\t1952\nThe Circle\tscience fiction\t2014\nThe Circular Ruins\tfiction\t1940\nThe Cistern\tscience fiction\t1947\nThe City of Silence\tscience fiction\t2005\nThe Crackpots\tscience fiction\t1956\nThe Crowd\tscience fiction\t1943\nThe Daughter of the Tree\tscience fiction\t1951\nThe Day After the Day the Martians Came\tscience fiction\t1967\nThe Day I Died\tscience fiction\t1973\nThe Dead Man\tfiction\t1946\nThe Death of Schillinger\teast euro lit\t1959\nThe Deathbird\tscience fiction\t1973\nThe Diagnosis of Dr. Darqueangel\tscience fiction\t1977\nThe Discarded\tscience fiction\t1959\nThe Doll-House\tscience fiction\t1967\nThe Dragon on the Bookshelf\tscience fiction\t1995\nThe Dreams a Nightmare Dreams\tscience fiction\t1997\nThe Dwarf\tscience fiction\t1954\nThe Earth Men\tscience fiction\t1948\nThe Emissary\tscience fiction\t1947\nThe Encounter\tscience fiction\t1970\nThe End\tfiction\t1953\nThe Evitable Conflict\tscience fiction\t1950\nThe Evolution of Human Science\tscience fiction\t2000\nThe Executioner of the Malformed Children\tscience fiction\t1978\nThe Extraordinary Voyages of Amelie Bertrand\tscience fiction\t1979\nThe Face of Helene Bournouw\tscience fiction\t1960\nThe Fearful Sphere of Pascal\tessay\t1947\nThe Few, the Proud\tscience fiction\t1987\nThe Fish of Lijiang\tscience fiction\t2006\nThe Five Orange Pips\tmystery\t1891\nThe Flower of Shazui\tscience fiction\t2012\nThe Forces that Crush\tscience fiction\t1958\nThe Form of the Sword\tfiction\t1942\nThe Funeral\tscience fiction\t1972\nThe Fusion Bomb\tscience fiction\t1972\nThe Garden of Forking Paths\tfiction\t1941\nThe Gateway Asteroid\tscience fiction\t1990\nThe Gernsback Continuum\tscience fiction\t1981\nThe Girl From Mars\tscience fiction\t1950\nThe Goddess in the Ice\tscience fiction\t1967\nThe God's Script\tfiction\t1949\nThe Golden Helix\tscience fiction\t1979\nThe Golden Man\tscience fiction\t1954\nThe Green Morning\tscience fiction\t1950\nThe Handler\tscience fiction\t1960\nThe Happy Breed\tscience fiction\t1967\nThe Heart of the Other Side\tscience fiction\t1962\nThe Henry Miller Dawn Patrol\tscience fiction\t1977\nThe Home Planet\tscience fiction\t1990\nThe Hounds\tscience fiction\t1974\nThe Hour That Stretches\tscience fiction\t1982\nThe House of Asterion\tfiction\t1947\nThe House the Blakeneys Built\tscience fiction\t1965\nThe Immortal\tfiction\t1947\nThe Indian Spirit Guide\tscience fiction\t1948\nThe Infinity Box\tscience fiction\t1971\nThe Invasion\tscience fiction\t1940\nThe January Offensive\teast euro lit\t1959\nThe Jar\tscience fiction\t1944\nThe Jigsaw Man\tscience fiction\t1967\nThe Jungle Rot Kid on the Nod\tscience fiction\t1968\nThe Lake\tscience fiction\t1944\nThe Lake Was Full of Artificial Things\tscience fiction\t1985\nThe Last Days of the Captain\tscience fiction\t1962\nThe Last Generation?\tscience fiction\t1946\nThe Leaser of Two Evils\tscience fiction\t1979\nThe Library of Babel\tfiction\t1941\nThe Life of Anybody\tscience fiction\t1984\nThe Lingering Scent of Woodsmoke\tscience fiction\t1996\nThe Literomancer\tscience fiction\t2010\nThe Litigation Master and the Monkey King\tscience fiction\t2013\nThe Locusts\tscience fiction\t1950\nThe Long Years\tscience fiction\t1948\nThe Longest Fall\tscience fiction\t2013\nThe Lottery in Babylon\tfiction\t1941\nThe Lucky Strike\tscience fiction\t1984\nThe Luggage Store\tscience fiction\t1950\nThe Maker\tfiction\t1958\nThe Malley System\tscience fiction\t1967\nThe Man on the Threshold\tfiction\t1952\nThe Man Upstairs\tscience fiction\t1947\nThe Man Who Ended History: A Documentary\tscience fiction\t2011\nThe Man Who Lost the Sea\tscience fiction\t1959\nThe Man Who Rowed Christopher Columbus Ashore\tscience fiction\t1991\nThe Man Who Sold the Moon\tscience fiction\t1950\nThe Man Who Was Heavily into Revenge\tscience fiction\t1978\nThe Man Who Went to the Moon-Twice\tscience fiction\t1967\nThe Man With English\tscience fiction\t1953\nThe Man with the Package\teast euro lit\t1959\nThe Man With the Twisted Lips\tmystery\t1891\nThe Man without a Planet\tscience fiction\t1962\nThe Mark Gable Foundation\tscience fiction\t1961\nThe Martian\tscience fiction\t1949\nThe Menace from Earth\tscience fiction\t1957\nThe Merchants of Venus\tscience fiction\t1972\nThe Micro-Age\tscience fiction\t2013\nThe Mile-Long Spaceship\tscience fiction\t1956\nThe Milk of Paradise\tscience fiction\t1972\nThe Million-Year Picnic\tscience fiction\t1946\nThe Miracle of the Broom Closet\tscience fiction\t1952\nThe Mirrors of Enigmas\tessay\t1940\nThe Mountains of Sunset, the Mountains of Dawn\tscience fiction\t1974\nThe Mountebank\tfiction\t1957\nThe Museum on Cyclops Avenue\tscience fiction\t1995\nThe Musicians\tscience fiction\t1950\nThe Naming of Names\tscience fiction\t1950\nThe New Atlantis\tscience fiction\t1975\nThe New York Review of Bird\tscience fiction\t1975\nThe Next in Line\tscience fiction\t1947\nThe Night That All Time Broke Out\tscience fiction\t1967\nThe Off Season\tscience fiction\t1948\nThe Old Ones\tscience fiction\t1950\nThe Oldest Soldier\tscience fiction\t1960\nThe Other Death\tfiction\t1949\nThe Other Eye of Polyphemus\tscience fiction\t1977\nThe Outpost Undiscovered by Tourists\tscience fiction\t1982\nThe Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1\tscience fiction\t1994\nThe Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2\tscience fiction\t1994\nThe Paper Menagerie\tscience fiction\t2011\nThe Patterns of Drone\tscience fiction\t1970\nThe People Who Walked On\teast euro lit\t1959\nThe Perfect Match\tscience fiction\t2012\nThe Phantom of the Sewers\tscience fiction\t1978\nThe Place with No Name\tscience fiction\t1969\nThe Plot\tfiction\t1957\nThe Plot Is the Thing\tscience fiction\t1966\nThe Private War of Private Jacob\tscience fiction\t1973\nThe Problem of the Sore Bridge-Among Others\tscience fiction\t1975\nThe Prowler in the City on the Edge of Forever\tscience fiction\t1967\nThe Recognition\tscience fiction\t1967\nThe Red Canary\tscience fiction\t1973\nThe Red-Headed League\tmystery\t1891\nThe Region Between\tscience fiction\t1970\nThe Regular\tscience fiction\t2014\nThe Resurgence of Miss Ankle-Strap Wedgie\tscience fiction\t1968\nThe Roads Must Roll\tscience fiction\t1940\nThe Season of Babies\tscience fiction\t1959\nThe Secret Miracle\tfiction\t1943\nThe Sect of Phoenix\tfiction\t1952\nThe Settlers\tscience fiction\t1950\nThe Sex Opposite\tscience fiction\t1952\nThe Shape of the Sword\tfiction\t1942\nThe Shore\tscience fiction\t1950\nThe Silent Towns\tscience fiction\t1949\nThe Silver Corridor\tscience fiction\t1956\nThe Simple Way\tscience fiction\t1951\nThe Singers\tscience fiction\t1956\nThe Skills of Xanadu\tscience fiction\t1956\nThe Sky is Burning\tscience fiction\t1958\nThe Small Assaassin\tscience fiction\t1962\nThe Smiling Future\tscience fiction\t1965\nThe South\tfiction\t1953\nThe Starseekers\tscience fiction\t1990\nThe Start of the End of It All\tscience fiction\t1981\nThe Summer Night\tscience fiction\t1949\nThe Superior Sex\tscience fiction\t1968\nThe Supper\teast euro lit\t1959\nThe Sycthe\tscience fiction\t1943\nThe Taxpayer\tscience fiction\t1950\nThe Test Stand\tscience fiction\t1955\nThe Test-Tube Creature, Afterward\tscience fiction\t1972\nThe Theologians\tfiction\t1947\nThe Third Expedition\tscience fiction\t1948\nThe Time Piece\tscience fiction\t1975\nThe Transit of Venus\tscience fiction\t1962\nThe Two Kings and the Two Labyrinths\tfiction\t1946\nThe Universe of Robert Blake\tscience fiction\t1962\nThe Unspeakable Betrothal\tscience fiction\t1949\nThe Very Last Day of a Good Woman\tscience fiction\t1958\nThe Village\tscience fiction\t1973\nThe Visit\tscience fiction\t1990\nThe Voice of the Sonar in My Veriform Appendix\tscience fiction\t1971\nThe Volcano\tscience fiction\t1976\nThe Wages of Humanity\tscience fiction\t2013\nThe Waiting\tfiction\t1950\nThe Wall and the Books\tessay\t1950\nThe Wandering Earth\tscience fiction\t2013\nThe War at Home\tscience fiction\t1985\nThe Warlord of Saturn's Moon\tscience fiction\t1974\nThe Watchers\tscience fiction\t1950\nThe Watchful Poker Chip of H. Matisse\tscience fiction\t1954\nThe Waves\tscience fiction\t2012\nThe Whimper of Whipped Dogs\tscience fiction\t1973\nThe Will\tscience fiction\t1953\nThe Wind\tscience fiction\t1943\nThe Wind Beyond the Mountains\tscience fiction\t1957\nThe Wine Has Been Left Open Too Long and the Memory Has Gone Flat\tscience fiction\t1976\nThe Winter Flies\tscience fiction\t1967\nThe Winter Market\tscience fiction\t1985\nThe Witness\tfiction\t1957\nThe Women Men Don't See\tscience fiction\t1973\nThe Wonderful Death of Dudley Stone\tscience fiction\t1954\nThe Word for World is Forrest\tscience fiction\t1972\nThe World of Stone\teast euro lit\t1959\nThe Writing of the God\tfiction\t1949\nThe Year of the Jackpot\tscience fiction\t1952\nThe Year of the Rat\tscience fiction\t2009\nThe Yellow Rose\tfiction\t1960\nThe Zahir\tfiction\t1947\nTheme of the Traitor and Hero\tfiction\t1944\nThere Was an Old Woman\tscience fiction\t1944\nThere Will Come Soft Rains\tscience fiction\t1950\nThings Lost\tscience fiction\t1972\nThis Way for the Gas, Ladies and Gentlemen\teast euro lit\t1959\nThree Versions of Judas\tfiction\t1944\nThrowback\tscience fiction\t1952\nThunder and Roses\tscience fiction\t1957\nTime Travel for Pedestrians\tscience fiction\t1972\nTiny Ally\tscience fiction\t1957\nTissue\tscience fiction\t1972\nTlon, Uqbar, Orbis Teritus\tfiction\t1940\nTo Be Continued\tscience fiction\t1956\nTo Explain to Mrs. Thompson\tscience fiction\t1951\nTo Here and the Easel\tscience fiction\t1954\nToenails\tfiction\t1936\nTongtong's Summer\tscience fiction\t2014\nTotenbuch\tscience fiction\t1972\nTouched With Fire\tscience fiction\t1954\nTower of Babylon\tscience fiction\t1990\nTracking Level\tscience fiction\t1956\nTranscending Destiny\tscience fiction\t1957\nTrouble With Ants\tscience fiction\t1951\nTry and Change the Past\tscience fiction\t1958\nTwink\tscience fiction\t1955\nUnaccompanied Sonata\tscience fiction\t1979\nUncle Einar\tscience fiction\t1947\nUncle Fremmis\tscience fiction\t1970\nUnderground\tscience fiction\t1967\nUnderstand\tscience fiction\t1991\nUnlocking the Air\tscience fiction\t1990\nUsher II\tscience fiction\t1950\nValerie\tscience fiction\t1972\nValery as Symbol\tessay\t1962\nVaster than Empires and More Slow\tscience fiction\t1971\nVisionary\tscience fiction\t1959\nWanted in Surgery\tscience fiction\t1957\nWater Is for Washing\tscience fiction\t1947\nWay in the Middle of the Air\tscience fiction\t1950\nWe See Things Differently\tscience fiction\t1989\nWhat Happened to Auguste Clarot?\tscience fiction\t1967\nWhat I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27\tscience fiction\t1964\nWhat's It Like Out There?\tscience fiction\t1952\nWhen Auld's Acquaintance is Forgot\tscience fiction\t1982\nWhen I was a Hired Gun\tscience fiction\t1973\nWhen I Was Miss Dow\tscience fiction\t1966\nWhen it Changed\tscience fiction\t1972\nWhen the Bentfin Boomer Boys on Old New Alabama\tscience fiction\t1972\nWhen the Change-Winds Blow\tscience fiction\t1964\nWhere Have You Been, Billy Boy, Billy Boy?\tscience fiction\t1971\nWhere I Shall Dwell in the Next World\tscience fiction\t1992\nWith a Finger in My I\tscience fiction\t1972\nWith Her Eyes\tscience fiction\t2013\nWith Virgin Oddum at the East Pole\tscience fiction\t1985\nWorking with the Little People\tscience fiction\t1979\nWould You Do It for a Penny\tscience fiction\t1967\nYlla\tscience fiction\t1950\nYou Triflin' Skunk\tscience fiction\t1954\nZero Gee\tscience fiction\t1972\nAnd the Moon be Still as Bright\tscience fiction\t1948"
  },
  {
    "path": "tests/data.hpp",
    "content": "#pragma once\n\n#include <string>\n#include <type_traits>\n\n#include \"sql.hpp\"\n\nusing books =\n\tsql::schema<\n\t\t\"books\", sql::index<>,\n#ifdef CROSS\n\t\tsql::column<\"book\", std::string>,\n#else\n\t\tsql::column<\"title\", std::string>,\n#endif\n\t\tsql::column<\"genre\", std::string>,\n\t\tsql::column<\"year\", unsigned>,\n\t\tsql::column<\"pages\", unsigned>\n\t>;\n\nusing stories =\n\tsql::schema<\n\t\t\"stories\", sql::index<>,\n#ifdef CROSS\n\t\tsql::column<\"story\", std::string>,\n#else\n\t\tsql::column<\"title\", std::string>,\n#endif\n\t\tsql::column<\"genre\", std::string>,\n\t\tsql::column<\"year\", unsigned>\n\t>;\n\nusing authored =\n\tsql::schema<\n\t\t\"authored\", sql::index<>,\n\t\tsql::column<\"title\", std::string>,\n\t\tsql::column<\"name\", std::string>\n\t>;\n\nusing collected =\n\tsql::schema<\n\t\t\"collected\", sql::index<>,\n\t\tsql::column<\"title\", std::string>,\n\t\tsql::column<\"collection\", std::string>,\n\t\tsql::column<\"pages\", unsigned>\n\t>;\n\nconst std::string data_folder{ \"./data/\" };\nconst std::string perf_folder{ \"../data/\" };\nconst std::string books_data{ \"books.tsv\" };\nconst std::string stories_data{ \"stories.tsv\" };\nconst std::string authored_data{ \"authored.tsv\" };\nconst std::string collected_data{ \"collected.tsv\" };\n\nusing books_row = std::tuple<std::string, std::string, int, int>;\nusing books_type = std::vector<books_row>;\nusing stories_row = std::tuple<std::string, std::string, int>;\nusing stories_type = std::vector<stories_row>;\nusing authored_row = std::tuple<std::string, std::string>;\nusing authored_type = std::vector<authored_row>; \nusing collected_row = std::tuple<std::string, std::string, int>;\nusing collected_type = std::vector<collected_row>;\n\nconstexpr std::size_t iters{ 65536 };\nconstexpr std::size_t offset{ 512 };\n\ntemplate <char Delim>\nbooks_type books_load()\n{\n\tauto file{ std::fstream(perf_folder + books_data) };\n\tbooks_type table{};\n\n\twhile (file)\n\t{\n\t\tbooks_row row{};\n\t\tstd::getline(file, std::get<0>(row), Delim);\n\t\tstd::getline(file, std::get<1>(row), Delim);\n\t\tfile >> std::get<2>(row);\n\t\tfile >> std::get<3>(row);\n\t\t\n\t\ttable.push_back(std::move(row));\n\n\t\tif (file.get() != '\\n')\n\t\t{\n\t\t\tfile.unget();\n\t\t}\n\t}\n\n\treturn table;\t\n}\n\ntemplate <char Delim>\nstories_type stories_load()\n{\n\tauto file{ std::fstream(perf_folder + stories_data) };\n\tstories_type table{};\n\n\twhile (file)\n\t{\n\t\tstories_row row{};\n\t\tstd::getline(file, std::get<0>(row), Delim);\n\t\tstd::getline(file, std::get<1>(row), Delim);\n\t\tfile >> std::get<2>(row);\n\t\t\n\t\ttable.push_back(std::move(row));\n\n\t\tif (file.get() != '\\n')\n\t\t{\n\t\t\tfile.unget();\n\t\t}\n\t}\n\n\treturn table;\t\n}\n\ntemplate <char Delim>\nauthored_type authored_load()\n{\n\tauto file{ std::fstream(perf_folder + authored_data) };\n\tauthored_type table{};\n\n\twhile (file)\n\t{\n\t\tauthored_row row{};\n\t\tstd::getline(file, std::get<0>(row), Delim);\n\t\tstd::getline(file, std::get<1>(row), Delim);\n\t\t\n\t\ttable.push_back(std::move(row));\n\n\t\tif (file.get() != '\\n')\n\t\t{\n\t\t\tfile.unget();\n\t\t}\n\t}\n\n\treturn table;\t\n}\n\ntemplate <char Delim>\ncollected_type collected_load()\n{\n\tauto file{ std::fstream(perf_folder + collected_data) };\n\tcollected_type table{};\n\n\twhile (file)\n\t{\n\t\tcollected_row row{};\n\t\tstd::getline(file, std::get<0>(row), Delim);\n\t\tstd::getline(file, std::get<1>(row), Delim);\n\t\tfile >> std::get<2>(row);\n\t\t\n\t\ttable.push_back(std::move(row));\n\n\t\tif (file.get() != '\\n')\n\t\t{\n\t\t\tfile.unget();\n\t\t}\n\t}\n\n\treturn table;\t\n}\n"
  },
  {
    "path": "tests/perf/data/lib-query0",
    "content": "6.81 user\n"
  },
  {
    "path": "tests/perf/data/lib-query1",
    "content": "4.73 user\n"
  },
  {
    "path": "tests/perf/data/lib-query2",
    "content": "3.70 user\n"
  },
  {
    "path": "tests/perf/data/lib-query3",
    "content": "11.81 user\n"
  },
  {
    "path": "tests/perf/data/lib-query4",
    "content": "1.54 user\n"
  },
  {
    "path": "tests/perf/data/lib-query5",
    "content": "38.04 user\n"
  },
  {
    "path": "tests/perf/data/query0",
    "content": "6.39 user\n"
  },
  {
    "path": "tests/perf/data/query1",
    "content": "4.18 user\n"
  },
  {
    "path": "tests/perf/data/query2",
    "content": "11.17 user\n"
  },
  {
    "path": "tests/perf/data/query3",
    "content": "12.39 user\n"
  },
  {
    "path": "tests/perf/data/query4",
    "content": "3.45 user\n"
  },
  {
    "path": "tests/perf/data/query5",
    "content": "44.35 user\n"
  },
  {
    "path": "tests/perf/queries/lib-query0.cpp",
    "content": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT title, genre AS type, year AS published \"\n\t\t\"FROM stories \"\n\t\t\"WHERE NOT genre <> \\\"science fiction\\\" AND NOT year <= 1970\",\n\t\tstories\n\t>;\n\nint main()\n{\n\tstories s{ sql::load<stories>(perf_folder + stories_data, '\\t') };\n\n\tfor (std::size_t i{}; i < iters; ++i)\n\t{\n\t\tfor (query q{ s }; auto const& [t, g, y] : q)\n\t\t{\n\t\t\tstd::cout << t << '\\t' << g << '\\t' << y << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/lib-query1.cpp",
    "content": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT title, genre AS type, year AS published, pages \"\n\t\t\"FROM books \"\n\t\t\"WHERE NOT genre <> \\\"science fiction\\\" AND NOT year >= 1970 OR pages < 300\",\n\t\tbooks\n\t>;\n\nint main()\n{\n\tbooks b{ sql::load<books>(perf_folder + books_data), '\\t' };\n\n\tfor (std::size_t i{}; i < iters; ++i)\n\t{\n\t\tfor (query q{ b }; auto const& [t, g, y, p] : q)\n\t\t{\n\t\t\tstd::cout << t << '\\t' << g << '\\t' << y << '\\t' << p << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/lib-query2.cpp",
    "content": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT genre AS type, name \"\n\t\t\"FROM books NATURAL JOIN authored \"\n\t\t\"WHERE NOT genre = \\\"science fiction\\\" AND name != \\\"Harlan Ellison\\\"\",\n\t\tbooks,\n\t\tauthored\n\t>;\n\nint main()\n{\n\tbooks b{ sql::load<books>(perf_folder + books_data, '\\t') };\n\tauthored a{ sql::load<authored>(perf_folder + authored_data, '\\t') };\n\n\tfor (std::size_t i{}; i < iters; ++i)\n\t{\n\t\tfor (query q{ b, a }; auto const& [g, n] : q)\n\t\t{\n\t\t\tstd::cout << g << '\\t' << n << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/lib-query3.cpp",
    "content": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT genre AS type, year AS published, title, name \"\n\t\t\"FROM stories NATURAL JOIN authored \"\n\t\t\"WHERE genre = \\\"science fiction\\\" AND year > 1970 AND name != \\\"Harlan Elison\\\"\",\n\t\tstories,\n\t\tauthored\n\t>;\n\nint main()\n{\n\tstories s{ sql::load<stories>(perf_folder + stories_data, '\\t') };\n\tauthored a{ sql::load<authored>(perf_folder + authored_data, '\\t') };\n\n\tfor (std::size_t i{}; i < iters; ++i)\n\t{\n\t\tfor (query q{ s, a }; auto const& [g, y, t, n] : q)\n\t\t{\n\t\t\tstd::cout << g << '\\t' << y << '\\t' << t << '\\t' << n << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/lib-query4.cpp",
    "content": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT book, genre AS type, year As published \"\n\t\t\"FROM books CROSS JOIN authored \"\n\t\t\"WHERE NOT genre != \\\"science fiction\\\" AND year > 1970\",\n\t\tbooks,\n\t\tauthored\n\t>;\n\nint main()\n{\n\tbooks b{ sql::load<books,>(perf_folder + books_data '\\t') };\n\tauthored a{ sql::load<authored>(perf_folder + authored_data, '\\t') };\n\n\tfor (std::size_t i{}; i < iters / offset; ++i)\n\t{\n\t\tfor (query q{ b, a }; auto const& [b, g, y] : q)\n\t\t{\n\t\t\tstd::cout << b << '\\t' << g << '\\t' << y << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/lib-query5.cpp",
    "content": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT story, genre AS type, year AS published, title, collection, pages \"\n\t\t\"FROM stories CROSS join collected \"\n\t\t\"WHERE genre != \\\"science fiction\\\" OR year >= 1970 OR NOT pages < 300\",\n\t\tstories,\n\t\tcollected\n\t>;\n\nint main()\n{\n\tstories s{ sql::load<stories>(perf_folder + stories_data, '\\t') };\n\tcollected c{ sql::load<collected>(perf_folder + collected_data, '\\t') };\n\n\tfor (std::size_t i{}; i < iters / offset; ++i)\n\t{\n\t\tfor (query q{ s, c }; auto const& [s, g, y, t, c, p] : q)\n\t\t{\n\t\t\tstd::cout << s << '\\t' << g << '\\t' << y << '\\t' << t << '\\t' << c << '\\t' << p << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/query0.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#include \"../../data.hpp\"\n\nstories_type query(stories_type const& s)\n{\n\tusing std::get;\n\tstories_type output{};\n\n\tfor (auto const& row : s)\n\t{\n\t\tif (!(get<1>(row) != \"science fiction\") && !(get<2>(row) <= 1970))\n\t\t{\n\t\t\toutput.push_back(row);\n\t\t}\n\t}\n\n\treturn output;\n}\n\nint main()\n{\n\tstories_type s{ stories_load<'\\t'>() };\n\n\tfor (std::size_t i{}; i < iters; ++i)\n\t{\n\t\tfor (auto data{ query(s) }; auto const& [t, g, y] : data)\n\t\t{\n\t\t\tstd::cout << t << '\\t' << g << '\\t' << y << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/query1.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#include \"../../data.hpp\"\n\nbooks_type query(books_type const& b)\n{\n\tusing std::get;\n\tbooks_type output{};\n\n\tfor (auto const& row : b)\n\t{\n\t\tif (!(get<1>(row) != \"science fiction\") && !(get<2>(row) >= 1970) || get<3>(row) < 300)\n\t\t{\n\t\t\toutput.push_back(row);\n\t\t}\n\t}\n\n\treturn output;\n}\n\nint main()\n{\n\tbooks_type b{ books_load<'\\t'>() };\n\n\tfor (std::size_t i{}; i < iters; ++i)\n\t{\n\t\tfor (auto data{ query(b) }; auto const& [t, g, y, p] : data)\n\t\t{\n\t\t\tstd::cout << t << '\\t' << g << '\\t' << y << '\\t' << p << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/query2.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#include \"../../data.hpp\"\n\nauthored_type query(books_type const& b, authored_type const& a)\n{\n\tusing std::get;\n\tauthored_type output{};\n\tstd::unordered_map<std::string, authored_row> cache{};\n\n\tfor (auto const& row : a)\n\t{\n\t\tcache[get<0>(row)] = row;\n\t}\n\n\tfor (auto const& b_row : b)\n\t{\n\t\tauto it{ cache.find(get<0>(b_row)) };\n\n\t\tif (it != cache.end())\n\t\t{\n\t\t\tauto const& a_row{ get<1>(*it) };\n\n\t\t\tif (!(get<1>(b_row) == \"science fiction\") && get<1>(a_row) != \"Harlan Ellison\")\n\t\t\t{\n\t\t\t\toutput.emplace_back(get<1>(b_row), get<1>(a_row));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn output;\n}\n\nint main()\n{\n\tbooks_type b{ books_load<'\\t'>() };\n\tauthored_type a{ authored_load<'\\t'>() };\n\n\tfor (std::size_t i{}; i < iters; ++i)\n\t{\n\t\tfor (auto data{ query(b, a) }; auto const& [g, n] : data)\n\t\t{\n\t\t\tstd::cout << g << '\\t' << n << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/query3.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#include \"../../data.hpp\"\n\nusing output_type = std::vector<std::tuple<std::string, int, std::string, std::string>>;\n\noutput_type query(stories_type const& s, authored_type const& a)\n{\n\tusing std::get;\n\toutput_type output{};\n\tstd::unordered_map<std::string, authored_row> cache{};\n\n\tfor (auto const& row : a)\n\t{\n\t\tcache[get<0>(row)] = row;\n\t}\n\n\tfor (auto const& s_row : s)\n\t{\n\t\tauto it{ cache.find(get<0>(s_row)) };\n\n\t\tif (it != cache.end())\n\t\t{\n\t\t\tauto const& a_row{ get<1>(*it) };\n\n\t\t\tif (get<1>(s_row) == \"science fiction\" && get<2>(s_row) > 1970 && get<1>(a_row) != \"Harlan Ellison\")\n\t\t\t{\n\t\t\t\toutput.emplace_back(get<1>(s_row), get<2>(s_row), get<0>(a_row), get<1>(a_row));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn output;\n}\n\nint main()\n{\n\tstories_type s{ stories_load<'\\t'>() };\n\tauthored_type a{ authored_load<'\\t'>() };\n\n\tfor (std::size_t i{}; i < iters; ++i)\n\t{\n\t\tfor (auto data{ query(s, a) }; auto const& [g, y, t, n] : data)\n\t\t{\n\t\t\tstd::cout << g << '\\t' << y << '\\t' << t << '\\t' << n << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/query4.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#include \"../../data.hpp\"\n\nusing output_type = std::vector<std::tuple<std::string, std::string, int>>;\n\noutput_type query(books_type const& b, authored_type const& a)\n{\n\tusing std::get;\n\toutput_type output{};\n\t\n\tfor (auto const& a_row : a)\n\t{\n\t\tfor (auto const& b_row : b)\n\t\t{\n\t\t\tif (!(get<1>(b_row) != \"science fiction\") && get<2>(b_row) > 1970)\n\t\t\t{\n\t\t\t\toutput.emplace_back(get<0>(b_row), get<1>(b_row), get<2>(b_row));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn output;\n}\n\nint main()\n{\n\tbooks_type b{ books_load<'\\t'>() };\n\tauthored_type a{ authored_load<'\\t'>() };\n\n\tfor (std::size_t i{}; i < iters / offset; ++i)\n\t{\n\t\tfor (auto data{ query(b, a) }; auto const& [b, g, y] : data)\n\t\t{\n\t\t\tstd::cout << b << '\\t' << g << '\\t' << y << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/queries/query5.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#include \"../../data.hpp\"\n\nusing output_type = std::vector<std::tuple<std::string, std::string, int, std::string, std::string, int>>;\n\noutput_type query(stories_type const& s, collected_type const& c)\n{\n\tusing std::get;\n\toutput_type output{};\n\t\n\tfor (auto const& c_row : c)\n\t{\n\t\tfor (auto const& s_row : s)\n\t\t{\n\t\t\tif (!(get<1>(s_row) != \"science fiction\") || get<2>(s_row) >= 1970 || !(get<2>(c_row) < 300))\n\t\t\t{\n\t\t\t\toutput.emplace_back(get<0>(s_row), get<1>(s_row), get<2>(s_row), get<0>(c_row), get<1>(c_row), get<2>(c_row));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn output;\n}\n\nint main()\n{\n\tstories_type s{ stories_load<'\\t'>() };\n\tcollected_type c{ collected_load<'\\t'>() };\n\n\tfor (std::size_t i{}; i < iters / offset; ++i)\n\t{\n\t\tfor (auto data{ query(s, c) }; auto const& [st, g, y, t, co, p] : data)\n\t\t{\n\t\t\tstd::cout << st << '\\t' << g << '\\t' << y << '\\t' << t << '\\t' << co << '\\t' << p << '\\n';\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/runner.sh",
    "content": "python3 scripts/runner.py\n\n"
  },
  {
    "path": "tests/perf/scripts/runner.py",
    "content": "import os\n\nQUERIES = 6\n\ndef exe(file, q):\n\tif int(q) >= 4:\n\t\tos.system(\"g++ -std=c++2a -DCROSS -O3 -I../../single-header -o test queries/\" + file)\n\telse:\n\t\tos.system(\"g++ -std=c++2a -O3 -I../../single-header -o test queries/\" + file)\n\tos.system(\"/usr/bin/time -f \\\"%U user\\\" -o data/\" + file[:-4] + \" ./test > /dev/null\")\n\tos.remove(\"test\")\n\ndef main():\n\tprint(\"Benchmark Test Begin\")\n\tfor q in range(QUERIES):\n\t\tq = str(q) \n\t\tprint(\"\\tTest Query \" + q)\n\t\texe(\"lib-query\" + q + \".cpp\", q)\n\t\texe(\"query\" + q + \".cpp\", q)\n\tprint(\"Benchmark Test End\")\n\nif __name__ == \"__main__\":\n\tmain()\n"
  },
  {
    "path": "tests/runner.sh",
    "content": "mkdir queries\npython3 scripts/generate.py\npython3 scripts/runner.py\n"
  },
  {
    "path": "tests/scripts/compose.py",
    "content": "# Composes a test file\n\nbegin = \"\"\"#include <iostream>\n\n#include \"data.hpp\"\n\nusing query =\n\tsql::query<\n\"\"\"\nmiddle = \"\"\"\n\t>;\n\nint main()\n{\n\"\"\"\nend = \"\"\"\n\treturn 0;\n}\n\"\"\"\n\ndef data(tokens):\n\tf = False\n\tcs = 1\n\tts = []\n\tfor tk in tokens:\n\t\ttk = tk.lower()\n\t\tif tk[-1] == \",\":\n\t\t\tcs += 1\n\t\tif tk == \"where\":\n\t\t\tbreak\n\t\tif tk == \"from\":\n\t\t\tf = True\n\t\telif f and tk != \"cross\" and tk != \"natural\" and tk != \"join\":\n\t\t\tts += [tk]\n\treturn cs, ts\n\ndef templ(query, ts):\n\ttempl_spec = \"\\t\\t\\\"\" + query + \"\\\"\"\n\tfor t in ts:\n\t\ttempl_spec += \",\\n\\t\\t\" + t\n\treturn templ_spec\n\ndef func(ts, cs):\n\tbody = \"\"\n\targs = \"\"\n\tout = \"\\tstd::cout << \"\n\tcount = 0\n\tfor t in ts:\n\t\tbody += \"\\t\" + t + \" t\" + str(count) + \"{ sql::load<\" + t + \">(data_folder + \" + t + \"_data, '\\\\t') };\\n\"\n\t\targs += \"t\" + str(count) + \", \"\n\t\tcount += 1\n\tbody += \"\\n\\tfor (query q{ \" + args[:-2] + \" }; auto const& [\"\n\tfor c in range(cs):\n\t\tbody += \"c\" + str(c) + \", \"\n\t\tout += \"c\" + str(c) + \" << \\'|\\' << \"\n\tbody = body[:-2] + \"] : q)\\n\\t{\\n\\t\" + out[:-11] + \" << \\'\\\\n\\';\\n\\t}\\n\"\n\treturn body\n\ndef main():\n\tinfile = open(\"queries/query\", \"r\")\n\tquery = infile.readline().strip()\n\tinfile.close()\n\ttokens = query.split()\n\tcs, ts = data(tokens[1:])\n\tspec = templ(query, ts)\n\tbody = func(ts, cs)\n\toutfile = open(\"test.cpp\", \"w\")\n\toutfile.write(begin + spec + middle + body + end)\n\toutfile.close()\n\nif __name__ == \"__main__\":\n\tmain()\n"
  },
  {
    "path": "tests/scripts/generate.py",
    "content": "# SQL query generator for test queries\n# Generates over 1.4 million unique queries\n\nimport itertools\nimport random\n\ntables = [\"books\", \"stories\", \"authored\", \"collected\"]\ncolumns = {\n\t\"books\": [\"book\", \"genre\", \"year\", \"pages\"],\n\t\"stories\": [\"story\", \"genre\", \"year\"],\n\t\"authored\": [\"title\", \"name\"],\n\t\"collected\": [\"title\", \"collection\", \"pages\"]\n}\njoinable = {\n\t\"books\": [\"authored\"],\n\t\"stories\": [\"authored\", \"collected\"],\n\t\"authored\": [],\n\t\"collected\": []\n}\njoins = [\"cross\"]\nrenames = {\n\t\"genre\": \"type\",\n\t\"year\": \"published\"\n}\nintegral = [\"year\", \"pages\"]\nall_comp = [\"=\", \"!=\", \"<>\"]\nintegral_comp = [\">\", \"<\", \">=\", \"<=\"]\nbool_op = [\"or\", \"and\"]\nnegate_op = [\"\", \"not \"]\nwhere_data = {\n\t\"name\": [\"Harlan Ellison\"],\n\t\"year\": [1970],\n\t\"pages\": [300],\n\t\"genre\": [\"science fiction\"]\n}\noutfiles = { \n\t\"joinless\": open(\"queries/joinless-queries.txt\", \"w\"),\n\t\"cross\": open(\"queries/cross-queries.txt\", \"w\") \n}\n\ndef col_list(cs):\n\tcl = []\n\tre = False\n\tcols = \"\"\n\tfor c in cs:\n\t\tcols += c\n\t\tif c in renames.keys():\n\t\t\tcols += \" as \" + renames[c]\n\t\t\tre = True\n\t\tcols += \", \"\n\tcl += [cols[:-2]]\n\tif re:\n\t\tcols = \"\"\n\t\tfor c in cs:\n\t\t\tcols += c\n\t\t\tcols += \", \"\t\n\t\tcl += [cols[:-2]]\n\treturn cl\n\ndef froms(ts):\n\tf = []\n\toutput = outfiles[\"joinless\"]\n\tif len(ts) == 1:\n\t\tf = [ts[0]]\n\telse:\n\t\tfor j in joins:\n\t\t\toutput = outfiles[j]\n\t\t\tif random.random() < 0.3333:\n\t\t\t\tj = j.upper()\n\t\t\tf += [ts[0] + \" \" + j + \" join \" + ts[1]]\n\treturn f, output\n\ndef compose(ts, cs, pred):\n\tif pred != \"\":\n\t\tpred = \" where \" + pred\n\tcols = col_list(cs)\n\tsel, output = froms(ts)\n\tfor s in sel:\n\t\tfor c in cols:\n\t\t\toutput.write(\"select \" + c + \" from \" + s + pred + \"\\n\")\n\ndef next(cs, ci):\n\tif ci >= len(cs):\n\t\treturn -1\n\telse:\n\t\twhile not cs[ci] in where_data.keys():\n\t\t\tci += 1\n\t\t\tif ci >= len(cs):\n\t\t\t\treturn -1\n\t\treturn ci\n\ndef predicate(ts, cs, ci, pred):\n\tci = next(cs, ci)\n\tif ci == -1:\n\t\tcompose(ts, cs, pred)\n\telse:\n\t\tfor op in bool_op:\n\t\t\tif random.random() < 0.3333:\n\t\t\t\top = op.upper()\n\t\t\tp = pred + \" \" + op + \" \"\n\t\t\toperation(ts, cs, ci, p)\n\ndef operation(ts, cs, ci, pred):\n\tc = cs[ci]\n\tops = []\n\tops += all_comp\n\tif c in integral:\n\t\tops += integral_comp\n\tfor nop in negate_op:\n\t\tfor op in ops:\n\t\t\tfor data in where_data[c]:\n\t\t\t\tif random.random() < 0.3333:\n\t\t\t\t\tnop = nop.upper()\n\t\t\t\tp = pred\n\t\t\t\tp += nop + c + \" \" + op + \" \"\n\t\t\t\tif type(data) is str:\n\t\t\t\t\tp += \"\\\\\\\"\" + data + \"\\\\\\\"\"\n\t\t\t\telse:\n\t\t\t\t\tp += str(data)\n\t\t\t\tpredicate(ts, cs, ci + 1, p)\n\ndef select(ts):\n\tcols = []\n\tfor t in ts:\n\t\tcols += columns[t]\n\tfor i in range(len(cols)):\n\t\tcomb = list(itertools.combinations(cols, i + 1))\n\t\tfor cs in comb:\n\t\t\tci = next(cs, 0)\n\t\t\tif ci == -1:\n\t\t\t\tcompose(ts, cs, \"\")\n\t\t\telse:\n\t\t\t\tpred = operation(ts, cs, ci, \"\")\n\ndef root_query(left):\n\tselect([left])\n\tfor right in joinable[left]:\n\t\tselect([left, right])\n\ndef main():\n\tprint(\"Test Generator\")\n\tfor table in tables:\n\t\tprint(\"\\tGenerating queries for \\\"\" + table + \"\\\" schema\")\n\t\troot_query(table)\n\nif __name__ == \"__main__\":\n\tmain()\n\tfor file in outfiles.keys():\n\t\toutfiles[file].close()\n\tjoins = [\"natural\"]\n\toutfiles = {\n\t\t\"joinless\": open(\"queries/joinless-queries.txt\", \"w\"),\n\t\t\"natural\": open(\"queries/natural-queries.txt\", \"w\")\n\t}\n\tcolumns = {\n\t\t\"books\": [\"title\", \"genre\", \"year\", \"pages\"],\n\t\t\"stories\": [\"title\", \"genre\", \"year\"],\n\t\t\"authored\": [\"title\", \"name\"],\n\t\t\"collected\": [\"title\", \"collection\", \"pages\"]\n\t}\n\tmain()\n\tfor file in outfiles.keys():\n\t\toutfiles[file].close()\n"
  },
  {
    "path": "tests/scripts/runner.py",
    "content": "import os\n\ndef main():\n\tprint(\"Test Runner\")\n\tos.system(\"python3 scripts/select.py\")\n\tprint(\"\\tTest queries selected\")\n\tnum = 1\n\ttoken = \"\"\n\tdb = \"library.db\"\n\twith open(\"queries/test-queries.txt\", \"r\") as queries:\n\t\tfor query in queries:\n\t\t\tquery = query.strip()\n\t\t\tif query[0] != \"s\":\n\t\t\t\ttoken = query\n\t\t\t\tif query == \"CROSS\":\n\t\t\t\t\tdb = \"library-cross.db\"\n\t\t\t\tcontinue\n\t\t\tq = open(\"queries/query\", \"w\")\n\t\t\tq.write(query + \"\\n\")\n\t\t\tq.close()\n\t\t\tos.system(\"python3 scripts/compose.py\")\n\t\t\tos.system(\"g++ -std=c++2a \" + \"-D\" + token + \" -O3 -I../single-header -o test test.cpp\")\n\t\t\tos.system(\"./test | sort > cpp-results.txt\")\n\t\t\tos.system(\"sqlite3 data/\" + db + \" \\\"\" + query + \";\\\" | sort > sql-results.txt\")\n\t\t\tstream = os.popen(\"diff cpp-results.txt sql-results.txt\")\n\t\t\tres = \"Passed\"\n\t\t\tfor line in stream:\n\t\t\t\tres = \"Failed\"\n\t\t\t\tbreak\n\t\t\tprint(\"\\tTest \" + str(num) + \":\\t\" + res + \"\\n\\t\\t\" + query)\n\t\t\tif res == \"Failed\":\n\t\t\t\texit()\n\t\t\tnum += 1\n\tos.remove(\"cpp-results.txt\")\n\tos.remove(\"sql-results.txt\")\n\tos.remove(\"queries/test-queries.txt\")\n\tos.remove(\"queries/query\")\n\nif __name__ == \"__main__\":\n\tmain()\n"
  },
  {
    "path": "tests/scripts/select.py",
    "content": "# Randomly selects ~500 queries to test from the 1.4mil query set\n\nimport random\n\ndef main():\n\toutfile = open(\"queries/test-queries.txt\", \"w\")\n\t#h = 100 / 23000\n\t#h = 0\n\th = 1.0\n\toutfile.write(\"JOINLESS\\n\")\n\twith open(\"queries/joinless-queries.txt\", \"r\") as infile:\n\t\tfor line in infile:\n\t\t\tif random.random() < h:\n\t\t\t\toutfile.write(line)\n\t#h = 500 / 700000\n\toutfile.write(\"NATURAL\\n\")\n\twith open(\"queries/natural-queries.txt\", \"r\") as infile:\n\t\tfor line in infile:\n\t\t\tif random.random() < h:\n\t\t\t\toutfile.write(line)\n\toutfile.write(\"CROSS\\n\")\n\twith open(\"queries/cross-queries.txt\", \"r\") as infile:\n\t\tfor line in infile:\n\t\t\tif random.random() < h:\n\t\t\t\toutfile.write(line)\n\toutfile.close()\n\nif __name__ == \"__main__\":\n\tmain()\n"
  }
]