The data table library provides a SQL-like table, but without the benefits of being able to run SQL against it. Instead it provides a set of list comprehension-like functionality:

This library is particularly useful when you have a page that is handling real-time data and you need a tool to manage changes and manipulate the document object model (DOM) or a visualization.

Prerequisites

HarbingerJS is included in the Rails Extensions gem. The gem provides both the HarbingerJS library to the asset rails pipeline as well as a Rails helper method to handle passing serverside information into the JavaScript library.

Warning: You must perform the HarbingerJS setup to use this code!

Additionally you'll need to include some specific JavaScript files in your asset pipeline to use these features. An example excerpt of an application.js:

//= require harbinger-js/core
//= require harbinger-js/data_table.js

Defining and Instantiating

The data table is a library that lets you define a schema or table representation. You can then instantiate that table representation or class with data. The resulting object is a data structure with manipulation methods. A schema definition is a hash where the key is the name of the field and a value of the field type. Valid field types are:

A schema definition also requires specifying a primary key. The primary key that you specify must be one of the fields defined in the hash. You may also extend the methods you can run on the data table object by providing a hash of functions. These functions will execute in the context of the data table (this will evaluate to the data table instantiation).

An example:

var extensions = {test: function() { console.log(this); };

//Instantiate a data table. It's like defining a schema.
//Arguments: (1) the primary key of the table,
//           (2) a hash of fields and their types,
//           (3) a list of extensions where an extension is a hash
//               of name: function that take the dataTable instance as an argument
var table_def = $.harbingerjs.dataTable("id",
                                             {
                                              "current_report_id":"int",
                                              "current_status_id":"int",
                                              "id":"int",
                                              "updated_at":"date"},[extensions]);

Manipulation

CRUD (Create, Read, Update, Delete)

Once you have a data table defined, you can build a table (instantiation of the schema) with data:

// Data is a list of hashes where the hash is a key value pair for the fields of the table.
var data = [{"id": 1, "current_report_id": null, "current_status_id":1, "updated_at":"2014-10-10 00:00:00"}];
// create a table with data as the initial set of data in it
var mytable = table_def.create(data);
// insert/update the data table with new data
// when a primary key exists in the table that row will be overwritten with this information
mytable.update({"id": 1, "current_report_id": 2, "current_status_id":2, "updated_at":"2014-10-1 01:00:00"})
// when a primary key does not exist it will add that row to the table
mytable.update({"id": 2, "current_report_id": 3, "current_status_id":2, "updated_at":"2014-10-2 00:00:00"})
// remove a record
mytable.remove(1); // the primary key or a row hash like above

Transformations

There are many transformation methods that can be run on the data table:

Method Description
transform(initial,fun) This function iterates over each row in the datatable and runs the given function passing in the initial state and the row object. The return of the function determines the initial state of the next row in the iteration.
groupWith(groupFun) This function takes a string representing a column or a function. The return of the function will be used as a key and the rows in the datatable will be segregated into a hash using the value returned by the groupFun as the key.
segregate(groupFun) This behaves similarly to groupWith, but the values of the hash returned will be a new instatiation of the data table instead of a list of row objects.
split(groupFun) This behaves similarly to groupWith but rather than a hash returned it is a list of new data tables instatiated with the rows grouped by the groupFun.
filter(filterFun) This returns a new instance of the data table only containing the rows for which the filterFun returned true.

Selection and Aggregation

There are also functions to find specific data in the table:

Function Description
extreme(funOrAttribute,testFun) This function iterates over the data model extracting a value based on a function or attribute name (string). It compares these values using testFun (which is given 2 values to compare). It will return one value from the row that is most extreme (according to the testFun).
min(funOrAttribute) Running the function or obtaining the attribute specified this function returns the minimum value in the datatable instance.
max(funOrAttribute) Running the function or obtaining the attribute specified this function returns the maximum value in the datatable instance.

Attaching Callbacks

It is possible to listen to changes in the data table using callbacks. To attach a callback function use the listenWith method:

mytable.listenWith(function(row) { console.log("got update",row); });
mytable.update({"id": 3, "current_report_id": 4, "current_status_id":2, "updated_at":"2014-10-3 00:00:00"});
// You should now see this update logged in the browser JavaScript console