Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Rlabkey/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: Rlabkey
Version: 3.4.4
Date: 2025-09-16
Version: 3.4.5
Date: 2026-01-20
Title: Data Exchange Between R and 'LabKey' Server
Authors@R: c(person(given = "Peter",
family = "Hussey",
Expand Down
5 changes: 5 additions & 0 deletions Rlabkey/NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Changes in 3.4.5
o Switch to using path first URLs for LabKey server requests.
o Utilize httr to generate request query parameters.
o labkey.makeFilter will produce a list of named elements using the asList parameter.

Changes in 3.4.4
o Issue 53481: additional validation for assay run configurations.
o Improve validation when a zero-row dataframe is passed to insertRows/updateRows/deleteRows
Expand Down
29 changes: 28 additions & 1 deletion Rlabkey/R/labkey.defaults.R
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ isWafEncoding <- function()
return (.lkdefaults$wafEncode)
}


isRequestError <- function(response, status_code)
{
status_code <- getStatusCode(response)
Expand Down Expand Up @@ -357,4 +356,32 @@ encodeURIComponent <- function(value)
value <- gsub("%28", "(", value)
value <- gsub("%29", ")", value)
return (value)
}

# Construct a LabKey URL (path first format)
labkey.buildURL <- function(baseUrl=NULL, controller, action, folderPath = NULL, parameters = NULL)
{
baseUrl=labkey.getBaseUrl(baseUrl)

# check required parameters
if (missing(baseUrl) || missing(controller) || missing(action) || is.null(folderPath))
stop (paste("A value must be specified for each of baseUrl, controller, action and folderPath."))

# normalize the folder path
folderPath <- encodeFolderPath(folderPath)

myUrl <- paste(baseUrl, folderPath, controller, "-", action, sep="")

if (!is.null(parameters))
{
if (!is.list(parameters))
stop (paste("parameters must be a list data structure."))

# add the parameters as a query string
url <- parse_url(myUrl)
url$query = parameters

myUrl <- build_url(url)
}
return (myUrl)
}
11 changes: 2 additions & 9 deletions Rlabkey/R/labkey.deleteRows.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ labkey.deleteRows <- function(baseUrl=NULL, folderPath, schemaName, queryName, t
if (!missing(options) & !is.list(options))
stop (paste("The options parameter must be a list data structure."))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

## URL encode folder path, JSON encode post body (if not already encoded)
toDelete <- convertFactorsToStrings(toDelete);

Expand All @@ -43,8 +40,7 @@ labkey.deleteRows <- function(baseUrl=NULL, folderPath, schemaName, queryName, t
params <- c(params, options)

pbody <- jsonEncodeRowsAndParams(toDelete, params, NULL)

myurl <- paste(baseUrl, "query", folderPath, "deleteRows.api", sep="")
myurl <- labkey.buildURL(baseUrl, "query", "deleteRows.api", folderPath)

## Execute via our standard POST function
mydata <- labkey.post(myurl, pbody)
Expand All @@ -65,10 +61,7 @@ labkey.truncateTable <- function(baseUrl=NULL, folderPath, schemaName, queryName
if (missing(schemaName)) stop (paste("A value must be specified for schemaName."))
if (missing(queryName)) stop (paste("A value must be specified for queryName."))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

url <- paste(baseUrl, "query", folderPath, "truncateTable.api", sep="")
url <- labkey.buildURL(baseUrl, "query", "truncateTable.api", folderPath)

params <- list(schemaName=schemaName, queryName=queryName)
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))
Expand Down
28 changes: 6 additions & 22 deletions Rlabkey/R/labkey.domain.R
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,7 @@ labkey.domain.get <- function(baseUrl=NULL, folderPath, schemaName, queryName)
if(missing(baseUrl) || is.null(baseUrl) || missing(folderPath) || missing(schemaName) || missing(queryName))
stop (paste("A value must be specified for each of baseUrl, folderPath, schemaName and queryName."))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

url <- paste(baseUrl, "property", folderPath, "getDomain.api", sep="")

url <- labkey.buildURL(baseUrl, "property", "getDomain.api", folderPath)
params <- list(schemaName=schemaName, queryName=queryName)
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))

Expand Down Expand Up @@ -63,11 +59,9 @@ labkey.domain.save <- function(baseUrl=NULL, folderPath, schemaName, queryName,
if (!is.list(domainDesign))
stop (paste("domainDesign must be a list data structure."))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)
params <- list(schemaName = schemaName, queryName = queryName, domainDesign = domainDesign)
url <- labkey.buildURL(baseUrl, "property", "saveDomain.api", folderPath)

url <- paste(baseUrl, "property", folderPath, "saveDomain.api", sep="")
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))

return (fromJSON(response))
Expand Down Expand Up @@ -157,10 +151,7 @@ labkey.domain.create <- function(baseUrl=NULL, folderPath, domainKind=NULL, doma
createDomain = createDomain, importData = importData)
}

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

url <- paste(baseUrl, "property", folderPath, "createDomain.api", sep="")
url <- labkey.buildURL(baseUrl, "property", "createDomain.api", folderPath)
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))

return (fromJSON(response))
Expand All @@ -175,11 +166,7 @@ labkey.domain.drop <- function(baseUrl=NULL, folderPath, schemaName, queryName)
if (missing(schemaName)) stop (paste("A value must be specified for schemaName."))
if (missing(queryName)) stop (paste("A value must be specified for queryName."))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

url <- paste(baseUrl, "property", folderPath, "deleteDomain.api", sep="")

url <- labkey.buildURL(baseUrl, "property", "deleteDomain.api", folderPath)
params <- list(schemaName=schemaName, queryName=queryName)
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))

Expand All @@ -194,17 +181,14 @@ labkey.domain.inferFields <- function(baseUrl=NULL, folderPath, df)
if (missing(baseUrl) || is.null(baseUrl) || missing(folderPath) || missing(df))
stop (paste("A value must be specified for each of baseUrl, folderPath and df."))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

## write the dataframe to a tempfile to post to the server
tf <- tempfile(fileext=".tsv")
write.table(df, file=tf, sep="\t", quote=FALSE, row.names=FALSE)

## Execute via our standard POST function
url <- paste(baseUrl, "property", folderPath, "inferDomain.api", sep="")

url <- labkey.buildURL(baseUrl, "property", "inferDomain.api", folderPath)
rawdata <- labkey.post(url, list(file=upload_file(tf)), encoding="multipart")

## delete the temp file
file.remove(tf)
response <- fromJSON(rawdata)
Expand Down
5 changes: 1 addition & 4 deletions Rlabkey/R/labkey.executeSql.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,8 @@ labkey.executeSql <- function(baseUrl=NULL, folderPath, schemaName, sql, maxRows
if (missing(schemaName)) stop (paste("A value must be specified for schemaName."))
if (missing(sql)) stop (paste("A value must be specified for sql."))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

## Construct url
myurl <- paste(baseUrl, "query", folderPath, "executeSql.api", sep="")
myurl <- labkey.buildURL(baseUrl, "query", "executeSql.api", folderPath)

## Apply wafEncode, if requested
if (isWafEncoding()) sql <- wafEncode(sql)
Expand Down
15 changes: 3 additions & 12 deletions Rlabkey/R/labkey.experiment.R
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,8 @@ labkey.experiment.saveBatch <- function(baseUrl=NULL, folderPath, assayConfig =
if (is.null(assayConfig) && is.null(protocolName))
stop (paste("Either an assay config list or protocolName must be specified. The assay configuration must contain either an assayId or both assayName and providerName"))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

## Now post form with batch object filled out
url <- paste(baseUrl, "assay", folderPath, "saveAssayBatch.api", sep="")
url <- labkey.buildURL(baseUrl, "assay", "saveAssayBatch.api", folderPath)

if (!is.null(assayConfig))
params = assayConfig
Expand All @@ -185,11 +182,8 @@ labkey.experiment.saveRuns <- function(baseUrl=NULL, folderPath, protocolName, r
if (missing(protocolName)) stop (paste("A value must be specified for protocolName."))
if (missing(runList)) stop (paste("A value must be specified for runList."))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

## Now post form with runs object filled out
url <- paste(baseUrl, "assay", folderPath, "saveAssayRuns.api", sep="")
url <- labkey.buildURL(baseUrl, "assay", "saveAssayRuns.api", folderPath)

if (!is.null(runList))
{
Expand Down Expand Up @@ -234,10 +228,7 @@ labkey.experiment.lineage <- function(baseUrl=NULL, folderPath, lsids, options =
if (!missing(options))
params <- c(params, options)

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

url <- paste(baseUrl, "experiment", folderPath, "lineage.api", sep="")
url <- labkey.buildURL(baseUrl, "experiment", "lineage.api", folderPath)
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))

return (fromJSON(response, simplifyVector=FALSE, simplifyDataFrame=FALSE))
Expand Down
30 changes: 21 additions & 9 deletions Rlabkey/R/labkey.getFolders.R
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,33 @@ labkey.getFolders <- function(baseUrl=NULL, folderPath, includeEffectivePermissi
folderPath <- encodeFolderPath(folderPath)

## Formatting
if(includeSubfolders) {inclsf <- paste("1&depth=", depth, sep="")} else {inclsf <- "0"}
if(includeEffectivePermissions) {inclep <- "1"} else {inclep <- "0"}
if(includeChildWorkbooks) {inclcw <- "1"} else {inclcw <- "0"}
params <- list()
if (includeSubfolders)
params <- c(params, list("includeSubfolders"=1, "depth"=depth))
else
params <- c(params, list("includeSubfolders"=0))

if (includeEffectivePermissions)
params <- c(params, list("includeEffectivePermissions"=1))
else
params <- c(params, list("includeEffectivePermissions"=0))

if (includeChildWorkbooks)
params <- c(params, list("includeChildWorkbooks"=1))
else
params <- c(params, list("includeChildWorkbooks"=0))

inclsp <- "0"
resultCols = c("name", "path", "id", "effectivePermissions")
if(includeStandardProperties) {
inclsp <- "1"
if (includeStandardProperties)
{
params <- c(params, list("includeStandardProperties"=1))
resultCols = c("name", "path", "id", "title", "type", "folderType", "effectivePermissions")
}
else
params <- c(params, list("includeStandardProperties"=0))

## Construct url
myurl <- paste(baseUrl,"project",folderPath,"getContainers.view?","includeSubfolders=",inclsf,
"&includeEffectivePermissions=",inclep,"&includeChildWorkbooks=",inclcw,"&includeStandardProperties=",inclsp,
sep="")
myurl <- labkey.buildURL(baseUrl, "project", "getContainers.api", folderPath, params)

## Execute via our standard GET function
mydata <- labkey.get(myurl);
Expand Down
16 changes: 5 additions & 11 deletions Rlabkey/R/labkey.getQueryInfo.R
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,14 @@ getQueryInfo <- function(baseUrl=NULL, folderPath, schemaName, queryName, showDe
if (missing(folderPath)) stop (paste("A value must be specified for folderPath."))
if (missing(schemaName)) stop (paste("A value must be specified for schemaName."))
if (missing(queryName)) stop (paste("A value must be specified for queryName."))
if (is.null(lookupKey)==FALSE) {char <- nchar(lookupKey); if(char<1) {lookupKey<-NULL} }

if(is.null(lookupKey)==FALSE) {char <- nchar(lookupKey); if(char<1) {lookupKey<-NULL} }

## URL encoding (if not already encoded)
if(schemaName==URLdecode(schemaName)) {schemaName <- URLencode(schemaName)}
if(queryName==URLdecode(queryName)) {queryName <- URLencode(queryName)}
if(is.null(lookupKey)==FALSE) {if(lookupKey==URLdecode(lookupKey)) lookupKey <- URLencode(lookupKey)}

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)
params <- list("schemaName"=schemaName, "query.queryName"=queryName, "apiVersion"="8.3")
if (!is.null(lookupKey))
params <- c(params, list("fk"=lookupKey))

## Construct url
myurl <- paste(baseUrl,"query",folderPath,"getQueryDetails.api?schemaName=", schemaName, "&queryName=", queryName, "&apiVersion=8.3", sep="")
if(is.null(lookupKey)==FALSE) {myurl <- paste(myurl,"&fk=",lookupKey,sep="")}
myurl <- labkey.buildURL(baseUrl, "query", "getQueryDetails.api", folderPath, params)

## Execute via our standard GET function
mydata <- labkey.get(myurl)
Expand Down
18 changes: 6 additions & 12 deletions Rlabkey/R/labkey.getQueryLists.R
Original file line number Diff line number Diff line change
Expand Up @@ -34,36 +34,30 @@ labkey.getQueryViews <- function(baseUrl=NULL, folderPath, schemaName, queryName
getQueryLists <- function(baseUrl=NULL, folderPath, schemaName, queryName=NULL)
{
baseUrl=labkey.getBaseUrl(baseUrl)
if((length(queryName)>0) && (queryName==URLdecode(queryName)) ) { queryName <- URLencode(queryName) }

## Validate required parameters
if (missing(folderPath)) stop (paste("A value must be specified for folderPath."))
if (missing(schemaName)) stop (paste("A value must be specified for schemaName."))

## URL encoding of schemaName (if not already encoded)
if(schemaName==URLdecode(schemaName)) {schemaName <- URLencode(schemaName)}

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)
params <- list("schemaName"=schemaName, "apiVersion"="8.3")

## now setup the different columns for views vs queries
if(length(queryName)==0)
if (length(queryName)==0)
{
serverAction <- "getQueries.view?schemaName="
qParam <- ""
serverAction <- "getQueries.api"
queryObjType <- "queries"
columnNames <- c("queryName", "fieldName")
}
else
{
serverAction <- "getQueryViews.api?schemaName="
qParam <- paste("&queryName=",queryName, sep="")
serverAction <- "getQueryViews.api"
params <- c(params, list("queryName"=queryName))
queryObjType <- "views"
columnNames <- c("viewName", "fieldName")
}

## Construct url
myurl <- paste(baseUrl, "query", folderPath, serverAction, schemaName, qParam, "&apiVersion=8.3", sep="")
myurl <- labkey.buildURL(baseUrl, "query", serverAction, folderPath, params)

## Execute via our standard GET function
mydata <- labkey.get(myurl);
Expand Down
6 changes: 2 additions & 4 deletions Rlabkey/R/labkey.getSchemas.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@ labkey.getSchemas <- function(baseUrl=NULL, folderPath)
## Validate required parameters
if (missing(folderPath)) stop (paste("A value must be specified for folderPath."))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

## Construct url
myurl <- paste(baseUrl,"query",folderPath,"getSchemas.view?apiVersion=9.3", sep="")
params <- list("apiVersion"="9.3")
myurl <- labkey.buildURL(baseUrl, "query", "getSchemas.api", folderPath, params)

## Execute via our standard GET function
mydata <- labkey.get(myurl)
Expand Down
5 changes: 1 addition & 4 deletions Rlabkey/R/labkey.importRows.R
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,12 @@ labkey.importRows <- function(baseUrl=NULL, folderPath, schemaName, queryName, t
if (missing(toImport)) stop (paste("A value must be specified for toImport."))
if (nrow(toImport) == 0) stop (paste("toImport must contain at least one row."))

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

## URL encode folder path, JSON encode post body (if not already encoded)
toImport <- convertFactorsToStrings(toImport);
params <- list(schemaName=schemaName, queryName=queryName, apiVersion=8.3)
pbody <- jsonEncodeRowsAndParams(toImport, params, na)

myurl <- paste(baseUrl, "query", folderPath, "importRows.api", sep="")
myurl <- labkey.buildURL(baseUrl, "query", "importRows.api", folderPath)

## Execute via our standard POST function
mydata <- labkey.post(myurl, pbody)
Expand Down
5 changes: 1 addition & 4 deletions Rlabkey/R/labkey.insertRows.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ labkey.insertRows <- function(baseUrl=NULL, folderPath, schemaName, queryName, t
## Default showAllRows=TRUE
showAllRows=TRUE

## normalize the folder path
folderPath <- encodeFolderPath(folderPath)

## URL encode folder path, JSON encode post body (if not already encoded)
toInsert <- convertFactorsToStrings(toInsert);

Expand All @@ -44,7 +41,7 @@ labkey.insertRows <- function(baseUrl=NULL, folderPath, schemaName, queryName, t

pbody <- jsonEncodeRowsAndParams(toInsert, params, na)

myurl <- paste(baseUrl, "query", folderPath, "insertRows.api", sep="")
myurl <- labkey.buildURL(baseUrl, "query", "insertRows.api", folderPath)

## Execute via our standard POST function
mydata <- labkey.post(myurl, pbody)
Expand Down
Loading