rladybugdb is a
native R interface to LadybugDB, an embedded columnar graph database
formerly known as Kuzu. It links directly to the LadybugDB 0.20.4 C API
and requires neither Python nor a database server.
Use ":memory:" for an ephemeral database or a file path
for persistence. Connections keep their database reachable, but explicit
cleanup gives errors a predictable scope.
For code that should automatically clean up, use a scoped connection:
Node and relationship tables define a graph schema.
lb_close(lb_execute(
conn,
"CREATE NODE TABLE Person (name STRING, age INT64, PRIMARY KEY(name))"
))
lb_close(lb_execute(
conn,
"CREATE NODE TABLE City (name STRING, PRIMARY KEY(name))"
))
lb_close(lb_execute(
conn,
"CREATE REL TABLE LivesIn (FROM Person TO City, since INT64)"
))
lb_close(lb_execute(
conn,
"CREATE (:Person {name: $name, age: $age})",
parameters = list(name = "Alice", age = 30L)
))
lb_close(lb_execute(conn, "CREATE (:City {name: 'London'})"))
lb_close(lb_execute(
conn,
paste(
"MATCH (p:Person {name: 'Alice'}), (c:City {name: 'London'})",
"CREATE (p)-[:LivesIn {since: 2018}]->(c)"
)
))
lb_query(
conn,
paste(
"MATCH (p:Person)-[r:LivesIn]->(c:City)",
"RETURN p.name AS person, p.age AS age, c.name AS city, r.since AS since"
)
)
#> person age city since
#> 1 Alice 30 London 2018Parameters must be a named list with unique, non-empty names.
Logical, integer, double, character, factor, Date,
POSIXct, integer64, raw, list, array, and
struct-like named-list values are supported. Typed missing scalars
become database NULL.
lb_query() materializes and closes a result
automatically. Use lb_execute() when you want result
metadata, conversion to another format, or bounded streaming.
result <- lb_execute(
conn,
"UNWIND range(1, 25) AS id RETURN id, 'row ' + CAST(id AS STRING) AS label"
)
print(result, n = 3)
#> <lb_result> [25 x 2]
#> id label
#> 1 1 row 1
#> 2 2 row 2
#> 3 3 row 3
#> # ... with 22 more rows
first <- lb_fetch(result, n = 10)
second <- lb_fetch(result, n = 10)
lb_result_info(result)
#> $column_names
#> [1] "id" "label"
#>
#> $column_types
#> [1] "INT64" "STRING"
#>
#> $num_columns
#> [1] 2
#>
#> $num_tuples
#> [1] 25
#>
#> $rows_fetched
#> [1] 20
#>
#> $complete
#> [1] FALSE
#>
#> $has_next_result
#> [1] FALSE
lb_query_summary(result)
#> $compiling_time_ms
#> [1] 7.216
#>
#> $execution_time_ms
#> [1] 0.162
lb_reset(result)
identical(as.data.frame(result), as.data.frame(result))
#> [1] TRUE
lb_close(result)Printing, formatting, and as.data.frame() preserve the
current cursor. Successive lb_fetch() calls advance it;
lb_reset() starts again.
With the optional arrow package, conversion uses the
Arrow C Data Interface instead of first creating a data frame.
result <- lb_execute(conn, "MATCH (p:Person) RETURN p.name AS name, p.age AS age")
arrow_table <- as_arrow_table(result)
lb_close(result)
arrow_table
#> Table
#> 1 rows x 2 columns
#> $name <string>
#> $age <int64>Create a target table before bulk loading.
lb_copy_from_df() prefers the Arrow path, which preserves
empty strings and missing strings distinctly, and warns if it must use
CSV instead.
lb_close(lb_execute(
conn,
"CREATE NODE TABLE Event (id INT64, note STRING, PRIMARY KEY(id))"
))
copy_result <- lb_copy_from_df(
conn,
data.frame(id = c(1, 2), note = c("", NA_character_)),
"Event"
)
lb_close(copy_result)
lb_query(conn, "MATCH (e:Event) RETURN e.* ORDER BY e.id")
#> e.id e.note
#> 1 1
#> 2 2 <NA>Use lb_copy_from_csv() for explicit file ingestion and
lb_copy_from_arrow() for an Arrow Table or RecordBatch.
The DBI backend supports queries, binding, bounded fetches, transactions, quoting, and table metadata.
Return full nodes and relationships to construct igraph
or tidygraph objects. Scalar property projections alone do
not contain graph structure.
graph_result <- lb_execute(
conn,
"MATCH (p:Person)-[r:LivesIn]->(c:City) RETURN p, r, c"
)
graph <- as_igraph(graph_result)
lb_close(graph_result)
graph
#> IGRAPH 87fc00d DN-- 2 1 --
#> + attr: name (v/c), _LABEL (v/c), age (v/n), _LABEL (e/c), _ID (e/c),
#> | since (e/n)
#> + edge from 87fc00d (vertex names):
#> [1] Alice->LondonRecursive relationship paths are supported as well. Internal identifiers are kept as exact character components rather than converted through floating point.