Skip to content

Commit

Permalink
Errors now return constraint violations. 0.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Jae Bach Hardie committed Mar 16, 2017
1 parent b4e9500 commit 81c9234
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ by adding `mssqlex` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[{:mssqlex, "~> 0.4"}]
[{:mssqlex, "~> 0.5"}]
end
```

Expand Down
24 changes: 20 additions & 4 deletions lib/mssqlex/error.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ defmodule Mssqlex.Error do
or the string representation of the code if it cannot be translated.
"""

defexception [:message, :odbc_code]
defexception [:message, :odbc_code, constraint_violations: []]

@type t :: %__MODULE__{
message: binary(),
odbc_code: atom() | binary()
odbc_code: atom() | binary(),
constraint_violations: Keyword.t
}

@not_allowed_in_transaction_messages [226, 574]
Expand All @@ -20,8 +21,9 @@ defmodule Mssqlex.Error do
@spec exception(binary()) :: t()
def exception({_, _, reason} = message) do
%__MODULE__{
message: to_string(reason),
odbc_code: get_code(message)
message: to_string(to_string reason),
odbc_code: get_code(message),
constraint_violations: get_constraint_violations(to_string reason)
}
end

Expand All @@ -48,4 +50,18 @@ defmodule Mssqlex.Error do
defp translate("42000"), do: :syntax_error_or_access_violation
defp translate(code), do: code

defp get_constraint_violations(reason) do
constraint_checks =
[unique: ~r/Violation of UNIQUE KEY constraint '(\S+?)'./,
foreign_key: ~r/conflicted with the FOREIGN KEY constraint "(\S+?)"./,
check: ~r/conflicted with the CHECK constraint "(\S+?)"./]
extract = fn {key, test}, acc ->
case Regex.scan(test, reason, capture: :all_but_first) do
[] -> acc
matches -> Enum.reduce(matches, acc, fn [match], acc ->
[{key, match} | acc] end)
end
end
Enum.reduce(constraint_checks, [], extract)
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Mssqlex.Mixfile do

def project do
[app: :mssqlex,
version: "0.4.5",
version: "0.5.0",
description: "Adapter to Microsoft SQL Server. Using DBConnection and ODBC.",
elixir: "~> 1.4",
build_embedded: Mix.env == :prod,
Expand Down
70 changes: 70 additions & 0 deletions test/mssqlex/constraints_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
defmodule Mssqlex.ConstraintsTest do
use ExUnit.Case, async: true

setup_all do
{:ok, pid} = Mssqlex.start_link([])
Mssqlex.query!(pid, "DROP DATABASE IF EXISTS constraints_test;", [])
{:ok, _, _} = Mssqlex.query(pid, "CREATE DATABASE constraints_test;", [])

{:ok, [pid: pid]}
end

test "Unique constraint", %{pid: pid} do
table_name = "constraints_test.dbo.uniq"
Mssqlex.query!(pid, """
CREATE TABLE #{table_name}
(id int CONSTRAINT id_unique UNIQUE)
""", [])
Mssqlex.query!(pid, "INSERT INTO #{table_name} VALUES (?)", [42])
error = assert_raise Mssqlex.Error, fn ->
Mssqlex.query!(pid, "INSERT INTO #{table_name} VALUES (?)", [42])
end
assert error.constraint_violations == [unique: "id_unique"]
end

test "Foreign Key constraint", %{pid: pid} do
assoc_table_name = "constraints_test.dbo.assoc"
table_name = "constraints_test.dbo.fk"
Mssqlex.query!(pid, """
CREATE TABLE #{assoc_table_name}
(id int CONSTRAINT id_pk PRIMARY KEY)
""", [])
Mssqlex.query!(pid, """
CREATE TABLE #{table_name}
(id int CONSTRAINT id_foreign FOREIGN KEY REFERENCES #{assoc_table_name})
""", [])
Mssqlex.query!(pid, "INSERT INTO #{assoc_table_name} VALUES (?)", [42])
error = assert_raise Mssqlex.Error, fn ->
Mssqlex.query!(pid, "INSERT INTO #{table_name} VALUES (?)", [12])
end
assert error.constraint_violations == [foreign_key: "id_foreign"]
end

test "Check constraint", %{pid: pid} do
table_name = "constraints_test.dbo.chk"
Mssqlex.query!(pid, """
CREATE TABLE #{table_name}
(id int CONSTRAINT id_check CHECK (id = 1))
""", [])
error = assert_raise Mssqlex.Error, fn ->
Mssqlex.query!(pid, "INSERT INTO #{table_name} VALUES (?)", [42])
end
assert error.constraint_violations == [check: "id_check"]
end

@tag skip: "Database doesn't support this"
test "Multiple constraints", %{pid: pid} do
table_name = "constraints_test.dbo.mult"
Mssqlex.query!(pid, """
CREATE TABLE #{table_name}
(id int CONSTRAINT id_unique UNIQUE,
foo int CONSTRAINT foo_check CHECK (foo = 3))
""", [])
Mssqlex.query!(pid, "INSERT INTO #{table_name} VALUES (?, ?)", [42, 3])
error = assert_raise Mssqlex.Error, fn ->
Mssqlex.query!(pid, "INSERT INTO #{table_name} VALUES (?, ?)", [42, 5])
end
assert error.constraint_violations == [unique: "id_unique", check: "foo_check"]
end

end
1 change: 0 additions & 1 deletion test/mssqlex/types_test.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
defmodule Mssqlex.TypesTest do
use ExUnit.Case, async: true
@moduletag :only

alias Mssqlex.Result

Expand Down

0 comments on commit 81c9234

Please sign in to comment.