---
title: "Installation and Basic Usage"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Installation and Basic Usage}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
header-includes:
- |
```{=html}
```
---
```{r setup, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
```
This vignette provides a guide to `lbugr` and performing basic operations, including creating a database, defining a schema, loading data from various sources, and executing Cypher queries.
## 1. Connecting to a Database
First, load the `lbugr` package and create a connection to a Ladybug database. You can create an in-memory database or specify a path to a database file on disk.
```{r, eval=FALSE}
library(lbugr)
con <- lb_connection(":memory:")
```
## 2. Data Types and Schema Definition
Ladybug supports a rich set of data types. When creating a schema, you need to map your R data types to the corresponding Ladybug `LogicalTypeID`.
### Ladybug to R Data Type Mapping
| **Ladybug `LogicalTypeID`** | **R Type Equivalent** | **Description** |
|-------------------|-------------------|----------------------------------|
| `BOOL` | `logical` | `TRUE`/`FALSE` values |
| `INT64` | `integer` | 64-bit signed integer |
| `DOUBLE` | `numeric` | Double-precision floating-point number |
| `STRING` | `character` | UTF-8 encoded string |
| `TIMESTAMP` | `POSIXct` | Date and time with timezone, stored as microseconds since epoch |
| `DATE` | `Date` | Date (year, month, day) |
| `INTERVAL` | `difftime` | Time interval (e.g., "1 year 2 months 3 days") |
| `UUID` | `character` | Universally Unique Identifier, stored as a string |
| `LIST` | `list` | Ordered collection of values of the same type |
| `MAP` | `list` (named list) | Unordered collection of key-value pairs |
### Creating a Complex Schema
You can define a schema with node and relationship tables using `lb_execute()`. Here's an example of a more complex schema:
```{r, eval=FALSE}
# Create a node table for users with various data types
lb_execute(con, paste("CREATE NODE TABLE User(userID UUID, name STRING,",
"age INT64, is_active BOOL, created_at TIMESTAMP,",
"last_login DATE, notes STRING[],",
"PRIMARY KEY (userID))"))
# Create a node table for products
lb_execute(con, "CREATE NODE TABLE Product(productID INT64, name STRING, PRIMARY KEY (productID))")
# Create a relationship table for user purchases
lb_execute(con, "CREATE REL TABLE Buys(FROM User TO Product, purchase_date DATE)")
```
## 3. Loading Data
You can load data into your Ladybug tables from R data frames or external files like CSV.
### Loading from a Data Frame
Use `lb_copy_from_df()` to load data from an R `data.frame`.
```{r, eval=FALSE}
library(jsonlite)
# Create data frames for nodes and relationships
users <- data.frame(
userID = c("a1b2c3d4-e5f6-7890-1234-567890abcdef", "b2c3d4e5-f6a7-8901-2345-67890abcdef0"),
name = c("Alice", "Bob"),
age = c(35, 45),
is_active = c(TRUE, FALSE),
created_at = as.POSIXct(c("2023-01-15 10:30:00", "2022-11-20 14:00:00")),
last_login = as.Date(c("2023-10-25", "2023-09-30")),
stringsAsFactors = FALSE
)
# LIST types should be formatted as JSON strings
users$notes <- c(toJSON(c("note1", "note2")), toJSON("note3"))
products <- data.frame(
productID = c(101, 102),
name = c("Laptop", "Mouse")
)
buys <- data.frame(
from_user = c("a1b2c3d4-e5f6-7890-1234-567890abcdef", "b2c3d4e5-f6a7-8901-2345-67890abcdef0"),
to_product = c(101, 102),
purchase_date = as.Date(c("2023-02-20", "2023-03-15"))
)
# Load data into Ladybug
lb_copy_from_df(con, users, "User")
lb_copy_from_df(con, products, "Product")
lb_copy_from_df(con, buys, "Buys")
```
### Loading from a CSV File
Use `lb_copy_from_csv()` to load data from a CSV file. For this to work, the file should be in the current working directory.
```{r, eval=FALSE}
# Create a CSV file in the project's root directory
csv_filename <- "products.csv"
write.csv(data.frame(productID = c(103, 104), name = c("Keyboard", "Monitor")),
csv_filename, row.names = FALSE)
# Load data from the CSV file using just the filename
lb_copy_from_csv(con, csv_filename, "Product")
# Clean up the created file
unlink(csv_filename)
```
## 4. Executing Queries and Converting Results
You can execute Cypher queries using `lb_execute()` and convert the results into various R formats.
```{r, eval=FALSE}
# Execute a query to get users and their purchases
query_result <- lb_execute(con, "MATCH (u:User)-[b:Buys]->(p:Product) RETURN u.name, p.name, b.purchase_date")
```
### A Note on Query Results
The `QueryResult` object returned by `lb_execute()` acts as an iterator over the results. This means it can only be consumed once. Functions like `as.data.frame()`, `as_tibble()`, `lb_get_all()`, and the graph conversion functions will exhaust this iterator.
### Convert to Data Frame or Tibble
```{r, eval=FALSE}
# Convert to a data frame
df_result <- as.data.frame(query_result)
print(df_result)
#> u.name p.name purchase_date
#> 1 Alice Laptop 2023-02-20
#> 2 Bob Mouse 2023-03-15
# Convert to a tibble
library(tibble)
query_result <- lb_execute(con, "MATCH (u:User)-[b:Buys]->(p:Product) RETURN u.name, p.name, b.purchase_date")
tibble_result <- as_tibble(query_result)
print(tibble_result)
#> # A tibble: 2 x 3
#> u.name p.name purchase_date
#>
#> 1 Alice Laptop 2023-02-20
#> 2 Bob Mouse 2023-03-15
```
### Use Query Results returned as list
```{r, eval=FALSE}
query_result <- lb_execute(con, "MATCH (u:User)-[b:Buys]->(p:Product) RETURN u.name, p.name, b.purchase_date")
result <- lb_get_all(query_result)
print(result)
#> [[1]]
#> [[1]]$u.name
#> [1] "Alice"
#> ...
# only fetch 1. result
query_result <- lb_execute(con, "MATCH (u:User)-[b:Buys]->(p:Product) RETURN u.name, p.name, b.purchase_date")
result <- lb_get_n(query_result, 1)
print(result)
#> [[1]]
#> [[1]]$u.name
#> [1] "Alice"
#> ...
#Fetch next result
result <- lb_get_next(query_result)
print(result)
#> $u.name
#> [1] "Bob"
#> ...
```
### Convert to Graph Objects
For queries that return graph structures, you can convert the results into graph objects from packages like `igraph` or `tidygraph`. To do this, the query must return the node and relationship variables themselves, not just their properties.
```{r, eval=FALSE}
# Execute a query that returns a graph structure
graph_query_result <- lb_execute(con, "MATCH (u:User)-[b:Buys]->(p:Product) RETURN u, p, b")
igraph_obj <- as_igraph(graph_query_result)
print(igraph_obj)
#> IGRAPH UN-- 3 2 --
#> + attr: name (v/c)
#> + edges (vertex names):
#> [1] Alice->Laptop Bob ->Mouse
plot(igraph_obj,
vertex.color = "#dc2626",
vertex.label.color = "#f3f4f6",
vertex.label.font = 2,
edge.color = "#9ca3af",
edge.arrow.size = 0.8,
edge.arrow.width = 0.5,
bg = "#030712",
main = "igraph: User Purchases")
# Convert to a tidygraph object
tidygraph_obj <- as_tidygraph(graph_query_result)
print(tidygraph_obj)
#> # A tbl_graph: 3 nodes and 2 edges
#> #
#> # A directed acyclic simple graph with 3 nodes and 2 edges
#> #
#> # Node Data: 3 x 1 (active)
#> name
#>
#> 1 Alice
#> 2 Bob
#> 3 Laptop
#> #
#> # Edge Data: 2 x 3
#> from to purchase_date
#>
#> 1 1 3 2023-02-20
#> 2 2 4 2023-03-15
ggraph::ggraph(tidygraph_obj, layout = "kk") +
ggraph::geom_edge_link(color = "#9ca3af", arrow = grid::arrow(angle = 30, length = grid::unit(3, "mm"))) +
ggraph::geom_node_point(color = "#dc2626", size = 8) +
ggraph::geom_node_text(ggplot2::aes(label = name), color = "#f3f4f6", size = 4, vjust = -1) +
ggplot2::theme_void() +
ggplot2::theme(plot.background = ggplot2::element_rect(fill = "#030712", color = NA))