alexdesousa / ayesql

Library for using raw SQL in Elixir
MIT License
135 stars 13 forks source link

attempt to allow configurable binding use of question marks #18

Closed iautom8things closed 2 years ago

iautom8things commented 4 years ago

This isn't the most elegant solution. But it was quick and got me able to play further with your library. I'd be happy to refactor this more towards your liking. Just let me know what you think!

iautom8things commented 4 years ago

closes #17

alexdesousa commented 4 years ago

@iautom8things Hello and thanks for the PR! I'm glad you wanted to contribute to this little project :grinning:

Sadly I cannot merge it to the core at the moment, because I want to have a general way of handling #16 and #17 in the same way. I already know how to generalize the problem and I have part of the design in another branch (I haven't pushed it yet though).

My plan is basically have these variables delegated to the AyeSQL.Runner instead. Right now the core it's too tightly coupled to PostgreSQL and that needs to change.


One work around that does not require to modify AyeSQL core and that I've used in the past with MSSQL is the following:

With MSSQL I used the TDS library. For this library, both statement and arguments needed to be modified to fit the query function, so I delegated the job to a custom AyeSQL.Runner. The transformation problem was the following:

This is the redacted code I wrote a while ago:

defmodule Redacted.Runner do
  use AyeSQL.Runner

  @impl AyeSQL
  def run(%AyeSQL.Query{statement: stmt, arguments: args}, options) do
    pool = Keyword.get(options, :conn, Redacted.Pool)
    stmt = transform_stmt(stmt)
    args = transform_args(args)

    with {:ok, result} <- Tds.query(pool, stmt, args) do
      AyeSQL.Runner.handle_result(result)
    end
  end

  @spec transform_stmt(AyeSQL.Query.statement()) :: AyeSQL.Query.statement()
  defp transform_stmt(stmt) do
    Regex.replace(~r/\$(\d+)/, stmt, "@\\1")
  end

  @spec transform_args(AyeSQL.Query.arguments()) :: [Tds.Parameter.t()]
  defp transform_args(arguments) do
    1..length(arguments)
    |> Stream.zip(arguments)
    |> Enum.map(fn {name, value} -> %Tds.Parameter{name: "@#{name}", value: value} end)
  end
end

It's not the most elegant approach, but it works :grimacing:


So, thank you very much again for your interest in AyeSQL. I'll let you know when I have the fix for both issues.

I'll leave this PR opened though as it might help other people with the same issue :grinning: