This commit is contained in:
Hong Ooi 2021-04-02 19:33:06 +11:00
Родитель f44e6a86a1
Коммит d09a8e05b8
3 изменённых файлов: 60 добавлений и 22 удалений

Просмотреть файл

@ -93,12 +93,20 @@ public=list(
#'
#' @param token An Azure OAuth token, of class [AzureToken].
#' @param requests A list of [graph_request] objects, representing individual requests to the Graph API.
#' @param depends_on An optional named list indicating which requests have dependencies. See the examples below.
#' @param depends_on An optional named vector, or TRUE. See below.
#' @param api_version The API version to use, which will form part of the URL sent to the host.
#'
#' @details
#' Use this function to combine multiple requests into a single HTTPS call. This can save significant network latency.
#'
#' The `depends_on` argument specifies the dependencies that may exist between requests. The default is to treat the requests as independent, which allows them to be executed in parallel. If `depends_on` is TRUE, each request is specified as depending on the immediately preceding request. Otherwise, this should be a named vector or list that gives the dependency or dependencies for each request.
#'
#' There are 2 restrictions on `depends_on`:
#' - If one request has a dependency, then all requests must have dependencies specified
#' - A request can only depend on previous requests in the list, not on later ones.
#'
#' A request list that has dependencies will be executed serially.
#'
#' @return
#' A list containing the responses to each request. Each item has components `id` and `status` at a minimum. It may also contain `headers` and `body`, depending on the specifics of the request.
#' @seealso
@ -115,7 +123,7 @@ public=list(
#' req1 <- graph_request$new("me")
#'
#' # a new email message in Outlook
#' req2 <- graph_request$new("me/messages",
#' req_create <- graph_request$new("me/messages",
#' body=list(
#' body=list(
#' content="Hello from R",
@ -128,16 +136,22 @@ public=list(
#' )
#'
#' # messages in drafts
#' req3 <- graph_request$new("me/mailFolders/drafts/messages")
#' req_get <- graph_request$new("me/mailFolders/drafts/messages")
#'
#' # depends_on signifies that request 3 depends on request 2
#' call_batch_endpoint(token, list(req1, req2, req3), depends_on=list("3"=2))
#' # requests are dependent: 2nd list of drafts will include just-created message
#' call_batch_endpoint(token, list(req_get, req_create, req_get), depends_on=TRUE)
#'
#' # alternate way: enumerate all requests
#' call_batch_endpoint(token, list(req_get, req_create, req_get), depends_on=c("2"=1, "3"=2))
#'
#' }
#' @export
call_batch_endpoint <- function(token, requests=list(), depends_on=list(),
call_batch_endpoint <- function(token, requests=list(), depends_on=NULL,
api_version=getOption("azure_graph_api_version"))
{
if(is_empty(requests))
return(invisible(NULL))
for(req in requests)
if(!inherits(req, "graph_request"))
stop("Must supply a list of request objects", call.=FALSE)
@ -146,9 +160,6 @@ call_batch_endpoint <- function(token, requests=list(), depends_on=list(),
stop("Maximum of 20 requests per batch job", call.=FALSE)
ids <- as.character(seq_along(requests))
id_depends <- names(depends_on)
if(!is_empty(id_depends) && !all(id_depends %in% ids))
stop("'depends_on' should be a named list identifying dependencies")
# populate the batch request body
reqlst <- lapply(requests, function(req) req$batchify())
@ -156,14 +167,21 @@ call_batch_endpoint <- function(token, requests=list(), depends_on=list(),
reqlst[[i]]$id <- as.character(i)
# insert depends_on if required
if(!is_empty(depends_on))
if(isTRUE(depends_on))
{
if(is_empty(names(depends_on)))
names(depends_on) <- seq_along(requests)
for(i in seq_along(requests)[-1])
reqlst[[i]]$dependsOn <- I(as.character(i - 1))
}
else if(!is_empty(depends_on))
{
names_depends <- names(depends_on)
if(is.null(names_depends) || any(names_depends == ""))
stop("'depends_on' should be TRUE or a named vector identifying dependencies")
for(i in seq_along(depends_on))
{
id <- as.numeric(names(depends_on)[i])
reqlst[[id]]$depends_on <- unname(depends_on[i])
id <- as.numeric(names_depends)[i]
reqlst[[id]]$dependsOn <- I(as.character(depends_on[[i]]))
}
}

Просмотреть файл

@ -4,7 +4,7 @@
\alias{call_batch_endpoint}
\title{Call the Graph API batch endpoint}
\usage{
call_batch_endpoint(token, requests = list(), depends_on = list(),
call_batch_endpoint(token, requests = list(), depends_on = NULL,
api_version = getOption("azure_graph_api_version"))
}
\arguments{
@ -12,7 +12,7 @@ call_batch_endpoint(token, requests = list(), depends_on = list(),
\item{requests}{A list of \link{graph_request} objects, representing individual requests to the Graph API.}
\item{depends_on}{An optional named list indicating which requests have dependencies. See the examples below.}
\item{depends_on}{An optional named vector, or TRUE. See below.}
\item{api_version}{The API version to use, which will form part of the URL sent to the host.}
}
@ -24,6 +24,16 @@ Call the Graph API batch endpoint
}
\details{
Use this function to combine multiple requests into a single HTTPS call. This can save significant network latency.
The \code{depends_on} argument specifies the dependencies that may exist between requests. The default is to treat the requests as independent, which allows them to be executed in parallel. If \code{depends_on} is TRUE, each request is specified as depending on the immediately preceding request. Otherwise, this should be a named vector or list that gives the dependency or dependencies for each request.
There are 2 restrictions on \code{depends_on}:
\itemize{
\item If one request has a dependency, then all requests must have dependencies specified
\item A request can only depend on previous requests in the list, not on later ones.
}
A request list that has dependencies will be executed serially.
}
\examples{
\dontrun{
@ -31,7 +41,7 @@ Use this function to combine multiple requests into a single HTTPS call. This ca
req1 <- graph_request$new("me")
# a new email message in Outlook
req2 <- graph_request$new("me/messages",
req_create <- graph_request$new("me/messages",
body=list(
body=list(
content="Hello from R",
@ -44,10 +54,13 @@ req2 <- graph_request$new("me/messages",
)
# messages in drafts
req3 <- graph_request$new("me/mailFolders/drafts/messages")
req_get <- graph_request$new("me/mailFolders/drafts/messages")
# depends_on signifies that request 3 depends on request 2
call_batch_endpoint(token, list(req1, req2, req3), depends_on=list("3"=2))
# requests are dependent: 2nd list of drafts will include just-created message
call_batch_endpoint(token, list(req_get, req_create, req_get), depends_on=TRUE)
# alternate way: enumerate all requests
call_batch_endpoint(token, list(req_get, req_create, req_get), depends_on=c("2"=1, "3"=2))
}
}

Просмотреть файл

@ -46,8 +46,7 @@ test_that("Batch request with dependency works",
req_update <- graph_request$new(file.path("users", user),
body=list(givenName=newname), http_verb="PATCH")
# deliberately out of order
res <- gr$call_batch_endpoint(list(req_update, req_get, req_get), depends_on=c("1"=2, "3"=1))
res <- gr$call_batch_endpoint(list(req_get, req_update, req_get), depends_on=c("2"=1, "3"=2))
expect_is(res, "list")
expect_identical(res[[1]]$id, "1")
expect_identical(res[[2]]$id, "2")
@ -55,6 +54,14 @@ test_that("Batch request with dependency works",
expect_false(identical(res[[1]]$body$givenName, newname))
expect_identical(res[[3]]$body$givenName, newname)
# auto-generated depends_on
newname2 <- paste0(sample(letters, 20, TRUE), collapse="")
req_update2 <- graph_request$new(file.path("users", user),
body=list(givenName=newname2), http_verb="PATCH")
res2 <- gr$call_batch_endpoint(list(req_get, req_update2, req_get), depends_on=TRUE)
expect_false(identical(res2[[1]]$body$givenName, newname2))
expect_identical(res2[[3]]$body$givenName, newname2)
})