Skip to content

Commit 206b84a

Browse files
committed
Make map encoding configurable
1 parent bbe7ebe commit 206b84a

File tree

4 files changed

+58
-6
lines changed

4 files changed

+58
-6
lines changed

lib/ecto/adapters/sqlite3.ex

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ defmodule Ecto.Adapters.SQLite3 do
5151
* `:uuid_type` - Defaults to `:string`. Determines the type of `:uuid` columns.
5252
Possible values and column types are the same as for
5353
[binary IDs](#module-binary-id-types).
54+
* `:map_type` - Defaults to `:string`. Determines the type of `:map` columns.
55+
Set to `:binary` to use the [JSONB](https://sqlite.org/draft/jsonb.html)
56+
storage format.
5457
* `:datetime_type` - Defaults to `:iso8601`. Determines how datetime fields are
5558
stored in the database. The allowed values are `:iso8601` and `:text_datetime`.
5659
`:iso8601` corresponds to a string of the form `YYYY-MM-DDThh:mm:ss` and

lib/ecto/adapters/sqlite3/data_type.ex

+14-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ defmodule Ecto.Adapters.SQLite3.DataType do
1717
def column_type(:string, _opts), do: "TEXT"
1818
def column_type(:float, _opts), do: "NUMERIC"
1919
def column_type(:binary, _opts), do: "BLOB"
20-
def column_type(:map, _opts), do: "TEXT"
2120
def column_type(:array, _opts), do: "TEXT"
22-
def column_type({:map, _}, _opts), do: "TEXT"
2321
def column_type({:array, _}, _opts), do: "TEXT"
2422
def column_type(:date, _opts), do: "TEXT"
2523
def column_type(:utc_datetime, _opts), do: "TEXT"
@@ -50,6 +48,20 @@ defmodule Ecto.Adapters.SQLite3.DataType do
5048
end
5149
end
5250

51+
def column_type(:map, _opts) do
52+
case Application.get_env(:ecto_sqlite3, :map_type, :string) do
53+
:string -> "TEXT"
54+
:binary -> "BLOB"
55+
end
56+
end
57+
58+
def column_type({:map, _}, _opts) do
59+
case Application.get_env(:ecto_sqlite3, :map_type, :string) do
60+
:string -> "TEXT"
61+
:binary -> "BLOB"
62+
end
63+
end
64+
5365
def column_type(:uuid, _opts) do
5466
case Application.get_env(:ecto_sqlite3, :uuid_type, :string) do
5567
:string -> "TEXT"

test/ecto/adapters/sqlite3/data_type_test.exs

+12-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ defmodule Ecto.Adapters.SQLite3.DataTypeTest do
55

66
setup do
77
Application.put_env(:ecto_sqlite3, :binary_id_type, :string)
8+
Application.put_env(:ecto_sqlite3, :map_type, :string)
89
Application.put_env(:ecto_sqlite3, :uuid_type, :string)
910

1011
on_exit(fn ->
1112
Application.put_env(:ecto_sqlite3, :binary_id_type, :string)
13+
Application.put_env(:ecto_sqlite3, :map_type, :string)
1214
Application.put_env(:ecto_sqlite3, :uuid_type, :string)
1315
end)
1416
end
@@ -46,12 +48,20 @@ defmodule Ecto.Adapters.SQLite3.DataTypeTest do
4648
assert DataType.column_type(:uuid, nil) == "BLOB"
4749
end
4850

49-
test ":map is TEXT" do
51+
test ":map is TEXT or BLOB" do
5052
assert DataType.column_type(:map, nil) == "TEXT"
53+
54+
Application.put_env(:ecto_sqlite3, :map_type, :binary)
55+
56+
assert DataType.column_type(:map, nil) == "BLOB"
5157
end
5258

53-
test "{:map, _} is TEXT" do
59+
test "{:map, _} is TEXT or BLOB" do
5460
assert DataType.column_type({:map, %{}}, nil) == "TEXT"
61+
62+
Application.put_env(:ecto_sqlite3, :map_type, :binary)
63+
64+
assert DataType.column_type({:map, %{}}, nil) == "BLOB"
5565
end
5666

5767
test ":array is TEXT" do

test/ecto/integration/json_test.exs

+29-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,40 @@
11
defmodule Ecto.Integration.JsonTest do
2-
use Ecto.Integration.Case
2+
use Ecto.Integration.Case, async: false
33

44
alias Ecto.Adapters.SQL
55
alias Ecto.Integration.TestRepo
66
alias EctoSQLite3.Schemas.Setting
77

88
@moduletag :integration
99

10-
test "serializes json correctly" do
10+
setup do
11+
Application.put_env(:ecto_sqlite3, :map_type, :string)
12+
on_exit(fn -> Application.put_env(:ecto_sqlite3, :map_type, :string) end)
13+
end
14+
15+
test "serializes json correctly with string format" do
16+
# Insert a record purposefully with atoms as the map key. We are going to
17+
# verify later they were coerced into strings.
18+
setting =
19+
%Setting{}
20+
|> Setting.changeset(%{properties: %{foo: "bar", qux: "baz"}})
21+
|> TestRepo.insert!()
22+
23+
# Read the record back using ecto and confirm it
24+
assert %Setting{properties: %{"foo" => "bar", "qux" => "baz"}} =
25+
TestRepo.get(Setting, setting.id)
26+
27+
assert %{num_rows: 1, rows: [["bar"]]} =
28+
SQL.query!(
29+
TestRepo,
30+
"select json_extract(properties, '$.foo') from settings where id = ?1",
31+
[setting.id]
32+
)
33+
end
34+
35+
test "serializes json correctly with binary format" do
36+
Application.put_env(:ecto_sqlite3, :map_type, :binary)
37+
1138
# Insert a record purposefully with atoms as the map key. We are going to
1239
# verify later they were coerced into strings.
1340
setting =

0 commit comments

Comments
 (0)