tarantool: Library for working with tarantool from nginx with the embedded Lua module or with nginx-module-lua
Installation
If you haven't set up RPM repository subscription, sign up. Then you can proceed with the following steps.
CentOS/RHEL 7 or Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-tarantool
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-tarantool
To use this Lua library with NGINX, ensure that nginx-module-lua is installed.
This document describes lua-resty-tarantool v0.3 released on Oct 21 2015.
Introduction
This is a library to connect to the tarantool NoSQL database. This database has very interesting features that make it be sort of a bridge between a traditional SQL based database and document oriented storages like CouchDB.
It's a fork of another project that I was unhappy with. It's abundantly documented and is update regarding the tarantool API. Notably wtih support for the upsert command.
Another thing to bear in minf is that the library tries to be
consistent between the way the update
and upsert
commands are
issued in the console using Lua and the way the API works. Notably the
field numbers. In the console a field number takes into account the
existence of a primary index as the first field. Hence any field that
come afterward will have an position that accounts for
it. Specifically when specifying the operators to use for the update
or upsert
operations.
Usage
Creating a connection
local tar = require 'resty.tarantool'
local tar, err = tnt:new({
host = '127.0.0.1',
port = 3301,
user = 'luser',
password = 'some password',
socket_timeout = 2000,
})
luser
with password some password
. See the
Tarantool manual in authentication
for details on how to setup users and assigning privileges to them.
The socket timeout (receive and send) is 2 seconds (2000 ms).
set_timeout
settimeout(<connection object>, <timeout in ms>)
Sets both the send and receive timeouts in miliseconds for a given socket.
tnt:set_timeout(5000) -- 5s timeout for send/receive operations
The function returns true if the setting succeeds, nil
if not. Note
that for the timeout to take effect this function needs to be invoked
before the connection is established, i.e., before invoking the
connect
function. Alternatively the timeout can be specified when
creating the connection object (cosocket).
connect
connect(<connection object>)
Connects the socket created above to the port and address specified when creating the connection object.
tar:connect()
nil
if not.
set_keepalive
set_keepalive(<connection object>)
Makes the connection created get pushed to a connection pool so that the connection is kept alive across multiple requests.
tar:set_keepalive()
The function returns true if the socket is successfully pushed to
connection pool (set keepalive). nil
if not.
disconnect
disconnect(<connection object>)
Closes a connection to a given tarantool server running on a given address and port.
tar:disconnect()
The function returns true if the connection is successfully closed. nil
if not.
ping
The ping command is useful for monitoring the tarantool server to see
if it's available. If it's available for queries it returns the string
PONG
.
tar:ping()
-- returns PONG
select
The select operation queries a given database (space) for retrieving records.
select(<connection object>, <space name>, <index>, <key>, <options>)
where <options>
is an optional argument that can consists of a table
that can have the following keys:
offset
: number of records to skip when doing the query.limit
: the maximum number of records to return.iterator
: a number specifiyng the iterator to use. Specified by the table:
local iterator_keys = {
EQ = 0, -- equality
REQ = 1, -- reverse equality
ALL = 2, -- all tuples in an index
LT = 3, -- less than
LE = 4, -- less than or equal
GE = 5, -- greater than or equal
GT = 6, -- greater than
BITSET_ALL_SET = 7, -- bits in the bitmask all set
BITSET_ANY_SET = 8, -- any of the bist in the bitmask are set
BITSET_ALL_NOT_SET = 9, -- none on the bits on the bitmask are set
}
select examples
Query the _space
space (DB) to get the space id of the _index
space.
local res, err = tar:select('_space', 'name', '_index')
-- response:
[2881,"_index","memtx",0,"",
[{"name":"id","type":"num"},
{"name":"iid","type":"num"},
{"name":"name","type":"str"},
{"name":"type","type":"str"},
{"name":"opts","type":"array"},
{"name":"parts","type":"array"}]]]
box.space._space.index.name:select{ '_index' }
Query the space 'activities' for the activities with a price
less than 300
-- N.B. price is an index of the activities space.
local res, err = tar:select('activities', 'price', 300, { iterator = 'LT' })
box.space.activities.index.price:select({ 300 }, { iterator = 'LT' })
insert
insert(<connection object>, <space name>, <tuple>)
where <tuple>
is the tuple to insert into <space>
while setting
the primary index, which is unique, to the value specified in the
tuple.
The function returns the inserted record if the operation succeeds.
insert examples
local res, err = tar:insert('activities', { 16, 120, { activity = 'surf', price = 121 } })
-- response:
[[16,120,{"activity":"surf","price":121}]]
box.space.activities:insert({16, 120, { activity = 'surf', price = 121 }})
replace
replace(<connection object>, <space name>, <tuple>)
The replace command is similar in the invocation and signature to the insert command. But now we're looking for replacing a record that exists already instead of inserting a new one. We need again the value of a primary unique index. But now the value must exist for the operation to succeed. If the operations succeeds the record with the replaced values is returned.
replace examples
local res, err = tar:replace('activities', { 16, 120, { activity = 'surf', price = 120 } })
-- response:
[[16,120,{"activity":"surf","price":120}]]
The above request is equivalent to the console request:
box.space.activities:update({ 16, 120, { activity = 'surf', price = 120 }})
update
update(<connection object>, <space name>, <index>, <key>, <operator list>)
where <operator list>
is the list of operators as specified n
tarantool manual.
The pair (<key>
is a value of the primary (unique) <index>
.
<operator list>
is a table of the form:
{ <operator>, <field position>, <value> }
+
for adding to a numeric field.-
for subtracting to a numeric field.&
for bitwise AND operation between two unsigned integers.|
for bitwise OR operation between two unsigned integers.^
for bitwise XOR operation between two unsigned integers.:
for string splicing.!
for field insertion.#
for field deletion.=
for assigning a given value to a field.
it returns the updated record if the operation is successful.
update examples
local res, err = tar:update('activities', 'primary', 16, { { '=', 2, 341 }, { '=', 3, { activity = 'kitesurfing', price = 341 }}} )
-- response:
[16,341,{"activity":"kitesurfing","price":341}]]
primary
index 16 that we inserted above was updated.
The above request is equivalent to the console request:
box.space.activities.index.primary({ 16 }, { { '=', 2, 341 }, { '=', 3, { activity = 'kitesurfing', price = 341 }}})
upsert
upsert(<connection object>, <space name>, <key>, <operator list>, <new tuple>)
apart from the <new tuple>
argument the function signature is
similar to update. In fact upsert is two commands in one. update if
the record specified by the pair (<new tuple>
is the tuple to be inserted if the <key>
value doesn't
exist in the <index>
. It returns an empty table {}
if the
operation is successful. If the operation is unsuccessful it returns nil
.
upsert examples
An insert.
local res, err = tar:upsert('activities', 17, { { '=', 2, 450 }, { '=', 3, { activity = 'submarine tour 8', price = 450 }}}, { 17, 450, { activity = 'waterski', price = 365 }})
-- response:
{}
{ 18, 450, { activity = 'waterski', price = 365 }}
box.space.activities:upsert({ 17 }, { { '=', 2, 450 }, { '=', 3, { activity = 'submarine tour 8', price = 450 }}}, { 17, 450, { activity = 'waterski', price = 365 }})
local res, err = tar:upsert('activities', 17, { { '=', 2, 450 }, { '=', 3, { activity = 'submarine tour 8', price = 450 }}}, { 18, 285, { activity = 'kitesurfing', price = 285 }})
-- response:
{}
primary
index (unique).
delete
delete(<connection object>, <space>, <key>)
deletes the record uniquely specified by <key>
from <space>
. Note
that <key>
must belong to a primary (unique) index. It returns the
deleted record if the operation is successful.
delete examples
local response, err = tar:delete('activities', 17)
-- response:
[17,450,{"activity":"waterski","price":365}]]
The above request is equivalent to the console request:
box.space.activities:delete({ 17 })
call
call(<connection object>, <proc>, <args>)
Invokes a stored procedure (Lua function) in the tarantool server we're connected to. It returns the results of the invocation.
call examples
Since the tarantool console is a Lua REPL any function can be invoked as long as it is available in the environment.
local res, err = tar:call('table.concat', { {'hello', ' ', 'world' } })
-- response:
[["hello world"]]
table.concat
function from the table library to
concatenate the table:
{'hello', ' ', 'world' }
table.concat({'hello', ' ', 'world' })
For many examples of tarantool stored procedures see the repository; https://github.com/mailru/tarlua
hide_version_header
hide_version_header(<connection object>)
By default each response sends a custom HTTP header
X-Tarantool-Version
with the version of the tarantool server.
X-Tarantool-Version: 1.6.6-191-g82d1bc3
Invoking hide_version_header
removes the header.
tar:hide_version_header()
It returns no values.
GitHub
You may find additional configuration tips and documentation for this module in the GitHub repository for nginx-module-tarantool.