Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Run query under cursor #121

Open
Rizhiy opened this issue Jun 9, 2024 · 5 comments
Open

[Feature Request] Run query under cursor #121

Rizhiy opened this issue Jun 9, 2024 · 5 comments

Comments

@Rizhiy
Copy link

Rizhiy commented Jun 9, 2024

Rather than having to select a query using visual mode, it would be great if you could just call a function to automatically select the query under cursor and run it.

Tree sitter sql grammar has statement node which selects the whole query.

@joao-alho
Copy link

I have created a custom keymap to do just that:

vim.api.nvim_create_autocmd({ "FileType" }, {
	desc = "On buffer enter with file type sql",
	group = vim.api.nvim_create_augroup("dbee", { clear = true }),
	pattern = { "sql" },
	callback = function()
		vim.keymap.set({ "n" }, "<leader>de", function()
			vim.api.nvim_feedkeys("vip", "n", false)
			local srow, scol, erow, ecol = require("dbee.utils").visual_selection()
			local selection = vim.api.nvim_buf_get_text(0, srow, scol, erow, ecol, {})
			local query = table.concat(selection, "\n")
			local command = string.format("Dbee execute %s", query)
			-- vim.print(command)
			vim.api.nvim_command(command)
		end, { desc = "[D]bee [e]xecute query under cursor" })
	end,
})

Two things to consider though:

  1. queries must be separated by an empty line
-- this will either run 2 queries or not work depending on the adapter I guess
select a from table;
select b from table_2;
-- this will run ok
select a from table;

select b from table_2;
  1. If you are on a .sql file and use this keybind it will open Dbee UI and run the selected query. But the query will not show up on Dbee editor

@Rizhiy Rizhiy changed the title [Feature Request] Run query under buffer [Feature Request] Run query under cursor Aug 8, 2024
@Rizhiy
Copy link
Author

Rizhiy commented Aug 9, 2024

@joao-alho I see you don't know that you shouldn't parse syntax using naive rules)

As I've said, you can and should do this using treesitter:

function M.get_query()
    local ts_utils = require("nvim-treesitter.ts_utils")
    local current_node = ts_utils.get_node_at_cursor()

    local last_statement = nil
    while current_node do
        if current_node:type() == "statement" then last_statement = current_node end
        if current_node:type() == "program" then break end
        current_node = current_node:parent()
    end

    if not last_statement then return "" end

    local srow, scol, erow, ecol = vim.treesitter.get_node_range(last_statement)
    local selection = vim.api.nvim_buf_get_text(0, srow, scol, erow, ecol, {})
    return table.concat(selection, "\n")
end

This should work properly with any valid query, even if it has queries next to it and blank lines inside, so allows you to use it with more complex queries. For example, all three queries will be extracted correctly from text below:

select name from table;
select two from three;
with items as (
	select name from table

	-- A comment
	where age > 20
)

select count(name) from items;

I haven't been working with databases recently, but might change it into a PR over the weekend.

@joao-alho
Copy link

hey thanks a lot, for both the docs and the proper way of doing it.

@willruggiano
Copy link

FWIW I personally find visual select + trigger to be a very nice way of doing this. I have the following setup;

  1. dbee
require("dbee").setup {
  editor = {
    mappings = {
      {
        action = "run_selection",
        key = "<C-M>",
        mode = "x",
        opts = { noremap = true, nowait = true, expr = true },
      },
    },
  },
}

This allows me to, for example, vip<cr> to execute the visual selection.

  1. as you've noted, vip isn't the right textobject for this. so i have nvim-treesitter-textobjects installed with the following sql textobjects;
(statement) @block.outer

[
 (select)
 (from)
 (join)
 (where)
 (group_by)
] @block.inner

and then in my treesitter config;

require("nvim-treesitter.configs").setup {
  textobjects = {
    select = {
      enable = true,
      keymaps = {
        ["ab"] = "@block.outer",
        ["ib"] = "@block.inner",
      },
    },
  },
}

Now vab<cr> accomplishes the same thing as @Rizhiy's snippet.

Again, doesn't answer your question specifically but thought I'd share regardless :)

@asmodeus812
Copy link

Fox executing the statements under the cursor one could do

            mappings = {
                {
                    key = "<C-g>",
                    mode = "i",
                    action = function()
                        local ts = require("vim.treesitter")
                        local current_node = ts.get_node()

                        while current_node and current_node:type() ~= "statement" do
                            current_node = current_node:parent()
                        end

                        if not current_node then
                            return
                        end
                        local srow, scol, erow, ecol = vim.treesitter.get_node_range(current_node)
                        local selection = vim.api.nvim_buf_get_text(0, srow, scol, erow, ecol, {})

                        if not selection or #selection == 0 then return end
                        selection = vim.tbl_map(fn.trim_empty_space, selection)

                        local editor = require("dbee.api.state").editor()
                        local conn = editor.handler:get_current_connection()
                        if not conn or not conn.id then return end

                        local query = table.concat(selection, " ")
                        local call = editor.handler:connection_execute(conn.id, query)
                        return editor.result:set_call(call)
                    end
                },
            },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants