Commit 8ca6c431 authored by illo's avatar illo
Browse files

Initial commit

parents
Pipeline #233366304 passed with stage
in 15 seconds
^.*\.Rproj$
^\.Rproj\.user$
^_pkgdown\.yml$
^docs$
^pkgdown$
^LICENSE\.md$
^mongopipe\.Rproj$
^README\.Rmd$
^cran-comments\.md$
^\.github$
^\.gitlab-ci\.yml
.Rproj.user
.Rhistory
.Rdata
.httr-oauth
.DS_Store
image: alpine:latest
pages:
stage: deploy
script:
mv docs public
artifacts:
paths:
- public
only:
- master
Package: mongopipe
Title: Translate R code into Mongo aggregation pipelines
Version: 0.0.0.9000
Authors@R:
person(given = "Oliver",
family = "Haag",
role = c("aut", "cre"),
email = "oliver_haag@e.mail.de")
Description: Translate R code into Mongo aggregation pipelines.
License: MIT + file LICENSE
Suggests:
testthat (>= 3.0.0),
mongolite (>= 2.2.0),
dotenv (>= 1.0.2),
nycflights13
Config/testthat/edition: 3
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.1
Remotes:
jeroen/mongolite,
gaborcsardi/dotenv
Imports:
magrittr,
jsonlite,
rlang
YEAR: 2020
COPYRIGHT HOLDER: mongopipe authors
# MIT License
Copyright (c) 2020 mongopipe authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Generated by roxygen2: do not edit by hand
S3method(add_stage,default)
S3method(add_stage,mongopipe)
S3method(field,mongopipe)
S3method(limit,mongopipe)
S3method(lookup,mongopipe)
S3method(match,mongopipe)
S3method(print,mongopipe)
S3method(project,mongopipe)
S3method(unwind,mongopipe)
export("%>%")
export(add_stage)
export(condition)
export(field)
export(limit)
export(lookup)
export(match)
export(mongopipe)
export(project)
export(unwind)
importFrom(jsonlite,toJSON)
importFrom(jsonlite,unbox)
importFrom(magrittr,"%>%")
importFrom(rlang,abort)
#' Conditional expression ($cond)
#'
#' Evaluates a boolean expression to return one of the two specified return expressions.
#'
#' @param test Expression which returns a boolean value.
#' @param yes Return this if the test returns true.
#' @param no Return this if the test returns false.
#'
#' @examples
#' \dontrun{
#' cond <- condition(test = list("$isArray"="$chart"), yes = list("$size"="$chart"), no = 0)
#' jsonlite::toJSON(cond)
#' }
#'
#' @export
condition <- function(test, yes, no) {
query <- check_query(list("if"=test, "then"=yes, "else"=no))
structure(list("$cond" = query), class=c("mongo_operator", "list"))
}
#' Pipeline Stages
#'
#' These functions translate R code to json readably by mongodb.
#'
#' @param x Object of class mongo
#' @param ... list object
#' @export
match <- function(x, ...) {
UseMethod("match")
}
#' @rdname match
#' @export
match.mongopipe <- function(x, ...) {
add_stage(x, "$match", list(...))
}
#' @rdname match
#' @export
field <-function(x, ...) {
UseMethod("field")
}
#' @rdname match
#' @export
field.mongopipe <- function(x, ...) {
add_stage(x, "$addFields", list(...))
}
#' @rdname match
#'
#' @param from Collection to join
#' @param local_field Field from the input documents
#' @param foreign_field Field from the documents of the "from" collection
#' @param as Name of output array field (Default: `from`)
#'
#' @export
lookup <-function(x, ...) {
UseMethod("lookup")
}
#' @rdname match
#' @export
lookup.mongopipe <- function(x, from, local_field=from, foreign_field="_id", as=from, ...) {
add_stage(x, "$lookup", list(from=from, localField=local_field, foreignField=foreign_field, as=as))
}
#' @rdname match
#' @export
unwind <-function(x, ...) {
UseMethod("unwind")
}
#' @rdname match
#'
#' @param field Field to unwind.
#'
#' @export
unwind.mongopipe <- function(x, field, ...) {
if(!grepl("^\\$.*", field, perl = T)) {
field <- paste0("$", field)
}
add_stage(x, "$unwind", field)
}
#' @rdname match
#' @export
limit <-function(x, ...) {
UseMethod("limit")
}
#' @rdname match
#'
#' @param limit Integer to limit the number of documents.
#'
#' @export
limit.mongopipe <- function(x, limit, ...) {
add_stage(x, "$limit", limit)
}
#' @rdname match
#' @export
project <-function(x, ...) {
UseMethod("project")
}
#' @rdname match
#' @export
project.mongopipe <- function(x, ...) {
add_stage(x, "$project", list(...))
}
#' @keywords internal
#' @importFrom rlang abort
#' @aliases mongopipe-package
"_PACKAGE"
#' Mongopipe
#'
#' @return Object of type mongopipe.
#' @rdname mongopipe-function
#' @export
mongopipe <- function() {
structure("{}", class=c("character","mongopipe"), pipe=list())
}
#' Create or append a mongo aggregation stage
#' @param x Object of class mongo or mongo_pipe
#' @param type Name of the stage.
#' @param ... query
#'
#' @export
add_stage <- function(x, ...) {
UseMethod("add_stage")
}
#' @rdname add_stage
#' @export
add_stage.default <- function(x, ...) {
add_stage(mongopipe(), type=x, ...)
}
#' @rdname add_stage
#' @export
add_stage.mongopipe <- function(x, type, ...) {
if (missing(type)) {
abort("`type` has to be specified")
}
if (missing(..1)) {
abort("further arguments have to be passed to `...`")
}
query <- check_query(...)
new_pipe <- list()
new_pipe[[type]] <- query
pipe <- attr(x, "pipe")
pipe[[length(pipe) + 1]] <- new_pipe
structure(toJSON(pipe), class=c("character","mongopipe"), pipe=pipe)
}
#' @importFrom jsonlite unbox
check_query <- function(query) {
if (!is.list(query)) {
return(unbox(query))
}
if (is.null(query)) {
return(unbox(query))
}
if(!all(names(query) != "") || is.null(names(query))) {
abort("all elements in query should have names!")
}
for (n in names(query)) {
if (!is.list(query[[n]]) && length(query[[n]]) == 1) {
query[[n]] <- unbox(query[[n]])
} else if (is.list(query[[n]])) {
query[[n]] <- check_query(query[[n]])
}
}
return(query)
}
#' @importFrom jsonlite toJSON
#' @export
print.mongopipe <- function(x, pretty = 2, ...) {
y <- toJSON(attr(x, "pipe"), pretty = pretty)
cat(y)
invisible(x)
}
#' @importFrom magrittr %>%
#' @export
magrittr::`%>%`
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# mongopipe
<!-- badges: start -->
[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental)
[![CRAN status](https://www.r-pkg.org/badges/version/mongopipe)](https://CRAN.R-project.org/package=mongopipe)
<!-- badges: end -->
The goal of mongopipe is to have a simple translator for R code into json based queries for Mongodb.
## Installation
You can install the released version of mongopipe from [CRAN](https://CRAN.R-project.org) with:
``` r
install.packages("mongopipe")
# or
# TODO: publish it on gitlab and insert address
# remotes::remotes("gitlab")
```
## Example
```{r example, message=FALSE}
library(mongopipe)
library(mongolite)
library(nycflights13)
m_flights <- mongo("test_flights", verbose = FALSE)
m_airports <- mongo("test_airports", verbose = FALSE)
m_flights$drop()
m_flights$insert(flights)
m_airports$drop()
m_airports$insert(airports)
result <- mongopipe() %>%
match(faa="ABQ") %>%
lookup(from = "test_flights", local_field = "faa", foreign_field = "dest") %>%
unwind(field = "test_flights") %>%
project(air_time="$test_flights.air_time", dep_delay="$test_flights.dep_delay", origin="$test_flights.origin") %>%
m_airports$aggregate()
head(result)
```
```{r}
pipe <- mongopipe() %>%
match(faa="ABQ") %>%
lookup(from = "test_flights", local_field = "faa", foreign_field = "dest") %>%
unwind(field = "test_flights") %>%
project(air_time="$test_flights.air_time", dep_delay="$test_flights.dep_delay", origin="$test_flights.origin")
print(pipe, pretty = 4)
```
<!-- README.md is generated from README.Rmd. Please edit that file -->
# mongopipe
<!-- badges: start -->
[![Lifecycle:
experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental)
[![CRAN
status](https://www.r-pkg.org/badges/version/mongopipe)](https://CRAN.R-project.org/package=mongopipe)
<!-- badges: end -->
The goal of mongopipe is to have a simple translator for R code into
json based queries for Mongodb.
## Installation
You can install the released version of mongopipe from
[CRAN](https://CRAN.R-project.org) with:
``` r
install.packages("mongopipe")
# or
# TODO: publish it on gitlab and insert address
# remotes::remotes("gitlab")
```
## Example
``` r
library(mongopipe)
library(mongolite)
library(nycflights13)
m_flights <- mongo("test_flights", verbose = FALSE)
m_airports <- mongo("test_airports", verbose = FALSE)
m_flights$drop()
m_flights$insert(flights)
#> List of 5
#> $ nInserted : num 336776
#> $ nMatched : num 0
#> $ nRemoved : num 0
#> $ nUpserted : num 0
#> $ writeErrors: list()
m_airports$drop()
m_airports$insert(airports)
#> List of 5
#> $ nInserted : num 1458
#> $ nMatched : num 0
#> $ nRemoved : num 0
#> $ nUpserted : num 0
#> $ writeErrors: list()
result <- mongopipe() %>%
match(faa="ABQ") %>%
lookup(from = "test_flights", local_field = "faa", foreign_field = "dest") %>%
unwind(field = "test_flights") %>%
project(air_time="$test_flights.air_time", dep_delay="$test_flights.dep_delay", origin="$test_flights.origin") %>%
m_airports$aggregate()
head(result)
#> _id air_time dep_delay origin
#> 1 5fe1f43f0d014e38242e1401 230 -6 JFK
#> 2 5fe1f43f0d014e38242e1401 238 9 JFK
#> 3 5fe1f43f0d014e38242e1401 251 -6 JFK
#> 4 5fe1f43f0d014e38242e1401 257 16 JFK
#> 5 5fe1f43f0d014e38242e1401 242 0 JFK
#> 6 5fe1f43f0d014e38242e1401 240 -2 JFK
```
``` r
pipe <- mongopipe() %>%
match(faa="ABQ") %>%
lookup(from = "test_flights", local_field = "faa", foreign_field = "dest") %>%
unwind(field = "test_flights") %>%
project(air_time="$test_flights.air_time", dep_delay="$test_flights.dep_delay", origin="$test_flights.origin")
print(pipe, pretty = 4)
#> [
#> {
#> "$match": {
#> "faa": "ABQ"
#> }
#> },
#> {
#> "$lookup": {
#> "from": "test_flights",
#> "localField": "faa",
#> "foreignField": "dest",
#> "as": "test_flights"
#> }
#> },
#> {
#> "$unwind": "$test_flights"
#> },
#> {
#> "$project": {
#> "air_time": "$test_flights.air_time",
#> "dep_delay": "$test_flights.dep_delay",
#> "origin": "$test_flights.origin"
#> }
#> }
#> ]
```
## Test environments
* GitHub Actions (ubuntu-16.04): devel, release, oldrel, 3.5, 3.4, 3.3
* GitHub Actions (windows): release, oldrel
* GitHub Actions (macOS): release
* win-builder: devel
## R CMD check results
0 errors | 0 warnings | 1 note
* This is a new release.
<!-- Generated by pkgdown: do not edit by hand -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page not found (404) • mongopipe</title>
<!-- jquery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha256-bZLfwXAP04zRMK2BjiO8iu9pf4FbLqX6zitd+tIvLhE=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha256-nuL8/2cJ5NDSSwnKD8VqreErSWHtnEP9E7AySL+1ev4=" crossorigin="anonymous"></script>
<!-- bootstrap-toc -->
<link rel="stylesheet" href="bootstrap-toc.css">
<script src="bootstrap-toc.js"></script>
<!-- Font Awesome icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/all.min.css" integrity="sha256-mmgLkCYLUQbXn0B1SRqzHar6dCnv9oZFPEC1g1cwlkk=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/v4-shims.min.css" integrity="sha256-wZjR52fzng1pJHwx4aV2AO3yyTOXrcDW7jBpJtTwVxw=" crossorigin="anonymous" />
<!-- clipboard.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.6/clipboard.min.js" integrity="sha256-inc5kl9MA1hkeYUt+EC3BhlIgyp/2jDIyBLS6k3UxPI=" crossorigin="anonymous"></script>
<!-- headroom.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/headroom/0.11.0/headroom.min.js" integrity="sha256-AsUX4SJE1+yuDu5+mAVzJbuYNPHj/WroHuZ8Ir/CkE0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/headroom/0.11.0/jQuery.headroom.min.js" integrity="sha256-ZX/yNShbjqsohH1k95liqY9Gd8uOiE1S4vZc+9KQ1K4=" crossorigin="anonymous"></script>
<!-- pkgdown -->
<link href="pkgdown.css" rel="stylesheet">
<script src="pkgdown.js"></script>
<meta property="og:title" content="Page not found (404)" />
<!-- mathjax -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js" integrity="sha256-nvJJv9wWKEm88qvoQl9ekL2J+k/RWIsaSScxxlsrv8k=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-84DKXVJXs0/F8OTMzX4UR909+jtl4G7SPypPavF+GfA=" crossorigin="anonymous"></script>
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body data-spy="scroll" data-target="#toc">
<div class="container template-title-body">
<header>
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<span class="navbar-brand">
<a class="navbar-link" href="index.html">mongopipe</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Released version">0.0.0.9000</span>
</span>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>
<a href="index.html">
<span class="fas fa fas fa-home fa-lg"></span>
</a>
</li>
<li>
<a href="reference/index.html">Reference</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
</ul>
</div><!--/.nav-collapse -->
</div><!--/.container -->
</div><!--/.navbar -->
</header>
<div class="row">
<div class="contents col-md-9">
<div class="page-header">
<h1>Page not found (404)</h1>
</div>
Content not found. Please use links in the navbar.
</div>
<div class="col-md-3 hidden-xs hidden-sm" id="pkgdown-sidebar">
<nav id="toc" data-toggle="toc" class="sticky-top">
<h2 data-toc-skip>Contents</h2>
</nav>
</div>
</div>
<footer>
<div class="copyright">
<p>Developed by Oliver Haag.</p>
</div>
<div class="pkgdown">