~mna/xpgsql

d598267981f39806dc989e25aa04e92513b78f5e — Martin Angers 2 months ago 9ea2b8a v0.6
Add :get and :select methods
4 files changed, 213 insertions(+), 1 deletions(-)

M README.md
A rockspecs/xpgsql-0.6-1.rockspec
M test/main.lua
M xpgsql.lua
M README.md => README.md +19 -0
@@ 105,6 105,25 @@ Note that INSERT..RETURNING must use Connection:query as it returns values.
The statement may contain $1, $2, etc. placeholders, they will be replaced
by the extra arguments provided to the method.

### `Connection:get(stmt, ...)`

Combines a call to `:query` with a call to `.model` to return the first row
decoded into a table with column names as keys. If the last parameter
after the statement is a function, it is used as the 'newf' argument to
the call to `.model`, to provide further initialization of the row's table.
Returns the resulting table, or nil if the query did not return any row.
It returns nil along with any error in case of failure, as returned by
`:query`.

### `Connection:select(stmt, ...)`

Combines a call to `:query` with a call to `.models` to return an array of rows
each decoded into a table with column names as keys. If the last parameter
after the statement is a function, it is used as the 'newf' argument to
the call to `.models`, to provide further initialization of each row's table.
Returns the resulting array (which is empty if the query returned no row),
or nil and any error as returned by `:query`.

### `Connection:close()`

Closes the connection and frees resources associated with it.

A rockspecs/xpgsql-0.6-1.rockspec => rockspecs/xpgsql-0.6-1.rockspec +19 -0
@@ 0,0 1,19 @@
package = "xpgsql"
version = "0.6-1"
source = {
   url = "git+ssh://git@git.sr.ht/~mna/xpgsql"
}
description = {
   homepage = "Lua module providing a straightforward API to the luapgsql library.",
   license = "BSD"
}
dependencies = {
   "lua >= 5.3, < 5.5",
   "luapgsql >= 1.6.1-1"
}
build = {
   type = "builtin",
   modules = {
      xpgsql = "xpgsql.lua"
   }
}

M test/main.lua => test/main.lua +124 -0
@@ 317,6 317,130 @@ function TestXpgsql.test_models_some_fn()
  conn:close()
end

function TestXpgsql.test_get_none()
  ensure_table()

  local conn = assert(xpgsql.connect())
  local res = conn:get([[
    SELECT
      *
    FROM
      test_xpgsql
    WHERE
      val = $1
  ]], 'no-such-val')

  lu.assertNil(res)

  conn:close()
end

function TestXpgsql.test_get_some()
  ensure_table()
  insert_rows('ee')

  local conn = assert(xpgsql.connect())
  local res = conn:get([[
    SELECT
      *
    FROM
      test_xpgsql
    WHERE
      val = $1
  ]], 'ee')

  lu.assertEquals(res.val, 'ee')
  lu.assertString(res.id)
  lu.assertTrue(tonumber(res.id) > 0)

  conn:close()
end

function TestXpgsql.test_get_some_fn()
  ensure_table()
  insert_rows('ff')

  local conn = assert(xpgsql.connect())
  local res = conn:get([[
    SELECT
      *
    FROM
      test_xpgsql
    WHERE
      val = $1
  ]], 'ff', newmodel)

  lu.assertEquals(res.val, 'ff')
  lu.assertNumber(res.id)
  lu.assertTrue(res.id > 0)

  conn:close()
end

function TestXpgsql.test_select_none()
  ensure_table()

  local conn = assert(xpgsql.connect())
  local res = conn:select([[
    SELECT
      *
    FROM
      test_xpgsql
    WHERE
      val = $1
  ]], 'no-such-val')

  lu.assertEquals(res, {})

  conn:close()
end

function TestXpgsql.test_select_some()
  ensure_table()
  insert_rows('gg', 'hh')

  local conn = assert(xpgsql.connect())
  local res = conn:select([[
    SELECT
      *
    FROM
      test_xpgsql
    WHERE
      val IN ($1, $2)
    ORDER BY
      val
  ]], 'gg', 'hh')

  lu.assertEquals(#res, 2)
  lu.assertEquals(res[1].val, 'gg')
  lu.assertEquals(res[2].val, 'hh')

  conn:close()
end

function TestXpgsql.test_select_some_fn()
  ensure_table()
  insert_rows('ii', 'jj')

  local conn = assert(xpgsql.connect())
  local res = conn:select([[
    SELECT
      *
    FROM
      test_xpgsql
    WHERE
      val IN ($1, $2)
    ORDER BY
      val
  ]], 'ii', 'jj', newmodel)

  lu.assertEquals(#res, 2)
  lu.assertNumber(res[1].id)
  lu.assertNumber(res[2].id)

  conn:close()
end

function TestXpgsql.test_format_array_string()
  ensure_table()
  insert_rows('k', 'l')

M xpgsql.lua => xpgsql.lua +51 -1
@@ 18,6 18,8 @@ local Connection = {
}
Connection.__index = Connection

local M = {}

local function new_connection(rawconn)
  local o = {_conn = rawconn}
  return setmetatable(o, Connection)


@@ 158,8 160,56 @@ function Connection:exec(stmt, ...)
  return exec_or_query(self._conn, stmt, pgsql.PGRES_COMMAND_OK, ...)
end

-- Combines a call to :query with a call to .model to return the first row
-- decoded into a table with column names as keys. If the last parameter
-- after the statement is a function, it is used as the 'newf' argument to
-- the call to .model, to provide further initialization of the row's table.
-- Returns the resulting table, or nil if the query did not return any row.
-- It returns nil along with any error in case of failure, as returned by
-- :query.
function Connection:get(stmt, ...)
	local newf

local M = {}
	local args = table.pack(...)
	if args.n > 0 then
		local last = args[#args]
		if type(last) == 'function' then
			newf = last
			args.n = args.n - 1
		end
	end

	local res, e1, e2, e3, e4 = self:query(stmt, table.unpack(args, 1, args.n))
	if not res then
		return e1, e2, e3, e4
	end
	return M.model(res, newf)
end

-- Combines a call to :query with a call to .models to return an array of rows
-- each decoded into a table with column names as keys. If the last parameter
-- after the statement is a function, it is used as the 'newf' argument to
-- the call to .models, to provide further initialization of each row's table.
-- Returns the resulting array (which is empty if the query returned no row),
-- or nil and any error as returned by :query.
function Connection:select(stmt, ...)
	local newf

	local args = table.pack(...)
	if args.n > 0 then
		local last = args[#args]
		if type(last) == 'function' then
			newf = last
			args.n = args.n - 1
		end
	end

	local res, e1, e2, e3, e4 = self:query(stmt, table.unpack(args, 1, args.n))
	if not res then
		return e1, e2, e3, e4
	end
	return M.models(res, newf)
end

-- Connects to the database specified by the connection string.  It may be an
-- empty string if the required settings are set in environment variables. If