cpptables

Tabular data for C++ using types for tables and columns.

Overview

Table schemas are defined at compile time allowing operations such as joins and grouping to be checked for type correctness.

Columns support column-oriented operations.

Examples

#include <cpptables/table.hh>
#include <cpptables/where.hh>
#include <iostream>

using namespace tables;
using namespace std;

struct col0  { constexpr static char const * const name = "col0"; };
struct col1  { constexpr static char const * const name = "col1"; };
struct col2  { constexpr static char const * const name = "col2"; };
struct col3  { constexpr static char const * const name = "col3"; };

int main()
{
  using table_t = table<
    pair<col0,std::string_view>,
    pair<col1,unsigned>,
    pair<col2,double>
  >;

  const table_t t(
    {"A", "B", "C", "A", "B", "C", "A", "B", "C"},
    {1,10,100,2,20,200,3,30,300},
    {100.0,200.0,300.0,400.0,500.0,600.0,700.0,800.0,900.0}
  );

  // Filter rows
  {
    // Select rows whose col0 is A
    const table_t t0 = t.at( where( t.col<col0>() == std::string_view("A"))); 
    cout << "select where col0 == A:\n" << t0 << "\n";

    // Same query, different syntax
    const table_t t1 = t.at( t.col<col0>().eq(std::string_view("A")).where() );

    // Select rows whose col0 > A
    const table_t t2 = t.at( t.col<col0>().gt(std::string_view("A")).where() );
    cout << "select where col0 > A:\n" << t2 << "\n";
  }

  // ================ Grouping with group_by ================

  using gtable_t = table_t::group_by_t<std::tuple<col0>>;
  const gtable_t gt = t.group_by<col0>();

  // Sum col1,col2 grouped by col0
  {
    const table_t t_sum = t.group_by<col0>().sum();
    cout << "sum col1,col2 by col0:\n" << t_sum << "\n";
  }

  // ================ apply aggregators or transformation to groups: fby  ================

  // Sum col1,avg col2 by col0
  {
    const auto fsum = [](const column<auto>& xs) { return xs.sum(); };
    const auto favg = [](const column<auto>& xs) { return xs.avg(); };
    const table_t t1 = t.fby<col0>().agg<col1,col2>(fsum,favg);
    cout << "sum col1,avg col2 by col0:\n" << t1 << "\n";
  }

  // Reverse col1 by col0
  {
    const auto freverse = [](const column<auto>& xs) { return xs.reverse(); };
    const table_t t1 = t.fby<col0>().fupdate<col1>(freverse);
    cout << "reverse col1 by col0:\n" << t1 << "\n";
  }

  // ================ Joins ================

  using table1_t = table<
    pair<col0,std::string_view>,
    std::pair<col3,std::string_view>
  >;

  const table1_t t1(
   {"A", "B"},
   {"alfa","beta"}
  );

  // Left join t with t1 on col0
  {
    const auto t_lj = t.lj( t1.key_by<col0>() );
    cout << "left join t with t1:\n" << t_lj << "\n";
  }
 
  // Inner join t with t1 on col0
  {
    const auto t_ij = t.ij( t1.key_by<col0>() );
    cout << "inner join t with t1:\n" << t_ij << "\n";
  }

  return 0;
}

Output:

select where col0 == A:
col0 col1 col2
--------------
   A    1  100
   A    2  400
   A    3  700

select where col0 > A:
col0 col1 col2
--------------
   B   10  200
   C  100  300
   B   20  500
   C  200  600
   B   30  800
   C  300  900

sum col1,col2 by col0:
col0 col1 col2
--------------
   A    6 1200
   B   60 1500
   C  600 1800

sum col1,avg col2 by col0:
col0 col1 col2
--------------
   A    6  400
   B   60  500
   C  600  600

reverse col1 by col0:
col0 col1 col2
--------------
   A    3  100
   B   30  200
   C  300  300
   A    2  400
   B   20  500
   C  200  600
   A    1  700
   B   10  800
   C  100  900

left join t with t1:
col0 col1 col2 col3
-------------------
   A    1  100 alfa
   B   10  200 beta
   C  100  300 none
   A    2  400 alfa
   B   20  500 beta
   C  200  600 none
   A    3  700 alfa
   B   30  800 beta
   C  300  900 none

inner join t with t1:
col0 col1 col2 col3
-------------------
   A    1  100 alfa
   B   10  200 beta
   A    2  400 alfa
   B   20  500 beta
   A    3  700 alfa
   B   30  800 beta