Rust bindings for RayforceDB - a high-performance time-series database.
- Complete Type System: Full support for all Rayforce types including scalars (I64, F64, Symbol, Date, Time, Timestamp, GUID), containers (List, Vector, Dict), and Table.
- Query Builder: Fluent API for building SELECT, UPDATE, INSERT, and UPSERT queries.
- Expression Builder: Type-safe expression construction for WHERE clauses and computed columns.
- IPC Support: Connect to remote Rayforce servers.
- Automatic Build: Automatically clones and builds the Rayforce C library from source.
Add to your Cargo.toml:
[dependencies]
rayforce-rs = "0.1"- Clang/LLVM: Required for bindgen
- Git: For cloning Rayforce sources
- Make: For building the C library
- C compiler (gcc or clang)
On Ubuntu/Debian:
sudo apt install llvm-dev libclang-dev clang git build-essentialOn macOS:
xcode-select --install
brew install llvmuse rayforce::{Rayforce, Table, Column, Vector, Symbol, I64, Result};
fn main() -> Result<()> {
// Initialize the runtime
let rf = Rayforce::new()?;
// Create a table
let table = Table::from_dict([
("id", Vector::<i64>::from_iter([1i64, 2, 3]).as_ray_obj().clone()),
("name", Vector::<Symbol>::from_iter(["Alice", "Bob", "Charlie"]).ptr().clone()),
("score", Vector::<f64>::from_iter([95.5, 87.3, 92.1]).as_ray_obj().clone()),
])?;
println!("Table:\n{}", table);
// Query with WHERE clause
let result = table
.select()
.columns(&["id", "name"])
.where_cond(Column::new("score").gt(90.0f64))
.execute()?;
println!("High scorers:\n{}", result);
// Evaluate Rayforce expressions
let sum = rf.eval("sum(1 2 3 4 5)")?;
println!("Sum: {}", sum);
Ok(())
}use rayforce::{I64, F64, B8, Symbol, Date, Time, Timestamp, GUID};
use chrono::{NaiveDate, NaiveTime, NaiveDateTime};
use uuid::Uuid;
let i = I64::new(42);
let f = F64::new(3.14);
let b = B8::new(true);
let sym = Symbol::new("hello");
// Temporal types
let date = Date::from_naive_date(NaiveDate::from_ymd_opt(2024, 1, 15).unwrap());
let time = Time::from_ms(43200000); // 12:00:00
let ts = Timestamp::from_nanos(1705312800000000000);
// GUID
let guid = GUID::random();
let guid2 = GUID::parse("550e8400-e29b-41d4-a716-446655440000")?;use rayforce::{List, Vector, Dict, Symbol};
// Vectors (homogeneous)
let ints: Vector<i64> = Vector::from_iter([1i64, 2, 3]);
let floats: Vector<f64> = Vector::from_iter([1.1, 2.2, 3.3]);
let symbols = Vector::<Symbol>::from_iter(["a", "b", "c"]);
// Lists (heterogeneous)
let mut list = List::new();
list.push(I64::new(42).ptr().clone());
list.push(RayString::new("hello").ptr().clone());
// Dictionaries
let dict = Dict::from_pairs([
("name", RayString::new("Alice").ptr().clone()),
("age", I64::new(30).ptr().clone()),
])?;use rayforce::{Table, Column, Vector, Symbol};
// Create from dictionary
let table = Table::from_dict([
("col1", Vector::<i64>::from_iter([1, 2, 3]).as_ray_obj().clone()),
("col2", Vector::<Symbol>::from_iter(["a", "b", "c"]).ptr().clone()),
])?;
// Reference a named table
let table_ref = Table::from_name("my_table");
// Access columns
let cols = table.columns()?;
let row_count = table.len()?;let result = table
.select()
.columns(&["id", "name", "score"])
.where_cond(Column::new("score").gt(80.0))
.group_by(&["department"])
.execute()?;let updated = table
.update()
.set("score", Column::new("score").sum())
.where_cond(Column::new("active").eq(true))
.execute()?;let inserted = table
.insert()
.values([
("id", I64::new(4).ptr().clone()),
("name", Symbol::new("Dave").ptr().clone()),
])
.execute()?;let upserted = table
.upsert(1) // match by first 1 column(s)
.values([
("id", I64::new(1).ptr().clone()),
("score", F64::new(99.9).ptr().clone()),
])
.execute()?;// Inner join
let result = table1.inner_join(&table2, &["key_column"])?;
// Left join
let result = table1.left_join(&table2, &["key_column"])?;use rayforce::ipc::hopen;
let conn = hopen("localhost", 5000)?;
let result = conn.execute("select * from trades")?;
conn.close()?;use rayforce::Column;
let col = Column::new("price");
// Comparisons
let expr1 = col.gt(100.0); // price > 100
let expr2 = col.le(200.0); // price <= 200
let expr3 = col.eq(150.0); // price == 150
// Combine with AND/OR
let combined = col.gt(100.0).and(col.lt(200.0));
// Aggregations
let sum_expr = col.sum();
let avg_expr = col.avg();
let count_expr = col.count();RAYFORCE_GITHUB: Override the Rayforce repository URL (default:https://github.com/RayforceDB/rayforce.git)
MIT License - see LICENSE for details.
- RayforceDB - The Rayforce database
- rayforce-py - Official Python bindings