-- 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