nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: elixir-ecto/ecto
Pull request #4159 (2023-04-17 06:41:41)

Guard against invalid kw lists
> a small check if the first element of the list is a tuple when non-empry

😄 


Patch:
diff --git a/lib/ecto/repo.ex b/lib/ecto/repo.ex
index 9d2882fb..b89c88d5 100644
--- a/lib/ecto/repo.ex
+++ b/lib/ecto/repo.ex
@@ -261,7 +261,9 @@ defmodule Ecto.Repo do
       def default_options(_operation), do: []
       defoverridable default_options: 1
 
-      defp prepare_opts(operation_name, opts) do
+      defp prepare_opts(operation_name, []), do: default_options(operation_name)
+
+      defp prepare_opts(operation_name, [{key, _} | _rest] = opts) when is_atom(key) do
         operation_name
         |> default_options()
         |> Keyword.merge(opts)


Test patch:
diff --git a/test/ecto/repo_test.exs b/test/ecto/repo_test.exs
index 2361500d..4125a54d 100644
--- a/test/ecto/repo_test.exs
+++ b/test/ecto/repo_test.exs
@@ -317,6 +317,13 @@ defmodule Ecto.RepoTest do
       assert query.from.source == {"my_parent", Ecto.RepoTest.MyParent}
       assert query.prefix == "fallback_schema"
     end
+
+    test "raises if options aren't a keyword list" do
+      assert_raise FunctionClauseError, fn -> 
+        {:ok, _pid} = DefaultOptionRepo.start_link(url: "ecto://user:pass@local/hello")
+        DefaultOptionRepo.all(MySchema, [1])
+      end
+    end
   end
 
   describe "aggregate" do
Repository: elixir-ecto/ecto
Pull request #4163 (2023-04-19 12:55:53)

Fix custom maps with json_extract_path
Closes https://github.com/elixir-ecto/ecto/issues/4162


Patch:
diff --git a/lib/ecto/query/planner.ex b/lib/ecto/query/planner.ex
index 537f5fb9..1b5ceb7b 100644
--- a/lib/ecto/query/planner.ex
+++ b/lib/ecto/query/planner.ex
@@ -1102,10 +1102,6 @@ defmodule Ecto.Query.Planner do
     {Enum.reverse(combinations), counter}
   end
 
-  defp validate_json_path!(_path, _field, :any), do: :ok
-  defp validate_json_path!(_path, _field, :map), do: :ok
-  defp validate_json_path!(_path, _field, {:map, _}), do: :ok
-
   defp validate_json_path!([path_field | rest], field, {:parameterized, Ecto.Embedded, embed}) do
     case embed do
       %{related: related, cardinality: :one} ->
@@ -1130,7 +1126,19 @@ defmodule Ecto.Query.Planner do
   end
 
   defp validate_json_path!([_path_field | _rest], field, other_type) do
-    raise "expected field `#{field}` to be an embed or a map, got: `#{inspect(other_type)}`"
+    case Ecto.Type.type(other_type) do
+      :any ->
+        :ok
+
+      :map ->
+        :ok
+
+      {:map, _} ->
+        :ok
+
+      type ->
+        raise "expected field `#{field}` to be an embed or a map, got: `#{inspect(type)}`"
+    end
   end
 
   defp validate_json_path!([], _field, _type) do


Test patch:
diff --git a/test/ecto/query/planner_test.exs b/test/ecto/query/planner_test.exs
index 117fd1bc..6f8a33be 100644
--- a/test/ecto/query/planner_test.exs
+++ b/test/ecto/query/planner_test.exs
@@ -8,6 +8,29 @@ defmodule Ecto.Query.PlannerTest do
   alias Ecto.Query.Planner
   alias Ecto.Query.JoinExpr
 
+  defmodule CustomMap do
+      use Ecto.Type
+      def type,      do: :map
+      def load(_),   do: {:ok, :load}
+      def dump(_),   do: {:ok, :dump}
+      def cast(_),   do: {:ok, :cast}
+      def equal?(true, _), do: true
+      def equal?(_, _), do: false
+      def embed_as(_), do: :dump
+    end
+
+  defmodule Custom do
+    use Ecto.Schema
+
+    schema "custom" do
+      field :custom_map, CustomMap
+
+      embeds_one :custom_embed, CustomEmbed do
+        field :nested_custom_map, CustomMap
+      end
+    end
+  end
+
   defmodule Comment do
     use Ecto.Schema
 
@@ -1221,6 +1244,17 @@ defmodule Ecto.Query.PlannerTest do
     assert inspect(normalized_query) =~ "where: p0.preferences[\"field\"] == \"value\", select: p0.preferences[\"field\"]>"
   end
 
+  test "normalize: json_extract_path with field having custom map type" do
+    normalized_query =
+      Custom
+      |> where([c], c.custom_map["field"] == "value")
+      |> select([c], [c.custom_map["field"], c.custom_embed["nested_custom_map"]["field"]])
+      |> normalize()
+
+    assert inspect(normalized_query) =~
+             "where: c0.custom_map[\"field\"] == \"value\", select: [c0.custom_map[\"field\"], c0.custom_embed[\"nested_custom_map\"][\"field\"]]>"
+  end
+
   test "normalize: flattens and expands right side of in expressions" do
     {query, cast_params, dump_params, _select} = where(Post, [p], p.id in [1, 2, 3]) |> normalize_with_params()
     assert Macro.to_string(hd(query.wheres).expr) == "&0.id() in [1, 2, 3]"
Repository: elixir-ecto/ecto
Pull request #4184 (2023-05-09 13:32:18)

Make aggregate respect parent query prefix
Closes https://github.com/elixir-ecto/ecto/issues/4183


Patch:
diff --git a/lib/ecto/repo/queryable.ex b/lib/ecto/repo/queryable.ex
index a2a0b1af..a42cfb30 100644
--- a/lib/ecto/repo/queryable.ex
+++ b/lib/ecto/repo/queryable.ex
@@ -486,10 +486,13 @@ defmodule Ecto.Repo.Queryable do
         %{distinct: nil, limit: nil, offset: nil, combinations: []} = query ->
           %{query | order_bys: []}
 
-        query ->
-          query
-          |> Query.subquery()
-          |> Queryable.Ecto.SubQuery.to_query()
+        %{prefix: prefix} = query ->
+          query =
+            query
+            |> Query.subquery()
+            |> Queryable.Ecto.SubQuery.to_query()
+
+          %{query | prefix: prefix}
       end
 
     select = %SelectExpr{expr: {aggregate, [], []}, file: __ENV__.file, line: __ENV__.line}
@@ -504,12 +507,15 @@ defmodule Ecto.Repo.Queryable do
         %{distinct: nil, limit: nil, offset: nil, combinations: []} = query ->
           %{query | order_bys: []}
 
-        query ->
+        %{prefix: prefix} = query ->
           select = %SelectExpr{expr: ast, file: __ENV__.file, line: __ENV__.line}
 
-          %{query | select: select}
-          |> Query.subquery()
-          |> Queryable.Ecto.SubQuery.to_query()
+          query =
+            %{query | select: select}
+            |> Query.subquery()
+            |> Queryable.Ecto.SubQuery.to_query()
+
+          %{query | prefix: prefix}
       end
 
     select = %SelectExpr{expr: {aggregate, [], [ast]}, file: __ENV__.file, line: __ENV__.line}


Test patch:
diff --git a/test/ecto/repo_test.exs b/test/ecto/repo_test.exs
index 21b649ec..85a99aa9 100644
--- a/test/ecto/repo_test.exs
+++ b/test/ecto/repo_test.exs
@@ -359,6 +359,22 @@ defmodule Ecto.RepoTest do
       assert query.prefix == "public"
     end
 
+    test "aggregate/3 respects parent query prefix" do
+      query = from(m in MySchema, limit: 1) |> put_query_prefix("public")
+      TestRepo.aggregate(query, :count)
+
+      assert_received {:all, query}
+      assert query.prefix == "public"
+    end
+
+    test "aggregate/4 respects parent query prefix" do
+      query = from(m in MySchema, limit: 1) |> put_query_prefix("public")
+      TestRepo.aggregate(query, :count, :id)
+
+      assert_received {:all, query}
+      assert query.prefix == "public"
+    end
+
     test "removes any preload from query" do
       from(MySchemaWithAssoc, preload: :parent) |> TestRepo.aggregate(:count, :id)
       assert_received {:all, query}
Repository: elixir-ecto/ecto
Pull request #4209 (2023-06-14 15:55:37)

Allow dynamic field/2 in type/2
Closes https://github.com/elixir-ecto/ecto/issues/4208


Patch:
diff --git a/lib/ecto/query/builder.ex b/lib/ecto/query/builder.ex
index 73adc906..54709086 100644
--- a/lib/ecto/query/builder.ex
+++ b/lib/ecto/query/builder.ex
@@ -757,6 +757,9 @@ defmodule Ecto.Query.Builder do
   def validate_type!({:field, _, [{var, _, context}, field]}, vars, _env)
     when is_atom(var) and is_atom(context) and is_atom(field),
     do: {find_var!(var, vars), field}
+  def validate_type!({:field, _, [{var, _, context}, {:^, _, [field]}]}, vars, _env)
+    when is_atom(var) and is_atom(context),
+    do: {find_var!(var, vars), field}
 
   def validate_type!(type, _vars, _env) do
     error! "type/2 expects an alias, atom, initialized parameterized type or " <>


Test patch:
diff --git a/test/ecto/query/builder_test.exs b/test/ecto/query/builder_test.exs
index 29187aab..0e47eb02 100644
--- a/test/ecto/query/builder_test.exs
+++ b/test/ecto/query/builder_test.exs
@@ -344,6 +344,7 @@ defmodule Ecto.Query.BuilderTest do
     assert validate_type!(quote do :string end, [], env) == :string
     assert validate_type!(quote do x.title end, [x: 0], env) == {0, :title}
     assert validate_type!(quote do field(x, :title) end, [x: 0], env) == {0, :title}
+    assert validate_type!(quote do field(x, ^:title) end, [x: 0], env) == {0, :title}
 
     assert_raise Ecto.Query.CompileError, ~r"^type/2 expects an alias, atom", fn ->
       validate_type!(quote do "string" end, [x: 0], env)
Repository: elixir-ecto/ecto
Pull request #4236 (2023-07-19 14:48:55)

Allow interpolated `selected_as/2` names in `dynamic/2`
Closes https://github.com/elixir-ecto/ecto/issues/4234


Patch:
diff --git a/lib/ecto/query/builder/dynamic.ex b/lib/ecto/query/builder/dynamic.ex
index e2832cd3..0cb8564d 100644
--- a/lib/ecto/query/builder/dynamic.ex
+++ b/lib/ecto/query/builder/dynamic.ex
@@ -13,7 +13,7 @@ defmodule Ecto.Query.Builder.Dynamic do
   def build(binding, expr, env) do
     {query, vars} = Builder.escape_binding(quote(do: query), binding, env)
     {expr, {params, acc}} = escape(expr, {[], %{subqueries: [], aliases: %{}}}, vars, env)
-    aliases = Builder.escape_select_aliases(acc.aliases)
+    aliases = escape_select_aliases(acc.aliases)
     params = Builder.escape_params(params)
 
     quote do
@@ -39,6 +39,9 @@ defmodule Ecto.Query.Builder.Dynamic do
     escape(expr, params_acc, vars, env)
   end
 
+  defp escape_select_aliases(%{} = aliases), do: Builder.escape_select_aliases(aliases)
+  defp escape_select_aliases(aliases), do: aliases
+
   @doc """
   Expands a dynamic expression for insertion into the given query.
   """


Test patch:
diff --git a/test/ecto/query/builder/select_test.exs b/test/ecto/query/builder/select_test.exs
index eee0b740..c74f4df3 100644
--- a/test/ecto/query/builder/select_test.exs
+++ b/test/ecto/query/builder/select_test.exs
@@ -439,6 +439,18 @@ defmodule Ecto.Query.Builder.SelectTest do
       end
     end
 
+    test "supports interpolated atom names in selected_as/2 with dynamic/2" do
+      escaped_alias = {:selected_as, [], [{{:., [], [{:&, [], [0]}, :title]}, [], []}, :alias]}
+      escaped_alias2 = {:selected_as, [], [{{:., [], [{:&, [], [0]}, :title]}, [], []}, :alias2]}
+
+      select_fields = %{title: dynamic([p], selected_as(p.title, ^:alias))}
+      merge_fields = %{title2: dynamic([p], selected_as(p.title, ^:alias2))}
+
+      query = from p in "posts", select: ^select_fields, select_merge: ^merge_fields
+      assert {:%{}, [], [title: escaped_alias, title2: escaped_alias2]} == query.select.expr
+      assert %{alias: _, alias2: _} = query.select.aliases
+    end
+
     test "supports interpolated atom names in selected_as/2 with select_merge" do
       escaped_select_alias = {:selected_as, [], [{{:., [], [{:&, [], [0]}, :visits]}, [], []}, :select]}
       escaped_merge_alias = {:selected_as, [], [{{:., [], [{:&, [], [0]}, :title]}, [], []}, :merge]}
Repository: elixir-ecto/ecto
Pull request #4255 (2023-07-31 13:39:09)

Require interpolation for dynamic hints
I realized a bit late I wanted to do this. Since they should always be dynamic I think it should be interpolated.


Patch:
diff --git a/lib/ecto/query/builder/from.ex b/lib/ecto/query/builder/from.ex
index d4e59491..606ddb0b 100644
--- a/lib/ecto/query/builder/from.ex
+++ b/lib/ecto/query/builder/from.ex
@@ -150,13 +150,10 @@ defmodule Ecto.Query.Builder.From do
       {:^, _, [value]} ->
         quote do: Ecto.Query.Builder.From.hint!(unquote(value))
 
-      hint when is_binary(hint) ->
-        hint
-
-      other ->
+      _ ->
         Builder.error!(
-          "`hints` must be a compile time string, unsafe fragment of the form `unsafe_fragment(^...)`, " <>
-            "or list containing either, got: `#{Macro.to_string(other)}`"
+          "`unsafe_fragment/1` in `hints` expects an interpolated value, such as " <>
+            "unsafe_fragment(^value), got: `#{Macro.to_string(fragment)}`"
         )
     end
   end


Test patch:
diff --git a/test/ecto/query_test.exs b/test/ecto/query_test.exs
index f8b02476..534b2ec0 100644
--- a/test/ecto/query_test.exs
+++ b/test/ecto/query_test.exs
@@ -577,8 +577,10 @@ defmodule Ecto.QueryTest do
         quote_and_eval(from "posts", hints: unsafe_fragment(^123))
       end
 
-      assert_raise Ecto.Query.CompileError, ~r"`hints` must be a compile time string", fn ->
-        quote_and_eval(from "posts", hints: ["string", unsafe_fragment(123)])
+      msg = ~r"`unsafe_fragment/1` in `hints` expects an interpolated value"
+
+      assert_raise Ecto.Query.CompileError, msg, fn ->
+        quote_and_eval(from "posts", hints: ["string", unsafe_fragment("123")])
       end
     end
   end
Repository: elixir-ecto/ecto
Pull request #4272 (2023-08-27 14:14:03)

Fix planned values inspect
Before planning it is `{:values, [], [types, num_rows]}` after planning it is `{:values, [], [types, start_param_ix, num_rows]}`


Patch:
diff --git a/lib/ecto/query/inspect.ex b/lib/ecto/query/inspect.ex
index 6f4f136c..faa926f2 100644
--- a/lib/ecto/query/inspect.ex
+++ b/lib/ecto/query/inspect.ex
@@ -140,7 +140,7 @@ defimpl Inspect, for: Ecto.Query do
   defp inspect_source(%{source: {nil, schema}}, _names), do: inspect(schema)
   defp inspect_source(%{source: {:fragment, _, _} = source} = part, names), do: "#{expr(source, names, part)}"
 
-  defp inspect_source(%{source: {:values, _, [types, _]}}, _names) do
+  defp inspect_source(%{source: {:values, _, [types | _]}}, _names) do
     fields = Keyword.keys(types)
     "values (#{Enum.join(fields, ", ")})"
   end


Test patch:
diff --git a/test/ecto/query/inspect_test.exs b/test/ecto/query/inspect_test.exs
index f189a8aa..4ecc7fab 100644
--- a/test/ecto/query/inspect_test.exs
+++ b/test/ecto/query/inspect_test.exs
@@ -499,6 +499,7 @@ defmodule Ecto.Query.InspectTest do
   test "values lists" do
     query = from v in values([%{a: 1, b: 2, c: 3}], %{a: :integer, b: :integer, c: :integer})
     assert i(query) == "from v0 in values (a, b, c)"
+    assert i(plan(query)) == "from v0 in values (a, b, c)"
   end
 
   def plan(query) do
Repository: elixir-ecto/ecto
Pull request #4316 (2023-11-14 19:24:29)

Fix late binding composite types
Closes https://github.com/elixir-ecto/ecto/issues/4315


Patch:
diff --git a/lib/ecto/query/planner.ex b/lib/ecto/query/planner.ex
index 550d941e..fe50472b 100644
--- a/lib/ecto/query/planner.ex
+++ b/lib/ecto/query/planner.ex
@@ -1854,6 +1854,12 @@ defmodule Ecto.Query.Planner do
     {composite, type!(kind, query, expr, ix, field, allow_virtuals?)}
   end
 
+  defp field_type!(kind, query, expr, {composite, {{bind_kind, _, [_]} = bind_expr, field}}, allow_virtuals?)
+       when bind_kind in [:as, :parent_as] do
+    {ix, _, ix_query} = get_ix!(bind_expr, kind, query)
+    {composite, type!(kind, ix_query, expr, ix, field, allow_virtuals?)}
+  end
+
   defp field_type!(kind, query, expr, {{bind_kind, _, [_]} = bind_expr, field}, allow_virtuals?)
        when bind_kind in [:as, :parent_as] do
     {ix, _, ix_query} = get_ix!(bind_expr, kind, query)


Test patch:
diff --git a/test/ecto/query/planner_test.exs b/test/ecto/query/planner_test.exs
index d09c97dd..0a07c84c 100644
--- a/test/ecto/query/planner_test.exs
+++ b/test/ecto/query/planner_test.exs
@@ -1003,6 +1003,7 @@ defmodule Ecto.Query.PlannerTest do
   end
 
   test "normalize: late bindings with as" do
+    # Singular comparison
     {query, cast_params, _, _} =
       from(Post, as: :posts, where: as(:posts).visits == ^"123") |> normalize_with_params()
 
@@ -1012,6 +1013,13 @@ defmodule Ecto.Query.PlannerTest do
     assert_raise Ecto.QueryError, ~r/could not find named binding `as\(:posts\)`/, fn ->
       from(Post, where: as(:posts).visits == ^"123") |> normalize()
     end
+
+    # Composite comparison
+    {query, cast_params, _, _} =
+      from(Post, as: :posts, where: as(:posts).id in ^[123]) |> normalize_with_params()
+
+    assert Macro.to_string(hd(query.wheres).expr) == "&0.id() in ^(0, 1)"
+    assert cast_params == [123]
   end
 
   test "normalize: late dynamic bindings with as" do
Repository: elixir-ecto/ecto
Pull request #4322 (2023-11-18 02:01:31)

Allow module attributes to be given to in operator
My attempt to close https://github.com/elixir-ecto/ecto/issues/4321. 

I'm a bit unsure about this one so opening this for discussion/my own learning as well.

The issue is that when a module attribute is used like `p.field in @list`, it gets [sent here](https://github.com/elixir-ecto/ecto/blob/master/lib/ecto/query/builder.ex#L357):

```elixir
def escape({:in, _, [left, right]} = expr, type, params_acc, vars, env) do
    assert_type!(expr, type, :boolean)

    ltype = {:out, quoted_type(right, vars)}
    rtype = {:in, quoted_type(left, vars)}

    ....
end
```

And the fact that it is actually a list is not known and the type eventually gets set to :any. Making it so that it can't be cast to the type of `p.field` by the planner. 

Ideally it should [go here](https://github.com/elixir-ecto/ecto/blob/master/lib/ecto/query/builder.ex#L344C18-L344C18) so it gets tagged with the field type:

```elixir
def escape({:in, _, [left, right]} = expr, type, params_acc, vars, env)
      when is_list(right)
      when is_tuple(right) and elem(right, 0) in ~w(sigil_w sigil_W)a do
    assert_type!(expr, type, :boolean)

    {:array, ltype} = quoted_type(right, vars)
    rtype = {:array, quoted_type(left, vars)}
  
    ...
end
```

My fix attempt is to expand `right` before choosing which path to go down. This should call `Module.get_attribute` from what I know. If I'm not mistaken these escape functions will always be called at compile time so it should be ok.


Patch:
diff --git a/lib/ecto/query/builder.ex b/lib/ecto/query/builder.ex
index 7f27578a..e40b11ff 100644
--- a/lib/ecto/query/builder.ex
+++ b/lib/ecto/query/builder.ex
@@ -343,9 +343,10 @@ defmodule Ecto.Query.Builder do
   # in operator
   def escape({:in, _, [left, right]} = expr, type, params_acc, vars, env)
       when is_list(right)
-      when is_tuple(right) and elem(right, 0) in ~w(sigil_w sigil_W)a do
+      when is_tuple(right) and elem(right, 0) in ~w(sigil_w sigil_W @)a do
     assert_type!(expr, type, :boolean)
 
+    right = Macro.expand_once(right, get_env(env))
     {:array, ltype} = quoted_type(right, vars)
     rtype = {:array, quoted_type(left, vars)}
 


Test patch:
diff --git a/test/ecto/query_test.exs b/test/ecto/query_test.exs
index 534b2ec0..0ff4762e 100644
--- a/test/ecto/query_test.exs
+++ b/test/ecto/query_test.exs
@@ -72,6 +72,18 @@ defmodule Ecto.QueryTest do
     test "allows arbitrary parentheses in where" do
       _ = from(p in "posts", where: (not is_nil(p.title)))
     end
+
+    @statuses [:draft, :published]
+
+    test "allows module attributes with in" do
+      expected_in = [
+        %Ecto.Query.Tagged{value: :draft, type: {0, :status}},
+        %Ecto.Query.Tagged{value: :published, type: {0, :status}}
+      ]
+
+      [%{expr: {:in, [], [_, actual_in]}}] = from(p in "posts", where: p.status in @statuses).wheres
+      assert actual_in == expected_in
+    end
   end
 
   describe "from" do
Repository: elixir-ecto/ecto
Pull request #4358 (2024-01-28 09:24:30)

Introduce is_named_binding guard
What do you think about adding this as a convenience? i.e. instead of

```elixir
def modify_query(query) do
  if has_named_binding?(query, :name) do
    ... do something ...
  else
    ... do something else ...
  end
end
```

you can do

```elixir
def modify_query(query) when is_named_binding(query, :name) do
  ... do something ...
end

def modify_query(query) do
  .. do something else...
end
```


Patch:
diff --git a/Earthfile b/Earthfile
index 3b98e575..d626dc68 100644
--- a/Earthfile
+++ b/Earthfile
@@ -1,4 +1,4 @@
-VERSION 0.5
+VERSION 0.6
 
 all:
     BUILD \
diff --git a/lib/ecto/query.ex b/lib/ecto/query.ex
index f4cddd12..87df08c2 100644
--- a/lib/ecto/query.ex
+++ b/lib/ecto/query.ex
@@ -2838,6 +2838,13 @@ defmodule Ecto.Query do
           "callback function for with_named_binding/3 should return an Ecto.Query struct, got: #{inspect(other)}"
   end
 
+  @doc """
+  The same as `has_named_binding?/2` but allowed in guards.
+  """
+  @doc guard: true
+  defguard is_named_binding(query, name)
+           when is_struct(query, Ecto.Query) and is_map_key(query.aliases, name)
+
   @doc """
   Reverses the ordering of the query.
 


Test patch:
diff --git a/test/ecto/query_test.exs b/test/ecto/query_test.exs
index 0ff4762e..4b87073f 100644
--- a/test/ecto/query_test.exs
+++ b/test/ecto/query_test.exs
@@ -1076,6 +1076,15 @@ defmodule Ecto.QueryTest do
                    ~r"protocol Ecto.Queryable not implemented for \[\]",
                    fn -> has_named_binding?([], :posts) end
     end
+
+    test "is_named_binding/2 guard" do
+      named_binding_query = from p in "posts", as: :posts
+      no_binding_query = from p in "posts"
+
+      assert is_named_binding(named_binding_query, :posts)
+      refute is_named_binding(no_binding_query, :posts)
+      refute is_named_binding("posts", :posts)
+    end
   end
 
   describe "with_named_binding/3" do
Repository: elixir-ecto/ecto
Pull request #4364 (2024-02-03 19:06:26)

Raise if user tries to query embedded schema
There are some edge cases around embedded schemas that I think can be cleaned up a little. This one happens when you try to query an embedded schema. Currently, you'll get  an error like this:

> (Postgrex.Error) ERROR 42P01 (undefined_table) relation "nil" does not exist


With this change you'll get this

>  ** (Protocol.UndefinedError) protocol Ecto.Queryable not implemented for Ecto.Integration.Item of type Atom, the given module is an embedded schema. This protocol is implemented for the following type(s): Atom, BitString, Ecto.Query, Ecto.SubQuery, Tuple


greg-rychlewski: I think this makes sense, but I might be missing something. Like if there is a special case for MongoDB or something like that.
v0idpwn: I don't think there's any case you could use this before. But I may also be missing something 🤔

Patch:
diff --git a/lib/ecto/queryable.ex b/lib/ecto/queryable.ex
index a09c404b..3a09f2d1 100644
--- a/lib/ecto/queryable.ex
+++ b/lib/ecto/queryable.ex
@@ -39,6 +39,9 @@ defimpl Ecto.Queryable, for: Atom do
           end
 
         raise Protocol.UndefinedError, protocol: @protocol, value: module, description: message
+
+      FunctionClauseError ->
+        raise Protocol.UndefinedError, protocol: @protocol, value: module, description: "the given module is an embedded schema"
     end
   end
 end
diff --git a/lib/ecto/schema.ex b/lib/ecto/schema.ex
index 785d2026..06a111f3 100644
--- a/lib/ecto/schema.ex
+++ b/lib/ecto/schema.ex
@@ -666,13 +666,15 @@ defmodule Ecto.Schema do
         def __schema__(:autogenerate_fields),
           do: unquote(Enum.flat_map(autogenerate, &elem(&1, 0)))
 
-        def __schema__(:query) do
-          %Ecto.Query{
-            from: %Ecto.Query.FromExpr{
-              source: {unquote(source), __MODULE__},
-              prefix: unquote(prefix)
+        if meta? do
+          def __schema__(:query) do
+            %Ecto.Query{
+              from: %Ecto.Query.FromExpr{
+                source: {unquote(source), __MODULE__},
+                prefix: unquote(prefix)
+              }
             }
-          }
+          end
         end
 
         for clauses <-


Test patch:
diff --git a/test/ecto/embedded_test.exs b/test/ecto/embedded_test.exs
index fd53f212..000164aa 100644
--- a/test/ecto/embedded_test.exs
+++ b/test/ecto/embedded_test.exs
@@ -86,4 +86,10 @@ defmodule Ecto.EmbeddedTest do
     assert not Map.has_key?(author1, :__struct__)
     assert not Map.has_key?(author1, :__meta__)
   end
+
+  test "embedded schemas are not queryable" do
+    assert_raise Protocol.UndefinedError,
+                   ~r"the given module is an embedded schema",
+                   fn -> Ecto.Queryable.to_query(Post) end
+  end
 end