Create Influx query as a function in R - r

I am trying to turn the Influx query into a function in R so I can change the fields as I see fit. Here is an example of the code I am running
my_bucket <- "my_bucket"
start <- "start_time"
stop <- "stop_time"
q <- paste('from(bucket:',my_bucket,')|> range(start:',start,'stop:,'stop')',sep = "")
data <- client$query(q)
Error in private$.throwIfNot2xx(resp) :
API client error (400): compilation failed: error at #1:1-1:2: invalid statement: '
This particular method uses paste() and it keeps the escape character \ in the query. I would like to get rid of that . I have tried using cat() but that is for printing to the console and also have tried capture.output() of the cat() string which still captures the escape characters.
What I would like to see and be stored as an object is the output below. I used cat() to show you exactly what I need (I know I can't use it to store things).
cat('\'from(bucket:\"',my_bucket,'\")|> range(start:',start,',stop:,',stop,')\'', sep = "")
>'from(bucket:"my_bucket")|> range(start:start_time,stop:,stop_time)'
Note the single quotes around the query beginning at from and ending after the parantheses after stop_time. In addtion the double quotes must be present around the bucket I call to. This is required syntax for the query from R.

I would suggest you try to use sprintf, I find it much easier to properly format the query.
q <- sprintf('from(bucket: "%s") |> range(start: %s, stop: %s)', my_bucket, start, stop)
Anyway, the same can be done with paste:
q <- paste('from(bucket: "',my_bucket,'") |> range(start: ',start,',stop: ',stop,')',sep = "")

Related

How to store a special character in a string in R

I am trying to store the special escape character \ in R as part of a string.
x = "abcd\efg"
# Error: '\e' is an unrecognized escape in character string starting ""abcd\e"
x = "abcd\\efg"
# Works
The problem is that x is actually a password that I am passing as part of an API web call so I need to find a way for the string to store a literal single slash in order for this to work.
Example using the ignoring literal command:
> x = r"(abcd\efg)"
> y = "https://url?password="
> paste(x, y, sep = "")
[1] "abcd\\efg123"
> # What I need is for it to return
[1] "abcd\efg123"
> z = paste(y, x, sep = "")
> z
[1] "https://url?password=abcd\\efg"
> cat(z)
https://url?password=abcd\efg
When I pass z as part of the API command I get "bad credentials" message because it's sending \\ as part of the string. cat returns it to the console correctly, but it appears to not be sending it the same way it's printing it back.
Like everyone else in the comments said, the string appears to be handled correctly by R. I would assume it becomes a trouble somewhere else down the line. Either the API or the pass-matching software itself might be doing something with it.
As one example, the backslash will not work in most browsers if written verbatim, you would need to use %5C instead. Here is one discussion about it.
So in your case - try replacing the backslash with something else, either %5C or, as #Roland mentioned in the comments, some extra back-slash symbols, like \\\\ or \\\ or \\. And then see if any of them work.
The answers and comments contain the solution, but for completeness ill post an answer that matches my specific situation.
My package expects the user to supply a password. If there is a \ in the password the command will fail as stated above. The solution seems to be to take care of it on the input rather than trying to alter the value once the user submits the password.
library(RobinHood)
# If the true password is: abc\def
# The following inputs will all work
rh <- RobinHood("username", pwd = r"(abc\def)")
rh <- RobinHood("username", pwd = "abc\\def")
rh <- RobinHood("username", pwd = "abc%5Cdef")

R customize error message when string contains unrecognized escape

I would like to give a more informative error message when users of my R functions supply a string with an unrecognized escape
my_string <- "sql\sql"
# Error: '\s' is an unrecognized escape in character string starting ""sql\s"
Something like this would be ideal.
my_string <- "sql\sql"
# Error: my_string contains an unrecognized escape. Try sql\\sql with double backslashes instead.
I have tried an if statement that looks for single backslashes
if (stringr::str_detect("sql\sql", "\")) stop("my error message")
but I get the same error.
Almost all of my users are Windows users running R 3.3 and up.
Code execution in R happens in two phases. First, R takes the raw string you enter and parses that into commands that can be run; then, R actually runs those commands. The parsing step makes sure what you've written actually makes sense as code. If it doesn't make any sense, then R can't even turn it into anything it can attempt to run.
The error message you are getting about the unrecognized escape sequence is happening at the parsing stage. That means R isn't really even attempting to execute the command, it just straight up can't understand what you are saying. There is no way to catch in error like this in code because there's no user code that's running at that point.
So if you are counting on your users writing code like my_string <- "something", then they need to write valid code. They can't change how strings are encoded or what the assignment operator looks like or how variables can be named. They also can't type !my_string! <=== %something% because R can't parse that either. R can't parse my_string <- "sql\sql" but it can parse my_string <- "sql\\sql" (slashes much be escaped in string literals). If they are not savy users, you might want to consider providing an alternative interface that can sanitize user input before trying to run it as code. Maybe make a shiny front end or have users pass arguments to your scripts via command line parameters.
If you're capturing your user input correctly, for a string input of\, R will store that in my_string as \\.
readline()
\
[1] "\\"
readline()
sql\sql
[1] "sql\\sql"
That means internally in R:
my_string <- "sql\\sql"
However
cat(my_string)
sql\sql
To check the input, you need to escape each escape, because you're looking for \\
stringr::str_detect(my_string, "\\\\")
Which returns TRUE if the input string is sql\sql. So the full line is:
if (stringr::str_detect("sql\\sql", "\\\\")) stop("my error message")

How can I keep toJSON from quoting my JSON string in R?

I am using OpenCPU and R to create a web API that takes in some inputs and returns a topoJSON file from a database, as well as some other information. OpenCPU automatically pushes the output through toJSON, which results in JSON output that has quoted JSON in it (i.e., the topoJSON). This is obviously not ideal--especially since it then gets incredibly cluttered with backticked quotes (\"). I tried using fromJSON to convert it to an R object, which could then be converted back (which is incredibly inefficient), but it returns a slightly different syntax and the result is that it doesn't work.
I feel like there should be some way to convert the string to some other type of object that results in toJSON calling a different handler that tells it to just leave it alone, but I can't figure out how to do that.
> s <- '{"type":"Topology","objects":{"map": "0"}}'
> fromJSON(s)
$type
[1] "Topology"
$objects
$objects$map
[1] "0"
> toJSON(fromJSON(s))
{"type":["Topology"],"objects":{"map":["0"]}}
That's just the beginning of the file (I replaced the actual map with "0"), and as you can see, brackets appeared around "Topology" and "0". Alternately, if I just keep it as a string, I end up with this mess:
> toJSON(s)
["{\"type\":\"Topology\",\"objects\":{\"0000595ab81ec4f34__csv\": \"0\"}}"]
Is there any way to fix this so that I just get the verbatim string but without quotes and backticks?
EDIT: Note that because I'm using OpenCPU, the output needs to come from toJSON (so no other function can be used, unfortunately), and I can't do any post-processing.
To it seems you just want the values rather than vectors. Set auto_unbox=TRUE to turn length-one vectors into scalar values
toJSON(fromJSON(s), auto_unbox = TRUE)
# {"type":"Topology","objects":{"map":"0"}}
That does print without escaping for me (using jsonlite_1.5). Maybe you are using an older version of jsonlite. You can also get around that by using cat() to print the result. You won't see the slashes when you do that.
cat(toJSON(fromJSON(s), auto_unbox = TRUE))
You can manually unbox the relevant entries:
library(jsonlite)
s <- '{"type":"Topology","objects":{"map": "0"}}'
j <- fromJSON(s)
j$type <- unbox(j$type)
j$objects$map <- unbox(j$objects$map)
toJSON(j)
# {"type":"Topology","objects":{"map":"0"}}

readChar from stdin

I would like to read in one character at a time and convert it to a string command to execute once a space is entered.
I tried
con <- file("stdin")
open(con, blocking=TRUE)
while(q!=" "){
#q=scan("",what="", nmax=1)
q=readChar(con,1)
cmd[i]=q;i=i+1
}
eval(cmd)
but I seem to not understand readChar() correctly.
Interesting question, but with a few flaws:
you use q, cmd and i and never assign them which leads to immediate error and program abort on undefined symbols being used in tests or assignments
you test for q at the top of your while loop but never give it a value (related to previous point)
you assign in the vector with i but never set to 1 first
you misunderstand how string concatenation works
you misunderstand how input from the console works, it is fundamentally by line and not by character so your approach has a deadly design issue (and blocking makes no difference)
you terminate the wrong way; your sentinel value of '' still gets assigned.
you open a console and never close it (though that may be ok with stdin)
you grow the result var the wrong way, but that doesn't matter here compared to all the other issues
If we repair the code a little, and use better style with whitespaces, no semicolons and an <- for assignment (all personal / common preferences) we get
con <- file("stdin")
open(con, blocking=TRUE)
cmd <- q <- ""
i <- 1
while (q != " ") {
q <- readChar(con,1)
cmd[i] <- q
i <- i+1
}
print(cmd) # for exposition only
close(con)
and note the final print rather than eval, we get this (and I typed the ls command letters followed by whitespace)
$ Rscript /tmp/marcusloecher.R
ls
[1] "l" "s" " "
$
I suggest you look into readLines() instead.
And now that I checked, I see that apparently you also never accept an answer to questions you asked. That is an ... interesting outcome for someone from our field which sometimes defines itself as being all about incentives...

Matching dates in sqldf

I have a data frame with stock data (date, symbol, high, low, open, close, volume). Using r and mysql and sqldf and rmysql I have a list of unique dates and unique stock symbols.
What I need now is to loop through the data and find the close on two specified dates. For instance:
stkData contains (date, symbol, high, low, open, close, volume)
dates contains unique dates
symbol contains unique symbols
I want to loop through the lists in a sqldf statement as such:
'select stkData$close from stkData where symbol = symbol[k] and date = dates[j]'
k and j would be looped numbers, but my problem is the symbol[k] and dates[j] parts.
sqldf won't read them properly (or I can't code properly). I've tried as.Date, as.character with no luck. I get the following error message:
Error in sqliteExecStatement(con, statement, bind.data) :
RS-DBI driver: (error in statement: near "[4,]": syntax error)
You're pretty far off in terms of syntax for sqldf, unfortunately. You can't use $ or [] notations in sqldf calls because those are both R syntax, not SQL syntax. It's an entirely separate language. What's happening is that sqldf is taking your data frame, importing it into SQLite3, executing the SQL query that you supply against the resulting table, and then importing the result set back into R as a data frame. No R functionality is available within the SQL.
It's not clear to me what you're trying to do, but if you want to run multiple queries in a loop, you probably want to construct the SQL query as a string using the R function paste(), so that when it gets to SQLite3 it'll just be static values where you currently have symbol[k] and dates[j].
So, you'll have something like the following, but wrapped in a loop for j and k:
sqldf(paste('select close from stkData where symbol = ', symbol[k],
' and date = ', dates[j]))
You might need to construct the select statement as a string with paste before it gets passed to your SQL caller. Something like:
combo_kj <- expand.grid(ksym=symbol[1:k], jdates=dates[1:j])
SQLcalls <- paste('select close from stkData where symbol = ',
combo_kj$ksym,
' and date = '
combo_kj$jdates,
sep="")
And then loop over SQLcalls with whatever code you are using.
Preface sqldf with fn$ as shown and then strings within backticks will be replaced by the result of running them in R and strings of the form $variable will be replaced by the contents of that variable (provided the variable name contains only word characters). Note that SQL requires that character constants be put in quotes so be sure to surround the backticks or $variable with quotes:
fn$sqldf("select close from stkData
where symbol = '`symbol[k]`' and
date = '`dates[j]`' ")
To use the $variable syntax try this:
mysymbol <- symbol[k]
mydate <- dates[j]
fn$sqldf("select close from stkData
where symbol = '$mysymbol' and
date = '$mydate' ")
Also see example 5 on the sqldf github page: https://github.com/ggrothendieck/sqldf

Resources