Skip to content

Commit c1b2f38

Browse files
committed
Add comprehensive tests for map/list default value handling
- Add tests for map defaults with JSON encoding - Add tests for list defaults with JSON encoding - Add tests for empty map and list defaults - Add tests for complex nested map defaults - Add tests for maps with various JSON types (string, number, bool, null) - Update existing empty map/list tests to reflect new behavior - All 43 migration tests + 54 connection tests pass
1 parent cbb852d commit c1b2f38

2 files changed

Lines changed: 96 additions & 6 deletions

File tree

lib/ecto/adapters/libsql/connection.ex

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,21 @@ defmodule Ecto.Adapters.LibSql.Connection do
473473
defp column_default(value) when is_binary(value), do: " DEFAULT '#{escape_string(value)}'"
474474
defp column_default(value) when is_number(value), do: " DEFAULT #{value}"
475475
defp column_default({:fragment, expr}), do: " DEFAULT #{expr}"
476+
477+
defp column_default(value) when is_map(value) do
478+
case Jason.encode(value) do
479+
{:ok, json} -> " DEFAULT '#{escape_string(json)}'"
480+
{:error, _} -> ""
481+
end
482+
end
483+
484+
defp column_default(value) when is_list(value) do
485+
case Jason.encode(value) do
486+
{:ok, json} -> " DEFAULT '#{escape_string(json)}'"
487+
{:error, _} -> ""
488+
end
489+
end
490+
476491
# Handle any other unexpected types (e.g., empty maps or third-party migrations)
477492
# Logs a warning to help with debugging while gracefully falling back to no DEFAULT clause
478493
defp column_default(unexpected) do

test/ecto_migration_test.exs

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -939,28 +939,30 @@ defmodule Ecto.Adapters.LibSql.MigrationTest do
939939
test "handles unexpected types gracefully (empty map)" do
940940
# This test verifies the catch-all clause for unexpected types.
941941
# Empty maps can come from some migrations or other third-party code.
942+
# As of the defaults update, empty maps are JSON encoded like other maps.
942943
table = %Table{name: :users, prefix: nil}
943944
columns = [{:add, :metadata, :string, [default: %{}]}]
944945

945946
# Should not raise FunctionClauseError.
946947
[sql] = Connection.execute_ddl({:create, table, columns})
947948

948-
# Empty map should be treated as no default.
949-
assert sql =~ ~r/"metadata".*TEXT/
950-
refute sql =~ ~r/"metadata".*DEFAULT/
949+
# Empty map should be JSON encoded to '{}'
950+
assert sql =~ ~r/"metadata".*TEXT.*DEFAULT/
951+
assert sql =~ "'{}'"
951952
end
952953

953954
test "handles unexpected types gracefully (list)" do
954955
# Lists are another unexpected type that might appear.
956+
# As of the defaults update, lists are JSON encoded.
955957
table = %Table{name: :users, prefix: nil}
956958
columns = [{:add, :tags, :string, [default: []]}]
957959

958960
# Should not raise FunctionClauseError.
959961
[sql] = Connection.execute_ddl({:create, table, columns})
960962

961-
# Empty list should be treated as no default.
962-
assert sql =~ ~r/"tags".*TEXT/
963-
refute sql =~ ~r/"tags".*DEFAULT/
963+
# Empty list should be JSON encoded to '[]'
964+
assert sql =~ ~r/"tags".*TEXT.*DEFAULT/
965+
assert String.contains?(sql, ["DEFAULT '[]'"])
964966
end
965967

966968
test "handles unexpected types gracefully (atom)" do
@@ -975,6 +977,79 @@ defmodule Ecto.Adapters.LibSql.MigrationTest do
975977
assert sql =~ ~r/"status".*TEXT/
976978
refute sql =~ ~r/"status".*DEFAULT/
977979
end
980+
981+
test "handles map defaults (JSON encoding)" do
982+
table = %Table{name: :users, prefix: nil}
983+
984+
columns = [
985+
{:add, :preferences, :text, [default: %{"theme" => "dark", "notifications" => true}]}
986+
]
987+
988+
[sql] = Connection.execute_ddl({:create, table, columns})
989+
990+
# Map should be JSON encoded
991+
assert sql =~ ~r/"preferences".*TEXT.*DEFAULT/
992+
assert sql =~ "theme"
993+
assert sql =~ "dark"
994+
end
995+
996+
test "handles list defaults (JSON encoding)" do
997+
table = %Table{name: :items, prefix: nil}
998+
999+
columns = [
1000+
{:add, :tags, :text, [default: ["tag1", "tag2", "tag3"]]}
1001+
]
1002+
1003+
[sql] = Connection.execute_ddl({:create, table, columns})
1004+
1005+
# List should be JSON encoded
1006+
assert sql =~ ~r/"tags".*TEXT.*DEFAULT/
1007+
assert sql =~ "tag1"
1008+
assert sql =~ "tag2"
1009+
end
1010+
1011+
test "handles empty list defaults" do
1012+
table = %Table{name: :items, prefix: nil}
1013+
columns = [{:add, :tags, :text, [default: []]}]
1014+
1015+
# Empty list encodes to "[]" in JSON
1016+
[sql] = Connection.execute_ddl({:create, table, columns})
1017+
1018+
# Should have a DEFAULT clause with empty array JSON
1019+
assert sql =~ ~r/"tags".*TEXT.*DEFAULT '\[\]'/
1020+
end
1021+
1022+
test "handles complex nested map defaults" do
1023+
table = %Table{name: :configs, prefix: nil}
1024+
1025+
columns = [
1026+
{:add, :settings, :text,
1027+
[default: %{"user" => %{"theme" => "light"}, "privacy" => false}]}
1028+
]
1029+
1030+
[sql] = Connection.execute_ddl({:create, table, columns})
1031+
1032+
# Nested map should be JSON encoded
1033+
assert sql =~ ~r/"settings".*TEXT.*DEFAULT/
1034+
assert sql =~ "user"
1035+
assert sql =~ "theme"
1036+
assert sql =~ "light"
1037+
end
1038+
1039+
test "handles map with various JSON types" do
1040+
table = %Table{name: :data, prefix: nil}
1041+
1042+
columns = [
1043+
{:add, :metadata, :text,
1044+
[default: %{"string" => "value", "number" => 42, "bool" => true, "null" => nil}]}
1045+
]
1046+
1047+
[sql] = Connection.execute_ddl({:create, table, columns})
1048+
1049+
assert sql =~ ~r/"metadata".*TEXT.*DEFAULT/
1050+
# Verify JSON is properly escaped
1051+
assert String.contains?(sql, ["string", "number", "bool"])
1052+
end
9781053
end
9791054

9801055
describe "CHECK constraints" do

0 commit comments

Comments
 (0)