Possible to omit "base_filter" for specific queries/use cases?

Hello everyone!

I was wondering if a base_filter specified on a resource can be omitted/disabled for specific queries?
(Sorry if this question was asked before and I didn’t find the thread).

Our current use case:

  • We have resource that supports soft-deletes. We use the base_filter to implement that (base_filter_sql "deleted_at IS NULL")
  • We need to (bulk) update data of that resource, including soft-deleted ones (for a clean up job)

The filter now, of course, correctly returns the entities as specified by the base filter (i.e. excludes soft-deleted ones).

Is there a (preferred) way to disable the base filter for specific queries to update even soft-deleted data?

(Note: we’re still on Ash 2.0)

Many thanks in advance and best regards,
Lukas

There is no way to do it currently, but it can be added relatively easily. A base_filter? true/false option can be added to read actions, and then when building the data layer query we would check that option. (In Ash.Query.data_layer_query)

We would also need it for an update action in our specific case.

Hmm…like for bulk updates you mean? Or do you mean for an update action in ash_graphql? That uses a read action paired with an update, so you’d configure it with a read action w/ the base filter removed. Soon it will use bulk updates where possible but it will be transparent to users.

bulk_update in this case. We need to merge some entities and delete one of them. In the process, we need to change all the foreign keys to point to the persistent entity. Do update statements not respect the base filter e.g. add a where clause to the update statement in AshPostgres?

bulk updates are always a combination of a read action and an update action as well, so they will honor the base filter (until we add an option to not do it)

Makes sense, although I was wondering specifically about a regular old non-atomic update where you would first read the record and then update it. Would that be

select
 ...
from resource
where id = <id>
and <base_filter>

and

update resource set
...
where id = <id>
and <base_filter>

Or would only the read have the base-filter.

I’m asking because above you said

A base_filter? true/false option can be added to read actions

mentioning only read actions.

Currently, when calling bulk_update, it looks like only the read query applies the base_filter. The update statement then updates using the primary key.

At least, that’s what I’ve seen when logging the queries (I hope I looked at the correct places).

Our current escape hatch to perform the queries without base filters is to use Ecto “directly”.

E.g.

import Ecto.Query, only: [from: 2] 

MyAshProject.Repo.update_all(
  from(e in Entity, where: e.something == ^value),
  set: [something: "new value"]
)

Works as expected and would be an ok enough solution in this case because
a) it is the only place right now where we want to not apply the base filter
b) we are in a somewhat “system role” when we perform the query. Auth can be checked before even calling the action

However, it would still be nice to know what the preferred solution for these cases “should” look like.

E.g. thinking of a use case like “Give me a list of soft-deleted entities (aka archived). Then, restore one of the entities”.

Right now, it would be tricky. Another solution could be to add an additional ArchivedResource (next to the original Resource) with perhaps only a subset of attributes of the original Resource (depending on the use case).

Yeah, so when updating we don’t apply a base filter because we assume you got one without applying it, but I think this may actually be a bug. I think we might need to apply the base filter on update/destroy changesets as well, making the base_filter? true/false actually relevant for read, update and destroy actions.