Moonshark/core/runner/sqlite.lua
2025-05-02 11:39:42 -05:00

181 lines
3.9 KiB
Lua

__active_sqlite_connections = {}
-- Connection metatable
local connection_mt = {
__index = {
-- Execute a query and return results as a table
query = function(self, query, params)
if type(query) ~= "string" then
error("connection:query: query must be a string", 2)
end
return __sqlite_query(self.db_name, query, params)
end,
-- Execute a statement and return affected rows
exec = function(self, query, params)
if type(query) ~= "string" then
error("connection:exec: query must be a string", 2)
end
return __sqlite_exec(self.db_name, query, params)
end,
-- Create a new table
create_table = function(self, table_name, schema)
if type(schema) ~= "table" then
error("connection:create_table: schema must be a table", 2)
end
local columns = {}
for name, definition in pairs(schema) do
table.insert(columns, name .. " " .. definition)
end
local query = string.format("CREATE TABLE IF NOT EXISTS %s (%s)",
table_name, table.concat(columns, ", "))
return self:exec(query)
end,
-- Insert a row or multiple rows
insert = function(self, table_name, data)
if type(data) ~= "table" then
error("connection:insert: data must be a table", 2)
end
-- Single row
if data[1] == nil and next(data) ~= nil then
local columns = {}
local placeholders = {}
local params = {}
for col, val in pairs(data) do
table.insert(columns, col)
table.insert(placeholders, ":" .. col)
params[col] = val
end
local query = string.format(
"INSERT INTO %s (%s) VALUES (%s)",
table_name,
table.concat(columns, ", "),
table.concat(placeholders, ", ")
)
return self:exec(query, params)
end
-- Multiple rows
if #data > 0 and type(data[1]) == "table" then
local affected = 0
for _, row in ipairs(data) do
local result = self:insert(table_name, row)
affected = affected + result
end
return affected
end
error("connection:insert: invalid data format", 2)
end,
-- Update rows
update = function(self, table_name, data, where, where_params)
if type(data) ~= "table" then
error("connection:update: data must be a table", 2)
end
local sets = {}
local params = {}
for col, val in pairs(data) do
table.insert(sets, col .. " = :" .. col)
params[col] = val
end
local query = string.format(
"UPDATE %s SET %s",
table_name,
table.concat(sets, ", ")
)
if where then
query = query .. " WHERE " .. where
if where_params then
for k, v in pairs(where_params) do
params[k] = v
end
end
end
return self:exec(query, params)
end,
-- Delete rows
delete = function(self, table_name, where, params)
local query = "DELETE FROM " .. table_name
if where then
query = query .. " WHERE " .. where
end
return self:exec(query, params)
end,
-- Get one row
get_one = function(self, query, params)
local results = self:query(query, params)
return results[1]
end,
-- Begin transaction
begin = function(self)
return self:exec("BEGIN TRANSACTION")
end,
-- Commit transaction
commit = function(self)
return self:exec("COMMIT")
end,
-- Rollback transaction
rollback = function(self)
return self:exec("ROLLBACK")
end,
-- Transaction wrapper function
transaction = function(self, callback)
self:begin()
local success, result = pcall(function()
return callback(self)
end)
if success then
self:commit()
return result
else
self:rollback()
error(result, 2)
end
end
}
}
-- Create sqlite() function that returns a connection object
return function(db_name)
if type(db_name) ~= "string" then
error("sqlite: database name must be a string", 2)
end
local conn = {
db_name = db_name,
id = tostring({}):match("table: (.*)") -- unique ID based on table address
}
__active_sqlite_connections[conn.id] = conn
return setmetatable(conn, connection_mt)
end