From 069ed71ec2b10d3737a477d00cba985771e75608 Mon Sep 17 00:00:00 2001 From: Jason Stiebs Date: Fri, 20 Jan 2023 09:23:10 -0600 Subject: [PATCH 1/2] Missing literal, selected_as and using CAST for floats. --- lib/ecto/adapters/sqlite3/connection.ex | 13 ++++-- .../ecto/adapters/sqlite3/connection_test.exs | 23 +++++++++- test/ecto/integration/crud_test.exs | 45 +++++++++++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/lib/ecto/adapters/sqlite3/connection.ex b/lib/ecto/adapters/sqlite3/connection.ex index 91d46bc..831c1d8 100644 --- a/lib/ecto/adapters/sqlite3/connection.ex +++ b/lib/ecto/adapters/sqlite3/connection.ex @@ -1203,7 +1203,6 @@ defmodule Ecto.Adapters.SQLite3.Connection do quote_name(field) end - # def expr({{:., _, [{:parent_as, _, [{:&, _, [idx]}]}, field]}, _, []}, _sources, query) def expr({{:., _, [{:parent_as, _, [as]}, field]}, _, []}, _sources, query) when is_atom(field) do {ix, sources} = get_parent_sources_ix(query, as) @@ -1288,6 +1287,14 @@ defmodule Ecto.Adapters.SQLite3.Connection do |> parens_for_select end + def expr({:literal, _, [literal]}, _sources, _query) do + quote_name(literal) + end + + def expr({:selected_as, _, [name]}, _sources, _query) do + [quote_name(name)] + end + def expr({:datetime_add, _, [datetime, count, interval]}, sources, query) do [ "CAST (", @@ -1366,6 +1373,7 @@ defmodule Ecto.Adapters.SQLite3.Connection do end end + #TODO It technically is, its just a json array, so we *could* support it def expr(list, _sources, query) when is_list(list) do raise Ecto.QueryError, query: query, @@ -1404,8 +1412,7 @@ defmodule Ecto.Adapters.SQLite3.Connection do end def expr(literal, _sources, _query) when is_float(literal) do - # Unsure if SQLite3 supports float casting - ["(0 + ", Float.to_string(literal), ?)] + ["CAST(", Float.to_string(literal), " AS REAL)"] end def expr(expr, _sources, query) do diff --git a/test/ecto/adapters/sqlite3/connection_test.exs b/test/ecto/adapters/sqlite3/connection_test.exs index 82ffda0..e1d2eee 100644 --- a/test/ecto/adapters/sqlite3/connection_test.exs +++ b/test/ecto/adapters/sqlite3/connection_test.exs @@ -946,7 +946,28 @@ defmodule Ecto.Adapters.SQLite3.ConnectionTest do |> select([], true) |> plan() - assert all(query) == ~s{SELECT 1 FROM "schema" AS s0 WHERE (s0."foo" = (0 + 123.0))} + assert all(query) == ~s{SELECT 1 FROM "schema" AS s0 WHERE (s0."foo" = CAST(123.0 AS REAL))} + + name = "y" + query = + "schema" + |> where(fragment("? = ?", literal(^name), "Main")) + |> select([], true) + |> plan() + + assert all(query) == ~s|SELECT 1 FROM "schema" AS s0 WHERE ("y" = 'Main')| + end + + test "selected_as" do + query = + from(s in "schema", + select: %{ + y: selected_as(s.y, :y2), + } + ) + |> plan() + + assert all(query) == ~s|SELECT s0."y" AS "y2" FROM "schema" AS s0| end test "tagged type" do diff --git a/test/ecto/integration/crud_test.exs b/test/ecto/integration/crud_test.exs index ef8d036..b89b02e 100644 --- a/test/ecto/integration/crud_test.exs +++ b/test/ecto/integration/crud_test.exs @@ -244,5 +244,50 @@ defmodule Ecto.Integration.CrudTest do assert [_] = TestRepo.all(from(a in Account, as: :user, where: exists(subquery))) end + + test "can handle fragment literal" do + account1 = TestRepo.insert!(%Account{name: "Main"}) + + name = "name" + query = + from(a in Account, where: fragment("? = ?", literal(^name), "Main")) + + assert [account] = TestRepo.all(query) + assert account.id == account1.id + end + + test "can handle selected_as" do + TestRepo.insert!(%Account{name: "Main"}) + TestRepo.insert!(%Account{name: "Main"}) + TestRepo.insert!(%Account{name: "Main2"}) + TestRepo.insert!(%Account{name: "Main3"}) + + query = + from(a in Account, + select: %{ + name: selected_as(a.name, :name2), + count: count() + }, + group_by: selected_as(:name2) + ) + + assert [%{name: "Main", count: 2}, %{name: "Main2", count: 1}, %{name: "Main3", count: 1}] = TestRepo.all(query) + end + + test "can handle floats" do + TestRepo.insert!(%Account{name: "Main"}) + + one = "1.0" + two = 2.0 + + query = + from(a in Account, + select: %{ + sum: ^one + ^two + } + ) + + assert [%{sum: 3.0}] = TestRepo.all(query) + end end end From 6464241f6bbcbecc6b6d0ce7b5e089078398b1b6 Mon Sep 17 00:00:00 2001 From: Jason Stiebs Date: Fri, 20 Jan 2023 09:42:18 -0600 Subject: [PATCH 2/2] Formatter --- lib/ecto/adapters/sqlite3/connection.ex | 2 +- test/ecto/adapters/sqlite3/connection_test.exs | 18 ++++++++++-------- test/ecto/integration/crud_test.exs | 15 +++++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/lib/ecto/adapters/sqlite3/connection.ex b/lib/ecto/adapters/sqlite3/connection.ex index 831c1d8..907f66d 100644 --- a/lib/ecto/adapters/sqlite3/connection.ex +++ b/lib/ecto/adapters/sqlite3/connection.ex @@ -1373,7 +1373,7 @@ defmodule Ecto.Adapters.SQLite3.Connection do end end - #TODO It technically is, its just a json array, so we *could* support it + # TODO It technically is, its just a json array, so we *could* support it def expr(list, _sources, query) when is_list(list) do raise Ecto.QueryError, query: query, diff --git a/test/ecto/adapters/sqlite3/connection_test.exs b/test/ecto/adapters/sqlite3/connection_test.exs index e1d2eee..1dc3c9f 100644 --- a/test/ecto/adapters/sqlite3/connection_test.exs +++ b/test/ecto/adapters/sqlite3/connection_test.exs @@ -946,9 +946,11 @@ defmodule Ecto.Adapters.SQLite3.ConnectionTest do |> select([], true) |> plan() - assert all(query) == ~s{SELECT 1 FROM "schema" AS s0 WHERE (s0."foo" = CAST(123.0 AS REAL))} + assert all(query) == + ~s{SELECT 1 FROM "schema" AS s0 WHERE (s0."foo" = CAST(123.0 AS REAL))} name = "y" + query = "schema" |> where(fragment("? = ?", literal(^name), "Main")) @@ -959,13 +961,13 @@ defmodule Ecto.Adapters.SQLite3.ConnectionTest do end test "selected_as" do - query = - from(s in "schema", - select: %{ - y: selected_as(s.y, :y2), - } - ) - |> plan() + query = + from(s in "schema", + select: %{ + y: selected_as(s.y, :y2) + } + ) + |> plan() assert all(query) == ~s|SELECT s0."y" AS "y2" FROM "schema" AS s0| end diff --git a/test/ecto/integration/crud_test.exs b/test/ecto/integration/crud_test.exs index b89b02e..51267d9 100644 --- a/test/ecto/integration/crud_test.exs +++ b/test/ecto/integration/crud_test.exs @@ -245,12 +245,11 @@ defmodule Ecto.Integration.CrudTest do assert [_] = TestRepo.all(from(a in Account, as: :user, where: exists(subquery))) end - test "can handle fragment literal" do + test "can handle fragment literal" do account1 = TestRepo.insert!(%Account{name: "Main"}) name = "name" - query = - from(a in Account, where: fragment("? = ?", literal(^name), "Main")) + query = from(a in Account, where: fragment("? = ?", literal(^name), "Main")) assert [account] = TestRepo.all(query) assert account.id == account1.id @@ -263,7 +262,7 @@ defmodule Ecto.Integration.CrudTest do TestRepo.insert!(%Account{name: "Main3"}) query = - from(a in Account, + from(a in Account, select: %{ name: selected_as(a.name, :name2), count: count() @@ -271,7 +270,11 @@ defmodule Ecto.Integration.CrudTest do group_by: selected_as(:name2) ) - assert [%{name: "Main", count: 2}, %{name: "Main2", count: 1}, %{name: "Main3", count: 1}] = TestRepo.all(query) + assert [ + %{name: "Main", count: 2}, + %{name: "Main2", count: 1}, + %{name: "Main3", count: 1} + ] = TestRepo.all(query) end test "can handle floats" do @@ -281,7 +284,7 @@ defmodule Ecto.Integration.CrudTest do two = 2.0 query = - from(a in Account, + from(a in Account, select: %{ sum: ^one + ^two }