0

Is there a way to implement global filters using the MongoDb integration for HotChocolate when all my types allow soft delete? Soft delete means marking the record to be deleted by setting the “IsDeleted” field to true, and then completely removing those records after a few weeks.

e.g.

public interface ISoftDelete
{
    bool IsDeleted { get; set; }
}

public class ExampleModel : ISoftDelete
{
    public string Id { get; set; }
    public string Name { get; set; }

    [GraphQLIgnore]
    public bool IsDeleted { get; set; }
}

While all my types have the “IsDeleted” flag, it is ignored in the GraphQL schema. My question is, how can I set a global filter for all Find and Aggregation operations so that all queries made to MongoDB include the filter “IsDeleted = false”?

This way, customers will never see deleted records, and developers won’t need to manually add that filter to each query anymore.

Cuban coffee
  • 294
  • 5
  • 14

1 Answers1

1

Field middleware best fits for your purpose.

Definition:

public class SoftDeletedEntitiesFilter
{
    private readonly FieldDelegate _next;

    public SoftDeletedEntitiesFilter(FieldDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(IMiddlewareContext context)
    {
        await _next(context);

        if (context.Result is IQueryable<ISoftDelete> deletableEntities)
        {
            context.Result = deletableEntities.Where(e => !e.IsDeleted);
        }
    }
}

Usage:

builder.Services
    .AddGraphQLServer()
    .UseField<SoftDeletedEntitiesFilter>()
    .AddQueryType<Query>();

With this usage the filter middleware will be applied globally for every queried field, but the filter condition will only pass for fields that have resolvers like this:

public class Query
{
    public IQueryable<ExampleModel> GetModels([Service] DbContext dbContext)
        => dbContext.Models;
}
Eugene
  • 169
  • 1
  • 6
  • Hi @Eugene ,Do you know if it is possible to use MongoDB-entities (https://mongodb-entities.com) in hot chocolate? MongoDB-entities also provides global filters. – Cuban coffee Jun 14 '23 at 08:25
  • 1
    @Cubancoffee unfortunately I don't know – Eugene Jun 14 '23 at 09:15
  • Hi @Eugene, I could not manage to get it to work. The line "if(.. IQueryable ..)" is never true. Can you provide more details? – Cuban coffee Jun 14 '23 at 14:40
  • @Cubancoffee I updated my answer and added example of suitable resolver method – Eugene Jun 14 '23 at 16:58
  • Thanks @Eugene. I see you are using DbContext, then I guess this integration will only work with SQL, right? Can also this work with the MongoDB integration for hot chocolate? – Cuban coffee Jun 14 '23 at 17:42
  • @Cubancoffee I don't have working prototype with MongoDB, but a little research led me to this code: "public IQueryable GetModels([Service] IMongoCollection collection) => collection.AsQueryable()". Can you try this? – Eugene Jun 14 '23 at 18:11
  • Amazing @Eugene. It works. Thank you very much. – Cuban coffee Jun 14 '23 at 18:41
  • I see though that normal filters using the annotation UseFiltering are no longer working. – Cuban coffee Jun 14 '23 at 19:24
  • 1
    @Cubancoffee yes, I was aware of that. MongoDB Filtering only works with IExecutable. For saving filtering you should rewrite middleware to make it work with IExecutable instead of IQueryable. I believe it can be reached because your filter middleware is simplified version of “UseFiltering”. HotChocolate is open source so you can read “UseFiltering” implementation to get how to work with IExecutable in your middleware – Eugene Jun 15 '23 at 02:47