Skip to content

Commit

Permalink
add Ecto.Adapters.MyXQL.Constraint and delegate from the connection
Browse files Browse the repository at this point in the history
  • Loading branch information
petermueller committed Jul 29, 2024
1 parent e5ea9f6 commit ca6f1bc
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 40 deletions.
4 changes: 4 additions & 0 deletions integration_test/myxql/constraints_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ defmodule Ecto.Integration.ConstraintsTest do
alias Ecto.Integration.PoolRepo

defmodule CustomConstraintHandler do
@behaviour Ecto.Adapters.SQL.Constraint

@quotes ~w(" ' `)

@impl Ecto.Adapters.SQL.Constraint
# An example of a custom handler a user might write
def to_constraints(%MyXQL.Error{mysql: %{name: :ER_SIGNAL_EXCEPTION}, message: message}, opts) do
# Assumes this is the only use-case of `ER_SIGNAL_EXCEPTION` the user has implemented custom errors for
Expand Down Expand Up @@ -194,6 +197,7 @@ defmodule Ecto.Integration.ConstraintsTest do
assert is_integer(result.id)
end

@tag :constraint_handler
test "custom handled constraint" do
changeset = Ecto.Changeset.change(%Constraint{}, from: 0, to: 10)
{:ok, item} = PoolRepo.insert(changeset)
Expand Down
43 changes: 3 additions & 40 deletions lib/ecto/adapters/myxql/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ if Code.ensure_loaded?(MyXQL) do

@behaviour Ecto.Adapters.SQL.Connection

@impl true
defdelegate to_constraints(exception, options), to: Ecto.Adapters.MyXQL.Constraint

## Connection

@impl true
Expand Down Expand Up @@ -56,46 +59,6 @@ if Code.ensure_loaded?(MyXQL) do
end
end

@quotes ~w(" ' `)

@impl true
def to_constraints(%MyXQL.Error{mysql: %{name: :ER_DUP_ENTRY}, message: message}, opts) do
with [_, quoted] <- :binary.split(message, " for key "),
[_, index | _] <- :binary.split(quoted, @quotes, [:global]) do
[unique: strip_source(index, opts[:source])]
else
_ -> []
end
end

def to_constraints(%MyXQL.Error{mysql: %{name: name}, message: message}, _opts)
when name in [:ER_ROW_IS_REFERENCED_2, :ER_NO_REFERENCED_ROW_2] do
with [_, quoted] <- :binary.split(message, [" CONSTRAINT ", " FOREIGN KEY "]),
[_, index | _] <- :binary.split(quoted, @quotes, [:global]) do
[foreign_key: index]
else
_ -> []
end
end

def to_constraints(
%MyXQL.Error{mysql: %{name: :ER_CHECK_CONSTRAINT_VIOLATED}, message: message},
_opts
) do
with [_, quoted] <- :binary.split(message, ["Check constraint "]),
[_, constraint | _] <- :binary.split(quoted, @quotes, [:global]) do
[check: constraint]
else
_ -> []
end
end

def to_constraints(_, _),
do: []

defp strip_source(name, nil), do: name
defp strip_source(name, source), do: String.trim_leading(name, "#{source}.")

## Query

@parent_as __MODULE__
Expand Down
45 changes: 45 additions & 0 deletions lib/ecto/adapters/myxql/constraint.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
defmodule Ecto.Adapters.MyXQL.Constraint do
@moduledoc false

@behaviour Ecto.Adapters.SQL.Constraint

@quotes ~w(" ' `)

@impl true
def to_constraints(%MyXQL.Error{mysql: %{name: :ER_DUP_ENTRY}, message: message}, opts) do
with [_, quoted] <- :binary.split(message, " for key "),
[_, index | _] <- :binary.split(quoted, @quotes, [:global]) do
[unique: strip_source(index, opts[:source])]
else
_ -> []
end
end

def to_constraints(%MyXQL.Error{mysql: %{name: name}, message: message}, _opts)
when name in [:ER_ROW_IS_REFERENCED_2, :ER_NO_REFERENCED_ROW_2] do
with [_, quoted] <- :binary.split(message, [" CONSTRAINT ", " FOREIGN KEY "]),
[_, index | _] <- :binary.split(quoted, @quotes, [:global]) do
[foreign_key: index]
else
_ -> []
end
end

def to_constraints(
%MyXQL.Error{mysql: %{name: :ER_CHECK_CONSTRAINT_VIOLATED}, message: message},
_opts
) do
with [_, quoted] <- :binary.split(message, ["Check constraint "]),
[_, constraint | _] <- :binary.split(quoted, @quotes, [:global]) do
[check: constraint]
else
_ -> []
end
end

def to_constraints(_, _),
do: []

defp strip_source(name, nil), do: name
defp strip_source(name, source), do: String.trim_leading(name, "#{source}.")
end

0 comments on commit ca6f1bc

Please sign in to comment.