Merge branch 'master' of git.curoverse.com:arvados into 11876-r-sdk
authorFuad Muhic <fmuhic@capeannenterprises.com>
Mon, 11 Dec 2017 16:36:50 +0000 (17:36 +0100)
committerFuad Muhic <fmuhic@capeannenterprises.com>
Mon, 11 Dec 2017 16:36:50 +0000 (17:36 +0100)
Arvados-DCO-1.1-Signed-off-by: Fuad Muhic <fmuhic@capeannenterprises.com>

18 files changed:
.gitignore
sdk/R/.RData [new file with mode: 0644]
sdk/R/.Rbuildignore [new file with mode: 0644]
sdk/R/ArvadosSDK.Rproj [new file with mode: 0644]
sdk/R/DESCRIPTION [new file with mode: 0644]
sdk/R/NAMESPACE [new file with mode: 0644]
sdk/R/R/Arvados.R [new file with mode: 0644]
sdk/R/R/ArvadosFile.R [new file with mode: 0644]
sdk/R/R/Collection.R [new file with mode: 0644]
sdk/R/R/HttpParser.R [new file with mode: 0644]
sdk/R/R/HttpRequest.R [new file with mode: 0644]
sdk/R/R/Subcollection.R [new file with mode: 0644]
sdk/R/README [new file with mode: 0644]
sdk/R/man/Arvados.Rd [new file with mode: 0644]
sdk/R/man/ArvadosFile.Rd [new file with mode: 0644]
sdk/R/man/Collection.Rd [new file with mode: 0644]
sdk/R/man/HttpParser.Rd [new file with mode: 0644]
sdk/R/man/Subcollection.Rd [new file with mode: 0644]

index e61f485237b6b1145e3527982d0fbbbadaf56727..d41eaeea5fa6ee53fef1dedf2e7c37440c844cfb 100644 (file)
@@ -27,3 +27,4 @@ services/api/config/arvados-clients.yml
 *#*
 .DS_Store
 .vscode
+.Rproj.user
diff --git a/sdk/R/.RData b/sdk/R/.RData
new file mode 100644 (file)
index 0000000..b08e775
Binary files /dev/null and b/sdk/R/.RData differ
diff --git a/sdk/R/.Rbuildignore b/sdk/R/.Rbuildignore
new file mode 100644 (file)
index 0000000..91114bf
--- /dev/null
@@ -0,0 +1,2 @@
+^.*\.Rproj$
+^\.Rproj\.user$
diff --git a/sdk/R/ArvadosSDK.Rproj b/sdk/R/ArvadosSDK.Rproj
new file mode 100644 (file)
index 0000000..a648ce1
--- /dev/null
@@ -0,0 +1,20 @@
+Version: 1.0
+
+RestoreWorkspace: Default
+SaveWorkspace: Default
+AlwaysSaveHistory: Default
+
+EnableCodeIndexing: Yes
+UseSpacesForTab: Yes
+NumSpacesForTab: 4
+Encoding: UTF-8
+
+RnwWeave: Sweave
+LaTeX: pdfLaTeX
+
+AutoAppendNewline: Yes
+StripTrailingWhitespace: Yes
+
+BuildType: Package
+PackageUseDevtools: Yes
+PackageInstallArgs: --no-multiarch --with-keep.source
diff --git a/sdk/R/DESCRIPTION b/sdk/R/DESCRIPTION
new file mode 100644 (file)
index 0000000..b0343c7
--- /dev/null
@@ -0,0 +1,19 @@
+Package: ArvadosSDK
+Type: Package
+Title: What the Package Does (Title Case)
+Version: 0.1.0
+Author: Who wrote it
+Maintainer: The package maintainer <yourself@somewhere.net>
+Description: More about what it does (maybe more than one line)
+    Use four spaces when indenting paragraphs within the Description.
+License: What license is it under?
+Encoding: UTF-8
+LazyData: true
+RoxygenNote: 6.0.1.9000
+Imports:
+    R6,
+    httr,
+    stringr,
+    jsonlite,
+    curl,
+    XML
diff --git a/sdk/R/NAMESPACE b/sdk/R/NAMESPACE
new file mode 100644 (file)
index 0000000..411deb8
--- /dev/null
@@ -0,0 +1,6 @@
+# Generated by roxygen2: do not edit by hand
+
+export(Arvados)
+export(ArvadosFile)
+export(Collection)
+export(Subcollection)
diff --git a/sdk/R/R/Arvados.R b/sdk/R/R/Arvados.R
new file mode 100644 (file)
index 0000000..196fcfb
--- /dev/null
@@ -0,0 +1,150 @@
+source("./R/HttpRequest.R")
+source("./R/HttpParser.R")
+
+#' Arvados SDK Object
+#'
+#' All Arvados logic is inside this class
+#'
+#' @field token Token represents user authentification token.
+#' @field host Host represents server name we wish to connect to.
+#' @examples arv = Arvados$new("token", "host_name")
+#' @export Arvados
+Arvados <- R6::R6Class(
+
+    "Arvados",
+
+    public = list(
+
+        initialize = function(auth_token = NULL, host_name = NULL) 
+        {
+            if(!is.null(host_name))
+               Sys.setenv(ARVADOS_API_HOST  = host_name)
+
+            if(!is.null(auth_token))
+                Sys.setenv(ARVADOS_API_TOKEN = auth_token)
+
+            host  <- Sys.getenv("ARVADOS_API_HOST");
+            token <- Sys.getenv("ARVADOS_API_TOKEN");
+
+            if(host == "" | token == "")
+                stop("Please provide host name and authentification token or set ARVADOS_API_HOST and ARVADOS_API_TOKEN environmental variables.")
+
+            discoveryDocumentURL <- paste0("https://", host, "/discovery/v1/apis/arvados/v1/rest")
+
+            version <- "v1"
+            host  <- paste0("https://", host, "/arvados/", version, "/")
+
+            private$http <- HttpRequest$new()
+            private$httpParser <- HttpParser$new()
+            private$token <- token
+            private$host <- host
+            
+            headers <- list(Authorization = paste("OAuth2", private$token))
+
+            serverResponse <- private$http$GET(discoveryDocumentURL, headers)
+
+            discoveryDocument <- private$httpParser$parseJSONResponse(serverResponse)
+            private$webDavHostName <- discoveryDocument$keepWebServiceUrl
+            print(private$webDavHostName)
+        },
+
+        getToken    = function() private$token,
+        getHostName = function() private$host,
+
+        #Todo(Fudo): Hardcoded credentials to WebDAV server. Remove them later
+        getWebDavHostName = function() private$webDavHostName,
+
+        getCollection = function(uuid) 
+        {
+            collectionURL <- paste0(private$host, "collections/", uuid)
+            headers <- list(Authorization = paste("OAuth2", private$token))
+
+            serverResponse <- private$http$GET(collectionURL, headers)
+
+            collection <- private$httpParser$parseJSONResponse(serverResponse)
+
+            if(!is.null(collection$errors))
+                stop(collection$errors)       
+
+            collection
+        },
+
+        listCollections = function(filters = NULL, limit = 100, offset = 0) 
+        {
+            collectionURL <- paste0(private$host, "collections")
+            headers <- list(Authorization = paste("OAuth2", private$token))
+
+            serverResponse <- private$http$GET(collectionURL, headers, NULL, filters, limit, offset)
+
+            collection <- private$httpParser$parseJSONResponse(serverResponse)
+
+            if(!is.null(collection$errors))
+                stop(collection$errors)       
+
+            collection
+        },
+
+        deleteCollection = function(uuid) 
+        {
+            collectionURL <- paste0(private$host, "collections/", uuid)
+            headers <- list("Authorization" = paste("OAuth2", private$token),
+                            "Content-Type"  = "application/json")
+
+            serverResponse <- private$http$DELETE(collectionURL, headers)
+
+            collection <- private$httpParser$parseJSONResponse(serverResponse)
+
+            if(!is.null(collection$errors))
+                stop(collection$errors)       
+
+            collection
+        },
+
+        updateCollection = function(uuid, body) 
+        {
+            collectionURL <- paste0(private$host, "collections/", uuid)
+            headers <- list("Authorization" = paste("OAuth2", private$token),
+                            "Content-Type"  = "application/json")
+
+            body <- jsonlite::toJSON(body, auto_unbox = T)
+
+            serverResponse <- private$http$PUT(collectionURL, headers, body)
+
+            collection <- private$httpParser$parseJSONResponse(serverResponse)
+
+            if(!is.null(collection$errors))
+                stop(collection$errors)       
+
+            collection
+        },
+
+        createCollection = function(body) 
+        {
+            collectionURL <- paste0(private$host, "collections")
+            headers <- list("Authorization" = paste("OAuth2", private$token),
+                            "Content-Type"  = "application/json")
+            body <- jsonlite::toJSON(body, auto_unbox = T)
+
+            serverResponse <- private$http$POST(collectionURL, headers, body)
+
+            collection <- private$httpParser$parseJSONResponse(serverResponse)
+
+            if(!is.null(collection$errors))
+                stop(collection$errors)       
+
+            collection
+        }
+
+    ),
+    
+    private = list(
+
+        token          = NULL,
+        host           = NULL,
+        webDavHostName = NULL,
+        http           = NULL,
+        httpParser     = NULL
+    ),
+    
+    cloneable = FALSE
+)
diff --git a/sdk/R/R/ArvadosFile.R b/sdk/R/R/ArvadosFile.R
new file mode 100644 (file)
index 0000000..f7c45dc
--- /dev/null
@@ -0,0 +1,61 @@
+#' ArvadosFile Object
+#'
+#' Update description
+#'
+#' @export ArvadosFile
+ArvadosFile <- R6::R6Class(
+
+    "ArvadosFile",
+
+    public = list(
+
+        initialize = function(name, relativePath, api, collection)
+        {
+            private$name         <- name
+            private$relativePath <- relativePath
+            private$api          <- api
+            private$collection   <- collection
+            private$http         <- HttpRequest$new()
+            private$httpParser   <- HttpParser$new()
+        },
+
+        getName = function() private$name,
+
+        getRelativePath = function() private$relativePath,
+
+        read = function(offset = 0, length = 0)
+        {
+            if(offset < 0 || length < 0)
+            stop("Offset and length must be positive values.")
+
+            range = paste0("bytes=", offset, "-")
+
+            if(length > 0)
+                range = paste0(range, offset + length - 1)
+            
+            fileURL = paste0(private$api$getWebDavHostName(), "c=", private$collection$uuid, "/", private$relativePath);
+            headers <- list(Authorization = paste("OAuth2", private$api$getToken()), 
+                            Range = range)
+
+            #TODO(Fudo): Move this to HttpRequest.R
+            # serverResponse <- httr::GET(url = fileURL,
+                                        # config = httr::add_headers(unlist(headers)))
+            serverResponse <- private$http$GET(fileURL, headers)
+            parsed_response <- httr::content(serverResponse, "raw")
+
+        }
+    ),
+
+    private = list(
+
+        name         = NULL,
+        relativePath = NULL,
+        parent       = NULL,
+        api          = NULL,
+        collection   = NULL,
+        http         = NULL,
+        httpParser   = NULL
+    ),
+    
+    cloneable = FALSE
+)
diff --git a/sdk/R/R/Collection.R b/sdk/R/R/Collection.R
new file mode 100644 (file)
index 0000000..c372bc2
--- /dev/null
@@ -0,0 +1,336 @@
+source("./R/Subcollection.R")
+source("./R/ArvadosFile.R")
+
+#' Arvados Collection Object
+#'
+#' Update description
+#'
+#' @examples arv = Collection$new(api, uuid)
+#' @export Collection
+Collection <- R6::R6Class(
+
+    "Collection",
+
+    public = list(
+
+        #Todo(Fudo): Encapsulate this?
+        uuid                     = NULL,
+        etag                     = NULL,
+        owner_uuid               = NULL,
+        created_at               = NULL,
+        modified_by_client_uuid  = NULL,
+        modified_by_user_uuid    = NULL,
+        modified_at              = NULL,
+        portable_data_hash       = NULL,
+        replication_desired      = NULL,
+        replication_confirmed_at = NULL,
+        replication_confirmed    = NULL,
+        updated_at               = NULL,
+        manifest_text            = NULL,
+        name                     = NULL,
+        description              = NULL,
+        properties               = NULL,
+        delete_at                = NULL,
+        file_names               = NULL,
+        trash_at                 = NULL,
+        is_trashed               = NULL,
+
+        initialize = function(api, uuid)
+        {
+            private$api <- api
+            result <- private$api$getCollection(uuid)
+
+            self$uuid                     <- result$uuid                               
+            self$etag                     <- result$etag                               
+            self$owner_uuid               <- result$owner_uuid                         
+            self$created_at               <- result$created_at                         
+            self$modified_by_client_uuid  <- result$modified_by_client_uuid            
+            self$modified_by_user_uuid    <- result$modified_by_user_uuid              
+            self$modified_at              <- result$modified_at                        
+            self$portable_data_hash       <- result$portable_data_hash                 
+            self$replication_desired      <- result$replication_desired                
+            self$replication_confirmed_at <- result$replication_confirmed_at           
+            self$replication_confirmed    <- result$replication_confirmed              
+            self$updated_at               <- result$updated_at                         
+            self$manifest_text            <- result$manifest_text                      
+            self$name                     <- result$name                               
+            self$description              <- result$description                        
+            self$properties               <- result$properties                         
+            self$delete_at                <- result$delete_at                          
+            self$file_names               <- result$file_names                         
+            self$trash_at                 <- result$trash_at                           
+            self$is_trashed               <- result$is_trashed                         
+
+            #Todo(Fudo): Replace this when you get access to webDAV server.
+            private$fileItems <- private$getCollectionContent()
+
+            private$fileTree <- private$generateTree(private$fileItems)
+        },
+
+        printFileContent = function(pretty = TRUE)
+        {
+            if(pretty)
+                private$fileTree$printContent(0)
+            else
+                print(private$fileItems)
+
+        },
+
+        get = function(relativePath)
+        {
+            treeNode <- private$traverseInOrder(private$fileTree, function(node)
+            {
+                if(node$relativePath == relativePath)
+                    return(node)
+                else
+                    return(NULL)
+            })
+
+            if(!is.null(treeNode))
+            {
+                return(private$createSubcollectionTree(treeNode))
+            }
+            else
+            {
+                return(NULL)
+            }
+        }
+    ),
+
+    active = list(
+        items = function(value)
+        {
+            if(missing(value))
+                return(private$fileItems)
+            else
+                print("Value is read-only.")
+
+            return(NULL)
+        }
+    ),
+    
+    private = list(
+
+        api       = NULL,
+        fileItems = NULL,
+        fileTree  = NULL,
+
+        createSubcollectionTree = function(treeNode)
+        {
+            if(treeNode$hasChildren())
+            {
+                children = NULL
+
+                for(child in treeNode$children)
+                {
+                    child <- private$createSubcollectionTree(child)
+                    children <- c(children, child)                   
+                }
+
+                return(Subcollection$new(treeNode$name, treeNode$relativePath, children))
+            }
+            else
+            {
+                if(treeNode$type == "file")
+                    return(ArvadosFile$new(treeNode$name, treeNode$relativePath, private$api, self))
+                else if(treeNode$type == "folder" || treeNode$type == "root")
+                    return(Subcollection$new(treeNode$name, treeNode$relativePath, NULL))
+            }
+        },
+
+        createSubcollectionFromNode = function(treeNode, children)
+        {
+            subcollection = NULL
+            if(treeNode$type == "file")
+                subcollection = ArvadosFile$new(treeNode$name, treeNode$relativePath)
+            else if(treeNode$type == "folder" || treeNode$type == "root")
+                subcollection = Subcollection$new(treeNode$name, treeNode$relativePath, children)
+            
+            subcollection
+        },
+
+        getCollectionContent = function()
+        {
+            #TODO(Fudo): Use proper URL here.
+            uri <- URLencode(paste0(private$api$getWebDavHostName(), "c=", self$uuid))
+
+            # fetch directory listing via curl and parse XML response
+            h <- curl::new_handle()
+            curl::handle_setopt(h, customrequest = "PROPFIND")
+
+            #TODO(Fudo): Use proper token here.
+            curl::handle_setheaders(h, "Authorization" = paste("OAuth2", private$api$getToken()))
+            response <- curl::curl_fetch_memory(uri, h)
+            print(response)
+
+            HttpParser$new()$parseWebDAVResponse(response, uri)
+        },
+
+        #Todo(Fudo): Move tree creation to another file.
+        generateTree = function(collectionContent)
+        {
+            treeBranches <- sapply(collectionContent, function(filePath)
+            {
+                splitPath <- unlist(strsplit(filePath, "/", fixed = TRUE))
+
+                pathEndsWithSlash <- substr(filePath, nchar(filePath), nchar(filePath)) == "/"
+                
+                branch = private$createBranch(splitPath, pathEndsWithSlash)      
+            })
+
+            root <- TreeNode$new("./", "root")
+            root$relativePath = ""
+
+            sapply(treeBranches, function(branch)
+            {
+                private$addNode(root, branch)
+            })
+
+            root
+        },
+
+        createBranch = function(splitPath, pathEndsWithSlash)
+        {
+            branch <- NULL
+            lastElementIndex <- length(splitPath)
+            
+            lastElementInPathType = "file"
+            if(pathEndsWithSlash)
+                lastElementInPathType = "folder"
+
+            for(elementIndex in lastElementIndex:1)
+            {
+                if(elementIndex == lastElementIndex)
+                {
+                    branch = TreeNode$new(splitPath[[elementIndex]], lastElementInPathType)
+                }
+                else
+                {
+                    newFolder = TreeNode$new(splitPath[[elementIndex]], "folder")
+                    newFolder$addChild(branch)
+                    branch = newFolder
+                }
+
+                branch$relativePath <- paste(unlist(splitPath[1:elementIndex]), collapse = "/")
+            }
+
+            branch
+        },
+
+        addNode = function(container, node)
+        {
+            child = container$getChild(node$name)
+
+            if(is.null(child))
+            {
+                container$addChild(node)
+            }
+            else
+            {
+                private$addNode(child, node$getFirstChild())
+            }
+        },
+
+        traverseInOrder = function(node, predicate)
+        {
+            if(node$hasChildren())
+            {
+                result <- predicate(node)
+
+                if(!is.null(result))
+                    return(result)               
+
+                for(child in node$children)
+                {
+                    result <- private$traverseInOrder(child, predicate)
+
+                    if(!is.null(result))
+                        return(result)
+                }
+
+                return(NULL)
+            }
+            else
+            {
+                return(predicate(node))
+            }
+        }
+
+    ),
+
+    cloneable = FALSE
+)
+
+TreeNode <- R6::R6Class(
+
+    "TreeNode",
+
+    public = list(
+
+        name = NULL,
+        relativePath = NULL,
+        children = NULL,
+        parent = NULL,
+        type = NULL,
+
+        initialize = function(name, type)
+        {
+            if(type == "folder")
+                name <- paste0(name, "/")
+
+            self$name <- name
+            self$type <- type
+            self$children <- list()
+        },
+
+        addChild = function(node)
+        {
+            self$children <- c(self$children, node)
+            node$setParent(self)
+            self
+        },
+
+        setParent = function(parent)
+        {
+            self$parent = parent
+        },
+
+        getChild = function(childName)
+        {
+            for(child in self$children)
+            {
+                if(childName == child$name)
+                    return(child)
+            }
+
+            return(NULL)
+        },
+
+        hasChildren = function()
+        {
+            if(length(self$children) != 0)
+                return(TRUE)
+            else
+                return(FALSE)
+        },
+
+        getFirstChild = function()
+        {
+            if(!self$hasChildren())
+                return(NULL)
+            else
+                return(self$children[[1]])
+        },
+
+        printContent = function(depth)
+        {
+            indentation <- paste(rep("....", depth), collapse = "")
+            print(paste0(indentation, self$name))
+            
+            for(child in self$children)
+                child$printContent(depth + 1)
+        }
+    ),
+
+    cloneable = FALSE
+)
diff --git a/sdk/R/R/HttpParser.R b/sdk/R/R/HttpParser.R
new file mode 100644 (file)
index 0000000..d54207e
--- /dev/null
@@ -0,0 +1,36 @@
+#' HttpParser
+#'
+HttpParser <- R6::R6Class(
+
+    "HttrParser",
+
+    public = list(
+        initialize = function() 
+        {
+        },
+
+        parseJSONResponse = function(serverResponse) 
+        {
+            parsed_response <- httr::content(serverResponse, as = "parsed", type = "application/json")
+        },
+
+        #Todo(Fudo): Test this.
+        parseWebDAVResponse = function(response, uri)
+        {
+            text <- rawToChar(response$content)
+            print(text)
+            doc <- XML::xmlParse(text, asText=TRUE)
+
+            # calculate relative paths
+            base <- paste(paste("/", strsplit(uri, "/")[[1]][-1:-3], sep="", collapse=""), "/", sep="")
+            result <- unlist(
+                XML::xpathApply(doc, "//D:response/D:href", function(node) {
+                    sub(base, "", URLdecode(XML::xmlValue(node)), fixed=TRUE)
+                })
+            )
+            result <- result[result != ""]
+
+            result[-1]
+        }
+    )
+)
diff --git a/sdk/R/R/HttpRequest.R b/sdk/R/R/HttpRequest.R
new file mode 100644 (file)
index 0000000..ea46bea
--- /dev/null
@@ -0,0 +1,125 @@
+HttpRequest <- R6::R6Class(
+
+    "HttrRequest",
+
+    public = list(
+
+        initialize = function() 
+        {
+        },
+
+        GET = function(url, headers = NULL, body = NULL,
+                       queryFilters = NULL, limit = NULL, offset = NULL)
+        {
+            headers <- httr::add_headers(unlist(headers))
+            query <- private$createQuery(queryFilters, limit, offset)
+            url <- paste0(url, query)
+
+            serverResponse <- httr::GET(url = url, config = headers)
+        },
+
+        PUT = function(url, headers = NULL, body = NULL,
+                       queryFilters = NULL, limit = 100, offset = 0)
+        {
+            headers <- httr::add_headers(unlist(headers))
+            query <- private$createQuery(queryFilters, limit, offset)
+            url <- paste0(url, query)
+
+            serverResponse <- httr::PUT(url = url, config = headers, body = body)
+        },
+
+        POST = function(url, headers = NULL, body = NULL,
+                        queryFilters = NULL, limit = 100, offset = 0)
+        {
+            headers <- httr::add_headers(unlist(headers))
+            query <- private$createQuery(queryFilters, limit, offset)
+            url <- paste0(url, query)
+
+            serverResponse <- httr::POST(url = url, config = headers, body = body)
+        },
+
+        DELETE = function(url, headers = NULL, body = NULL,
+                          queryFilters = NULL, limit = NULL, offset = NULL)
+        {
+            headers <- httr::add_headers(unlist(headers))
+            query <- private$createQuery(queryFilters, limit, offset)
+            url <- paste0(url, query)
+
+            serverResponse <- httr::DELETE(url = url, config = headers)
+        }
+    ),
+
+    private = list(
+
+        #Todo(Fudo): Refactor this and find a better way to build
+        # Python array from R list (recursion?)
+        createQuery = function(filters, limit, offset)
+        {
+            finalQuery <- "?alt=json"
+
+            if(!is.null(filters))
+            {
+                filters <- sapply(filters, function(filter)
+                {
+                    if(length(filter) != 3)
+                        stop("Filter list must have exacthey 3 elements.")
+
+                    attributeAndOperator = filter[c(1, 2)]
+                    filterList = filter[[3]]
+                    filterListIsPrimitive = TRUE
+                    if(length(filterList) > 1)
+                        filterListIsPrimitive = FALSE
+
+                    attributeAndOperator <- sapply(attributeAndOperator, function(component) {
+                        component <- paste0("\"", component, "\"")
+                    })
+
+                    filterList <- sapply(unlist(filterList), function(filter) {
+                        filter <- paste0("\"", filter, "\"")
+                    })
+
+                    filterList <- paste(filterList, collapse = ",+")
+
+                    if(!filterListIsPrimitive)
+                        filterList <- paste0("[", filterList, "]")
+
+                    filter <- c(attributeAndOperator, filterList)
+
+                    queryParameter <- paste(filter, collapse = ",+")
+                    queryParameter <- paste0("[", queryParameter, "]")
+        
+                })
+
+                filters <- paste(filters, collapse = ",+")
+                filters <- paste0("[", filters, "]")
+
+                encodedQuery <- URLencode(filters, reserved = T, repeated = T)
+
+                finalQuery <- paste0(finalQuery, "&filters=", encodedQuery)
+
+                #Todo(Fudo): This is a hack for now. Find a proper solution.
+                finalQuery <- stringr::str_replace_all(finalQuery, "%2B", "+")
+            }
+
+            if(!is.null(limit))
+            {
+                if(!is.numeric(limit))
+                    stop("Limit must be a numeric type.")
+                
+                finalQuery <- paste0(finalQuery, "&limit=", limit)
+            }
+
+            if(!is.null(offset))
+            {
+                if(!is.numeric(offset))
+                    stop("Offset must be a numeric type.")
+                
+                finalQuery <- paste0(finalQuery, "&offset=", offset)
+            }
+
+            finalQuery
+        }
+    ),
+
+    cloneable = FALSE
+)
diff --git a/sdk/R/R/Subcollection.R b/sdk/R/R/Subcollection.R
new file mode 100644 (file)
index 0000000..4053546
--- /dev/null
@@ -0,0 +1,35 @@
+#' Arvados SubCollection Object
+#'
+#' Update description
+#'
+#' @export Subcollection
+Subcollection <- R6::R6Class(
+
+    "Subcollection",
+
+    public = list(
+
+        initialize = function(name, relativePath, children)
+        {
+            private$name <- name
+            private$relativePath <- relativePath
+            private$children <- children
+        },
+
+        getName = function() private$name,
+
+        getRelativePath = function() private$relativePath,
+
+        setParent = function(parent) private$parent <- parent
+    ),
+
+    private = list(
+
+        name = NULL,
+        relativePath = NULL,
+        children = NULL,
+        parent = NULL
+    ),
+    
+    cloneable = FALSE
+)
diff --git a/sdk/R/README b/sdk/R/README
new file mode 100644 (file)
index 0000000..6f4e31e
--- /dev/null
@@ -0,0 +1,82 @@
+R SDK for Arvados
+
+Examples of usage:
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#Initialize API:
+
+arv <- Arvados$new("insert_token", "insert_host_name")
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#Get collection:
+
+arv$getCollection("uuid")
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#List collections:
+
+collectionList <- arv$listCollections(list("uuid", "=" "aaaaa-bbbbb-ccccccccccccccc"), limit = 10, offset = 2)
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#Delete collection:
+
+deletedCollection <- arv$deleteCollection("uuid")
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#Update collection:
+
+updatedCollection <- arv$updateCollection("uuid", list(collection = list(name = "new_name", description = "new_desciption")))
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#Create collection:
+
+updatedCollection <- arv$createCollection("uuid", list(collection = list(name = "new_name", description = "new_desciption")))
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#Collection manipulation:
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#Create collection object:
+
+arv <- Arvados$new("insert_token", "insert_host_name")
+collection <- Collection$new(arv, "uuid")
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#Print content of the collection
+
+collection$printFileContent()
+
+#of if you just want a list of relative paths:
+
+collection$printFileContent(pretty = FALSE)
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#This will return ArvadosFile or Subcollection from internal tree-like structure.
+
+arvadosFile <- collection$get("location/to/my/file.cpp")
+
+#or
+
+arvadosSubcollection <- collection.get("location/to/my/directory/")
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+#Read whole file or just a portion of it.
+
+arvadosFile$read(offset = 1024, length = 512)
+
+--------------------------------------------------------------------------------------------------------------------------------
diff --git a/sdk/R/man/Arvados.Rd b/sdk/R/man/Arvados.Rd
new file mode 100644 (file)
index 0000000..6dfb0ce
--- /dev/null
@@ -0,0 +1,25 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/Arvados.R
+\docType{data}
+\name{Arvados}
+\alias{Arvados}
+\title{Arvados SDK Object}
+\format{An object of class \code{R6ClassGenerator} of length 24.}
+\usage{
+Arvados
+}
+\description{
+All Arvados logic is inside this class
+}
+\section{Fields}{
+
+\describe{
+\item{\code{token}}{Token represents user authentification token.}
+
+\item{\code{host}}{Host represents server name we wish to connect to.}
+}}
+
+\examples{
+arv = Arvados$new("token", "host_name")
+}
+\keyword{datasets}
diff --git a/sdk/R/man/ArvadosFile.Rd b/sdk/R/man/ArvadosFile.Rd
new file mode 100644 (file)
index 0000000..f48a71f
--- /dev/null
@@ -0,0 +1,14 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/ArvadosFile.R
+\docType{data}
+\name{ArvadosFile}
+\alias{ArvadosFile}
+\title{ArvadosFile Object}
+\format{An object of class \code{R6ClassGenerator} of length 24.}
+\usage{
+ArvadosFile
+}
+\description{
+Update description
+}
+\keyword{datasets}
diff --git a/sdk/R/man/Collection.Rd b/sdk/R/man/Collection.Rd
new file mode 100644 (file)
index 0000000..46c76cb
--- /dev/null
@@ -0,0 +1,17 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/Collection.R
+\docType{data}
+\name{Collection}
+\alias{Collection}
+\title{Arvados Collection Object}
+\format{An object of class \code{R6ClassGenerator} of length 24.}
+\usage{
+Collection
+}
+\description{
+Update description
+}
+\examples{
+arv = Collection$new(api, uuid)
+}
+\keyword{datasets}
diff --git a/sdk/R/man/HttpParser.Rd b/sdk/R/man/HttpParser.Rd
new file mode 100644 (file)
index 0000000..68d314f
--- /dev/null
@@ -0,0 +1,14 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/HttpParser.R
+\docType{data}
+\name{HttpParser}
+\alias{HttpParser}
+\title{HttpParser}
+\format{An object of class \code{R6ClassGenerator} of length 24.}
+\usage{
+HttpParser
+}
+\description{
+HttpParser
+}
+\keyword{datasets}
diff --git a/sdk/R/man/Subcollection.Rd b/sdk/R/man/Subcollection.Rd
new file mode 100644 (file)
index 0000000..e644e02
--- /dev/null
@@ -0,0 +1,14 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/Subcollection.R
+\docType{data}
+\name{Subcollection}
+\alias{Subcollection}
+\title{Arvados SubCollection Object}
+\format{An object of class \code{R6ClassGenerator} of length 24.}
+\usage{
+Subcollection
+}
+\description{
+Update description
+}
+\keyword{datasets}