#!/usr/bin/env lua
local resp = require("resp_osn")
--local resp = require("resp_luaposix")
-- luasocket may need tuning of timeout - default 0.002
--local resp = require("resp_luasocket")
--local resp = require("resp_cqueues")
-- set 0 to disable os.execute(string.format("sleep %d", RECONNECT_TIMEOUT))
local RECONNECT_TIMEOUT = 3
local RESP_SERVER="localhost"
local RESP_PORT=6379
--local RESP_USOCK="/var/lib/resp.sock"
local TEST_AUTH = "foobared"
local TEST_DB = "15"
local result = nil
local log = nil
---[==[
log = require("log").init({
  error = "stdout",
  notice = "stdout",
  info = "stdout",
--  socket = "stdout",
--  debug = "stdout",
})
--]==]
-- instead of DSN parsing a table is used
-- optional receive_buffer_size (64K) might be changed, if big results are expected
local r = resp.init({server = RESP_SERVER, port = RESP_PORT, usock = RESP_USOCK}, log)
-- will give an error log message, if auth fails
r.q({{"DBSIZE"}})
-- authentication will give an error message, if not required
r.q({{"AUTH", TEST_AUTH}})
print(string.format("DBSIZE -> %d", r.q({{"DBSIZE"}})[1][1]))

-- simple string reply
if not(r.q({{"SELECT", TEST_DB}})[1][1] == "OK") then
  print(string.format("Selection of DB %s failed.. test aborted", TEST_DB))
  os.exit(1)
end
 -- integer number reply
if not(r.q({{"DBSIZE"}})[1][1] == 0) then
  print(string.format("DB %s contains data.. test aborted", TEST_DB))
  os.exit(1)
end
print(string.format("SET key_1 = value_1 -> %s", r.q({{"SET", "key_1", "value_1"}})[1][1]))
-- set multi key, command pipelining -- returns {{"OK"}{"OK"}}
result = r.q({{"SET", "key_2", "value_2"}, {"SET", "key_3", "value_3"}})
print(string.format("number of results: %i{", #result))
for n, v in pairs(result) do print(string.format(" SET key_%d = value_%d -> %s", (n + 1), (n + 1), v[1])); end
print("}");
-- bulk reply
print(string.format("GET key_1 -> \"%s\"", r.q({{"GET", "key_1"}})[1][1]))
-- multi-bulk ("array") reply
result = r.q({{"MGET", "key_2", "key_3"}})
print(string.format("MGET key_2 key_3 = %i{%i{\"%s\" \"%s\"}}", #result, #result[1], result[1][1], result[1][2]))
-- open second connection
local r1 = resp.init({server = RESP_SERVER, port = RESP_PORT, usock = RESP_USOCK, pass = TEST_AUTH, db = TEST_DB}, log)
print("== named result: The name at the position will be used ==")
print(" if a only the subresult should be named place the table at the number")
print(" if the subresult itself should be named, add the name on the position and create a table with that name")
print(" if a name is set, the result is not available via the result number")
result = r1.q({{"GET", "key_1"}, {"MGET", "key_2", "key_3"}}, {"key_1", "multi_bulk", multi_bulk = {"key_2", "key_3"}})
print('query: {{"GET", "key_1"}, {"MGET", "key_2", "key_3"}}, {"key_1", "multi_bulk", multi_bulk = {"key_2", "key_3"}}')
print(string.format("named result: %i{result[\"key_1\"][1] = \"%s\", %i{result[\"multi_bulk\"][\"key_2\"] = \"%s\", result.multi_bulk.key_3 = \"%s\"}}", #result, result["key_1"][1], #result["multi_bulk"], result["multi_bulk"]["key_2"], result.multi_bulk.key_3))
result = r.q({{"MGET", table.unpack(r.q({{"KEYS", "key_*"}})[1])}}, {{"key_1", [3] = "key_3"}})
print('query: {{"MGET", table.unpack(r.q({{"KEYS", "key_*"}})[1])}}, {{"key_1", [3] = "key_3"}}')
print(string.format("mixed result: %i{%i{result[1][\"key_1\"] = \"%s\", result[1][2] = \"%s\", result[1][3] = \"%s\"}}", #result, #result[1], result[1]["key_1"], result[1][2], result[1][3] or "nil"))
print('== "true" result ==')
print(' if instead of a name "true" is given, the result is "value = true"')
print(" e.g. SMEMBERS will get a table filled with the members, easy to check")
result = r.q({{"MGET", "key_1", "key_2"}, {"MGET", "key_1", "key_2"}}, {nil, r.RESULT_TRUE})
print('query: {{"MGET", "key_1", "key_2"}, {"MGET", "key_1", "key_2"}}, {nil, r.RESULT_TRUE}')
print(string.format("normal result, values true: %i{%i{result[1][1] = \"%s\", result[1][2] = \"%s\"}, %i{result[2][1] = \"%s\", result[2][\"key_1\"] = \"%s\", result[2][\"value_1\"] = \"%s\", result[2][\"value_2\"] = \"%s\"}}", #result, #result[1], result[1][1], result[1][2], #result[2], result[2][1] or "nil", result[2]["key_1"] or "nil", result[2]["value_1"], result[2]["value_2"]))
print('== dict result ==')
result = r.q({{"HSET", "hkey", "hkey_1", "hvalue_1"}, {"HSET", "hkey", "hkey_2", "hvalue_2"}, {"HGETALL", "hkey"}}, {nil, nil, r.RESULT_DICT})
print('query: {{"HSET", "hkey", "hkey_1", "hvalue_1"}, {"HSET", "hkey", "hkey_2", "hvalue_2"}, {"HGETALL", "hkey"}}, {nil, nil, r.RESULT_DICT}')
print(string.format("result[3] = %s{", #result[3]))
for k, v in pairs(result[3]) do print(string.format("  %s = %s", k, v)) end
print("}");
print(string.format("FLUSHDB -> %s", r1.q({{"FLUSHDB"}})[1][1]))
-- test reconnect
if RECONNECT_TIMEOUT > 0 then
  print(string.format("Test timeout reconnect .. sleep %d", RECONNECT_TIMEOUT))
  os.execute(string.format("sleep %d", RECONNECT_TIMEOUT))
end
r.close()
result = r1.q({{"KEYS", "*"}, {"EXISTS", "none"}})
print(string.format("KEYS *, EXISTS none -> %s, %d", (result[1][1] or "nil"), result[2][1]))
r1.close()
-- reconnect works even after connection was closed
print(string.format("DBSIZE -> %d", r1.q({{"DBSIZE"}})[1][1]))
r1.close()

