Skip to content

Commit 0ffb3c6

Browse files
committed
✨ tbl:last_id and db:last_insert_id + more tests
1 parent a322be9 commit 0ffb3c6

File tree

7 files changed

+103
-12
lines changed

7 files changed

+103
-12
lines changed

lua/sqlite/assert.lua

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ M.should_match_pk_type = function(name, kt, pk, key)
9090
return error(errors.no_primary_key:format(name))
9191
end
9292

93-
if knotstr and (pt == "string" or pt == "text") or knotnum and (pt == "number" or pt == "integer") then
93+
if
94+
kt ~= "boolean"
95+
and (knotstr and (pt == "string" or pt == "text") or knotnum and (pt == "number" or pt == "integer"))
96+
then
9497
return error(errors.miss_match_pk_type:format(pk.name, pk.type, kt, name, key))
9598
end
9699

lua/sqlite/db.lua

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -560,15 +560,25 @@ function sqlite.db:select(tbl_name, spec, schema)
560560

561561
spec = spec or {}
562562
spec.select = spec.keys and spec.keys or spec.select
563+
local select = p.select(tbl_name, spec)
564+
local st = ""
563565

564-
local stmt = s:parse(self.conn, p.select(tbl_name, spec))
565-
s.each(stmt, function()
566-
table.insert(ret, s.kv(stmt))
566+
local stmt = s:parse(self.conn, select, tbl_name)
567+
stmt:each(function()
568+
table.insert(ret, stmt:kv())
567569
end)
568-
s.reset(stmt)
569-
if s.finalize(stmt) then
570+
if tbl_name == "todos_indexer" then
571+
st = stmt:expand()
572+
end
573+
574+
stmt:reset()
575+
if stmt:finalize() then
570576
self.modified = false
571577
end
578+
if tbl_name == "todos_indexer" and spec.id == 3 then
579+
error(st)
580+
end
581+
572582
return p.post_select(ret, schema)
573583
end)
574584
end
@@ -611,6 +621,10 @@ function sqlite.db:table(tbl_name, opts)
611621
return self:tbl(tbl_name, opts)
612622
end
613623

624+
function sqlite.db:last_insert_rowid()
625+
return tonumber(clib.last_insert_rowid(self.conn))
626+
end
627+
614628
---Sqlite functions sugar wrappers. See `sql/strfun`
615629
sqlite.db.lib = require "sqlite.strfun"
616630

lua/sqlite/helpers.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ M.run = function(func, o)
9191
o.db_schema = o.db:schema(o.name)
9292
end
9393

94+
rawset(o, "last_id", o.db:last_insert_rowid())
9495
--- Run wrapped function
9596
return func()
9697
end

lua/sqlite/stmt.lua

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ function sqlstmt:__parse()
3535
assert(
3636
code == flags.ok,
3737
string.format(
38-
"sqlite.lua: sql statement parse, , stmt: `%s`, err: `(`%s`)`",
39-
self.str,
40-
clib.to_str(clib.errmsg(self.conn))
38+
"sqlite.lua\n(parse error): `%s` code == %d\nstatement == '%s'",
39+
clib.to_str(clib.errmsg(self.conn)),
40+
code,
41+
self.str
4142
)
4243
)
44+
4345
self.pstmt = pstmt[0]
4446
end
4547

lua/sqlite/tbl.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,12 @@ function sqlite.tbl:set_db(db)
460460
self.db = db
461461
end
462462

463+
function sqlite.tbl:last_id()
464+
h.run(function()
465+
self.last_id = self.db:last_insert_rowid()
466+
end, self)
467+
end
468+
463469
sqlite.tbl = setmetatable(sqlite.tbl, {
464470
__call = function(_, ...)
465471
return sqlite.tbl.new(...)

lua/sqlite/tbl/indexer.lua

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ local sep_query_and_where = function(q, keys)
8989
end
9090
return kv
9191
end
92+
93+
---Print errors to the user
94+
---@param func function
95+
local sc = function(func)
96+
local ok, val = xpcall(func, function(msg)
97+
print(msg)
98+
end)
99+
return ok and val
100+
end
101+
92102
return function(tbl)
93103
local pk = get_primary_key(tbl.tbl_schema)
94104
local extend = tbl_row_extender(tbl, pk)
@@ -109,7 +119,12 @@ return function(tbl)
109119

110120
if kt == "string" or kt == "number" and pk then
111121
a.should_match_pk_type(tbl.name, kt, pk, arg)
112-
return extend(tbl:where { [pk.name] = arg }, arg)
122+
return extend(
123+
tbl:where {
124+
[pk.name] = arg,
125+
},
126+
arg
127+
)
113128
end
114129

115130
return kt == "table" and tbl:get(sep_query_and_where(arg, tbl_keys))
@@ -141,7 +156,11 @@ return function(tbl)
141156

142157
if vt == "table" and pk then
143158
a.should_match_pk_type(tbl.name, kt, pk, arg)
144-
return tbl:update { where = { [pk.name] = arg }, set = val }
159+
if arg == 0 or arg == true or arg == "" then
160+
return tbl:insert(val)
161+
else
162+
return tbl:update { where = { [pk.name] = arg }, set = val }
163+
end
145164
end
146165
end
147166

test/auto/tbl_spec.lua

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,7 @@ describe("sqlite.tbl", function()
980980

981981
describe("string_index:", function()
982982
local kv = tbl("kvpair", {
983-
key = { "text", primary = true, required = true, unique = true },
983+
key = { "text", primary = true, required = true, default = "none" },
984984
len = "integer",
985985
}, db)
986986

@@ -1038,6 +1038,13 @@ describe("sqlite.tbl", function()
10381038
}]
10391039
)
10401040
end)
1041+
1042+
it("insert with 0 or true to skip the primary key value.", function()
1043+
kv[true] = { len = 5 }
1044+
eq(5, kv.none.len)
1045+
kv[""] = { len = 6 }
1046+
eq({ key = "none", len = 6 }, kv:where { len = 6 })
1047+
end)
10411048
end)
10421049

10431050
describe("number_index", function()
@@ -1080,8 +1087,47 @@ describe("sqlite.tbl", function()
10801087
limit = 2,
10811088
}]
10821089
)
1090+
t[0] = { name = "x" }
1091+
eq("x", t[t.last_id].name)
1092+
end)
1093+
-- t[""] = { len = 6 }
1094+
-- eq({ key = "none", len = 6 }, t:where { len = 6 })
1095+
end)
1096+
1097+
describe("Relationships", function()
1098+
local todos = tbl("todos_indexer", {
1099+
id = true,
1100+
title = "text",
1101+
project = {
1102+
reference = "projects.title",
1103+
required = true,
1104+
on_delete = "cascade",
1105+
on_update = "cascade",
1106+
},
1107+
}, db)
1108+
1109+
local projects = tbl("projects", {
1110+
title = { type = "text", primary = true, required = true, unique = true },
1111+
deadline = { "date", default = db.lib.date("now", "3 days") },
1112+
}, db)
1113+
1114+
it("create new table with default values", function()
1115+
projects.neovim = {}
1116+
eq(true, projects.neovim.deadline == "2021-09-05")
1117+
projects["sqlite"] = {}
1118+
--- TODO: if you have sqilte.lua todos[2] return empty table
1119+
end)
1120+
1121+
it("fails if foregin key doesn't exists", function()
1122+
eq(
1123+
false,
1124+
pcall(function()
1125+
todos[2].project = "ram"
1126+
end)
1127+
)
10831128
end)
10841129
end)
1130+
10851131
-- vim.loop.fs_unlink(db_path)
10861132
end)
10871133

0 commit comments

Comments
 (0)