Skip to content

table

The table package queries lists of hashmaps (rows) the way you would a database table. Wrap rows with table::from, chain operations, and finish with a method that returns a result. Rows from csv, json and sqlite all work.

users = [
{id: 1, name: "Ada", active: true, score: 91},
{id: 2, name: "Grace", active: true, score: 87},
{id: 3, name: "Linus", active: false, score: 75}
]
top = table::from(users)
.where(do (r) => r["active"] end)
.select(["name", "score"])
.order_by("score", false) # descending
.to_list()
println top # [{"name": "Ada", "score": 91}, {"name": "Grace", "score": 87}]

Each step returns a new table; the source rows are not modified.

MethodDoes
where(predicate)Keeps rows for which the predicate is truthy.
select(fields), drop(fields)Keeps or removes fields.
rename(old, new)Renames a field.
add_field(name, compute)Adds a field computed from each row.
map(transform)Replaces each row with the transform’s result.
order_by(field, ascending)Sorts by a field; ascending by default.
limit(n), offset(n)Keeps the first n rows, or skips them.
distinct()Removes duplicate rows.
graded = table::from([{name: "Ada", score: 91}, {name: "Linus", score: 75}])
.add_field("grade", do (r) => r["score"] >= 90 ? "A" : "B" end)
.pluck("grade")
println graded # ["A", "B"]

inner_join, left_join, right_join and full_join take the other rows, the key field on this side, and the key field on the other side. Joined rows merge the fields of both; if both sides have a field with the same name, rename one first.

users = [{id: 1, name: "Ada"}, {id: 2, name: "Grace"}, {id: 3, name: "Linus"}]
orders = [
{user_id: 1, product: "kiwi", qty: 3},
{user_id: 2, product: "mango", qty: 1}
]
println table::from(users)
.inner_join(orders, "id", "user_id")
.select(["name", "product"])
.to_list()
# [{"name": "Ada", "product": "kiwi"}, {"name": "Grace", "product": "mango"}]
# Users without orders: left join, then keep rows that gained no order fields.
println table::from(users)
.left_join(orders, "id", "user_id")
.where(do (r) => !r.keys().contains("product") end)
.pluck("name")
# ["Linus"]

group_by(field) followed by agg(specs) produces one row per group. Each spec is a lambda that receives the group’s rows:

orders = [
{region: "west", qty: 3},
{region: "east", qty: 1},
{region: "west", qty: 2}
]
println table::from(orders)
.group_by("region")
.agg({
"orders": do (rows) => rows.size() end,
"units": do (rows) => rows.map(do (r) => r["qty"] end).sum() end
})
.to_list()
# [{"region": "west", "orders": 2, "units": 5}, {"region": "east", "orders": 1, "units": 1}]
MethodReturns
to_list()The rows.
pluck(field)One field’s values.
first()The first row, or null.
count()The number of rows.
to_hashmap(field)A hashmap from each row’s field value, as a string, to the row.
display(max_width)Prints the rows as a table and returns the table, so it can sit mid-chain while debugging.
table::from([{id: 1, name: "Ada"}, {id: 2, name: "Grace"}]).display()
+----+-------+
| id | name |
+----+-------+
| 1 | Ada |
| 2 | Grace |
+----+-------+
(2 row(s))
table::from(rows: list): Table

Creates a new Table from a list of hashmaps.

ParameterTypeDefaultDescription
rowslistThe source data.

Returns Table — A new Table instance.

An in-memory table of rows (list of hashmaps) with a fluent transform API.

# Filter, project, sort
result = table::from(rows)
.where(do (r) => r["active"] == true end)
.select(["id", "name", "score"])
.order_by("score", false)
.limit(10)
.to_list()
# Join two datasets
result = table::from(users)
.inner_join(orders, "id", "user_id")
.select(["name", "product", "qty"])
.to_list()
# Group and aggregate
result = table::from(orders)
.group_by("product")
.agg({
"total": do (rows) => rows.map(do (r) => r["qty"] end).sum() end,
"n": do (rows) => rows.size() end
})
.order_by("total", false)
.to_list()
Table.new(rows: list)

Creates a new Table wrapping a list of hashmaps.

ParameterTypeDefaultDescription
rowslistThe source data — a list of hashmaps.
where(predicate: lambda): Table

Keeps only rows for which predicate(row) is truthy.

ParameterTypeDefaultDescription
predicatelambdaA lambda accepting a row hashmap.

Returns Table — self, for chaining.

select(keys: list): Table

Projects each row to only the specified keys.

ParameterTypeDefaultDescription
keyslistThe field names to retain.

Returns Table — self, for chaining.

rename(old_name: string, new_name: string): Table

Renames a field in every row.

ParameterTypeDefaultDescription
old_namestringThe existing field name.
new_namestringThe replacement field name.

Returns Table — self, for chaining.

add_field(name: string, compute: lambda): Table

Adds a computed field to every row.

ParameterTypeDefaultDescription
namestringThe new field name.
computelambdaA lambda accepting a row and returning the field value.

Returns Table — self, for chaining.

drop(keys: list): Table

Removes the specified fields from every row.

ParameterTypeDefaultDescription
keyslistThe field names to drop.

Returns Table — self, for chaining.

map(transform: lambda): Table

Applies a custom transform lambda to every row.

ParameterTypeDefaultDescription
transformlambdaA lambda accepting a row hashmap and returning a hashmap.

Returns Table — self, for chaining.

order_by(field: string, asc: boolean = true): Table

Sorts rows by a field value.

ParameterTypeDefaultDescription
fieldstringThe field name to sort by.
ascbooleantruetrue for ascending (default), false for descending.

Returns Table — self, for chaining.

limit(n: integer): Table

Keeps only the first n rows.

ParameterTypeDefaultDescription
nintegerMaximum number of rows to keep.

Returns Table — self, for chaining.

offset(n: integer): Table

Skips the first n rows.

ParameterTypeDefaultDescription
nintegerNumber of rows to skip.

Returns Table — self, for chaining.

distinct(): Table

Removes duplicate rows (compares all fields).

Returns Table — self, for chaining.

inner_join(other: list, left_key: string, right_key: string): Table

Keeps only rows that have a matching row in other.

ParameterTypeDefaultDescription
otherlistThe right-side list of hashmaps.
left_keystringThe join field on the left (this table).
right_keystringThe join field on the right (other).

Returns Table — self, for chaining.

left_join(other: list, left_key: string, right_key: string): Table

Keeps all left rows; right-side fields are absent when there is no match.

ParameterTypeDefaultDescription
otherlistThe right-side list of hashmaps.
left_keystringThe join field on the left (this table).
right_keystringThe join field on the right (other).

Returns Table — self, for chaining.

right_join(other: list, left_key: string, right_key: string): Table

Keeps all right rows; left-side fields are absent when there is no match.

ParameterTypeDefaultDescription
otherlistThe right-side list of hashmaps.
left_keystringThe join field on the left (this table).
right_keystringThe join field on the right (other).

Returns Table — self, for chaining.

full_join(other: list, left_key: string, right_key: string): Table

Keeps all rows from both sides; unmatched rows have fields only from their side.

ParameterTypeDefaultDescription
otherlistThe right-side list of hashmaps.
left_keystringThe join field on the left (this table).
right_keystringThe join field on the right (other).

Returns Table — self, for chaining.

group_by(field: string): Table

Groups rows by the unique values of field.

ParameterTypeDefaultDescription
fieldstringThe field to group by.

Returns Table — self, for chaining.

agg(specs: hashmap): Table

Collapses groups into one row per group using aggregate functions.

ParameterTypeDefaultDescription
specshashmap{ "out_field": do (rows) => ... end, ... }

Returns Table — self, for chaining.

Throws string — If called without a preceding group_by().

table::from(orders)
.group_by("product")
.agg({
"total": do (rows) => rows.map(do (r) => r["qty"] end).sum() end,
"n": do (rows) => rows.size() end
})
.to_list()
to_list(): list

Returns the current rows as a plain list.

Returns list — List of row hashmaps.

to_hashmap(key_field: string): hashmap

Returns a hashmap keyed by the values of key_field.

ParameterTypeDefaultDescription
key_fieldstringThe field whose value becomes each hashmap key.

Returns hashmap — A hashmap mapping key values to row hashmaps.

pluck(field: string): list

Extracts a single field's values as a flat list.

ParameterTypeDefaultDescription
fieldstringThe field name to extract.

Returns list — A list of the field values.

first()

Returns the first row, or null if the table is empty.

Returns hashmap|null — The first row, or null.

count(): integer

Returns the number of rows.

Returns integer — Row count.

display(max_width: integer = 0): Table

Prints the table as a formatted ASCII grid and returns self.

ParameterTypeDefaultDescription
max_widthinteger0Maximum column width in characters (0 = unlimited). Values longer than max_width are truncated with ….

Returns Table — self, for chaining.

table::from(rows)
.where(do (r) => r["active"] end)
.order_by("name")
.display()
# Cap every column at 30 characters
table::from(rows).display(30)