From f0da206370d3910bea82438e7e6b557cbff8881e Mon Sep 17 00:00:00 2001 From: Tami <65782666+tami5@users.noreply.github.com> Date: Thu, 2 Sep 2021 12:46:18 +0300 Subject: [PATCH] :sparkles: tbl:last_id and db:last_insert_id + more tests --- lua/sqlite/assert.lua | 5 ++++- lua/sqlite/db.lua | 24 ++++++++++++++++----- lua/sqlite/helpers.lua | 1 + lua/sqlite/stmt.lua | 8 ++++--- lua/sqlite/tbl.lua | 6 ++++++ lua/sqlite/tbl/indexer.lua | 23 ++++++++++++++++++-- test/auto/tbl_spec.lua | 44 +++++++++++++++++++++++++++++++++++++- 7 files changed, 99 insertions(+), 12 deletions(-) diff --git a/lua/sqlite/assert.lua b/lua/sqlite/assert.lua index 47ce1880..4fc3c656 100644 --- a/lua/sqlite/assert.lua +++ b/lua/sqlite/assert.lua @@ -90,7 +90,10 @@ M.should_match_pk_type = function(name, kt, pk, key) return error(errors.no_primary_key:format(name)) end - if knotstr and (pt == "string" or pt == "text") or knotnum and (pt == "number" or pt == "integer") then + if + kt ~= "boolean" + and (knotstr and (pt == "string" or pt == "text") or knotnum and (pt == "number" or pt == "integer")) + then return error(errors.miss_match_pk_type:format(pk.name, pk.type, kt, name, key)) end diff --git a/lua/sqlite/db.lua b/lua/sqlite/db.lua index 9e83d840..e518b099 100644 --- a/lua/sqlite/db.lua +++ b/lua/sqlite/db.lua @@ -560,15 +560,25 @@ function sqlite.db:select(tbl_name, spec, schema) spec = spec or {} spec.select = spec.keys and spec.keys or spec.select + local select = p.select(tbl_name, spec) + local st = "" - local stmt = s:parse(self.conn, p.select(tbl_name, spec)) - s.each(stmt, function() - table.insert(ret, s.kv(stmt)) + local stmt = s:parse(self.conn, select, tbl_name) + stmt:each(function() + table.insert(ret, stmt:kv()) end) - s.reset(stmt) - if s.finalize(stmt) then + if tbl_name == "todos_indexer" then + st = stmt:expand() + end + + stmt:reset() + if stmt:finalize() then self.modified = false end + if tbl_name == "todos_indexer" and spec.id == 3 then + error(st) + end + return p.post_select(ret, schema) end) end @@ -611,6 +621,10 @@ function sqlite.db:table(tbl_name, opts) return self:tbl(tbl_name, opts) end +function sqlite.db:last_insert_rowid() + return tonumber(clib.last_insert_rowid(self.conn)) +end + ---Sqlite functions sugar wrappers. See `sql/strfun` sqlite.db.lib = require "sqlite.strfun" diff --git a/lua/sqlite/helpers.lua b/lua/sqlite/helpers.lua index c572eb6b..a3075eaa 100644 --- a/lua/sqlite/helpers.lua +++ b/lua/sqlite/helpers.lua @@ -91,6 +91,7 @@ M.run = function(func, o) o.db_schema = o.db:schema(o.name) end + rawset(o, "last_id", o.db:last_insert_rowid()) --- Run wrapped function return func() end diff --git a/lua/sqlite/stmt.lua b/lua/sqlite/stmt.lua index d42b630e..ee17f998 100644 --- a/lua/sqlite/stmt.lua +++ b/lua/sqlite/stmt.lua @@ -35,11 +35,13 @@ function sqlstmt:__parse() assert( code == flags.ok, string.format( - "sqlite.lua: sql statement parse, , stmt: `%s`, err: `(`%s`)`", - self.str, - clib.to_str(clib.errmsg(self.conn)) + "sqlite.lua\n(parse error): `%s` code == %d\nstatement == '%s'", + clib.to_str(clib.errmsg(self.conn)), + code, + self.str ) ) + self.pstmt = pstmt[0] end diff --git a/lua/sqlite/tbl.lua b/lua/sqlite/tbl.lua index 91490d66..9ec24347 100644 --- a/lua/sqlite/tbl.lua +++ b/lua/sqlite/tbl.lua @@ -460,6 +460,12 @@ function sqlite.tbl:set_db(db) self.db = db end +function sqlite.tbl:last_id() + h.run(function() + rawset(self, "last_id", self.db:last_insert_rowid()) + end, self) +end + sqlite.tbl = setmetatable(sqlite.tbl, { __call = function(_, ...) return sqlite.tbl.new(...) diff --git a/lua/sqlite/tbl/indexer.lua b/lua/sqlite/tbl/indexer.lua index 8f483a2a..f3e74448 100644 --- a/lua/sqlite/tbl/indexer.lua +++ b/lua/sqlite/tbl/indexer.lua @@ -89,6 +89,16 @@ local sep_query_and_where = function(q, keys) end return kv end + +---Print errors to the user +---@param func function +-- local sc = function(func) +-- local ok, val = xpcall(func, function(msg) +-- print(msg) +-- end) +-- return ok and val +-- end + return function(tbl) local pk = get_primary_key(tbl.tbl_schema) local extend = tbl_row_extender(tbl, pk) @@ -109,7 +119,12 @@ return function(tbl) if kt == "string" or kt == "number" and pk then a.should_match_pk_type(tbl.name, kt, pk, arg) - return extend(tbl:where { [pk.name] = arg }, arg) + return extend( + tbl:where { + [pk.name] = arg, + }, + arg + ) end return kt == "table" and tbl:get(sep_query_and_where(arg, tbl_keys)) @@ -141,7 +156,11 @@ return function(tbl) if vt == "table" and pk then a.should_match_pk_type(tbl.name, kt, pk, arg) - return tbl:update { where = { [pk.name] = arg }, set = val } + if arg == 0 or arg == true or arg == "" then + return tbl:insert(val) + else + return tbl:update { where = { [pk.name] = arg }, set = val } + end end end diff --git a/test/auto/tbl_spec.lua b/test/auto/tbl_spec.lua index 4bdefcaf..16752cfa 100644 --- a/test/auto/tbl_spec.lua +++ b/test/auto/tbl_spec.lua @@ -980,7 +980,7 @@ describe("sqlite.tbl", function() describe("string_index:", function() local kv = tbl("kvpair", { - key = { "text", primary = true, required = true, unique = true }, + key = { "text", primary = true, required = true, default = "none" }, len = "integer", }, db) @@ -1038,6 +1038,13 @@ describe("sqlite.tbl", function() }] ) end) + + it("insert with 0 or true to skip the primary key value.", function() + kv[true] = { len = 5 } + eq(5, kv.none.len) + kv[""] = { len = 6 } + eq({ key = "none", len = 6 }, kv:where { len = 6 }) + end) end) describe("number_index", function() @@ -1082,6 +1089,41 @@ describe("sqlite.tbl", function() ) end) end) + + describe("Relationships", function() + local todos = tbl("todos_indexer", { + id = true, + title = "text", + project = { + reference = "projects.title", + required = true, + on_delete = "cascade", + on_update = "cascade", + }, + }, db) + + local projects = tbl("projects", { + title = { type = "text", primary = true, required = true, unique = true }, + deadline = { "date", default = db.lib.date "now" }, + }, db) + + it("create new table with default values", function() + projects.neovim = {} + eq(true, projects.neovim.deadline == os.date "!%Y-%m-%d") + projects["sqlite"] = {} + --- TODO: if you have sqilte.lua todos[2] return empty table + end) + + it("fails if foregin key doesn't exists", function() + eq( + false, + pcall(function() + todos[2].project = "ram" + end) + ) + end) + end) + -- vim.loop.fs_unlink(db_path) end)