-
Notifications
You must be signed in to change notification settings - Fork 52
Description
I've recently written a macro tool for conveniently capturing query parameters as part of a private project. I've found it handy, so I wondered whether people would be interested in having this as part of LibPQ. Or if not, whether you have suggestions for a better home for it.
The general idea is that we should be able to build up queries by pasting together fragments of SQL and interpolated parameters like one might do with strings or Cmd
backtick interpolation. But with all interpolations turned into SQL parameters for safety and consistency in converting those to SQL types.
To just paste the readme in here:
The readme
The main thing provided here is the @query
macro to allow queries to be
constructed by normal-looking string interpolation but without danger of SQL
injection attacks.
Note that @query
does not parse or understand the SQL source text as this
would be a lot of work. Instead, it keeps any literal SQL text you write as-is
and only treats the Julia-level string interpolations specially.
Use runquery
to execute queries generated by @query
.
Simple usage
Creating a table and inserting some values
conn = LibPQ.connection(your_connection_string)
runquery(conn, @query "create table foo (email text, userid integer)")
for (email,id) in [ ("[email protected]", 1)
("[email protected]", 2)]
runquery(conn, @query "insert into foo values ($email, $id)")
end
Thence:
julia> runquery(conn, @query "select * from foo") |> DataFrame
2×2 DataFrame
Row │ email userid
│ String? Int32?
─────┼───────────────────────────
1 │ [email protected] 1
2 │ [email protected] 2
Howto: Inserting values from a Julia array into a row
In some circumstances it can be useful to use splatting syntax to interpolate a
Julia collection into a comma-separated list of values. Generally simple scalar
parameters should be preferred for simplicity, but splatting can be useful on
occasion:
email_and_id = ("[email protected]", 3)
runquery(conn, @query "insert into foo values ($(email_and_id...))")
Howto: Using the in
operator with a Julia collection
There's two ways to do this. First, using in
and splatting syntax
julia> ids = (1,2)
runquery(conn, @query "select * from foo where userid in ($(ids...))") |> DataFrame
2×2 DataFrame
Row │ email userid
│ String? Int32?
─────┼───────────────────────────
1 │ admin@example.com 1
2 │ foo@example.com 2
Second, using the SQL any
operator and simply passing a single SQL array parameter:
julia> ids = [1,2]
runquery(conn, @query "select * from foo where userid = any($ids)") |> DataFrame
2×2 DataFrame
Row │ email userid
│ String? Int32?
─────┼───────────────────────────
1 │ [email protected] 1
2 │ [email protected] 2
Howto: Building up a query from fragments
conn = LibPQ.connection(your_connection_string)
some_condition = true
x = 100
x = 20
# Example of an optional clauses - use empty @query() to disable it.
and_clause = some_condition ? @query("and y=$y") : @query()
# Interpolation of values produces SQL parameters; interpolating @query
# fragments adds them to the query.
q = @query "select * from table where x=$x $and_clause"
runquery(conn, q)