151 lines
No EOL
3 KiB
Lua
151 lines
No EOL
3 KiB
Lua
-- Database connection and initialization module
|
|
local M = {}
|
|
|
|
local sqlite3 = require('lsqlite3')
|
|
local utils = require('notex.utils')
|
|
|
|
-- Database connection state
|
|
local db = nil
|
|
local db_path = nil
|
|
|
|
-- Initialize database connection
|
|
function M.init(path)
|
|
if db then
|
|
return true, "Database already initialized"
|
|
end
|
|
|
|
db_path = path or vim.fn.stdpath('data') .. '/notex/notex.db'
|
|
|
|
-- Ensure directory exists
|
|
local dir = vim.fn.fnamemodify(db_path, ':h')
|
|
vim.fn.mkdir(dir, 'p')
|
|
|
|
local ok, err = pcall(function()
|
|
db = sqlite3.open(db_path)
|
|
end)
|
|
|
|
if not ok then
|
|
return false, "Failed to open database: " .. tostring(err)
|
|
end
|
|
|
|
-- Enable foreign key constraints
|
|
db:exec("PRAGMA foreign_keys = ON")
|
|
|
|
-- Set WAL mode for better performance
|
|
db:exec("PRAGMA journal_mode = WAL")
|
|
|
|
-- Set synchronous mode for performance vs safety balance
|
|
db:exec("PRAGMA synchronous = NORMAL")
|
|
|
|
return true, "Database initialized successfully"
|
|
end
|
|
|
|
-- Get database connection
|
|
function M.get_connection()
|
|
if not db then
|
|
error("Database not initialized. Call init() first.")
|
|
end
|
|
return db
|
|
end
|
|
|
|
-- Close database connection
|
|
function M.close()
|
|
if db then
|
|
db:close()
|
|
db = nil
|
|
return true, "Database closed successfully"
|
|
end
|
|
return false, "Database not initialized"
|
|
end
|
|
|
|
-- Execute query with error handling
|
|
function M.execute(query, params)
|
|
local conn = M.get_connection()
|
|
local stmt = conn:prepare(query)
|
|
|
|
if not stmt then
|
|
return false, "Failed to prepare query: " .. query
|
|
end
|
|
|
|
local result = {}
|
|
local ok, err = pcall(function()
|
|
if params then
|
|
stmt:bind_names(params)
|
|
end
|
|
|
|
for row in stmt:nrows() do
|
|
table.insert(result, row)
|
|
end
|
|
|
|
stmt:finalize()
|
|
end)
|
|
|
|
if not ok then
|
|
stmt:finalize()
|
|
return false, "Query execution failed: " .. tostring(err)
|
|
end
|
|
|
|
return true, result
|
|
end
|
|
|
|
-- Execute transaction
|
|
function M.transaction(queries)
|
|
local conn = M.get_connection()
|
|
local ok, err = pcall(function()
|
|
conn:exec("BEGIN TRANSACTION")
|
|
|
|
for _, query_data in ipairs(queries) do
|
|
local stmt = conn:prepare(query_data.query)
|
|
if query_data.params then
|
|
stmt:bind_names(query_data.params)
|
|
end
|
|
stmt:step()
|
|
stmt:finalize()
|
|
end
|
|
|
|
conn:exec("COMMIT")
|
|
end)
|
|
|
|
if not ok then
|
|
conn:exec("ROLLBACK")
|
|
return false, "Transaction failed: " .. tostring(err)
|
|
end
|
|
|
|
return true, "Transaction completed successfully"
|
|
end
|
|
|
|
-- Get database status
|
|
function M.status()
|
|
if not db then
|
|
return {
|
|
initialized = false,
|
|
path = nil,
|
|
size_bytes = 0,
|
|
wal_mode = false
|
|
}
|
|
end
|
|
|
|
local size = 0
|
|
local file = io.open(db_path, "r")
|
|
if file then
|
|
size = file:seek("end")
|
|
file:close()
|
|
end
|
|
|
|
local wal_mode = false
|
|
local wal_file = db_path .. "-wal"
|
|
local wal = io.open(wal_file, "r")
|
|
if wal then
|
|
wal_mode = true
|
|
wal:close()
|
|
end
|
|
|
|
return {
|
|
initialized = true,
|
|
path = db_path,
|
|
size_bytes = size,
|
|
wal_mode = wal_mode
|
|
}
|
|
end
|
|
|
|
return M |