---
title: "Getting started with rladybugdb"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting started with rladybugdb}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
library(rladybugdb)
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
```

`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.

Optional integrations use packages such as `arrow`, `igraph`, and `tidygraph`
that must already be installed. Functions and examples do not install packages;
examples using an optional package are skipped when it is unavailable.

## Open a database

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.

```{r}
db <- lb_database(":memory:")
conn <- lb_connection(db)
```

For code that should automatically clean up, use a scoped connection:

```{r}
with_lb_connection(":memory:", {
  ladybugdb_version()
})
```

## Create and query a property graph

Node and relationship tables define a graph schema.

```{r}
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"
  )
)
```

Parameters 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`.

## Reusable and streaming results

`lb_query()` materializes and closes a result automatically. Use
`lb_execute()` when you want result metadata, conversion to another format, or
bounded streaming.

```{r}
result <- lb_execute(
  conn,
  "UNWIND range(1, 25) AS id RETURN id, 'row ' + CAST(id AS STRING) AS label"
)

print(result, n = 3)
first <- lb_fetch(result, n = 10)
second <- lb_fetch(result, n = 10)
lb_result_info(result)
lb_query_summary(result)

lb_reset(result)
identical(as.data.frame(result), as.data.frame(result))
lb_close(result)
```

Printing, formatting, and `as.data.frame()` preserve the current cursor.
Successive `lb_fetch()` calls advance it; `lb_reset()` starts again.

## Arrow and data loading

With the optional `arrow` package, conversion uses the Arrow C Data Interface
instead of first creating a data frame.

```{r eval=requireNamespace("arrow", quietly=TRUE)}
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
```

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.

```{r eval=requireNamespace("arrow", quietly=TRUE)}
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")
```

Use `lb_copy_from_csv()` for explicit file ingestion and
`lb_copy_from_arrow()` for an Arrow Table or RecordBatch.

## DBI

The DBI backend supports queries, binding, bounded fetches, transactions,
quoting, and table metadata.

```{r}
dbi_conn <- DBI::dbConnect(Ladybug(), dbname = ":memory:")
DBI::dbGetQuery(dbi_conn, "RETURN $value AS value", params = list(value = 42L))
DBI::dbDisconnect(dbi_conn)
```

## Graph objects

Return full nodes and relationships to construct `igraph` or `tidygraph`
objects. Scalar property projections alone do not contain graph structure.

```{r eval=requireNamespace("igraph", quietly=TRUE)}
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
```

Recursive relationship paths are supported as well. Internal identifiers are
kept as exact character components rather than converted through floating
point.

## Close resources

```{r}
lb_close(conn)
lb_close(db)
```

Calling `lb_close()` twice is harmless. Closing a connection with a live result
or a database with a live connection raises a clear error rather than risking
use-after-free.
