Initial vibecoded proof of concept
This commit is contained in:
parent
74812459af
commit
461318a656
61 changed files with 13306 additions and 0 deletions
365
lua/notex/query/init.lua
Normal file
365
lua/notex/query/init.lua
Normal file
|
@ -0,0 +1,365 @@
|
|||
-- Query engine coordination module
|
||||
local M = {}
|
||||
|
||||
local query_parser = require('notex.query.parser')
|
||||
local query_executor = require('notex.query.executor')
|
||||
local database = require('notex.database.schema')
|
||||
local utils = require('notex.utils')
|
||||
|
||||
-- Execute query from string
|
||||
function M.execute_query(query_string, options)
|
||||
options = options or {}
|
||||
local start_time = utils.timer("Query execution")
|
||||
|
||||
-- Parse query
|
||||
local parsed_query = query_parser.parse(query_string)
|
||||
if #parsed_query.parse_errors > 0 then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "parse_error",
|
||||
errors = parsed_query.parse_errors,
|
||||
query_string = query_string
|
||||
}
|
||||
end
|
||||
|
||||
-- Validate query
|
||||
local valid, validation_errors = query_executor.validate_query(parsed_query)
|
||||
if not valid then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "validation_error",
|
||||
errors = validation_errors,
|
||||
query_string = query_string
|
||||
}
|
||||
end
|
||||
|
||||
-- Execute query
|
||||
local result = query_executor.execute(parsed_query, options)
|
||||
|
||||
start_time()
|
||||
|
||||
-- Add metadata
|
||||
result.query_string = query_string
|
||||
result.parsed_query = parsed_query
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Execute saved query
|
||||
function M.execute_saved_query(query_name, options)
|
||||
options = options or {}
|
||||
|
||||
-- Get saved query from database
|
||||
local ok, query_result = database.queries.get_by_name(query_name)
|
||||
if not ok then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "database_error",
|
||||
error = "Failed to retrieve saved query: " .. query_result
|
||||
}
|
||||
end
|
||||
|
||||
if not query_result then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "not_found",
|
||||
error = "Saved query not found: " .. query_name
|
||||
}
|
||||
end
|
||||
|
||||
-- Update usage statistics
|
||||
database.queries.update_usage(query_result.id)
|
||||
|
||||
-- Execute the query
|
||||
local result = M.execute_query(query_result.definition, options)
|
||||
result.query_name = query_name
|
||||
result.saved_query_id = query_result.id
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Save query for reuse
|
||||
function M.save_query(query_name, query_string, options)
|
||||
options = options or {}
|
||||
|
||||
-- Validate query before saving
|
||||
local parsed_query = query_parser.parse(query_string)
|
||||
if #parsed_query.parse_errors > 0 then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "parse_error",
|
||||
errors = parsed_query.parse_errors
|
||||
}
|
||||
end
|
||||
|
||||
-- Check if query already exists
|
||||
local existing_query, get_err = database.queries.get_by_name(query_name)
|
||||
if get_err then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "database_error",
|
||||
error = "Failed to check existing query: " .. get_err
|
||||
}
|
||||
end
|
||||
|
||||
local query_id = utils.generate_id()
|
||||
local current_time = os.time()
|
||||
|
||||
local query_data = {
|
||||
id = existing_query and existing_query.id or query_id,
|
||||
name = query_name,
|
||||
definition = query_string,
|
||||
created_at = existing_query and existing_query.created_at or current_time
|
||||
}
|
||||
|
||||
local ok, err
|
||||
if existing_query then
|
||||
ok, err = database.queries.update(query_data)
|
||||
else
|
||||
ok, err = database.queries.create(query_data)
|
||||
end
|
||||
|
||||
if not ok then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "database_error",
|
||||
error = "Failed to save query: " .. err
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
success = true,
|
||||
query_id = query_data.id,
|
||||
query_name = query_name,
|
||||
action = existing_query and "updated" or "created"
|
||||
}
|
||||
end
|
||||
|
||||
-- List saved queries
|
||||
function M.list_saved_queries(options)
|
||||
options = options or {}
|
||||
|
||||
local ok, queries = database.queries.get_all()
|
||||
if not ok then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "database_error",
|
||||
error = "Failed to retrieve saved queries: " .. queries
|
||||
}
|
||||
end
|
||||
|
||||
-- Add metadata to each query
|
||||
for _, query in ipairs(queries) do
|
||||
query.definition_preview = query.definition:sub(1, 100) .. (#query.definition > 100 and "..." or "")
|
||||
query.last_used_formatted = query.last_used > 0 and os.date("%Y-%m-%d %H:%M", query.last_used) or "Never"
|
||||
end
|
||||
|
||||
return {
|
||||
success = true,
|
||||
queries = queries,
|
||||
total_count = #queries
|
||||
}
|
||||
end
|
||||
|
||||
-- Delete saved query
|
||||
function M.delete_saved_query(query_name)
|
||||
local ok, query_result = database.queries.get_by_name(query_name)
|
||||
if not ok then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "database_error",
|
||||
error = "Failed to find query: " .. query_result
|
||||
}
|
||||
end
|
||||
|
||||
if not query_result then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "not_found",
|
||||
error = "Query not found: " .. query_name
|
||||
}
|
||||
end
|
||||
|
||||
local delete_ok, delete_err = database.queries.delete(query_result.id)
|
||||
if not delete_ok then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "database_error",
|
||||
error = "Failed to delete query: " .. delete_err
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
success = true,
|
||||
query_name = query_name,
|
||||
deleted_query_id = query_result.id
|
||||
}
|
||||
end
|
||||
|
||||
-- Get query suggestions
|
||||
function M.get_suggestions(partial_query, cursor_pos)
|
||||
cursor_pos = cursor_pos or #partial_query
|
||||
|
||||
-- Parse partial query to get context
|
||||
local parsed_query = query_parser.parse(partial_query)
|
||||
|
||||
-- Get suggestions based on context
|
||||
local suggestions = query_executor.get_suggestions(parsed_query, {
|
||||
cursor_pos = cursor_pos
|
||||
})
|
||||
|
||||
return {
|
||||
success = true,
|
||||
suggestions = suggestions,
|
||||
cursor_pos = cursor_pos
|
||||
}
|
||||
end
|
||||
|
||||
-- Validate query syntax
|
||||
function M.validate_query_syntax(query_string)
|
||||
local parsed_query = query_parser.parse(query_string)
|
||||
|
||||
return {
|
||||
valid = #parsed_query.parse_errors == 0,
|
||||
errors = parsed_query.parse_errors,
|
||||
parsed_query = parsed_query
|
||||
}
|
||||
end
|
||||
|
||||
-- Explain query
|
||||
function M.explain_query(query_string, options)
|
||||
options = options or {}
|
||||
|
||||
local parsed_query = query_parser.parse(query_string)
|
||||
if #parsed_query.parse_errors > 0 then
|
||||
return {
|
||||
success = false,
|
||||
error_type = "parse_error",
|
||||
errors = parsed_query.parse_errors
|
||||
}
|
||||
end
|
||||
|
||||
local explanation = query_executor.explain_query(parsed_query, options)
|
||||
|
||||
return explanation
|
||||
end
|
||||
|
||||
-- Format query string
|
||||
function M.format_query(query_string)
|
||||
local parsed_query = query_parser.parse(query_string)
|
||||
if #parsed_query.parse_errors > 0 then
|
||||
return query_string, parsed_query.parse_errors
|
||||
end
|
||||
|
||||
-- Rebuild query with proper formatting
|
||||
local formatted_parts = {}
|
||||
|
||||
-- Add filters
|
||||
if next(parsed_query.filters) then
|
||||
local filter_parts = {}
|
||||
for key, value in pairs(parsed_query.filters) do
|
||||
if type(value) == "string" then
|
||||
table.insert(filter_parts, string.format('%s: "%s"', key, value))
|
||||
elseif type(value) == "table" then
|
||||
table.insert(filter_parts, string.format('%s: [%s]', key, vim.inspect(value)))
|
||||
else
|
||||
table.insert(filter_parts, string.format('%s: %s', key, tostring(value)))
|
||||
end
|
||||
end
|
||||
table.insert(formatted_parts, table.concat(filter_parts, "\n"))
|
||||
end
|
||||
|
||||
-- Add conditions
|
||||
if parsed_query.conditions then
|
||||
table.insert(formatted_parts, "WHERE " .. M.format_conditions(parsed_query.conditions))
|
||||
end
|
||||
|
||||
-- Add order by
|
||||
if parsed_query.order_by then
|
||||
table.insert(formatted_parts, string.format("ORDER BY %s %s", parsed_query.order_by.field, parsed_query.order_by.direction))
|
||||
end
|
||||
|
||||
-- Add group by
|
||||
if parsed_query.group_by then
|
||||
table.insert(formatted_parts, "GROUP BY " .. parsed_query.group_by)
|
||||
end
|
||||
|
||||
-- Add limit
|
||||
if parsed_query.limit then
|
||||
table.insert(formatted_parts, "LIMIT " .. parsed_query.limit)
|
||||
end
|
||||
|
||||
local formatted_query = table.concat(formatted_parts, "\n")
|
||||
|
||||
return formatted_query, {}
|
||||
end
|
||||
|
||||
-- Format conditions recursively
|
||||
function M.format_conditions(conditions)
|
||||
if conditions.type == "comparison" then
|
||||
return string.format("%s %s %s", conditions.field, conditions.operator, tostring(conditions.value))
|
||||
elseif conditions.type == "existence" then
|
||||
return conditions.field
|
||||
elseif conditions.clauses then
|
||||
local clause_parts = {}
|
||||
for _, clause in ipairs(conditions.clauses) do
|
||||
table.insert(clause_parts, M.format_conditions(clause))
|
||||
end
|
||||
local operator = conditions.type:upper()
|
||||
return "(" .. table.concat(clause_parts, " " .. operator .. " ") .. ")"
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
-- Get query statistics
|
||||
function M.get_query_statistics(options)
|
||||
options = options or {}
|
||||
|
||||
local stats = {
|
||||
total_queries = 0,
|
||||
saved_queries = 0,
|
||||
recent_queries = {},
|
||||
popular_queries = {},
|
||||
average_execution_time = 0
|
||||
}
|
||||
|
||||
-- Get saved queries count
|
||||
local ok, saved_queries = database.queries.get_all()
|
||||
if ok then
|
||||
stats.saved_queries = #saved_queries
|
||||
|
||||
-- Get popular queries
|
||||
local popular = {}
|
||||
for _, query in ipairs(saved_queries) do
|
||||
if query.use_count > 0 then
|
||||
table.insert(popular, {
|
||||
name = query.name,
|
||||
use_count = query.use_count,
|
||||
last_used = query.last_used
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(popular, function(a, b) return a.use_count > b.use_count end)
|
||||
stats.popular_queries = vim.list_slice(popular, 1, 10)
|
||||
end
|
||||
|
||||
return {
|
||||
success = true,
|
||||
statistics = stats
|
||||
}
|
||||
end
|
||||
|
||||
-- Initialize query engine
|
||||
function M.init(database_path)
|
||||
local ok, err = require('notex.database.init').init(database_path)
|
||||
if not ok then
|
||||
return false, "Failed to initialize database for query engine: " .. err
|
||||
end
|
||||
|
||||
utils.log("INFO", "Query engine initialized")
|
||||
return true, "Query engine initialized successfully"
|
||||
end
|
||||
|
||||
return M
|
Loading…
Add table
Add a link
Reference in a new issue