telescope-frecency.nvim/lua/telescope/_extensions/frecency/sql_wrapper.lua
2021-01-14 01:37:37 +01:00

143 lines
3.9 KiB
Lua

local vim = vim
local uv = vim.loop
local has_sql, sql = pcall(require, "sql")
if not has_sql then
error("This plugin requires sql.nvim (https://github.com/tami5/sql.nvim)")
end
-- TODO: pass in max_timestamps from db.lua
local MAX_TIMESTAMPS = 10
-- TODO: prioritize files in project root!
local schemas = {[[
CREATE TABLE IF NOT EXISTS files (
id INTEGER PRIMARY KEY,
count INTEGER,
path TEXT
);
]],
[[
CREATE TABLE IF NOT EXISTS timestamps (
id INTEGER PRIMARY KEY,
file_id INTEGER,
timestamp REAL,
FOREIGN KEY(file_id) REFERENCES files(id)
);
]]}
local queries = {
["file_add_entry"] = "INSERT INTO files (path, count) values(:path, 1);",
["file_update_counter"] = "UPDATE files SET count = count + 1 WHERE path = :path;",
["timestamp_add_entry"] = "INSERT INTO timestamps (file_id, timestamp) values(:file_id, julianday('now'));",
["timestamp_delete_before_id"] = "DELETE FROM timestamps WHERE id < :id and file_id == :file_id;",
["get_all_filepaths"] = "SELECT * FROM files;",
["get_all_timestamp_ages"] = "SELECT id, file_id, CAST((julianday('now') - julianday(timestamp)) * 24 * 60 AS INTEGER) AS age FROM timestamps;",
["get_row"] = "SELECT * FROM files WHERE path == :path;",
["get_timestamp_ids_for_file"] = "SELECT id FROM timestamps WHERE file_id == :file_id;",
}
-- local ignore_patterns = {
-- }
--
local function fs_stat(path) -- TODO: move this to new file with M
local stat = uv.fs_stat(path)
local res = {}
res.exists = stat and true or false -- TODO: this is silly
res.isdirectory = (stat and stat.type == "directory") and true or false
return res
end
local M = {}
M.queries = queries
function M:new()
local o = {}
setmetatable(o, self)
self.__index = self
self.db = nil
return o
end
function M:bootstrap(opts)
opts = opts or {}
if self.db then
print("sql wrapper already initialised")
return
end
self.max_entries = opts.max_entries or 2000
-- create the db if it doesn't exist
local db_root = opts.docs_root or "$XDG_DATA_HOME/nvim"
local db_filename = db_root .. "/file_frecency.sqlite3"
self.db = sql.open(db_filename)
if not self.db then
print("error")
return
end
-- create tables if they don't exist
for _, s in pairs(schemas) do
self.db:eval(s)
end
self.db:close()
end
function M:do_transaction(query, params)
if not queries[query] then
print("invalid query_preset: " .. query )
return
end
local res
self.db:with_open(function(db) res = db:eval(queries[query], params) end)
return res
end
function M:get_row_id(filepath)
local result = self:do_transaction('get_row', { path = filepath })
return type(result) == "table" and result[1].id or nil
end
function M:update(filepath)
local filestat = fs_stat(filepath)
if (vim.tbl_isempty(filestat) or
filestat.exists == false or
filestat.isdirectory == true) then
return end
-- create entry if it doesn't exist
local file_id
file_id = self:get_row_id(filepath)
if not file_id then
self:do_transaction('file_add_entry', { path = filepath })
file_id = self:get_row_id(filepath)
else
-- ..or update existing entry
self:do_transaction('file_update_counter', { path = filepath })
end
-- register timestamp for this update
self:do_transaction('timestamp_add_entry', { file_id = file_id })
-- trim timestamps to MAX_TIMESTAMPS per file (there should be up to MAX_TS + 1 at this point)
local timestamps = self:do_transaction('get_timestamp_ids_for_file', { file_id = file_id })
local trim_at = timestamps[(#timestamps - MAX_TIMESTAMPS) + 1]
if trim_at then
self:do_transaction('timestamp_delete_before_id', { id = trim_at.id, file_id = file_id })
end
end
function M:validate()
end
return M