Skip to content

Commit a6bd3d1

Browse files
committed
💥 sql.schema return detailed description of table.
Not sure if this is a wise decision or not. But it beat having the schema returned given the key and the value the user written.
1 parent 5b0710f commit a6bd3d1

5 files changed

Lines changed: 152 additions & 76 deletions

File tree

lua/sql.lua

Lines changed: 13 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -266,46 +266,20 @@ end
266266

267267
---Get {name} table schema, if table does not exist then return an empty table.
268268
---@param tbl_name string: the table name.
269-
---@param info boolean: whether to return table info. default false.
270269
---@return table list of keys or keys and their type.
271-
function DB:schema(tbl_name, info)
270+
function DB:schema(tbl_name)
272271
local sch = self:eval(string.format("pragma table_info(%s)", tbl_name))
273-
if type(sch) == "boolean" then
274-
return {}
275-
end
276-
277-
local tbl_info = {}
278-
local req = {}
279-
local def = {}
280-
local types = {}
281-
282-
for _, v in ipairs(sch) do
283-
if v.notnull == 1 and v.pk == 0 then
284-
req[v.name] = v
285-
end
286-
if v.dflt_value then
287-
def[v.name] = v.dflt_value
288-
end
289-
290-
tbl_info[v.name] = {
272+
local schema = {}
273+
for _, v in ipairs(type(sch) == "boolean" and {} or sch) do
274+
schema[v.name] = {
275+
cid = v.cid,
291276
required = v.notnull == 1,
292277
primary = v.pk == 1,
293278
type = v.type,
294-
cid = v.cid,
295279
default = v.dflt_value,
296280
}
297-
298-
types[v.name] = v.type
299281
end
300-
301-
local obj = {
302-
info = tbl_info,
303-
req = req == {} and nil or req,
304-
def = def == {} and nil or def,
305-
types = types,
306-
}
307-
308-
return info and obj or obj.types
282+
return schema
309283
end
310284

311285
---Insert to lua table into sqlite database table.
@@ -426,26 +400,21 @@ end
426400
---@return table[]
427401
function DB:select(tbl_name, spec)
428402
a.is_sqltbl(self, tbl_name, "select")
429-
spec = spec or {}
430-
self.modified = false
431-
432-
local ret = {}
433-
local types = self:schema(tbl_name)
434-
435-
self.modified = false
436-
437-
clib.wrap_stmts(self.conn, function()
403+
return clib.wrap_stmts(self.conn, function()
404+
local ret = {}
405+
spec = spec or {}
438406
spec.select = spec.keys and spec.keys or spec.select
439407

440408
local s = stmt:parse(self.conn, P.select(tbl_name, spec))
441409
stmt.each(s, function()
442410
table.insert(ret, stmt.kv(s))
443411
end)
444412
stmt.reset(s)
445-
stmt.finalize(s)
413+
if stmt.finalize(s) then
414+
self.modified = false
415+
end
416+
return P.post_select(ret, self:schema(tbl_name))
446417
end)
447-
448-
return P.post_select(ret, types)
449418
end
450419

451420
---Create new sql-table object.

lua/sql/defs.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -627,9 +627,9 @@ end
627627
---@param fn func()
628628
M.wrap_stmts = function(conn_ptr, fn)
629629
M.exec_stmt(conn_ptr, "BEGIN")
630-
fn()
630+
local res = fn()
631631
M.exec_stmt(conn_ptr, "COMMIT")
632-
return
632+
return res
633633
end
634634

635635
---Get last error msg

lua/sql/parser.lua

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ M.sqlvalue = function(v)
1919
return type(v) == "boolean" and (v == true and 1 or 0) or (v == nil and "null" or v)
2020
end
2121

22-
M.luavalue = function(v, schema_type)
23-
if schema_type == "luatable" or schema_type == "json" then
22+
M.luavalue = function(v, key_type)
23+
if key_type == "luatable" or key_type == "json" then
2424
return json.decode(v)
25-
elseif schema_type == "boolean" then
25+
elseif key_type == "boolean" then
2626
return v == 0 and false or true
2727
end
2828

@@ -393,16 +393,21 @@ M.create = function(tbl, defs)
393393
local items = {}
394394

395395
tbl = defs.ensure and "if not exists " .. tbl or tbl
396-
defs.ensure = nil
397396

398397
for k, v in u.opairs(defs) do
399-
local t = type(v)
400-
if t == "boolean" then
401-
tinsert(items, k .. " integer not null primary key")
402-
elseif t ~= "table" then
403-
tinsert(items, string.format("%s %s", k, v))
404-
else
405-
tinsert(items, ("%s %s"):format(k, opts_to_str(v)))
398+
if k ~= "ensure" then
399+
local t = type(v)
400+
if t == "boolean" then
401+
tinsert(items, k .. " integer not null primary key")
402+
elseif t ~= "table" then
403+
tinsert(items, string.format("%s %s", k, v))
404+
else
405+
if u.is_list(v) then
406+
tinsert(items, ("%s %s"):format(k, tconcat(v, " ")))
407+
else
408+
tinsert(items, ("%s %s"):format(k, opts_to_str(v)))
409+
end
410+
end
406411
end
407412
end
408413
return ("create table %s(%s)"):format(tbl, tconcat(items, ", "))
@@ -425,11 +430,12 @@ M.pre_insert = function(rows, schema)
425430
local res = {}
426431
rows = u.is_nested(rows) and rows or { rows }
427432
for i, row in ipairs(rows) do
428-
u.foreach(schema.req, function(k)
429-
a.missing_req_key(row[k], k)
430-
end)
433+
-- u.foreach(schema.req, function(k)
434+
-- a.missing_req_key(row[k], k)
435+
-- end)
431436
res[i] = u.map(row, function(v, k)
432-
local is_json = schema.types[k] == "luatable" or schema.types[k] == "json"
437+
a.missing_req_key(v, schema[k].required)
438+
local is_json = schema[k].type == "luatable" or schema[k].type == "json"
433439
return is_json and json.encode(v) or M.sqlvalue(v)
434440
end)
435441
end
@@ -442,13 +448,18 @@ end
442448
---@param schema table tbl schema
443449
---@return table pre processed rows
444450
---@TODO support boolean values.
445-
M.post_select = function(rows, types)
451+
M.post_select = function(rows, schema)
446452
local is_nested = u.is_nested(rows)
447453
rows = is_nested and rows or { rows }
448454

449455
for _, row in ipairs(rows) do
450456
for k, v in pairs(row) do
451-
row[k] = M.luavalue(v, types[k])
457+
local info = schema[k]
458+
if info then
459+
row[k] = M.luavalue(v, info.type)
460+
else
461+
row[k] = v
462+
end
452463
end
453464
end
454465

test/auto/sql_spec.lua

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -680,11 +680,37 @@ describe("sql", function()
680680

681681
it("gets a sql table schema", function()
682682
local sch = db:schema "test"
683-
eq({ a = "text", b = "int", c = "int", d = "text" }, sch)
683+
eq({
684+
a = {
685+
cid = 0,
686+
primary = false,
687+
required = false,
688+
type = "text",
689+
},
690+
b = {
691+
cid = 1,
692+
primary = false,
693+
required = false,
694+
type = "int",
695+
},
696+
c = {
697+
cid = 2,
698+
primary = false,
699+
required = true,
700+
type = "int",
701+
},
702+
d = {
703+
cid = 3,
704+
default = "def",
705+
primary = false,
706+
required = false,
707+
type = "text",
708+
},
709+
}, sch)
684710
end)
685711

686712
it("gets a sql table schema info", function()
687-
local sch = db:schema("test", true).info
713+
local sch = db:schema "test"
688714
eq({
689715
a = {
690716
cid = 0,
@@ -732,10 +758,10 @@ describe("sql", function()
732758
eq(true, db:exists "test")
733759
end)
734760

735-
it("won't override the table schema if it exists", function()
761+
it("skip overriding the table schema if it exists", function()
736762
db:create("test", { id = "not_a_type", ensure = true })
737763
local sch = db:schema "test"
738-
eq("text", sch.title, "should not be nil")
764+
eq("text", sch.title.type, "should exists and should be still text not be nil")
739765
end)
740766
it("auto enable foreign_keys on usage", function()
741767
db:create("test_keys", {

test/auto/table_spec.lua

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,38 +53,108 @@ describe("table", function()
5353
name = "text",
5454
},
5555
}
56+
local detailed_schema = {
57+
id = {
58+
cid = 0,
59+
primary = false,
60+
required = false,
61+
type = "int",
62+
},
63+
name = {
64+
cid = 1,
65+
primary = false,
66+
required = false,
67+
type = "text",
68+
},
69+
}
5670
local new = db:table("newtbl", opts)
5771

5872
it("initalizes db with schema", function()
59-
eq(opts.schema, new:schema(), "should be identical")
60-
eq(opts.schema, new.tbl_schema, "should be identical")
73+
eq(detailed_schema, new:schema(), "should be identical")
6174
end)
6275
it("should not rewrite schema.", function()
6376
local new2 = db:table "newtbl"
64-
eq(opts.schema, new2:schema(), "should be identical")
65-
eq(opts.schema, new2.tbl_schema, "should be identical")
77+
eq(detailed_schema, new2:schema(), "should be identical")
78+
eq(detailed_schema, new2.tbl_schema, "should be identical")
6679

6780
local new3 = db:table("newtbl", { schema = { id = "string" } })
68-
eq(opts.schema, new3:schema(), "should be identical")
69-
eq(opts.schema, new3.tbl_schema, "should be identical")
81+
eq(detailed_schema, new3:schema(), "should be identical")
82+
eq(detailed_schema, new3.tbl_schema, "should be identical")
7083
end)
7184
end)
7285

7386
describe(":schema", function()
7487
it("returns schema if self.tbl exists", function()
75-
eq({ a = "integer", b = "text", c = "text" }, t1:schema())
88+
eq({
89+
a = {
90+
cid = 0,
91+
primary = false,
92+
required = false,
93+
type = "integer",
94+
},
95+
b = {
96+
cid = 1,
97+
primary = false,
98+
required = false,
99+
type = "text",
100+
},
101+
c = {
102+
cid = 2,
103+
primary = false,
104+
required = false,
105+
type = "text",
106+
},
107+
}, t1:schema())
76108
end)
77109
it("returns empty table if schema doesn't exists", function()
78110
eq({}, t2:schema())
79111
end)
80112
it("creates new table with schema", function()
81-
local schema = { id = "int", a = "text", d = "text" }
113+
local schema = {
114+
a = {
115+
cid = 0,
116+
primary = false,
117+
required = false,
118+
type = "text",
119+
},
120+
d = {
121+
cid = 1,
122+
primary = false,
123+
required = false,
124+
type = "text",
125+
},
126+
id = {
127+
cid = 2,
128+
primary = false,
129+
required = false,
130+
type = "int",
131+
},
132+
}
82133
eq(true, t2:schema(schema), "Should return true")
83134
eq(schema, t2:schema(), "should return the schema.")
84135
eq(true, t2.tbl_exists, "should alter self.exists value")
85136
end)
86137
it("should drop and recreate the table if not schema.ensure", function()
87-
local new = { id = "int", a = "text", f = "text" }
138+
local new = {
139+
a = {
140+
cid = 0,
141+
primary = false,
142+
required = false,
143+
type = "text",
144+
},
145+
f = {
146+
cid = 1,
147+
primary = false,
148+
required = false,
149+
type = "text",
150+
},
151+
id = {
152+
cid = 2,
153+
primary = false,
154+
required = false,
155+
type = "int",
156+
},
157+
}
88158
eq(true, t2:schema(new), "Should return true")
89159
eq(new, t2:schema(), "should return the schema.")
90160
eq(true, t2.tbl_exists, "should alter self.exists value")

0 commit comments

Comments
 (0)