Add textMetadata function to retrieve metadata via sigle(s)

Change-Id: I34714bce07635732d0534f83a48865d6d64903da
diff --git a/DESCRIPTION b/DESCRIPTION
index 2136bf2..b2f7978 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -67,4 +67,5 @@
     'hc_freq_by_year_ci.R'
     'misc.R'
     'reexports.R'
+    'textMetadata.R'
 Roxygen: list(markdown = TRUE)
diff --git a/NAMESPACE b/NAMESPACE
index 1efd608..3261a8e 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -47,6 +47,7 @@
 exportMethods(initialize)
 exportMethods(persistAccessToken)
 exportMethods(show)
+exportMethods(textMetadata)
 import(R.cache)
 import(highcharter)
 import(httr)
@@ -71,6 +72,7 @@
 importFrom(dplyr,if_else)
 importFrom(dplyr,mutate)
 importFrom(dplyr,n)
+importFrom(dplyr,relocate)
 importFrom(dplyr,rename)
 importFrom(dplyr,rowwise)
 importFrom(dplyr,select)
diff --git a/NEWS.md b/NEWS.md
index 50afcf8..58c83b0 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,6 @@
 # RKorAPClient 0.7.7.9000 (unpublished)
 
+- added `textMetadata` KorAPConnection method to retrieve all metadata for a text based on its sigle
 - if not `metadataOnly`, also retrieve tokenized snippets (in `collectedMatches$tokens`)
 - uses server side tokenized matches in collocation analysis, if supported by KorAP server
 
diff --git a/R/textMetadata.R b/R/textMetadata.R
new file mode 100644
index 0000000..c743fa8
--- /dev/null
+++ b/R/textMetadata.R
@@ -0,0 +1,56 @@
+setGeneric("textMetadata", function(kco, ...)  standardGeneric("textMetadata") )
+
+#' Retrieve metadata for a text, identified by its sigle (id)
+#'
+#' @aliases textMetadata
+#'
+#' @description
+#' Retrieves metadata for a text, identified by its sigle (id) using the corresponding KorAP API
+#' (see [Kustvakt Wiki](https://github.com/KorAP/Kustvakt/wiki/Service:-Metadata-Retrieval)).
+#'
+#'
+#' @param kco [KorAPConnection()] object (obtained e.g. from `new("KorAPConnection")`)
+#' @param textSigle unique text id (concatenation of corpus, document and text ids, separated by `/`, e.g. ) or vector thereof
+#' @param verbose logical. If `TRUE`, additional diagnostics are printed. Defaults to `kco@verbose`.
+#'
+#' @return Tibble with columns for every metadata property. In case of errors, like non-existing texts/sigles, the tibble will also contain a row called `errors`.
+#'
+#' @importFrom urltools url_encode
+#' @importFrom dplyr bind_rows relocate mutate
+#'
+#' @examples
+#' \dontrun{
+#' new("KorAPConnection") %>% textMetadata(c("WUD17/A97/08542", "WUD17/B96/57558", "WUD17/A97/08541"))
+#' }
+#'
+#' @export
+setMethod("textMetadata", "KorAPConnection",
+ function(kco, textSigle, verbose = kco@verbose) {
+  if (length(textSigle) > 1)
+    do.call(bind_rows, Map(function(atomicSigle)
+      textMetadata(kco, atomicSigle), textSigle))
+  else {
+    url <-
+      paste0(kco@apiUrl, 'corpus/',
+             URLencode(enc2utf8(textSigle), reserved = TRUE))
+    log_info(verbose, "Getting metadata for ", textSigle, sep = "")
+    res <- apiCall(kco, url)
+    log_info(verbose, ifelse(is.null(res) || "errors" %in% names(res), " [error]\n",  "\n"))
+
+    if(is.null(res)) {
+      res <- tibble(errors="API request failed")
+    } else {
+      res <- lapply(res, function(x) paste0(x, collapse = "\\t")) # flatten list
+      res <- as_tibble(res) %>%
+        head(n=1) %>%
+        mutate(
+          requestUrl = url,
+          textSigle = textSigle,
+          webUIRequestUrl = paste0(kco@KorAPUrl, sprintf('?q=<base/s=t>&cq=textSigle+%%3D+"%s"', url_encode(enc2utf8(textSigle))))) %>%
+        relocate(textSigle)
+    }
+    res
+  }
+})
+
+
diff --git a/man/textMetadata-KorAPConnection-method.Rd b/man/textMetadata-KorAPConnection-method.Rd
new file mode 100644
index 0000000..d5a3d23
--- /dev/null
+++ b/man/textMetadata-KorAPConnection-method.Rd
@@ -0,0 +1,29 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/textMetadata.R
+\name{textMetadata,KorAPConnection-method}
+\alias{textMetadata,KorAPConnection-method}
+\alias{textMetadata}
+\title{Retrieve metadata for a text, identified by its sigle (id)}
+\usage{
+\S4method{textMetadata}{KorAPConnection}(kco, textSigle, verbose = kco@verbose)
+}
+\arguments{
+\item{kco}{\code{\link[=KorAPConnection]{KorAPConnection()}} object (obtained e.g. from \code{new("KorAPConnection")})}
+
+\item{textSigle}{unique text id (concatenation of corpus, document and text ids, separated by \code{/}, e.g. ) or vector thereof}
+
+\item{verbose}{logical. If \code{TRUE}, additional diagnostics are printed. Defaults to \code{kco@verbose}.}
+}
+\value{
+Tibble with columns for every metadata property. In case of errors, like non-existing texts/sigles, the tibble will also contain a row called \code{errors}.
+}
+\description{
+Retrieves metadata for a text, identified by its sigle (id) using the corresponding KorAP API
+(see \href{https://github.com/KorAP/Kustvakt/wiki/Service:-Metadata-Retrieval}{Kustvakt Wiki}).
+}
+\examples{
+\dontrun{
+new("KorAPConnection") \%>\% textMetadata(c("WUD17/A97/08542", "WUD17/B96/57558", "WUD17/A97/08541"))
+}
+
+}
diff --git a/tests/testthat/test-textMetadata.R b/tests/testthat/test-textMetadata.R
new file mode 100644
index 0000000..b81ec00
--- /dev/null
+++ b/tests/testthat/test-textMetadata.R
@@ -0,0 +1,12 @@
+test_that("textMetadata works", {
+  skip_if_offline()
+  m <- new("KorAPConnection") %>% textMetadata(c("WUD17/B96/57558", "WUD17/A97/08541"))
+  expect("textType" %in% names(m), "textMetadata value should contain a textType column")
+})
+
+
+test_that("textMetadata works for unknown text sigles", {
+  skip_if_offline()
+  m <- new("KorAPConnection") %>% textMetadata(c("WUD17/B96/57558", "unknownsigle"))
+  expect("errors" %in% names(m), "textMetadata should return an errors column if a text does not exist")
+})