Clojure RethinkDB client. Asynchronous, lock-free, efficient, and easy to use!
Query RethinkDB using semantics familiar to any Clojure programmer.
Alpha-grade at this point, we're seeking people who want to use Clojure and RethinkDB to help us harden it up.
We're confident this is already one of the more feature-complete community-maintained libraries.
These docs are - for now - loosely based on the python api docs. The driver
works on version 1.9
and 1.10
(in our testing so far) of RethinkDB.
(require '[bitemyapp.revise.connection :refer [connect close]])
(require '[bitemyapp.revise.query :as r])
(require '[bitemyapp.revise.core :refer [run run-async]])
;; connect returns the connection agent
(let [local-conn (connect) ;; defaults to localhost
;; pass in connection options map to specify beyond the defaults
remote-conn (connect {:host "99.99.99.1"
:port 28015
:auth-key ""})
;; Run a query and return the result. Blocks as long as it needs to
;; get a result (or an error)
response1 (-> (r/db "test") (r/table-create-db "authors") (run local-conn))
;; We may be having issues so we specify a timeout to run
response2 (-> (r/db "test") (r/table-list-db) (run remote-conn 15000))
;; We want to run a query asynchronously - giving up the error handling
response3 (-> (r/db-list) (run-async local-conn))]
;; dereference the promise to block on it.
(println @response3)
;; We are done using the local connection
(close local-conn))
Inside the namespace bitemyapp.revise.connection
there are 2 functions we need:
connect
([& [conn-map]])
close
([conn])
connect
takes an optional connection map to override any or all of the default
values:
:host
"127.0.0.1"
:port
28015
:token
0
The token of the first query to the connection. Autoincrements.:auth-key
""
The authentication key.
Connect will return an agent to which you can send queries.
To close the connection use the function close
with the agent as argument.
Inside the namespace bitemyapp.revise.core
there are again 2 functions we need:
run
([query connection & [timeout]])
run-async
([query connection])
Our queries are compiled and sent to the connection using those two functions.
run
takes an optional timeout in milliseconds (default 10000
) and will block
until it has a response or it times out. It will throw when it times out or the
agent dies due to an exception when sending a query.
run
will return a map which includes the autoincrementing token
that was
implicitly sent to the agent and either a :response
in case the query was
successful or an :error
, :response
and :backtrace
in case there was
an error with our request (in this case the driver doesn't throw an exception).
Alternatively we might decide to use run-async
to send and run queries
asynchronously. This will return us a promise which we can dereference.
Note that run-async
gives up the error handling of run
. The agent might
die and you will have to check for it manually.
After dereferencing the promise the return value will be the same as run
.
run
and run-async
have an implicit call to bitemyapp.revise.protoengine/compile-term
.
This compiles the query into protocol buffers. If you know about the official
RethinkDB API and you want to inspect the protocol buffers Revise gives you, you
can compile a query using that function. To send manually compiled queries to the
database, use send-term
in the bitemyapp.revise.connection
namespace.
That will be the equivalent of using run-async
.
The api is under the namespace bitemyapp.revise.query.
(require '[bitemyapp.revise.query :as r])
Note: rethinkdb doesn't let you use hyphens (-
) as part of database or table
names. Revise won't 'fix' those names for you.
Also note that keywords and strings are interchangeable.
Many queries such as map
, filter
, etc. support lambdas. Lambdas are anonymous
functions with syntax like clojure's fn
.
Example:
(-> [1 2 3 4 5 6 7]
(r/map (r/lambda [n]
(r/* n 2)))
(run conn))
This will give you the response ([2 4 6 8 10 12 14])
([db-name])
Create a database.
(-> (r/db-create "my_db") (run conn))
([db-name])
Drop a database.
(-> (r/db-drop "my_db") (run conn))
([])
List the database names in the system.
(-> (r/db-list) (run conn))
([db table-name & {:as optargs}])
Create a table on the specified database. The following options are available:
:primary-key
The name of the primary key. Default::id
.:durability
If set to:soft
, this enables soft durability on this table: writes will be acknowledged by the server immediately and flushed to disk in the background. Default is:hard
(acknowledgement of writes happens after data has been written to disk).:cache-size
Set the cache size (in bytes) to be used by the table. The default is 1073741824 (1024MB).:datacenter
The name of the datacenter this table should be assigned to.
(-> (r/db "test") (r/table-create-db "authors") (run conn))
(-> (r/db "test") (r/table-create-db "users" :primary-key :email) (run conn))
([table-name & {:as optargs}])
Like table-create-db
except that the db is the default db.
(-> (r/table-create "authors") (run conn))
([db table-name])
Drop a table from a specific db. The table and all its data will be deleted.
(-> (r/db "test") (r/table-drop-db "authors") (run conn))
([table-name])
Like table-drop-db
except the default db is used.
(-> (r/table-drop "authors") (run conn))
([table index-name lambda1 & [multi?]])
Create a new secondary index with a given name on the specified table.
(-> (r/table "authors")
(r/index-create :author
(r/lambda [author]
(r/get-field author :name)))
(run conn))
;; Compound index
(-> (r/table "authors")
(r/index-create :name-tv-show
(r/lambda [author]
[(r/get-field author :name)
(r/get-field author :tv-show)]))
(run conn))
;; A multi index. The r/lambda of a multi index should return an array. It will allow
;; you to query based on whether a value is present in the returned array
(-> (r/table "authors")
(r/index-create :posts
(r/lambda [author]
(r/get-field author :posts)) ; returns an array
true) ; :multi -> true
(run conn))
([table index-name])
Delete a previously created secondary index of this table.
(-> (r/table "authors") (r/index-drop :posts) (run conn))
([table])
List all the secondary indexes of this table.
(-> (r/table "authors") (r/index-list) (run conn))
([table data & {:as optargs}])
Insert json documents into a table. Accepts a single json document (a clojure map) or an array of documents (a clojure vector of clojure maps).
Accepts the following options:
:upsert
Abool
. Default is true. If true it will overwrite documents that already exist.:durability
:soft
or:hard
. Override the durability of the table for this operation.:return-vals
Abool
. Only valid for single object inserts. Iftrue
you get back the row you inserted on the key:nev_val
. And if you overwrote a row it will be in:old_val
(def authors [{:name "William Adama" :tv-show "Battlestar Galactica"
:posts [{:title "Decommissioning speech",
:rating 3.5
:content "The Cylon War is long over..."},
{:title "We are at war",
:content "Moments ago, this ship received word..."},
{:title "The new Earth",
:content "The discoveries of the past few days..."}]}
{:name "Laura Roslin", :tv-show "Battlestar Galactica",
:posts [{:title "The oath of office",
:rating 4
:content "I, Laura Roslin, ..."},
{:title "They look like us",
:content "The Cylons have the ability..."}]}])
(def jean-luc {:name "Jean-Luc Picard", :tv-show "Star Trek TNG",
:posts [{:title "Civil rights",
:content "There are some words I've known since..."}]})
(-> (r/table "authors")
(r/insert authors)
(run conn))
(-> (r/table "authors")
(r/insert jean-luc :return-vals true)
(run conn))
Insert returns a map with the following attributes:
:inserted
The number of documents that were succesfully inserted.:replaced
The number of documents that were updated when upsert is used.:unchanged
The number of documents that would have been modified, except that the new value was the same as the old value when doing an upsert.:errors
The number of errors encountered while inserting; if errors were encountered while inserting, first_error contains the text of the first error.:generated_keys
A list of generated primary key values deleted and skipped: 0 for an insert operation.
If you specified :return-vals true you will also get the following keys:
:nev_val
The value of the object you inserted:old_val
The value of the object you overwrote (nil
if you didn't)
([stream-or-single-selection lambda1-or-obj])
Update JSON documents in a table. Accepts a JSON document (clojure map), a RQL expression or a combination of the two. Accepts the following optional keys:
:durability
:soft
or:hard
- Override the table's durability for this operation.:return-vals
Abool
. Only valid for single-row modifications. Iftrue
return the new value in:new_val
and the old value in:old_val
.non-atomic
Abool
. Allow the server to run non-atomic operations.
;; Make all authors be fictional
(-> (r/table "authors") (r/update {:type "fictional"}))
;; Add the rank of admiral to William Adama
(-> (r/table "authors")
(r/filter (r/lambda [row]
(r/= "William Adama"
(r/get-field row :name))))
(r/update {:rank "Admiral"})
(run conn))
;; Add a post to Jean-Luc
(-> (r/table "authors")
(r/filter (r/lambda [row]
(r/= "Jean-Luc Picard"
(r/get-field row :name))))
(r/update
(r/lambda [row]
{:posts
(r/append (r/get-field row :posts)
{:title "Shakespeare"
:content "What a piece of work is man.."})}))
(run conn))
Update returns a map that contains the following attributes:
:replaced
The number of documents that were updated.:unchanged
The number of documents that would have been modified except the new value was the same as the old value.:skipped
The number of documents that were left unmodified because there was nothing to do: either the row didn't exist or the new value is null.:errors
The number of errors encountered while performing the update; if errors occured, first_error contains the text of the first error.:deleted
and:inserted
Are 0 for an update operation.
([stream-or-single-selection lambda1-or-obj & {:as optargs}])
Replace documents in a table. The new document must have the same primary key as the original document. Accepts the following optional arguments:
:non-atomic
Allow non-atomic updates.:durability
:soft
or:hard
. Override the table or query's default durability setting.:return-vals
Abool
Return the old and new values of the row you're modifying when set to true (only valid for single row replacements).
;; Assuming :name is the primary key on the table
(-> (r/table "authors") (r/get "Wooster")
(r/replace {:tv-show "Jeeves"} :return-vals true)
(run conn))
([stream-or-single-selection & {:as optargs}])
Delete the rows in a selection. Accepts the following optional arguments:
:durability
Default::soft
; Override the table or query's default durability setting. Other possible values::hard
:return-vals
Default:true
; Return the old value of the row you're deleting when set to true (only valid for single row deletes) on the key:old_val
(-> (r/table "authors")
(r/filter (r/lambda [row]
(r/< (r/count (r/get-field row :posts))
3)))
(r/delete)
(run conn))
delete
returns a map with the following attributes:
:deleted
The number of documents that were deleted.:skipped
The number of documents from the selection that were left unmodified because there was nothing to do. For example, if you delete a row that has already been deleted, that row will be skipped.:errors
The number of errors encountered while deleting if errors occured, first_error contains the text of the first error.:inserted
Replaced, and unchanged: all 0 for a delete operation.
If you deleted only one row and return-vals
is true
then you also get the
following keys:
:new_val
Is nil.:old_val
Contains the value of the document you deleted
([db-name])
Reference a database. This will give you an error if you try to run it. If you want
a list of tables use r/table-list-db
(r/db "test")
(r/db :test)
([db table-name])
Select all documents on a table. This command can be chained with other commands to do further processing on the data
(-> (r/db "test") (r/table-db "authors") (run conn))
([table-name])
Like table-db except that it uses the default database.
(-> (r/table "authors") (run conn))
([table key])
Get a document by its primary key.
;; After setting the secondary index :name on the table "authors"
(-> (r/table "authors") (r/get "7644aaf2-9928-4231-aa68-4e65e31bf219")
(run conn))
([table keys-vec & [index]])
Get all documents where the given value matches the value of the requested index
;; After setting the secondary key :name on the table :authors
(-> (r/table "authors")
(r/get-all ["William Adama"] :name)
(run conn))
([stream-selection lower-key upper-key & [index]])
Get all documents between two keys. index can be the name of a secondary index.
[lower-key upper-key)
;; Assuming the primary key on our table is a number.
(-> (r/table "authors") (r/between 10 20) (run conn))
([sequence lambda1-or-obj & [default-val]])
Filter a sequence with either a function or a shortcut object.
The body of filter
is wrapped in an implicit (default .. false)
and you
can change the default value by specifying the default-val
optarg. If you
make the default (error)
, all errors caught by default will be rethrown
as if the default did not exist
(-> (r/table "authors")
(r/filter (r/lambda [row]
(r/= (r/get-field row :name) "William Adama")))
(run conn))
([sequence1 sequence2 predicate])
Returns the inner product of two sequences (e.g. a table and a filter result) filtered
by the predicate. The query compares each row of the left sequence with each row of
the right sequence to find all pairs of rows which satisfy the predicate (a lambda
of two arguments). When the predicate is satisfied, each matched pair of rows of both
sequences are combined into a result row.
(-> (r/table "marvel")
(r/inner-join (r/table "dc")
(lambda [marvel-row dc-row]
(r/< (get-field marvel-row :strength)
(get-field dc-row :strength))))
(run conn))
([sequence1 sequence2 predicate])
Computes a left outer join by retaining each row in the left table even if no match was found in the right table.
(-> (r/table "marvel")
(r/outer-join (r/table "dc")
(r/lambda [marvel-row dc-row]
(r/< (get-field marvel-row :strength)
(get-field dc-row :strength))))
(run conn))
([sequence1 left-attr sequence2 & [index]])
An efficient join that looks up elements in the right table by primary key.
index
defaults to :id
(-> (r/table "marvel") (r/eq-join "main_dc_collaborator" (r/table "dc"))
(run conn))
([sequence])
Used to 'zip' up the result of a join by merging the 'right' fields into 'left' fields of each member of the sequence.
(-> (r/table "marvel") (r/eq-join "main_dc_collaborator" (r/table "dc"))
(r/zip)
(run conn))
([sequence lambda1])
Transform each element of the sequence by applying the given mapping function.
(-> (r/table "authors")
(r/map (r/lambda [author]
(r/count (r/get-field author :posts))))
(run conn))
([sequence & pathspecs])
Takes a sequence of objects and a variable number of fields. If any objects in the sequence don't have all of the specified fields, they're dropped from the sequence. The remaining objects have the specified fields plucked out. Identical to has-fields followed by pluck.
;; Get a list of authors and their posts, excluding any authors that lack one.
(-> (r/table "authors") (r/with-fields :name :posts)
(run conn))
([sequence lambda1])
Map a function over a sequence and then concatenate the results together
;; Get all of the posts of all authors
(-> (r/table "authors")
(r/mapcat (r/lambda [author]
(r/get-field author :posts)))
(run conn))
([sequence & keys-or-orderings])
Sort the sequence by document values of the given key(s). Defaults to ascending
ordering. To specify order, wrap the key with (r/asc ..)
or (r/desc ..)
(-> (r/table "marvel")
(r/order-by :enemies_vanquished :damsels_saved)
(run conn))
([sequence n])
Skip a number of elements from the head of the sequence
;; Ignore the first authors sorted alphabetically
(-> (r/table "authors")
(r/order-by :name)
(r/skip 2)
(run conn))
([sequence n])
End the sequence after the given number of elements
;; Get 10 posts from all of our authors
(-> (r/table "authors")
(r/mapcat (r/lambda [author]
(r/get-field author :posts)))
(r/limit 10)
(run conn))
([sequence start-index end-index])
Trim the sequence to within the bounds provided.
(-> (r/table "marvel")
(r/order-by :strength)
(r/slice 5 10)
(run conn))
([sequence idx])
Get the nth element of a sequence. Zero indexed.
(-> (r/table "authors")
(r/nth 1)
(run conn))
([sequence item-or-predicate])
Get the indexes of an element in a sequence. If the argument is a predicate, get the indexes of all elements matching it.
(-> (r/indexes-of ["a" "b" "c"] "c") (run conn))
([sequence])
Test if a sequence is empty.
(-> (r/table "authors")
(r/empty?)
(run conn))
([sequence1 sequence2])
Concatenate 2 sequences
(-> (r/table "marvel")
(r/union
(r/table "dc"))
(run conn))
([sequence n])
Select a number of elements from the sequence with uniform random distribution.
(-> (r/table "authors")
(r/sample 2)
(run conn))
Compute smaller values from large sequences.
([sequence lambda2 & [init-val]])
Produce a single value from a sequence through repeated application of a reduction function.
;; How many posts are there?
(-> (r/table "authors")
(r/map (r/lambda [author] (r/count (r/get-field :posts))))
(r/reduce (r/lambda [acc next] (r/+ acc next)) 0)
(run conn))
([sequence & [filter]])
Count the number of elements in the sequence. With a single argument, count the number of elements equal to it. If the argument is a function, it is equivalent to calling filter before count.
(-> (r/table "authors")
(r/count)
(run conn))
([sequence])
Remove duplicates from the sequence.
(-> (r/table "marvel")
(r/mapcat (r/lambda [hero]
(r/get-field hero :villain-list)))
(r/distinct)
(run conn))
([sequence grouping mapping reduction & [base]])
Partition the sequence into groups based on the grouping
function. The elements of
each group are then mapped using the mapping
function and reduced using the
reduction
function. Generalized form of group-by.
;; Compare heroes against their weight class
(-> (r/table "marvel")
(r/grouped-map-reduce
(r/lambda [hero] (r/get-field :weight-class)) ; grouping
(r/lambda [hero] (r/pluck hero :name :strength)) :mapping
(r/lambda [acc hero]
(r/branch (r/< (r/get-field acc :strength) ; if
(r/get-field hero :strength))
hero ; then
acc ; else
))
{:name "none" :strength 0}) ; base
(run conn))
([sequence keys-array operation-map])
Groups a sequence by one or more attributes and then applies a reduction. The third argument is a special literal giving the kind of operation to be performed and anay necessary arguments.
At present group-by supports the following operations
- :count - count the size of the group
- {:sum attr} - sum the values of the given attribute accross the group
- {:avg attr} - average the values of the given attribute accross the group"
(-> (r/table "marvel")
(r/group-by [:weight-class] {:avg :strength})
(run conn))
(-> (r/table "marvel")
(r/group-by [:age :weight-class] :count)
(run conn))
(-> (r/table "marvel")
(r/group-by [:weight-class] {:sum :foes-defeated})
(run conn))
([sequence item-or-lambda1])
Returns whether or not a sequence contains the specified value, or if functions are provided instead, returns whether or not a sequence contains values matching all the specified functions.
(-> (r/table "marvel")
(r/get "ironman")
(r/get-field "opponents")
(r/contains? "superman")
(run conn))
([object-or-sequence & selectors])
Get a subset of an object by selecting some attributes to preserve, or map that over a sequence
(-> (r/table "marvel")
(r/get "IronMan")
(r/pluck :reactor-state :reactor-power)
(run conn))
([object-or-sequence & pathspecs])
The opposite of pluck. Get a subset of an object by selecting some attributes to discard, or map that over a sequence.
(-> (r/table "marvel") (r/get "IronMan") (without :personal-victories-list)
(run conn))
([& objects])
Merge objects. Right-preferential.
(-> (r/table "marvel") (r/get "IronMan")
(r/merge (-> (r/table "loadouts")
(r/get :alien-invasion-kit)))
(run conn))
The query literal
takes a single argument and it can be used to indicate merge
to replace the other object rather than merge it.
([sequence item])
Append a value to an array
(-> (r/table "authors")
(r/filter (r/lambda [author]
(r/= "William Adama"
(r/get-field author name))))
(r/update (r/lambda [author]
{:posts
(r/append (r/get-field row :posts)
;; Appending a new post
{:title "Earth"
:content "Earth is a dream.."}))))
(run conn))
([array item])
Prepend a value to an array
(-> (r/table "authors")
(r/filter (r/lambda [author]
(r/= "William Adama"
(r/get-field author name))))
(r/update (r/lambda [author]
{:posts
(r/prepend (r/get-field row :posts)
;; Prepend a post
{:title "Cylons"
:content "The cylon war is long over"}))))
(run conn))
([array1 array2])
Remove the elements of one array from another array.
(-> (r/table "marvel")
(r/get "IronMan")
(r/get-field :equipment)
(r/difference "Boots")
(run conn))
([array item])
Add a value to an array as if the array was a set.
(-> (r/table "marvel")
(r/get "IronMan")
(r/get-field "equipment")
(r/set-insert "new-boots")
(run conn))
([array1 array2])
Add several values to an array as if it was a set
(-> (r/table "marvel")
(r/get "IronMan")
(r/get-field "equipment")
(r/set-union ["new-boots" "arc-reactor"])
(run conn))
([array1 array2])
Intersect 2 arrays returning values that occur in both of them as a set.
(-> (r/table "marvel")
(r/get "IronMan")
(r/get-field "equipment")
(r/set-intersection ["new-boots" "arc-reactor"])
(run conn))
([sequence-or-object])
Get a single field from an object. If called on a sequence, gets that field from every object in the sequence, skipping objects that lack it.
(-> (r/table "marvel")
(r/get "IronMan")
(r/get-field "first-appearance")
(run conn))
([object & pathspecs])
Check whether an object contains all the specified fields or filters a sequence so that al objects inside of it contain all the specified fields
(-> (r/table "marvel")
(r/has-fields "spouse")
(run conn))
([array idx item])
Insert a value in to an array at a given index.
(-> ["IronMan" "SpiderMan"]
(r/insert-at 1 "Hulk")
(run conn))
([array1 idx array2])
Insert several values into an array at a given index.
(-> ["IronMan" "SpiderMan"]
(r/splice-at 1 ["Hulk" "Thor"])
(run conn))
([array idx & [end-idx]])
Remove an element from an array at a given index.
(-> ["IronMan" "Hulk" "SpiderMan"]
(r/delete-at 1)
(run conn))
([array idx item])
Change a value in an array at a given index.
(-> ["IronMan" "Bruce" "SpiderMan"]
(r/change-at 1 "Hulk")
(run conn))
([object-or-single-selection])
Return an array containing all of the object's keys
(-> (r/table "authors")
(r/get "7644aaf2-9928-4231-aa68-4e65e31bf219")
(r/keys)
(run conn))
([str regexp])
Returns a match object if the string matches the regexp. Accepts RE2 syntax https://code.google.com/p/re2/wiki/Syntax Accepts clojure regexp.
(-> (r/table "users")
(r/filter (r/lambda [user]
(r/match (r/get-field user :name)
#"^A")))
(run conn))
The following symbols are also part of the api and they should be properly namespace qualified:
r/+
Add numbers or concatenate strings or arrays.
r/-
Substract numbers.
r/*
Multiply numbers or make a periodic array.
r/div
Divide numbers. Note that it's not r//
r/mod
Find the remainder of two numbers.
r/=
Test for equality.
r/not=
Test for inequality.
r/>
Greater than.
r/>=
Greater equal.
r/<
Lower than.
r/<=
Lower equal.
r/not
Logical inverse.
([])
Return a time object representing the time in UTC. The command now() is computed once when the server receives the query, so multiple instances of r.now() will always return the same time inside a query.
(-> (r/table "users")
(r/insert {:name "John"
:subscription-date (r/now)})
(run conn))
([year month day & [timezone]] [year month day hour minute second & [timezone])
Create a time object for a specific time. Timezone is a string like: "-06:00"
;; Update the birthdate of the user "John" to November 3rd, 1986 UTC
(-> (r/table "user")
(r/get "John")
(r/update {:birthdate (r/time 1986 11 3 "Z")])
(run conn))
([epoch-time])
Create a time object based on seconds since epoch.
;; Update the birthdate of the user "John" to November 3rd, 1986
(-> (r/table "user")
(r/get "john")
(r/update {:birthdate (r/epoch-time 531360000)})
(run conn))
([iso8601-date])
Create a time object based on an iso8601 date-time string.
(-> (r/table "user")
(r/get "John")
(r/update {:birth (r/iso8601 "1986-11-03T08:30:00-07:00")})
(run conn))
([time timezone])
Return a new time object with a different timezone. Results returned by functions that take the timezone into account will be different.
(-> (r/now)
(r/in-timezone "-08:00)
(r/hours)
(run conn))
([time])
Return the timezone of the time object
(-> (r/table "user")
(r/filter (r/lambda [user]
(r/= "-07:00"
(-> (r/get-field user :subscription-date)
(r/timezone)))))
(run conn))
([time start-time end-time])
Returns whether the time is in the range [start-time end-time)
(-> (r/table "posts")
(r/filter (r/lambda [post]
(-> (r/get-field :date)
(r/during (r/time 2013 12 1) (r/time 2013 12 10)))))
(run conn))
([time])
Return a new time object only based on the day, month and year
(-> (r/table "users")
(r/filter (r/lambda [user]
(r/= (-> (r/now) (r/date))
(r/get-field user :birthday))))
(run conn))
([time])
Return the number of seconds elapsed since the beginning of the day stored in the time object.
;; Posts submitted before noon
(-> (r/table "posts")
(r/filter (r/lambda [post]
(r/> (* 12 60 60) ; Can be left as clojure.core/*
(-> (r/get-field post :date)
(r/time-of-day)))))
(run conn))
All of these take a time
as the only argument.
r/year
Return the year of a time object.
r/month
Return the month as a number between 1 and 12.
r/day
Return the day as a number between 1 and 31.
r/day-of-week
Return the day of week as a number between 1 and 7 (ISO 8601).
r/day-of-year
Return the day of the year as a number between 1 and 366 (ISO 8601).
r/hours
Return the hour as a number between 0 and 23.
r/minutes
Return the minute in a time object as a number between 0 and 59.
r/seconds
Return the seconds in a time object as a number between 0 and 59.999 (double precision).
([time])
Convert a time object to its ISO 8601 format.
(-> (r/now)
(r/to-iso8601)
(run conn))
([time])
Convert a time to its epoch time.
(-> (r/now)
(r/->epoch-time)
(run conn))
([test then else])
Like an if. The test can be any value. Truthiness appears to be similar to
clojure's (false
and nil
are falsey, everything else is truthy).
(-> (r/table "marvel")
(r/map (r/lambda [hero]
(r/branch (r/<= 100
(r/get-field hero :victories))
(r/+ (r/get-field hero :name) " is a superhero") ; then
(r/+ (r/get-field hero :name) " is a hero")))) ; else
(run conn))
([& bools])
Like clojure's short-circuiting or
except that: It short circuits inside
RethinkDB and it is a little inneficient in that if your "booleans" are queries
it will probably run them twice.
The same truthy/falsey rules apply as with branch
.
(-> (r/or false false false true) (run conn))
(-> (r/or false nil false "hello!" nil) (run conn))
([& bools])
Like clojure's short-circuiting and
except that: It short circuits inside
RethinkDB and it is a little inneficient in that if your "booleans" are queries
it will probably run them twice.
The same truthy/falsey rules apply as with branch
.
(-> (r/and true true true) (run conn))
(-> (r/and 1 2 3 nil) (run conn))
([& bools])
A short circuiting or that returns a boolean
(-> (r/any false false true) (run conn))
([& bools])
Returns true if all of its arguments are true (short-circuiting).
(-> (r/all true true true) (run conn))
([sequence lambda1])
Calls its function with each entry in the sequence and executes the array of terms that function returns.
(-> (r/table "marvel")
(r/foreach (r/lambda [hero]
(-> (r/table "villains")
(r/get (r/get-field hero :villain-defeated)))))
(r/delete)
(run conn))
([& [s]])
Throw a runtime error. If called with no arguments inside the second argument to default, re-throw the current error.
(-> (r/error "kaput") (run conn))
([item-to-check item-or-lambda1])
Evaluates its first argument. If that argument returns NULL or throws an error related to the absence of an expected value, default will either return its second argument or execute it if it's a function. If the second argument is a function it will be passed either the text of the error or NULL as its argument.
(-> (r/table "projects")
(r/map (r/lambda [p]
(r/+ (r/default (r/get-field p :staff) 0)
(r/default (r/get-field p :management) 0))))
(run conn))
([item])
Parse a clojure value to construct a json value. Strings, keywords, numbers,
vectors, maps and booleans are allowed. This is the equivalent of expr
in
python. Note that since these queries are functions and not methods, this
function is hardly ever needed since it is already implicit.
(r/parse-val [1 false "hello" :goodbye])
([js-string])
Create a javascript expression.
(-> (r/js "1 + 1") (run conn))
([item type-string])
Convert a value of one type into another.
You can convert: a selection, sequence, or object into an ARRAY, an array of pairs into an OBJECT, and any DATUM into a STRING.
(-> (r/table "marvel")
(r/coerce-to :array)
(run conn))
([item])
Get the type of a value.
(-> (r/parse-val "hello!")
(r/type)
(run conn))
([any])
Get information about a rql value
(-> (r/table "marvel")
(r/info)
(run conn))
([json-str])
Parse a JSON string on the server.
(-> (r/json "[1,2,3]") (run conn))
Time constants are already evaluated and so they don't have to be called as fns.
r/monday
=> 1
r/tuesday
=> 2
r/wednesday
=> 3
r/thursday
=> 4
r/friday
=> 5
r/saturday
=> 6
r/sunday
=> 7
r/january
=> 1
r/february
=> 2
r/march
=> 3
r/april
=> 4
r/may
=> 5
r/june
=> 6
r/july
=> 7
r/august
=> 8
r/september
=> 9
r/october
=> 10
r/november
=> 11
r/december
=> 12
Copyright © 2013 Chris Allen, César Bolaños
Distributed under the Eclipse Public License, the same as Clojure.