Using Ash.Query.filter makes query ignore custom repo in context

I have an action that I want to run in my replica database, I’m doing it like this:

Core.Pacman.Markets.Entity
|> Ash.Query.for_read(:summary, %{builder: builder})
|> Ash.Query.set_context(%{data_layer: %{repo: Core.ReplicaRepo}})
|> Ash.Query.limit(10)
|> Ash.read!()

The action itself is just a read without anything special.

I attached a dbg to my telemtry handler to check the metadata that comes from this query being run, I will get this from the above code:

metadata #=> %{
  type: :ecto_sql_query,
  options: [],
  stacktrace: nil,
  result: {:ok,
   %Postgrex.Result{
     command: :select,
     columns: ["address_street_name", "total_buy_and_holds",
      "last_year_unknowns_buy_prices",
      "year_before_last_wholesalers_sell_prices",
      "current_year_fix_and_flips_buy_prices", "current_year_unknowns",
      "address_street_direction", "current_year_buy_and_holds",
      "year_before_last_buy_and_holds", "total_fix_and_flips_buy_prices",
      "year_before_last_buy_transfer_amount", "address_house_number",
      "middle_name", "address_street_post_direction",
      "current_year_portfolios_buy_prices", "full_name", "address",
      "last_year_fix_and_flips_sell_prices", "last_year_sell_transfer_amount",
      "last_name", "year_before_last_sell_records",
      "total_wholesalers_buy_prices", "total_sell_records",
      "year_before_last_sell_transfer_amount", "likely_names",
      "total_wholesalers_sell_prices", "address_zip", "current_year",
      "current_year_fix_and_flips", "last_year_buy_and_holds_buy_prices",
      "created_from", "total_portfolios_sell_prices",
      "current_year_sell_records", "likely_addresses",
      "year_before_last_buy_records",
      "year_before_last_buy_and_holds_sell_prices",
      "year_before_last_fix_and_flips_buy_prices", "score_version",
      "year_before_last_portfolios_sell_prices", "name_suffix",
      "total_wholesalers", "total_unknowns_sell_prices", ...],
     rows: [
       [nil, 0, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil, nil, 0, 0,
        Decimal.new("0.00"), Decimal.new("0.00"), nil, nil, nil, nil,
        "044-2021-027856", nil, Decimal.new("0.00"), Decimal.new("0.00"),
        "044-2021-027856", 0, Decimal.new("0.00"), 0, Decimal.new("0.00"), [],
        Decimal.new("0.00"), nil, 2024, 0, Decimal.new("0.00"), "records", nil,
        0, [], 0, Decimal.new("0.00"), Decimal.new("0.00"), "v1", nil, nil,
        ...],
       [nil, 0, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil, nil, 0, 0,
        Decimal.new("0.00"), Decimal.new("0.00"), nil, nil, nil, nil, "901 2.0",
        nil, Decimal.new("0.00"), Decimal.new("289000.00"), "901 2.0", 0,
        Decimal.new("0.00"), 0, Decimal.new("0.00"), [], Decimal.new("0.00"),
        nil, 2024, 0, Decimal.new("0.00"), "records", nil, 0, [], 0,
        Decimal.new("0.00"), Decimal.new("0.00"), "v1", nil, ...],
       [nil, 0, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil, nil, 0, 0,
        Decimal.new("0.00"), Decimal.new("0.00"), nil, nil, nil, nil,
        "2504010020200901", nil, Decimal.new("0.00"), Decimal.new("0.00"),
        "2504010020200901", 0, Decimal.new("0.00"), 0, Decimal.new("0.00"), [],
        Decimal.new("0.00"), nil, 2024, 0, Decimal.new("0.00"), "records", nil,
        0, [], 0, Decimal.new("0.00"), Decimal.new("0.00"), "v1", ...],
       [nil, 0, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil, nil, 0, 0,
        Decimal.new("0.00"), Decimal.new("0.00"), nil, nil, nil, nil,
        "2022-001397", nil, Decimal.new("0.00"), Decimal.new("0.00"),
        "2022-001397", 1, Decimal.new("0.00"), 0, Decimal.new("0.00"), [],
        Decimal.new("0.00"), nil, 2024, 0, Decimal.new("0.00"), "records", nil,
        0, [], 0, Decimal.new("0.00"), Decimal.new("0.00"), ...],
       ["DIVISION", 1, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil, nil,
        1, 0, Decimal.new("0.00"), Decimal.new("0.00"), "8344", nil, nil, nil,
        "2013 13", "8344 DIVISION AVE, BIRMINGHAM, AL 35206",
        Decimal.new("0.00"), Decimal.new("0.00"), "2013 13", 0,
        Decimal.new("0.00"), 1, Decimal.new("0.00"), [], Decimal.new("0.00"),
        "35206", 2024, 0, Decimal.new("0.00"), "records", nil, 0, [], 0,
        Decimal.new("0.00"), ...],
       ["33RD", 1, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil, nil, 1,
        0, Decimal.new("0.00"), Decimal.new("0.00"), "1526", nil, "N", nil,
        "245000 00", "1526 33RD ST N, BIRMINGHAM, AL 35234",
        Decimal.new("0.00"), Decimal.new("0.00"), "245000 00", 0,
        Decimal.new("0.00"), 1, Decimal.new("0.00"), [], Decimal.new("0.00"),
        "35234", 2024, 0, Decimal.new("0.00"), "records", nil, 0, [], 0, ...],
       ["barryknoll", 0, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil,
        nil, 0, 0, Decimal.new("0.00"), Decimal.new("0.00"), "11933", nil, nil,
        nil, "z & h properties llc",
        "11933 barryknoll ln, houston, tx usa 77024-4301", Decimal.new("0.00"),
        Decimal.new("727000.00"), "z & h properties llc", 0,
        Decimal.new("0.00"), 1, Decimal.new("0.00"), [], Decimal.new("0.00"),
        "77024", 2024, 0, Decimal.new("0.00"), "records", nil, 2, [], ...],
       ["urban center", 15, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil,
        nil, 6, 4, Decimal.new("0.00"), Decimal.new("19860000.00"), "1200", nil,
        nil, nil, "vulcan lands inc",
        "1200 urban center dr, vestavia, al usa 35242-2545",
        Decimal.new("0.00"), Decimal.new("0.00"), "vulcan lands inc", 0,
        Decimal.new("500000.00"), 24, Decimal.new("0.00"), [],
        Decimal.new("0.00"), "35242", 2024, 0, Decimal.new("35610000.00"),
        "records", nil, 2, ...],
       ["lloyds", 0, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil, nil, 0,
        0, Decimal.new("0.00"), Decimal.new("0.00"), "1189", nil, nil, nil,
        "vickie neumann hastad",
        "1189 lloyds rd, little elm, tx usa 75068-2625", Decimal.new("0.00"),
        Decimal.new("0.00"), "neumann hastad", 0, Decimal.new("0.00"), 0,
        Decimal.new("0.00"), [], Decimal.new("0.00"), "75068", 2024, 0,
        Decimal.new("0.00"), "records", nil, ...],
       ["winecup", 0, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil, nil,
        0, 0, Decimal.new("0.00"), Decimal.new("0.00"), "3015", "melvin", nil,
        nil, "wayne melvin detweiler",
        "3015 winecup ct, heartland, tx usa 75126-0895", Decimal.new("0.00"),
        Decimal.new("0.00"), "detweiler", 0, Decimal.new("0.00"), 0,
        Decimal.new("0.00"), [], Decimal.new("0.00"), "75126", 2024, 0,
        Decimal.new("0.00"), "records", ...],
       ["clarendon", 5, nil, Decimal.new("0.00"), Decimal.new("0.00"), nil, nil,
        0, 5, Decimal.new("0.00"), Decimal.new("2729000.00"), "5715", nil, nil,
        nil, "the suzanne k adams revocable trust",
        "5715 clarendon dr, naples, fl usa 34113-8385", Decimal.new("0.00"),
        Decimal.new("0.00"), "the suzanne k adams revocable trust", 0,
        Decimal.new("0.00"), 5, Decimal.new("0.00"), [], Decimal.new("0.00"),
        "34113", 2024, 0, Decimal.new("0.00"), ...]
     ],
     num_rows: 11,
     connection_id: 29770,
     messages: []
   }},
  params: ~c"\v",
  source: "entities",
  repo: Core.ReplicaRepo,
  query: "SELECT e0.\"address_street_name\", e0.\"total_buy_and_holds\", e0.\"last_year_unknowns_buy_prices\", e0.\"year_before_last_wholesalers_sell_prices\", e0.\"current_year_fix_and_flips_buy_prices\", e0.\"current_year_unknowns\", e0.\"address_street_direction\", e0.\"current_year_buy_and_holds\", e0.\"year_before_last_buy_and_holds\", e0.\"total_fix_and_flips_buy_prices\", e0.\"year_before_last_buy_transfer_amount\", e0.\"address_house_number\", e0.\"middle_name\", e0.\"address_street_post_direction\", e0.\"current_year_portfolios_buy_prices\", e0.\"full_name\", e0.\"address\", e0.\"last_year_fix_and_flips_sell_prices\", e0.\"last_year_sell_transfer_amount\", e0.\"last_name\", e0.\"year_before_last_sell_records\", e0.\"total_wholesalers_buy_prices\", e0.\"total_sell_records\", e0.\"year_before_last_sell_transfer_amount\", e0.\"likely_names\", e0.\"total_wholesalers_sell_prices\", e0.\"address_zip\", e0.\"current_year\", e0.\"current_year_fix_and_flips\", e0.\"last_year_buy_and_holds_buy_prices\", e0.\"created_from\", e0.\"total_portfolios_sell_prices\", e0.\"current_year_sell_records\", e0.\"likely_addresses\", e0.\"year_before_last_buy_records\", e0.\"year_before_last_buy_and_holds_sell_prices\", e0.\"year_before_last_fix_and_flips_buy_prices\", e0.\"score_version\", e0.\"year_before_last_portfolios_sell_prices\", e0.\"name_suffix\", e0.\"total_wholesalers\", e0.\"total_unknowns_sell_prices\", e0.\"total_fix_and_flips\", e0.\"current_year_wholesalers_buy_prices\", e0.\"last_year_buy_and_holds\", e0.\"first_name\", e0.\"last_year_wholesalers_sell_prices\", e0.\"total_portfolios\", e0.\"current_year_sell_transfer_amount\", e0.\"total_records\", e0.\"current_year_unknowns_buy_prices\", e0.\"year_before_last_fix_and_flips_sell_prices\", e0.\"year_before_last_portfolios\", e0.\"address_normalized\", e0.\"year_before_last\", e0.\"last_year_fix_and_flips\", e0.\"total_buy_and_holds_sell_prices\", e0.\"updated_at\", e0.\"total_fix_and_flips_sell_prices\", e0.\"last_year_buy_transfer_amount\", e0.\"year_before_last_wholesalers_buy_prices\", e0.\"current_year_buy_and_holds_buy_prices\", e0.\"last_year_portfolios_sell_prices\", e0.\"last_year_portfolios_buy_prices\", e0.\"last_year_buy_records\", e0.\"total_buy_and_holds_buy_prices\", e0.\"year_before_last_portfolios_buy_prices\", e0.\"total_portfolios_buy_prices\", e0.\"current_year_buy_and_holds_sell_prices\", e0.\"current_year_buy_transfer_amount\", e0.\"address_state\", e0.\"status\", e0.\"year_before_last_unknowns_buy_prices\", e0.\"address_country\", e0.\"address_unit_prefix\", e0.\"last_year_fix_and_flips_buy_prices\", e0.\"last_year_sell_records\", e0.\"current_year_fix_and_flips_sell_prices\", e0.\"address_legacy\", e0.\"address_zip_4\", e0.\"address_unit_value\", e0.\"total_unknowns\", e0.\"address_street_suffix\", e0.\"inserted_at\", e0.\"score\", e0.\"year_before_last_unknowns_sell_prices\", e0.\"last_year\", e0.\"current_year_wholesalers\", e0.\"id\", e0.\"current_year_portfolios\", e0.\"primary_strategy\", e0.\"total_unknowns_buy_prices\", e0.\"year_before_last_wholesalers\", e0.\"last_year_unknowns\", e0.\"last_year_portfolios\", e0.\"last_year_unknowns_sell_prices\", e0.\"last_year_wholesalers_buy_prices\", e0.\"address_full_street_normalized\", e0.\"total_buy_records\", e0.\"year_before_last_buy_and_holds_buy_prices\", e0.\"address_full_street\", e0.\"current_year_wholesalers_sell_prices\", e0.\"type\", e0.\"year_before_last_unknowns\", e0.\"current_year_portfolios_sell_prices\", e0.\"current_year_unknowns_sell_prices\", e0.\"year_before_last_fix_and_flips\", e0.\"last_year_wholesalers\", e0.\"last_year_buy_and_holds_sell_prices\", e0.\"address_city\", e0.\"current_year_buy_records\" FROM \"pacman.public\".\"entities\" AS e0 ORDER BY e0.\"id\" LIMIT $1",
  cast_params: ~c"\v"
}

The important part is this one:

  source: "entities",
  repo: Core.ReplicaRepo,

Which shows that the source is "entities’ and that it ran in the Core.ReplicaRepo.

Now, if I add some filter to that query:

Core.Pacman.Markets.Entity
|> Ash.Query.for_read(:summary, %{builder: builder})
|> Ash.Query.set_context(%{data_layer: %{repo: Core.ReplicaRepo}})
|> Ash.Query.filter(expr(transactions.financing_type in [:buy_and_hold]))
|> Ash.Query.limit(10)
|> Ash.read!()

Now the telemetry will return the following metadata:

metadata #=> %{
  type: :ecto_sql_query,
  options: [],
  stacktrace: nil,
  result: {:ok,
   %Postgrex.Result{
     command: :select,
     columns: ["address_street_name", "total_buy_and_holds",
      "last_year_unknowns_buy_prices",
      "year_before_last_wholesalers_sell_prices",
      "current_year_fix_and_flips_buy_prices", "current_year_unknowns",
      "address_street_direction", "current_year_buy_and_holds",
      "year_before_last_buy_and_holds", "total_fix_and_flips_buy_prices",
      "year_before_last_buy_transfer_amount", "address_house_number",
      "middle_name", "address_street_post_direction",
      "current_year_portfolios_buy_prices", "full_name", "address",
      "last_year_fix_and_flips_sell_prices", "last_year_sell_transfer_amount",
      "last_name", "year_before_last_sell_records",
      "total_wholesalers_buy_prices", "total_sell_records",
      "year_before_last_sell_transfer_amount", "likely_names",
      "total_wholesalers_sell_prices", "address_zip", "current_year",
      "current_year_fix_and_flips", "last_year_buy_and_holds_buy_prices",
      "created_from", "total_portfolios_sell_prices",
      "current_year_sell_records", "likely_addresses",
      "year_before_last_buy_records",
      "year_before_last_buy_and_holds_sell_prices",
      "year_before_last_fix_and_flips_buy_prices", "score_version",
      "year_before_last_portfolios_sell_prices", "name_suffix",
      "total_wholesalers", "total_unknowns_sell_prices", ...],
     rows: [],
     num_rows: 0,
     connection_id: 29755,
     messages: []
   }},
  params: [["buy_and_hold"], 11],
  source: nil,
  repo: Core.Repo,
  query: "SELECT s0.\"address_street_name\", s0.\"total_buy_and_holds\", s0.\"last_year_unknowns_buy_prices\", s0.\"year_before_last_wholesalers_sell_prices\", s0.\"current_year_fix_and_flips_buy_prices\", s0.\"current_year_unknowns\", s0.\"address_street_direction\", s0.\"current_year_buy_and_holds\", s0.\"year_before_last_buy_and_holds\", s0.\"total_fix_and_flips_buy_prices\", s0.\"year_before_last_buy_transfer_amount\", s0.\"address_house_number\", s0.\"middle_name\", s0.\"address_street_post_direction\", s0.\"current_year_portfolios_buy_prices\", s0.\"full_name\", s0.\"address\", s0.\"last_year_fix_and_flips_sell_prices\", s0.\"last_year_sell_transfer_amount\", s0.\"last_name\", s0.\"year_before_last_sell_records\", s0.\"total_wholesalers_buy_prices\", s0.\"total_sell_records\", s0.\"year_before_last_sell_transfer_amount\", s0.\"likely_names\", s0.\"total_wholesalers_sell_prices\", s0.\"address_zip\", s0.\"current_year\", s0.\"current_year_fix_and_flips\", s0.\"last_year_buy_and_holds_buy_prices\", s0.\"created_from\", s0.\"total_portfolios_sell_prices\", s0.\"current_year_sell_records\", s0.\"likely_addresses\", s0.\"year_before_last_buy_records\", s0.\"year_before_last_buy_and_holds_sell_prices\", s0.\"year_before_last_fix_and_flips_buy_prices\", s0.\"score_version\", s0.\"year_before_last_portfolios_sell_prices\", s0.\"name_suffix\", s0.\"total_wholesalers\", s0.\"total_unknowns_sell_prices\", s0.\"total_fix_and_flips\", s0.\"current_year_wholesalers_buy_prices\", s0.\"last_year_buy_and_holds\", s0.\"first_name\", s0.\"last_year_wholesalers_sell_prices\", s0.\"total_portfolios\", s0.\"current_year_sell_transfer_amount\", s0.\"total_records\", s0.\"current_year_unknowns_buy_prices\", s0.\"year_before_last_fix_and_flips_sell_prices\", s0.\"year_before_last_portfolios\", s0.\"address_normalized\", s0.\"year_before_last\", s0.\"last_year_fix_and_flips\", s0.\"total_buy_and_holds_sell_prices\", s0.\"updated_at\", s0.\"total_fix_and_flips_sell_prices\", s0.\"last_year_buy_transfer_amount\", s0.\"year_before_last_wholesalers_buy_prices\", s0.\"current_year_buy_and_holds_buy_prices\", s0.\"last_year_portfolios_sell_prices\", s0.\"last_year_portfolios_buy_prices\", s0.\"last_year_buy_records\", s0.\"total_buy_and_holds_buy_prices\", s0.\"year_before_last_portfolios_buy_prices\", s0.\"total_portfolios_buy_prices\", s0.\"current_year_buy_and_holds_sell_prices\", s0.\"current_year_buy_transfer_amount\", s0.\"address_state\", s0.\"status\", s0.\"year_before_last_unknowns_buy_prices\", s0.\"address_country\", s0.\"address_unit_prefix\", s0.\"last_year_fix_and_flips_buy_prices\", s0.\"last_year_sell_records\", s0.\"current_year_fix_and_flips_sell_prices\", s0.\"address_legacy\", s0.\"address_zip_4\", s0.\"address_unit_value\", s0.\"total_unknowns\", s0.\"address_street_suffix\", s0.\"inserted_at\", s0.\"score\", s0.\"year_before_last_unknowns_sell_prices\", s0.\"last_year\", s0.\"current_year_wholesalers\", s0.\"id\", s0.\"current_year_portfolios\", s0.\"primary_strategy\", s0.\"total_unknowns_buy_prices\", s0.\"year_before_last_wholesalers\", s0.\"last_year_unknowns\", s0.\"last_year_portfolios\", s0.\"last_year_unknowns_sell_prices\", s0.\"last_year_wholesalers_buy_prices\", s0.\"address_full_street_normalized\", s0.\"total_buy_records\", s0.\"year_before_last_buy_and_holds_buy_prices\", s0.\"address_full_street\", s0.\"current_year_wholesalers_sell_prices\", s0.\"type\", s0.\"year_before_last_unknowns\", s0.\"current_year_portfolios_sell_prices\", s0.\"current_year_unknowns_sell_prices\", s0.\"year_before_last_fix_and_flips\", s0.\"last_year_wholesalers\", s0.\"last_year_buy_and_holds_sell_prices\", s0.\"address_city\", s0.\"current_year_buy_records\", s0.\"__order__\" FROM (SELECT DISTINCT ON (se0.\"id\") se0.\"address_street_name\" AS \"address_street_name\", se0.\"total_buy_and_holds\" AS \"total_buy_and_holds\", se0.\"last_year_unknowns_buy_prices\" AS \"last_year_unknowns_buy_prices\", se0.\"year_before_last_wholesalers_sell_prices\" AS \"year_before_last_wholesalers_sell_prices\", se0.\"current_year_fix_and_flips_buy_prices\" AS \"current_year_fix_and_flips_buy_prices\", se0.\"current_year_unknowns\" AS \"current_year_unknowns\", se0.\"address_street_direction\" AS \"address_street_direction\", se0.\"current_year_buy_and_holds\" AS \"current_year_buy_and_holds\", se0.\"year_before_la" <> ...,
  cast_params: [["buy_and_hold"], 11]
}

Again, with the important being:

  source: nil,
  repo: Core.Repo,

It loses the information about the source and the repo is revert back to the one configured in the resource.

I’m not 100% sure if this means that the query actually ran on Core.Repo or not, but assuming that the metadata is correct, adding a filter basically makes Ash ignore the custom data I have in my context.

Edit: Now I’m sure that is not running in my replica db when adding the filter, I tried with an invalid module as the repo and it will correctly give me an error with the query without the filter but it will run fine with the query with the filter.

Since I’m pretty sure this is a bug, I created a issue in the Ash repo: Using Ash.Query.filter makes query ignore custom repo in context · Issue #1587 · ash-project/ash · GitHub

Btw, testing a little more, I noticed that the bug only triggers if the action has a keyset pagination turned on (I didn’t test with offset)

@zachdaniel any news on this? I pushed a PR with a possible fix for ash_sql Send context to default_bindings call in ash_sql query.ex by sezaru · Pull Request #76 · ash-project/ash_sql · GitHub some days ago.

Zach is currently on a much needed vacation, taking a break from all online activities (even left his latpop at home). He should be back in about a week. :slight_smile:

Ah, that explains it haha :smile: Thanks for the information!