diff --git a/.Rbuildignore b/.Rbuildignore index 03b11c6..94743c7 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -7,3 +7,5 @@ appveyor.yml ^Makefile$ man-roxygen ^CONDUCT\.md$ +\.deb$ + diff --git a/.travis.yml b/.travis.yml index ab4a2e9..ddc05bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,57 @@ language: r -sudo: required +env: + matrix: + - ES_VERSION=1.0.0 + - ES_VERSION=1.4.0 + - ES_VERSION=1.7.2 + - ES_VERSION=2.0.0 + - ES_VERSION=2.1.0 + - ES_VERSION=2.2.0 + +before_install: + - case "$ES_VERSION" in + "") ;; + + "1.0.0") + export ES_VERSION=1.0.0 ; + curl -O https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-$ES_VERSION.deb && sudo dpkg -i --force-confnew elasticsearch-$ES_VERSION.deb && sudo service elasticsearch start + ;; + + "1.4.0") + export ES_VERSION=1.4.0 ; + curl -O https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-$ES_VERSION.deb && sudo dpkg -i --force-confnew elasticsearch-$ES_VERSION.deb && sudo service elasticsearch start + ;; + + "1.7.2") + export ES_VERSION=1.7.2 ; + curl -O https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-$ES_VERSION.deb && sudo dpkg -i --force-confnew elasticsearch-$ES_VERSION.deb && sudo service elasticsearch start + ;; + + "2.0.0") + export ES_VERSION=2.0.0 ; + curl -O https://download.elasticsearch.org/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/$ES_VERSION/elasticsearch-$ES_VERSION.deb && sudo dpkg -i --force-confnew elasticsearch-$ES_VERSION.deb && sudo service elasticsearch start + ;; + + "2.1.0") + export ES_VERSION=2.1.0 ; + curl -O https://download.elasticsearch.org/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/$ES_VERSION/elasticsearch-$ES_VERSION.deb && sudo dpkg -i --force-confnew elasticsearch-$ES_VERSION.deb && sudo service elasticsearch start + ;; + + "2.2.0") + export ES_VERSION=2.2.0 ; + curl -O https://download.elasticsearch.org/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/$ES_VERSION/elasticsearch-$ES_VERSION.deb && sudo dpkg -i --force-confnew elasticsearch-$ES_VERSION.deb && sudo service elasticsearch start + ;; + esac + + - sleep 3 + - sudo service elasticsearch status + +r_packages: +- covr + +after_success: +- Rscript -e 'covr::codecov()' notifications: email: diff --git a/DESCRIPTION b/DESCRIPTION index 9f3337a..d47e9e8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: elasticdsl Title: Elasticsearch DSL Description: Elasticsearch DSL. -Version: 0.0.3.9550 -Date: 2016-01-03 +Version: 0.0.3.9800 +Date: 2016-03-01 License: MIT + file LICENSE Authors@R: person("Scott", "Chamberlain", role = c("aut", "cre"), email = "myrmecocystus@gmail.com") @@ -16,5 +16,7 @@ Imports: lazyeval, dplyr Suggests: - roxygen2, - knitr + roxygen2 (>= 5.0.1), + knitr, + testthat +RoxygenNote: 5.0.1 diff --git a/NAMESPACE b/NAMESPACE index d9804c4..ab0318e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,13 +1,15 @@ -# Generated by roxygen2 (4.1.1): do not edit by hand +# Generated by roxygen2: do not edit by hand S3method(as.query,bool) S3method(as.query,ids) S3method(as.query,params) S3method(as.query,prefix) S3method(as.query,range) +S3method(print,elasticdsl_query) S3method(print,index) export("%>%") export(Search_) +export(aggs) export(and) export(bool) export(bool_) @@ -15,6 +17,7 @@ export(boosting) export(boosting_) export(common) export(common_) +export(describe) export(exec) export(fbool) export(fbool_) diff --git a/R/aggs.R b/R/aggs.R new file mode 100644 index 0000000..25ea9a6 --- /dev/null +++ b/R/aggs.R @@ -0,0 +1,31 @@ +#' elastic DSL aggs +#' +#' @name aggs +#' +#' @param .obj An index object. If nothing passed defaults to all indices, equivalent to +#' doing e.g., \code{localhost:9200/_search} +#' @param ... Further args passed on +NULL + +#' Aggregations +#' +#' @export +#' @rdname aggs +#' +aggs <- function(.obj = list(), ...) { + aggs_(.obj, .dots = lazyeval::lazy_dots(...)) +} + +aggs_ <- function(.obj=list(), ..., .dots) { + dots <- lazyeval::all_dots(.dots, ...) + + as.json.aggs <- function(x, ...) { + jsonlite::toJSON(list(aggs = x), ..., auto_unbox = TRUE) + } + + query <- as.json.aggs(structure(lazy_eval(dots$x), class=c("aggs", "lazy_dots", "list"))) + execute <- function(.obj, query){ + Search_(.obj, body = query) + } + execute(.obj, query) +} diff --git a/R/as.fjson.R b/R/as.fjson.R index 76f093e..6339f3a 100644 --- a/R/as.fjson.R +++ b/R/as.fjson.R @@ -42,6 +42,11 @@ as.fjson.query <- function(x, ...){ jsonlite::toJSON(x, ..., auto_unbox = TRUE) } +as.fjson.esdsl <- function(x, ...){ + x <- list(query = list(range = parse_range(get_eq(x[[1]])))) + jsonlite::toJSON(x, ..., auto_unbox = TRUE) +} + as.fjson.range <- function(x, ...){ x <- list(query = list(range = parse_range(get_eq(x[[1]])))) jsonlite::toJSON(x, ..., auto_unbox = TRUE) diff --git a/R/describe.R b/R/describe.R new file mode 100644 index 0000000..dd31432 --- /dev/null +++ b/R/describe.R @@ -0,0 +1,52 @@ +#' Explain a query +#' +#' @export +#' @param .data (list) input, using higher level interface +#' @examples +#' elastic::connect() +#' +#' shakespeare <- system.file("examples", "shakespeare_data.json", package = "elastic") +#' invisible(elastic::docs_bulk(shakespeare)) +#' # index("shakespeare") %>% range( speech_number <= 5 ) %>% describe +#' +#' index("shakespeare") %>% +#' bool(must_not = list(term=list(speaker="KING HENRY IV"))) %>% +#' describe +#' +#' geoshape <- system.file("examples", "gbif_geoshape.json", package = "elastic") +#' invisible(elastic::docs_bulk(geoshape)) +#' index("geoshape") %>% +#' geoshape(field = "location", type = "envelope", +#' coordinates = list(c(-30, 50), c(30, 0))) %>% +#' describe() +#' +describe <- function(.data) { + pipe_autoexec(toggle = FALSE) + if (!inherits(.data, "esdsl")) stop("must be of class esdsl", call. = FALSE) + structure(make_query(.data), class = "elasticdsl_query") +} + +#' @export +print.elasticdsl_query <- function(x, ...) { + cat("", sep = "\n") + cat(paste0(" base: ", x$url), sep = "\n") + cat(paste0(" index: ", x$index), sep = "\n") + cat(paste0(" query: \n", x$query), sep = "\n") +} + +make_query <- function(x) { + list( + url = es_make_url(elastic::connection()), + index = attr(x$index, "index"), + query = jsonlite::prettify(x$query) + ) +} + +es_make_url <- function(x) { + if (is.null(x$port) || nchar(x$port) == 0) { + x$base + } + else { + paste(x$base, ":", x$port, sep = "") + } +} diff --git a/R/exec.R b/R/exec.R index 52fff7a..8484cac 100644 --- a/R/exec.R +++ b/R/exec.R @@ -8,6 +8,11 @@ exec <- function(.obj, query, ...) { Search_(attr(.obj, "index"), body = tmp$body, params = tmp$params, ...) } +exec2 <- function(.obj, query, ...) { + pipe_autoexec(toggle = FALSE) + Search_(.obj$index, body = .obj$query, ...) +} + # execute on Search execute <- function(.obj, query){ Search_(.obj, body = query) diff --git a/R/pipers.R b/R/pipers.R index 340b0d0..1593e02 100644 --- a/R/pipers.R +++ b/R/pipers.R @@ -1,9 +1,34 @@ # from @smbache Stefan Milton Bache +#' Information on Potential Pipeline +#' +#' This function figures out whether it is called from within a pipeline. +#' It does so by examining the parent evironment of the active system frames, +#' and whether any of these are the same as the enclosing environment of +#' \code{\%>\%}. +#' +#' @return A list with the values \code{is_piped} (logical) and \code{env} +#' (an environment reference). The former is \code{TRUE} if a pipeline is +#' identified as \code{FALSE} otherwise. The latter holds a reference to +#' the \code{\%>\%} frame where the pipeline is created and evaluated. +#' +#' @noRd +pipeline_info <- function() { + parents <- lapply(sys.frames(), parent.env) + + is_magrittr_env <- + vapply(parents, identical, logical(1), y = environment(`%>%`)) + + is_piped <- any(is_magrittr_env) + + list(is_piped = is_piped, + env = if (is_piped) sys.frames()[[max(which(is_magrittr_env))]]) +} + #' Toggle Auto Execution On or Off for Pipelines #' #' A call to \code{pipe_autoexec} allows a function to toggle auto execution of -#' \code{http} on or off at the end of a pipeline. +#' \code{jq} on or off at the end of a pipeline. #' #' @param toggle logical: \code{TRUE} toggles auto execution on, \code{FALSE} #' toggles auto execution off. @@ -14,7 +39,7 @@ #' changed to \code{identity}. #' #' @noRd -pipe_autoexec <- function(toggle, method = "GET") { +pipe_autoexec <- function(toggle) { if (!identical(toggle, TRUE) && !identical(toggle, FALSE)) { stop("Argument 'toggle' must be logical.") } @@ -22,44 +47,20 @@ pipe_autoexec <- function(toggle, method = "GET") { info <- pipeline_info() if (isTRUE(info[["is_piped"]])) { + es_exit <- function(j) if (inherits(j, "esdsl")) exec2(j) else j pipeline_on_exit(info$env) - info$env$.exec_exitfun <- if (toggle) exec else identity + info$env$.es_exitfun <- if (toggle) es_exit else identity } invisible() } -#' Information on Potential Pipeline -#' -#' This function figures out whether it is called from within a pipeline. -#' It does so by examining the parent evironment of the active system frames, -#' and whether any of these are the same as the enclosing environment of -#' \code{\%>\%}. -#' -#' @return A list with the values \code{is_piped} (logical) and \code{env} -#' (an environment reference). The former is \code{TRUE} if a pipeline is -#' identified as \code{FALSE} otherwise. The latter holds a reference to -#' the \code{\%>\%} frame where the pipeline is created and evaluated. -#' -#' @noRd -pipeline_info <- function() { - parents <- lapply(sys.frames(), parent.env) - - is_magrittr_env <- - vapply(parents, identical, logical(1), y = environment(`%>%`)) - - is_piped <- any(is_magrittr_env) - - list(is_piped = is_piped, - env = if (is_piped) sys.frames()[[min(which(is_magrittr_env))]]) -} - #' Setup On-Exit Action for a Pipeline #' #' A call to \code{pipeline_on_exit} will setup the pipeline for auto execution by #' making \code{result} inside \code{\%>\%} an active binding. The initial #' call will register the \code{identity} function as the exit action, -#' but this can be changed to \code{jq} with a call to \code{pipe_autoexec}. +#' but this can be changed to \code{exec} with a call to \code{pipe_autoexec}. #' Subsequent calls to \code{pipeline_on_exit} has no effect. #' #' @param env A reference to the \code{\%>\%} environment, in which @@ -68,21 +69,20 @@ pipeline_info <- function() { #' @noRd pipeline_on_exit <- function(env) { # Only activate the first time; after this the binding is already active. - if (exists(".exec_exitfun", envir = env, inherits = FALSE, mode = "function")) { + if (exists(".es_exitfun", envir = env, inherits = FALSE, mode = "function")) { return(invisible()) } - env$.exec_exitfun <- identity + env$.es_exitfun <- identity res <- NULL - exec_result <- function(v) { + es_result <- function(v) { if (missing(v)) { res - } - else { - res <<- `$<-`(v, value, env$.exec_exitfun(v$value)) + } else { + res <<- `$<-`(v, value, env$.es_exitfun(v$value)) } } - makeActiveBinding("result", exec_result, env) + makeActiveBinding("result", es_result, env) } diff --git a/R/query.R b/R/query.R index a94b260..291bbee 100644 --- a/R/query.R +++ b/R/query.R @@ -46,8 +46,9 @@ #' #' # range query #' index("shakespeare") %>% range( speech_number <= 5 ) -#' index("shakespeare") %>% range( speech_number <= c(1,5) ) # doens't work -#' index("shakespeare") %>% range( speech_number >= c(1,5) ) # doens't work +#' index("shakespeare") %>% range( speech_number >= 5 ) +#' # index("shakespeare") %>% range( speech_number <= c(1,5) ) # doens't work +#' # index("shakespeare") %>% range( speech_number >= c(1,5) ) # doens't work #' #' # geographic query #' ## point @@ -65,7 +66,11 @@ #' # polygon #' coords <- list(c(80.0, -20.0), c(-80.0, -20.0), c(-80.0, 60.0), c(40.0, 60.0), c(80.0, -20.0)) #' index("geoshape") %>% -#' geoshape(field = "location", type = "polygon", coordinates = coords) +#' geoshape(field = "location", type = "polygon", coordinates = coords) %>% +#' n() +#' +#' # common query - not working yet +#' # index("shakespeare") %>% common( speech_number <= 5 ) #' } NULL @@ -78,9 +83,11 @@ range <- function(.obj=list(), ..., boost=1, time_zone=NULL, execution=NULL, cac #' @export #' @rdname query range_ <- function(.obj=list(), ..., .dots) { + pipe_autoexec(toggle = TRUE) dots <- lazyeval::all_dots(.dots, ...) - query <- as.json(structure(dots, class=c("range","lazy_dots"))) - execute(.obj, query) + query <- as.json(structure(dots, class = c("range", "lazy_dots"))) + structure(list(index = .obj, query = query), class = "esdsl") + #execute(.obj, query) } #' @export @@ -92,61 +99,64 @@ bool <- function(.obj=list(), ...){ #' @export #' @rdname query bool_ <- function(.obj=list(), ..., .dots){ + pipe_autoexec(toggle = TRUE) dots <- lazyeval::all_dots(.dots, ...) - query <- as.json(structure(dots, class=c("bool","lazy_dots"))) - execute(.obj, query) + query <- as.json(structure(dots, class = c("bool","lazy_dots"))) + structure(list(index = .obj, query = query), class = "esdsl") + #execute(.obj, query) } #' @export #' @rdname query geoshape <- function(.obj=list(), ..., field=NULL){ - geoshape_(.obj, .dots = lazyeval::lazy_dots(...), field=field) + geoshape_(.obj, .dots = lazyeval::lazy_dots(...), field = field) } #' @export #' @rdname query geoshape_ <- function(.obj=list(), ..., .dots, field=NULL){ - pipe_autoexec(toggle = FALSE) + pipe_autoexec(toggle = TRUE) dots <- lazyeval::all_dots(.dots, ...) query <- as.json(structure(dots, class = c("geoshape", "lazy_dots")), field = field) - structure(.obj, class = "query", query = query) + structure(list(index = .obj, query = query), class = "esdsl") } #' @export #' @rdname query boosting <- function(.obj=list(), ..., negative_boost=NULL){ - boosting_(.obj, .dots = lazyeval::lazy_dots(...), negative_boost=negative_boost) + boosting_(.obj, .dots = lazyeval::lazy_dots(...), negative_boost = negative_boost) } #' @export #' @rdname query boosting_ <- function(.obj=list(), ..., .dots, negative_boost=NULL){ dots <- lazyeval::all_dots(.dots, ...) - query <- as.json(structure(dots, class=c("boosting","lazy_dots")), negative_boost=negative_boost) - execute(.obj, query) + query <- as.json(structure(dots, class = c("boosting", "lazy_dots")), negative_boost = negative_boost) + structure(list(index = .obj, query = query), class = "esdsl") + #execute(.obj, query) } #' @export #' @rdname query common <- function(.obj=list(), field, query=NULL, cutoff_frequency=NULL, low_freq_operator=NULL, minimum_should_match=NULL){ - common_(.obj, field=field, query=query, - cutoff_frequency=cutoff_frequency, - low_freq_operator=low_freq_operator, - minimum_should_match=minimum_should_match) + common_(.obj, field = field, query = query, + cutoff_frequency = cutoff_frequency, + low_freq_operator = low_freq_operator, + minimum_should_match = minimum_should_match) } #' @export #' @rdname query common_ <- function(.obj=list(), field, query=NULL, cutoff_frequency=NULL, low_freq_operator=NULL, minimum_should_match=NULL){ - args <- ec(list(field=field, query=query, - cutoff_frequency=cutoff_frequency, - low_freq_operator=low_freq_operator, - minimum_should_match=minimum_should_match)) + args <- ec(list(field = field, query = query, + cutoff_frequency = cutoff_frequency, + low_freq_operator = low_freq_operator, + minimum_should_match = minimum_should_match)) dots <- lazyeval::as.lazy_dots(args) query <- as.json( - structure(dots, class=c("common","lazy_dots")) + structure(dots, class = c("common", "lazy_dots")) ) execute(.obj, query) } @@ -168,8 +178,8 @@ as.json.bool <- function(x, ...){ as.json.geoshape <- function(x, field, ...){ out <- list() - for(i in seq_along(x)){ - dat <- if(is.character(x[[i]]$expr)){ + for (i in seq_along(x)) { + dat <- if (is.character(x[[i]]$expr)) { unbox(x[[i]]$expr) } else { list(eval(x[[i]]$expr)) @@ -204,7 +214,8 @@ get_eq <- function(y) { eq = dat$token[ dat$token %in% c("LT","GT","GE","LE","EQ_ASSIGN","EQ","NE") ], num = dat[ dat$token == "NUM_CONST", "text"] ) - tmp$eq <- switch(tolower(tmp$eq), lt="lt", gt="gt", ge="gte", le="lte", eq_assign=NA, eq=NA) + tmp$eq <- switch(tolower(tmp$eq), lt = "lt", gt = "gt", ge = "gte", + le = "lte", eq_assign = NA, eq = NA) tmp } diff --git a/R/utils.R b/R/utils.R index 8b07d0d..9585dc4 100644 --- a/R/utils.R +++ b/R/utils.R @@ -32,9 +32,16 @@ #' } NULL +#' The number of returned documents +#' +#' @param .data A list returned by a query +#' #' @export #' @rdname utils -n <- function(x) x$hits$total +n <- function(.data) { + pipe_autoexec(toggle = FALSE) + exec2(structure(.data, class = "esdsl"))$hits$total +} #' @export #' @rdname utils diff --git a/R/zzz.r b/R/zzz.r index 2fdc91c..73feb79 100644 --- a/R/zzz.r +++ b/R/zzz.r @@ -1,7 +1,5 @@ ec <- function (l) Filter(Negate(is.null), l) -ec <- function (l) Filter(Negate(is.null), l) - cl <- function(x) if(is.null(x)) NULL else paste0(x, collapse = ",") pluck <- function(x, name, type) { diff --git a/inst/ignore/pipers_old.R b/inst/ignore/pipers_old.R new file mode 100644 index 0000000..8bef0e0 --- /dev/null +++ b/inst/ignore/pipers_old.R @@ -0,0 +1,86 @@ +#' Toggle Auto Execution On or Off for Pipelines +#' +#' A call to \code{pipe_autoexec} allows a function to toggle auto execution of +#' \code{http} on or off at the end of a pipeline. +#' +#' @param toggle logical: \code{TRUE} toggles auto execution on, \code{FALSE} +#' toggles auto execution off. +#' +#' @details Once auto execution is turned on the \code{result} identifier inside +#' the pipeline is bound to an "Active Binding". This will not be changed on +#' toggling auto execution off, but rather the function to be executed is +#' changed to \code{identity}. +#' +#' @noRd +pipe_autoexec <- function(toggle, method = "GET") { + if (!identical(toggle, TRUE) && !identical(toggle, FALSE)) { + stop("Argument 'toggle' must be logical.") + } + + info <- pipeline_info() + + if (isTRUE(info[["is_piped"]])) { + pipeline_on_exit(info$env) + info$env$.exec_exitfun <- if (toggle) exec else identity + } + + invisible() +} + +#' Information on Potential Pipeline +#' +#' This function figures out whether it is called from within a pipeline. +#' It does so by examining the parent evironment of the active system frames, +#' and whether any of these are the same as the enclosing environment of +#' \code{\%>\%}. +#' +#' @return A list with the values \code{is_piped} (logical) and \code{env} +#' (an environment reference). The former is \code{TRUE} if a pipeline is +#' identified as \code{FALSE} otherwise. The latter holds a reference to +#' the \code{\%>\%} frame where the pipeline is created and evaluated. +#' +#' @noRd +pipeline_info <- function() { + parents <- lapply(sys.frames(), parent.env) + + is_magrittr_env <- + vapply(parents, identical, logical(1), y = environment(`%>%`)) + + is_piped <- any(is_magrittr_env) + + list(is_piped = is_piped, + env = if (is_piped) sys.frames()[[min(which(is_magrittr_env))]]) +} + +#' Setup On-Exit Action for a Pipeline +#' +#' A call to \code{pipeline_on_exit} will setup the pipeline for auto execution by +#' making \code{result} inside \code{\%>\%} an active binding. The initial +#' call will register the \code{identity} function as the exit action, +#' but this can be changed to \code{jq} with a call to \code{pipe_autoexec}. +#' Subsequent calls to \code{pipeline_on_exit} has no effect. +#' +#' @param env A reference to the \code{\%>\%} environment, in which +#' \code{result} is to be bound. +#' +#' @noRd +pipeline_on_exit <- function(env) { + # Only activate the first time; after this the binding is already active. + if (exists(".exec_exitfun", envir = env, inherits = FALSE, mode = "function")) { + return(invisible()) + } + env$.exec_exitfun <- identity + + res <- NULL + + exec_result <- function(v) { + if (missing(v)) { + res + } + else { + res <<- `$<-`(v, value, env$.exec_exitfun(v$value)) + } + } + + makeActiveBinding("result", exec_result, env) +} diff --git a/man/Search.Rd b/man/Search.Rd index 3158f6d..6ac2ada 100644 --- a/man/Search.Rd +++ b/man/Search.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.1): do not edit by hand +% Generated by roxygen2: do not edit by hand % Please edit documentation in R/search.R \name{Search_} \alias{Search_} diff --git a/man/aggs.Rd b/man/aggs.Rd new file mode 100644 index 0000000..845ed35 --- /dev/null +++ b/man/aggs.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/aggs.R +\name{aggs} +\alias{aggs} +\title{elastic DSL aggs} +\usage{ +aggs(.obj = list(), ...) +} +\arguments{ +\item{.obj}{An index object. If nothing passed defaults to all indices, equivalent to +doing e.g., \code{localhost:9200/_search}} + +\item{...}{Further args passed on} +} +\description{ +elastic DSL aggs + +Aggregations +} + diff --git a/man/as.query.Rd b/man/as.query.Rd index f581fc2..5520fb7 100644 --- a/man/as.query.Rd +++ b/man/as.query.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.1): do not edit by hand +% Generated by roxygen2: do not edit by hand % Please edit documentation in R/as.query.R \name{as.query} \alias{as.query} diff --git a/man/describe.Rd b/man/describe.Rd new file mode 100644 index 0000000..8e5607a --- /dev/null +++ b/man/describe.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/describe.R +\name{describe} +\alias{describe} +\title{Explain a query} +\usage{ +describe(.data) +} +\arguments{ +\item{.data}{(list) input, using higher level interface} +} +\description{ +Explain a query +} +\examples{ +elastic::connect() + +shakespeare <- system.file("examples", "shakespeare_data.json", package = "elastic") +invisible(elastic::docs_bulk(shakespeare)) +# index("shakespeare") \%>\% range( speech_number <= 5 ) \%>\% describe + +index("shakespeare") \%>\% + bool(must_not = list(term=list(speaker="KING HENRY IV"))) \%>\% + describe + +geoshape <- system.file("examples", "gbif_geoshape.json", package = "elastic") +invisible(elastic::docs_bulk(geoshape)) +index("geoshape") \%>\% + geoshape(field = "location", type = "envelope", + coordinates = list(c(-30, 50), c(30, 0))) \%>\% + describe() + +} + diff --git a/man/elasticdsl.Rd b/man/elasticdsl.Rd index 08f6324..9537033 100644 --- a/man/elasticdsl.Rd +++ b/man/elasticdsl.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.1): do not edit by hand +% Generated by roxygen2: do not edit by hand % Please edit documentation in R/elasticdsl-package.r \docType{package} \name{elasticdsl} diff --git a/man/filters.Rd b/man/filters.Rd index b20d916..4663a97 100644 --- a/man/filters.Rd +++ b/man/filters.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.1): do not edit by hand +% Generated by roxygen2: do not edit by hand % Please edit documentation in R/filter.R \name{filters} \alias{and} diff --git a/man/hits.Rd b/man/hits.Rd index 605b63a..f559b59 100644 --- a/man/hits.Rd +++ b/man/hits.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.1): do not edit by hand +% Generated by roxygen2: do not edit by hand % Please edit documentation in R/hits.R \name{hits} \alias{hits} diff --git a/man/index.Rd b/man/index.Rd index 8454598..b13c021 100644 --- a/man/index.Rd +++ b/man/index.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.1): do not edit by hand +% Generated by roxygen2: do not edit by hand % Please edit documentation in R/index.R \name{index} \alias{index} diff --git a/man/indices.Rd b/man/indices.Rd index cc13053..97b7922 100644 --- a/man/indices.Rd +++ b/man/indices.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand +% Generated by roxygen2: do not edit by hand % Please edit documentation in R/index.R \name{indices} \alias{indices} diff --git a/man/pipe.Rd b/man/pipe.Rd index b1b12f8..036511e 100644 --- a/man/pipe.Rd +++ b/man/pipe.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.1): do not edit by hand +% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe.R \name{\%>\%} \alias{\%>\%} diff --git a/man/query.Rd b/man/query.Rd index 89c1df9..be1e7ec 100644 --- a/man/query.Rd +++ b/man/query.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.1): do not edit by hand +% Generated by roxygen2: do not edit by hand % Please edit documentation in R/query.R \name{query} \alias{bool} @@ -97,8 +97,9 @@ index("shakespeare") \%>\% # range query index("shakespeare") \%>\% range( speech_number <= 5 ) -index("shakespeare") \%>\% range( speech_number <= c(1,5) ) # doens't work -index("shakespeare") \%>\% range( speech_number >= c(1,5) ) # doens't work +index("shakespeare") \%>\% range( speech_number >= 5 ) +# index("shakespeare") \%>\% range( speech_number <= c(1,5) ) # doens't work +# index("shakespeare") \%>\% range( speech_number >= c(1,5) ) # doens't work # geographic query ## point @@ -116,7 +117,11 @@ index("geoshape") \%>\% # polygon coords <- list(c(80.0, -20.0), c(-80.0, -20.0), c(-80.0, 60.0), c(40.0, 60.0), c(80.0, -20.0)) index("geoshape") \%>\% - geoshape(field = "location", type = "polygon", coordinates = coords) + geoshape(field = "location", type = "polygon", coordinates = coords) \%>\% + n() + +# common query - not working yet +# index("shakespeare") \%>\% common( speech_number <= 5 ) } } diff --git a/man/tabl.Rd b/man/tabl.Rd index 2f2ce79..31ac028 100644 --- a/man/tabl.Rd +++ b/man/tabl.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.1): do not edit by hand +% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tabl.R \name{tabl} \alias{tabl} diff --git a/man/utils.Rd b/man/utils.Rd index 2b6029f..3122fd4 100644 --- a/man/utils.Rd +++ b/man/utils.Rd @@ -1,6 +1,6 @@ -% Generated by roxygen2 (4.1.1): do not edit by hand -% Please edit documentation in R/utils.R -\name{utils} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/exec.R, R/utils.R +\name{exec} \alias{exec} \alias{fields} \alias{glimpse} @@ -9,13 +9,13 @@ \alias{sort} \alias{sort_} \alias{utils} -\title{elastic DSL utilities} +\title{Execute Elasticsearch query} \usage{ -n(x) +exec(.obj, query, ...) -glimpse(x, pretty = TRUE, ...) +n(.data) -exec(.obj, query, ...) +glimpse(x, pretty = TRUE, ...) fields(x, ...) @@ -26,22 +26,28 @@ sort(.obj = list(), ...) sort_(.obj = list(), ..., .dots) } \arguments{ -\item{x}{Input} +\item{.obj}{Input} -\item{pretty}{Pretty print} +\item{query}{Query statement} \item{...}{Further args passed on to \code{\link[jsonlite]{toJSON}}} -\item{.obj}{Input} +\item{.data}{A list returned by a query} -\item{query}{Query statement} +\item{x}{Input} + +\item{pretty}{Pretty print} \item{y}{Input} \item{.dots}{Input} } \description{ +Execute Elasticsearch query + elastic DSL utilities + +The number of returned documents } \details{ Various utilities. diff --git a/tests/test-all.R b/tests/test-all.R new file mode 100644 index 0000000..92cae72 --- /dev/null +++ b/tests/test-all.R @@ -0,0 +1,23 @@ +library('testthat') +library('elasticdsl') + +if (Sys.getenv("ES_IP") != "") { + # The ES_IP environmental var can be set the root ip of the + # Elasticsearch for convenience. Continuous integration uses + # the default localhost address. + # + # If developing with docker, it is possible to forward the VM's ip + # to localhost using a reverse proxy server like nginx. + # https://forums.docker.com/t/using-localhost-for-to-access-running-container/3148/6 + invisible(elastic::connect(Sys.getenv("ES_IP"))) +} else { + invisible(elastic::connect()) +} + +library('elastic') +shakespeare <- system.file("examples", "shakespeare_data.json", package = "elastic") +invisible(elastic::docs_bulk(shakespeare)) +gbif <- system.file("examples", "gbif_data.json", package = "elastic") +invisible(elastic::docs_bulk(gbif)) + +test_check("elasticdsl") diff --git a/tests/testthat/test-filter.R b/tests/testthat/test-filter.R new file mode 100644 index 0000000..05a02a0 --- /dev/null +++ b/tests/testthat/test-filter.R @@ -0,0 +1,50 @@ +context("filter.R") + +first_available_index <- indices()[[1]] + +test_that("filter", { + expect_true("filtered" %in% class(filter(NULL))) +}) + +test_that("ids", { + expect_true("comb" %in% class(ids_(c(1, 2)))) + expect_true("ids" %in% class(ids_(c(1, 2))[[1]])) +}) + +test_that("ids_", { + expect_true("comb" %in% class(ids_(c(1, 2)))) + expect_true("ids" %in% class(ids_(c(1, 2))[[1]])) +}) + +test_that("ids", { + expect_equal( + index("shakespeare") %>% + filter() %>% + ids(c(1, 2)) %>% + exec() %>% + hits() %>% + sapply(., FUN = function(i) { i$`_id` }) %>% + as.integer() %>% + sort.default(), + c(1, 2)) +}) + +test_that("operands", { + expect_equal(index("shakespeare") %>% and() %>% attr("operand"), "and") + expect_equal(index("shakespeare") %>% or() %>% attr("operand"), "or") + expect_equal(index("shakespeare") %>% not() %>% attr("operand"), "not") +}) + +test_that("exec", { + expect_true( + index("shakespeare") %>% + filter() %>% + prefix(speaker = "KING H") %>% + exec() %>% + hits() %>% + sapply(., FUN = function(i) { i$`_source`$speaker }) %>% + grepl("KING HENRY IV", .) %>% + all() + ) +}) + diff --git a/tests/testthat/test-index.R b/tests/testthat/test-index.R new file mode 100644 index 0000000..502e4d4 --- /dev/null +++ b/tests/testthat/test-index.R @@ -0,0 +1,16 @@ +context("index.R") + +first_available_index <- indices()[[1]] + + +test_that("index() returns the right class", { + expect_equal(class(index(first_available_index)), "index") +}) + +test_that("indices returns at least one index", { + expect_more_than(length(indices()), 0) +}) + +test_that("get_map", { + expect_is(names(elasticdsl:::get_map(first_available_index)), "character") +}) diff --git a/tests/testthat/test-pipers.R b/tests/testthat/test-pipers.R new file mode 100644 index 0000000..6083442 --- /dev/null +++ b/tests/testthat/test-pipers.R @@ -0,0 +1,8 @@ +context("pipers.R") + +test_that("pipline_info()", { + expect_named(elasticdsl:::pipeline_info(), c("is_piped", "env")) + expect_is(index("shakespeare") %>% { elasticdsl:::pipeline_info() }, "list") + expect_true(index("shakespeare") %>% { elasticdsl:::pipeline_info() } %>% .$is_piped) + expect_false((elasticdsl:::pipeline_info())$is_piped) +})