Browse Source

Release v0.6

Change API, please, do not pull me, just see README
Now have `types` object, see README
Standartized API of connections and connection pools
By default, will not create connection pool, but connection
Other small changes and fixes
master
annelin 1 year ago
parent
commit
f7446ebc28
3 changed files with 81 additions and 80 deletions
  1. 26
    36
      README.md
  2. 19
    19
      pg_tarantool/init.lua
  3. 36
    25
      pg_tarantool/types/init.lua

+ 26
- 36
README.md View File

@@ -35,30 +35,29 @@ data = conn:query("SELECT 1 as ONE, '2' as TWOSTRING")

## API Documentation

### `link = pg:connect(opts = {})`
### `conn = pg:connect(opts = {size = 0})`
### `link = pg:connect(opts = {connections = 1})` or `conn = pg:connect(opts = {})`

Connect to a database.
Connect to a database.
Returns _link_ (connections pool) or _conn_ (single connection)

*Options*:

- `host` - a hostname to connect
- `port` - a port numner to connect
- `user` - username
- `pass` or `password` - a password
- `db` - a database name
- `password` - a password
- `dbname` - a database name
- `sslmode` - a ssl mode used in this connection (see [Table 31-1. SSL Mode Descriptions][PG_sslmode]) (default = 'disable')
- `size` - connection pool size (0 means do not create connection pool, just establish single connection) (default = '1')
- `connections` - connection pool size (0 means do not create connection pool, just establish single connection) (default = '0')
- `conn_string` (mutual exclusive with host, port, user, pass, db) (see [PostgreSQL Connection String][PG_connstring]

*Returns*:

- `link` (or `conn` if single connection established) on success
- `link`, database connections pool,
- `conn`, database conection,
- `false`, `error_reason` on error

### `conn:query(statement, ...)`
### `link:query(statement, ...)`
### `link(statement, ...)`
### `link:query(statement, ...)` or `conn:query(statement, ...)`

Execute a statement with arguments in the current transaction.
Arguments can be: numeric, string or table types. Arguments will escape-quote automatically.
@@ -77,8 +76,7 @@ tarantool> conn:query("SELECT ? AS a, 'xx' AS b", 42)
b: xx
...
```
### `conn:fetch(statement, ...)`
### `link:fetch(statement, ...)`
### `link:fetch(statement, ...)` or `conn:fetch(statement, ...)`

Execute a statement and returns query results without an associative array.

@@ -99,31 +97,13 @@ Release single connection to database link pool.

*Returns*: `true`

### `link:close()`
### `link:close()` or `conn:close()`

Closes database link.
Closes connection or link.

*Returns*: `true`

### `conn:begin()`,

Begin a transaction.

*Returns*: `true`

### `conn:commit()`

Commit current transaction.

*Returns*: `true`

### `conn:rollback()`

Rollback current transaction.

*Returns*: `true`

### `conn:ping()`
### `link:ping()` or `conn:ping()`

Execute a dummy statement to check that connection is alive.

@@ -132,11 +112,21 @@ Execute a dummy statement to check that connection is alive.
- `true` on success
- `false` on failure

### `conn:close()`
### `link.types` or `conn.types`

Closes connection.
PostgreSQL types classes.

*Returns*: `true`
*Cointains methods*:

- `types.encode(string, escape_function)` -- encodes SQL expression and escapes it with given function
- `types.decode(variable, pgsql_typeid)` -- decodes SQL result as given type id
- `types.array.<type>` -- encodes Lua table as <type> (_json_ or _hstore_)

*You also can re-define handlers*:

- For example, to re-define decoder for `nil`: `types.enum[-1] = function()...`
- For example, to re-define encoder for `nil`: `types.enum['nil'] = function()...`

## Comments


+ 19
- 19
pg_tarantool/init.lua View File

@@ -13,8 +13,8 @@ local function build_conn_string(opts)
if opts.host then table.insert(conn_opts, string.format(" host='%s'", opts.host)) end
if opts.port then table.insert(conn_opts, string.format(" port='%s'", opts.port)) end
if opts.user then table.insert(conn_opts, string.format(" user='%s'", opts.user)) end
if opts.pass or opts.password then table.insert(conn_opts, string.format(" password='%s'", opts.pass or opts.password)) end
if opts.db then table.insert(conn_opts, string.format(" dbname='%s'", opts.db)) end
if opts.password then table.insert(conn_opts, string.format(" password='%s'", opts.password)) end
if opts.dbname then table.insert(conn_opts, string.format(" dbname='%s'", opts.dbname)) end
if opts.sslmode then table.insert(conn_opts, string.format(" sslmode='%s'", opts.sslmode)) end
return table.concat(conn_opts)
end
@@ -100,15 +100,6 @@ conn_mt = {
for k,v in pairs(res[1] or {}) do table.insert(result, v) end
if #result == 0 then return nil; elseif #result == 1 then return result[1]; elseif #result > 1 then return unpack(result); end
end,
begin = function(self)
return self:query('BEGIN') ~= nil
end,
commit = function(self)
return self:query('COMMIT') ~= nil
end,
rollback = function(self)
return self:query('ROLLBACK') ~= nil
end,
ping = function(self)
local status, data, msg = pcall(self.query, self, 'SELECT 1 AS code')
return (status and data[1] and data[1].code == 1)
@@ -141,7 +132,8 @@ conn_mt = {
end
self.queue:put(true)
return msg
end
end,
types = types
}
}

@@ -154,7 +146,7 @@ conn_mt = {
-- Close pool
local function pool_close(self)
self.usable = false
for i = 1, self.size do
for i = 1, self.connections do
local pg_conn = self.queue:get()
if pg_conn ~= nil then
pg_conn:close()
@@ -196,6 +188,12 @@ local function pool_fetch(self, sql, ...)
self:put(conn)
return res, err
end
local function pool_ping(self, sql, ...)
local conn = self:get()
local res, err = conn:ping(sql, ...)
self:put(conn)
return res, err
end

pool_mt = {
__call = pool_query,
@@ -205,6 +203,7 @@ pool_mt = {
close = pool_close;
query = pool_query;
fetch = pool_fetch;
ping = pool_ping;
},
}

@@ -214,21 +213,21 @@ pool_mt = {
------------------------------------------------------------------

-- Create connection pool. Accepts pg connection params (host, port, user,
-- password, dbname) separatelly or in one string, connections ( pool size or 0 if single ) and raise flag.
local function connect(opts)
opts = opts or {}
opts.connections = opts.connections or 0
local conn_string = build_conn_string(opts)
opts.size = opts.size or 1
local queue = fiber.channel(opts.size)

-- create single conn --
if opts.size == 0 then
if opts.connections == 0 then
local status, pg_conn = driver.connect(conn_string)
if status < 0 then return false, pg_conn end
return conn_create(pg_conn)
-- create connection pool --
else
for i = 1, opts.size do
local queue = fiber.channel(opts.connections)
for i = 1, opts.connections do
local status, conn = driver.connect(conn_string)
if status < 0 then
while queue:count() > 0 do local pg_conn = queue:get(); pg_conn:close(); end
@@ -237,8 +236,8 @@ local function connect(opts)
queue:put(conn)
end

return setmetatable({ host = opts.host, port = opts.port, user = opts.user, pass = opts.pass, db = opts.db, size = opts.size, conn_string = conn_string, queue = queue, usable = true, types = types}, pool_mt)
return setmetatable({ host = opts.host, port = opts.port, user = opts.user, pass = opts.pass, db = opts.db, connections = opts.connections, conn_string = conn_string, queue = queue, usable = true, types = types}, pool_mt)
end
end

return { connect = connect }
return { connect = connect, types = types }

+ 36
- 25
pg_tarantool/types/init.lua View File

@@ -1,39 +1,48 @@
-- pg-tarantool types handler --
local _e = {}
local t = {
local _t = {}

-- type classes --
_t.class = {
varchar = { encode = function(str, escape) return escape(str) end },
integer = { decode = tonumber },
boolean = { decode = function(str) return (str == 't') end },
null = { decode = function() return "\0" end, encode = function() return "NULL" end },
bytea = { decode = function(str) if str:sub(1, 2) == '\\x' then return str:sub(3):gsub('..', function(hex) return string.char(tonumber(hex, 16)) end); else return str:gsub('\\(%d%d%d)', function(oct) return string.char(tonumber(oct, 8)) end); end end },
array = {}, json = {}, hstore = {},
array = require 'pg_tarantool.types.array',
json = require 'pg_tarantool.types.json',
hstore = require 'pg_tarantool.types.hstore',
default = function(str) return str end,
}

_e.enum = {}
_e.types = t
_e.decode = function(str, n) return (_e.enum[n] or _e.enum.default)(str) end
_e.encode = function(str, esc) return (_e.enum[type(str)] or _e.enum.default)(str, esc) end
_e.init = function(typ)
t[typ or 0] = (typ) and require('pg_tarantool.types.' .. typ) or nil
_e.types, _e.enum = t, {
-- conversion from pg types to lua types --
[-1] = t.null.decode, [16] = t.boolean.decode, [17] = t.bytea.decode, [114] = t.json.decode, [3802] = t.json.decode, [16526] = t.hstore.decode,
[20] = t.integer.decode, [21] = t.integer.decode, [23] = t.integer.decode, [700] = t.integer.decode, [701] = t.integer.decode, [1700] = t.integer.decode,
[1000] = t.array.decode_int, [1005] = t.array.decode_int, [1007] = t.array.decode_int, [1016] = t.array.decode_int, [1021] = t.array.decode_int, [1022] = t.array.decode_int, [1031] = t.array.decode_int,
[1002] = t.array.decode_str, [1009] = t.array.decode_str, [1014] = t.array.decode_str, [1015] = t.array.decode_str, [2951] = t.array.decode_str,
-- conversion from lua types to pg types --
['string'] = t.varchar.encode,
['table'] = t.array.encode,
['nil'] = t.null.encode,
-- default: return value without any modifying --
default = t.default,
}
end
-- types enum --
_t.enum = {
[-1] = _t.class.null.decode,
[16] = _t.class.boolean.decode,
[17] = _t.class.bytea.decode,
[114] = _t.class.json.decode, [3802] = _t.class.json.decode,
[16526] = _t.class.hstore.decode,
[20] = _t.class.integer.decode, [21] = _t.class.integer.decode, [23] = _t.class.integer.decode, [700] = _t.class.integer.decode, [701] = _t.class.integer.decode, [1700] = _t.class.integer.decode,
[1000] = _t.class.array.decode_int, [1005] = _t.class.array.decode_int, [1007] = _t.class.array.decode_int, [1016] = _t.class.array.decode_int, [1021] = _t.class.array.decode_int, [1022] = _t.class.array.decode_int, [1031] = _t.class.array.decode_int,
[1002] = _t.class.array.decode_str, [1009] = _t.class.array.decode_str, [1014] = _t.class.array.decode_str, [1015] = _t.class.array.decode_str, [2951] = _t.class.array.decode_str,
-- conversion from lua types to pg types --
['string'] = _t.class.varchar.encode,
['table'] = _t.class.array.encode,
['json'] = _t.class.json.encode,
['hstore'] = _t.class.hstore.encode,
['nil'] = _t.class.null.encode,
-- default: return value without any modifying --
default = _t.class.default,
}

_e.init()
return _e
-- encode / decode fuctions --
_t.decode = function(var, id) return (_t.enum[id] or _t.enum.default)(var) end
_t.encode = function(var, escape) local id = (type(var) == 'table' and var.___type___) and var.___type___ or type(var); return (_t.enum[id] or _t.enum.default)(var, escape) end

-- type flags (for arrays) --
_t.array = {
json = function(var) var.___type___ = 'json'; return var; end,
hstore = function(var) var.___type___ = 'hstore'; return var; end,
}

-- return pg-tarantool types handler --
return _t

Loading…
Cancel
Save