Skip to content

Commit db9a414

Browse files
authored
Merge pull request #15 from elixir-sqlite/kcl-case-insensitive
add collate options to :string column
2 parents b878567 + 342efeb commit db9a414

File tree

7 files changed

+50
-0
lines changed

7 files changed

+50
-0
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog][keepachangelog], and this project
66
adheres to [Semantic Versioning][semver].
77

88
## [Unreleased]
9+
- Added `collate:` opts support to `:string` column type
910

1011
## [0.5.1] - 2021-03-18
1112
- Updated exqlite to 0.5.0

lib/ecto/adapters/sqlite3.ex

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,24 @@ defmodule Ecto.Adapters.SQLite3 do
9191
We have the DSQLITE_LIKE_DOESNT_MATCH_BLOBS compile-time option set to true,
9292
as [recommended][3] by SQLite. This means you cannot do LIKE queries on BLOB columns.
9393
94+
### Case sensitivity
95+
96+
Case sensitivty for `LIKE` is off by default, and controlled by the `:case_sensitive_like`
97+
option outlined above.
98+
99+
However, for equality comparison, case sensitivity is always _on_.
100+
If you want to make a column not be case sensitive, for email storage for example, you can
101+
make it case insensitive by using the [`COLLATE NOCASE`][6] option in SQLite. This is configured
102+
via the `:collate` option.
103+
104+
So instead of:
105+
106+
add :email, :string
107+
108+
You would do:
109+
110+
add :email, :string, collate: :nocase
111+
94112
### Schemaless queries
95113
96114
Using [schemaless Ecto queries][5] will not work well with SQLite. This is because
@@ -101,6 +119,7 @@ defmodule Ecto.Adapters.SQLite3 do
101119
[3]: https://www.sqlite.org/compile.html
102120
[4]: https://www.sqlite.org/whentouse.html
103121
[5]: https://www.sqlite.org/datatype3.html
122+
[6]: https://www.sqlite.org/datatype3.html#collating_sequences
104123
"""
105124

106125
use Ecto.Adapters.SQL,

lib/ecto/adapters/sqlite3/data_type.ex

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ defmodule Ecto.Adapters.SQLite3.DataType do
1414
def column_type(:bigint, _opts), do: "INTEGER"
1515
# TODO: We should make this configurable
1616
def column_type(:binary_id, _opts), do: "TEXT"
17+
18+
def column_type(:string, opts) when is_list(opts) do
19+
collate = Keyword.get(opts, :collate)
20+
21+
if collate do
22+
str = collate |> Atom.to_string() |> String.upcase()
23+
"TEXT COLLATE #{str}"
24+
else
25+
"TEXT"
26+
end
27+
end
28+
1729
def column_type(:string, _opts), do: "TEXT"
1830
def column_type(:float, _opts), do: "NUMERIC"
1931
def column_type(:binary, _opts), do: "BLOB"

test/ecto/adapters/sqlite3/data_type_test.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ defmodule Ecto.Adapters.SQLite3.DataTypeTest do
2424
assert DataType.column_type(:string, nil) == "TEXT"
2525
end
2626

27+
test ":string, collate: :nocase is TEXT COLLATE NOCASE" do
28+
assert DataType.column_type(:string, collate: :nocase) == "TEXT COLLATE NOCASE"
29+
end
30+
2731
test ":uuid is TEXT" do
2832
assert DataType.column_type(:uuid, nil) == "TEXT"
2933
end

test/ecto/integration/crud_test.exs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,5 +191,17 @@ defmodule Ecto.Integration.CrudTest do
191191
assert [] = TestRepo.all from a in Account, where: a.name in ["404"]
192192
assert [_] = TestRepo.all from a in Account, where: a.name in ["hi"]
193193
end
194+
195+
test "handles case sensitive text" do
196+
TestRepo.insert!(%Account{name: "hi"})
197+
assert [_] = TestRepo.all from a in Account, where: a.name == "hi"
198+
assert [] = TestRepo.all from a in Account, where: a.name == "HI"
199+
end
200+
201+
test "handles case insensitive text" do
202+
TestRepo.insert!(%Account{name: "hi", email: "[email protected]"})
203+
assert [_] = TestRepo.all from a in Account, where: a.email == "[email protected]"
204+
assert [_] = TestRepo.all from a in Account, where: a.email == "[email protected]"
205+
end
194206
end
195207
end

test/support/migration.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ defmodule EctoSQLite3.Integration.Migration do
44
def change do
55
create table(:accounts) do
66
add(:name, :string)
7+
add(:email, :string, collate: :nocase)
78
timestamps()
89
end
910

test/support/schemas.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ defmodule EctoSQLite3.Integration.Account do
88

99
schema "accounts" do
1010
field(:name, :string)
11+
field(:email, :string)
1112

1213
timestamps()
1314

0 commit comments

Comments
 (0)