Skip to content

Commit eca58dd

Browse files
authored
Add support for :check constraint at column level (#29)
* bump ecto to 3.6.1, remove forked repo.exs tests * add check constraint column option * initial implementation without name * require name for column constraint, clean up errors * better docs * format
1 parent 7ce09c4 commit eca58dd

File tree

10 files changed

+134
-2051
lines changed

10 files changed

+134
-2051
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ adheres to [Semantic Versioning][semver].
77

88
## [0.5.5] - Unreleased
99
- Fix "database is locked" issue by setting `journal_mode` at `storage_up` time.
10+
- Add :check constraint column option.
1011

1112

1213
## [0.5.4] - 2021-04-06

integration_test/all_test.exs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ Code.require_file "#{ecto}/integration_test/cases/repo.exs", __DIR__
77
Code.require_file "#{ecto}/integration_test/cases/windows.exs", __DIR__
88
Code.require_file "#{ecto}/integration_test/cases/interval.exs", __DIR__
99
Code.require_file "#{ecto}/integration_test/cases/type.exs", __DIR__
10-
11-
# add :concat tag, waiting for 3.6.1 release
12-
Code.require_file "./ecto/repo.exs", __DIR__
10+
Code.require_file "#{ecto}/integration_test/cases/repo.exs", __DIR__
1311

1412
ecto_sql = Mix.Project.deps_paths()[:ecto_sql]
1513
# Code.require_file "#{ecto_sql}/integration_test/sql/lock.exs", __DIR__

integration_test/constraints_test.exs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
defmodule Ecto.Integration.ConstraintsTest do
2+
use ExUnit.Case, async: true
3+
4+
import Ecto.Migrator, only: [up: 4]
5+
alias Ecto.Integration.PoolRepo
6+
7+
defmodule ConstraintMigration do
8+
use Ecto.Migration
9+
10+
@table table(:constraints_test)
11+
12+
def change do
13+
create @table do
14+
add :price, :integer
15+
add :fromm, :integer
16+
add :too, :integer, check: %{name: "cannot_overlap", expr: "fromm < too"}
17+
end
18+
end
19+
end
20+
21+
defmodule Constraint do
22+
use Ecto.Integration.Schema
23+
24+
schema "constraints_test" do
25+
field :price, :integer
26+
field :fromm, :integer
27+
field :too, :integer
28+
end
29+
end
30+
31+
@base_migration 2_000_000
32+
33+
setup_all do
34+
ExUnit.CaptureLog.capture_log(fn ->
35+
num = @base_migration + System.unique_integer([:positive])
36+
up(PoolRepo, num, ConstraintMigration, log: false)
37+
end)
38+
39+
:ok
40+
end
41+
42+
test "check constraint" do
43+
changeset = Ecto.Changeset.change(%Constraint{}, fromm: 0, too: 10)
44+
{:ok, _} = PoolRepo.insert(changeset)
45+
46+
non_overlapping_changeset = Ecto.Changeset.change(%Constraint{}, fromm: 11, too: 12)
47+
{:ok, _} = PoolRepo.insert(non_overlapping_changeset)
48+
49+
overlapping_changeset = Ecto.Changeset.change(%Constraint{}, fromm: 1900, too: 12)
50+
51+
exception =
52+
assert_raise Ecto.ConstraintError, ~r/constraint error when attempting to insert struct/, fn ->
53+
PoolRepo.insert(overlapping_changeset)
54+
end
55+
assert exception.message =~ "cannot_overlap (check_constraint)"
56+
assert exception.message =~ "The changeset has not defined any constraint."
57+
assert exception.message =~ "call `check_constraint/3`"
58+
59+
{:error, changeset} =
60+
overlapping_changeset
61+
|> Ecto.Changeset.check_constraint(:fromm, name: :cannot_overlap)
62+
|> PoolRepo.insert()
63+
assert changeset.errors == [fromm: {"is invalid", [constraint: :check, constraint_name: "cannot_overlap"]}]
64+
assert changeset.data.__meta__.state == :built
65+
end
66+
end

0 commit comments

Comments
 (0)