Skip to content

Commit 8e47074

Browse files
committed
feat(sqlite): make opts.lazy false by default and add opts.keep_open
Before lazy was default and there was no way of changing that. I've decided to make it optional because it seems that: 1. People expects sqlite {} or sqlite:extend {} to create all the defined table in advance. 2. Performance impact of initializing db object is only 1.0 slower in microseconds, so it seems to not be as important as I thought it would: ```lua -- test/lazy.lua Benchmark #1: 'Logical Component' Time(mean ± σ): 23.7 μs ± 18.7 μs Range(min … max): 17.4 μs … 102.3 μs 20 runs Benchmark #2: 'Full Initialization' Time(mean ± σ): 28.7 μs ± 12.9 μs Range(min … max): 24.1 μs … 83.1 μs 20 runs Summary 'Logical Component' ran 1.2 ± 1.1 times faster than 'Full Initialization' ```
1 parent ee1ad88 commit 8e47074

File tree

3 files changed

+143
-15
lines changed

3 files changed

+143
-15
lines changed

lua/sqlite/db.lua

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ local tbl = require "sqlite.tbl"
2626

2727
---Creates a new sqlite.lua object, without creating a connection to uri.
2828
---|sqlite.new| is identical to |sqlite.db:open| but it without opening sqlite db
29-
---connection. Thus its most suited for cases where the database might be
30-
---acccess from multiple places. For neovim use cases, this mean from different
31-
---neovim instances.
29+
---connection (unless opts.keep_open). Its most suited for cases where the
30+
---database might be -acccess from multiple places. For neovim use cases, this
31+
---mean from different -neovim instances.
3232
---
3333
---<pre>
3434
---```lua
@@ -39,16 +39,26 @@ local tbl = require "sqlite.tbl"
3939
---@param opts sqlite_opts: (optional) see |sqlite_opts|
4040
---@return sqlite_db
4141
function sqlite.db.new(uri, opts)
42+
opts = opts or {}
43+
local keep_open = opts.keep_open
44+
opts.keep_open = nil
4245
uri = type(uri) == "string" and u.expand(uri) or ":memory:"
43-
return setmetatable({
46+
47+
local o = setmetatable({
4448
uri = uri,
4549
conn = nil,
4650
closed = true,
47-
opts = opts or {},
51+
opts = opts,
4852
modified = false,
4953
created = nil,
5054
tbl_schemas = {},
5155
}, sqlite.db)
56+
57+
if keep_open then
58+
o:open()
59+
end
60+
61+
return o
5262
end
5363

5464
---Extend |sqlite_db| object with extra sugar syntax and api. This is recommended
@@ -61,27 +71,40 @@ end
6171
---
6272
---Like |sqlite_tbl| original methods can be access through pre-appending "__"
6373
---when user overwrites it.
74+
---
75+
---if { conf.opts.lazy } then only return a logical object with self-dependent
76+
--tables, e.g. a table exists and other not because the one that
77+
---exists, it's method was called. (default false).
78+
---if { conf.opts.keep_open } then the sqlite extend db object will be returned
79+
---with an open connection (default false)
80+
6481
---<pre>
6582
---```lua
6683
--- local db = sqlite { -- or sqlite_db:extend
6784
--- uri = "path/to/db", -- path to db file
6885
--- entries = require'entries', -- a pre-made |sqlite_tbl| object.
6986
--- category = { title = { "text", unique = true, primary = true} },
7087
--- opts = {} or nil -- custom sqlite3 options, see |sqlite_opts|
88+
--- --- if opts.keep_open, make connection and keep it open.
89+
--- --- if opts.lazy, then just provide logical object
7190
--- }
7291
--- --- Overwrite method and access it using through pre-appending "__"
7392
--- db.select = function(...) db:__select(...) end
7493
---```
7594
---</pre>
76-
---@param opts table: see 'Fields'
95+
---@param conf table: see 'Fields'
7796
---@field uri string: path to db file.
78-
---@field opts sqlite_opts: (optional) see |sqlite_opts|
97+
---@field opts sqlite_opts: (optional) see |sqlite_opts| + lazy (default false), open (default false)
7998
---@field tname1 string: pointing to |sqlite_etbl| or |sqlite_schema_dict|
8099
---@field tnameN string: pointing to |sqlite_etbl| or |sqlite_schema_dict|
81100
---@see sqlite_tbl:extend
82101
---@return sqlite_db
83-
function sqlite.db:extend(opts)
84-
local db = self.new(opts.uri, opts.opts)
102+
function sqlite.db:extend(conf)
103+
conf.opts = conf.opts or {}
104+
local lazy = conf.opts.lazy
105+
conf.opts.lazy = nil
106+
107+
local db = self.new(conf.uri, conf.opts)
85108
local cls = setmetatable({ db = db }, {
86109
__index = function(_, key, ...)
87110
if type(key) == "string" then
@@ -93,15 +116,16 @@ function sqlite.db:extend(opts)
93116
end,
94117
})
95118

96-
for tbl_name, schema in pairs(opts) do
97-
if tbl_name ~= "uri" and tbl_name ~= "opts" and u.is_tbl(schema) then
119+
for tbl_name, schema in pairs(conf) do
120+
if tbl_name ~= "uri" and tbl_name ~= "opts" and tbl_name ~= "lazy" and u.is_tbl(schema) then
98121
local name = schema._name and schema._name or tbl_name
99-
cls[tbl_name] = schema.set_db and schema or require("sqlite.tbl").new(name, schema)
122+
cls[tbl_name] = schema.set_db and schema or require("sqlite.tbl").new(name, schema, not lazy and db or nil)
100123
if not cls[tbl_name].db then
101124
(cls[tbl_name]):set_db(db)
102125
end
103126
end
104127
end
128+
105129
return cls
106130
end
107131

test/auto/db_spec.lua

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -802,12 +802,13 @@ describe("sqlite.db", function()
802802
describe(":extend", function()
803803
local testrui = "/tmp/extend_db_new"
804804
local testrui2 = "/tmp/extend_db_new5"
805+
local testrui3 = "/tmp/extend_db_new5"
805806
local ok, manager
806807

807808
it("Initialize manager", function()
808-
---@class Manager:sqldb
809-
---@field projects sqltable
810-
---@field todos sqltable
809+
---@class ManagerLazy:sqlite_db
810+
---@field projects sqlite_tbl
811+
---@field todos sqlite_tbl
811812
ok, manager = pcall(sql, {
812813
uri = testrui,
813814
projects = {
@@ -825,6 +826,7 @@ describe("sqlite.db", function()
825826
},
826827
opts = {
827828
foreign_keys = true,
829+
lazy = true,
828830
},
829831
})
830832
eq(true, ok, manager)
@@ -914,7 +916,38 @@ describe("sqlite.db", function()
914916
eq(3, db.st:count(), "should have inserted.")
915917
end)
916918

919+
it("Initialize manager", function()
920+
---@class ManagerFull:sqlite_db
921+
---@field projects sqlite_tbl
922+
---@field todos sqlite_tbl
923+
ok, manager = pcall(sql, {
924+
uri = testrui,
925+
projects = {
926+
id = true,
927+
title = "text",
928+
objectives = "luatable",
929+
},
930+
todos = {
931+
id = true,
932+
title = "text",
933+
client = "integer",
934+
status = "text",
935+
completed = "boolean",
936+
details = "text",
937+
},
938+
opts = {
939+
foreign_keys = true,
940+
keep_open = true
941+
}
942+
})
943+
eq(true, ok, manager)
944+
end)
945+
it("should exists", function()
946+
eq(true, manager:exists("projects"))
947+
end)
948+
917949
luv.fs_unlink(testrui)
918950
luv.fs_unlink(testrui2)
951+
luv.fs_unlink(testrui3)
919952
end)
920953
end)

test/lazy.lua

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
local bunch = require'plenary.benchmark'
2+
R('sqlite')
3+
local sqlite = require('sqlite')
4+
local remove_db = function ()
5+
vim.loop.fs_unlink("/tmp/uri")
6+
end
7+
8+
bunch("Logical Component vs Full initialization", {
9+
runs = 20,
10+
fun = {
11+
{
12+
"Logical Component",
13+
function ()
14+
---@class __ManagerA:sqlite_db
15+
---@field projects sqlite_tbl
16+
---@field todos sqlite_tbl
17+
local db = sqlite {
18+
uri = "/tmp/uri",
19+
projects = {
20+
id = true,
21+
title = "text",
22+
objectives = "luatable",
23+
},
24+
todos = {
25+
id = true,
26+
title = "text",
27+
client = "integer",
28+
status = "text",
29+
completed = "boolean",
30+
details = "text",
31+
},
32+
clients = { name = "text" },
33+
opts = {
34+
foreign_keys = true,
35+
},
36+
lazy = true
37+
}
38+
remove_db()
39+
end
40+
},
41+
{
42+
"Full Initialization",
43+
function ()
44+
---@class __ManagerB:sqlite_db
45+
---@field projects sqlite_tbl
46+
---@field todos sqlite_tbl
47+
local db = sqlite {
48+
uri = "/tmp/uri",
49+
projects = {
50+
id = true,
51+
title = "text",
52+
objectives = "luatable",
53+
},
54+
todos = {
55+
id = true,
56+
title = "text",
57+
client = "integer",
58+
status = "text",
59+
completed = "boolean",
60+
details = "text",
61+
},
62+
clients = { name = "text" },
63+
opts = {
64+
foreign_keys = true,
65+
},
66+
}
67+
remove_db()
68+
end
69+
}
70+
}
71+
})

0 commit comments

Comments
 (0)