---
title: "Create consistent metadata for pins"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Create consistent metadata for pins}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

The `metadata` argument in pins is flexible and can hold any kind of metadata that you can formulate as a `list()`. In some situations, you may want to read and write with _consistent_ customized metadata; you can create functions to wrap `pin_write()` and `pin_read()` for your particular use case.

To see a different approach for when you want to write and read whole file(s) in a customized way, see `vignette("managing-custom-formats")`.

We'll begin by creating a temporary board for demonstration:

```{r setup}
library(pins)

board <- board_temp()
```


# A function to store factors

Say you want to store a factor as JSON together with the _levels_ of the factor in the metadata. We can write a function wrapping `pin_write()` that creates the standardized metadata we are interested in and writes it in a consistent way.

```{r}
pin_write_factor_json <- function(board, 
                                  x, 
                                  name, 
                                  title = NULL, 
                                  description = NULL, 
                                  metadata = list(), 
                                  versioned = NULL, 
                                  tags = NULL, 
                                  ...) {
  if (!is.factor(x)) rlang::abort("`x` is not a factor")
  factor_levels <- levels(x)
  metadata <- modifyList(metadata, list(factor_levels = factor_levels))
  pin_write(
    board = board, 
    x = x, 
    name = name, 
    type = "json", 
    title = title, 
    description = description, 
    metadata = metadata,
    ...
  )
}
```

We can use this new function to write a pin as JSON with our specific metadata:

```{r}
ten_letters <- factor(sample(letters, size = 10), levels = letters)
board |> pin_write_factor_json(ten_letters, "letters-as-json")
```

## A function to read factors

It's possible to read this pin using the regular `pin_read()` function, but the object we get is no longer a factor!

```{r}
board |> pin_read("letters-as-json")
```

Instead, we can also write a special function for reading, to reconstruct the factor including its levels:

```{r}
pin_read_factor_json <- function(board, name, version = NULL, hash = NULL, ...) {
  ret <- pin_read(board = board, name = name, version = version, hash = hash, ...)
  meta <- pin_meta(board = board, name = name, version = version, ...)
  factor(ret, levels = meta$user$factor_levels)
}

board |> pin_read_factor_json("letters-as-json")
```

## Examples of using consistent metadata

How are these approaches used in real projects?

- The vetiver package wraps pins functions [to write and read model binaries together with their metadata, including an renv lockfile](https://github.com/rstudio/vetiver-r/blob/main/R/pin-read-write.R).
- You can record version control information such as Git commit and SHA as pin metadata.
- You can create data lineage or data governance metadata appropriate to your use case.
