I am trying to understand what is the best approach to utilize query
with filters in GraphQL
for my scenario.
So far what I have learned is, GraphQL
does not have filter
concept. UI/Consumer can fetch records per their need. I have GroupDataLoader which takes Location
and give me all records for that. This satisfies my 1st query.
Now on top of that, if I want to add other search criteria than I can make Type, Number, and Supplier as the optional parameters for my query, but I can only pass one parameter to .LoadAsync
(or at least that's my understanding).
Question:
- Is it possible to use
GroupDataLoader
AND multiple search filter(s)? - If no, then what is the best practice? Fetch all records and let UI/consumer pull other fields?
Scenario:
Expectation:
Queries:
- Give me records for location ATL => Should return 3 records
- Give me records for location ATL and Type Car => Should return 2 records
- Give me records for location ATL and Type Car and Supplier Hertz => Should return 1 record
Code:
query.cs
[Authorize(policy: "ProjectAccess")]
public async Task<IEnumerable<Exception>> GetExceptionsAsync(
string location,
[Service(ServiceKind.Synchronized)] IExceptionService exceptionService,
long stockNumber = 0
)
{
return await exceptionService.GetExceptionsByStockNumberV2(location);
}
Service.cs
namespace Services
{
public interface IExceptionService
{
Task<IEnumerable<Database.Entities.Sql.Exception>> GetExceptionsByStockNumberV2(
string location, long stockNumber = 0);
}
public class ExceptionService: ServiceBase, IExceptionService
{
private readonly IProjectXSupplyChainDbManagement _projectXSupplyChainDbManagement;
private readonly ExceptionGroupDataLoader _exceptionDataLoader;
public ExceptionService(ILogger<ExceptionService> logger, IProjectXSupplyChainDbManagement projectXSupplyChainDbManagement, IMapper mapper,
ExceptionGroupDataLoader exceptionDataLoader)
{
_projectXSupplyChainDbManagement = projectXSupplyChainDbManagement;
_exceptionDataLoader = exceptionDataLoader;
}
#region DATA LOADER
public async Task<IEnumerable<Database.Entities.Sql.Exception>> GetExceptionsByStockNumberV2(
string location,
long stockNumber = 0 // Not sure how such filters can be passed to dataLoader
)
{
var result = await _exceptionDataLoader.LoadAsync(location);
return result;
}
#endregion DATA LOADER
}
}
GroupDataLoader.cs
namespace DataLoader;
public class ExceptionGroupDataLoader : GroupedDataLoader<string, Exception>
{
private readonly IProjectXSupplyChainDbManagement _projectXSupplyChainDbManagement;
public ExceptionGroupDataLoader(
IBatchScheduler batchScheduler,
IProjectXSupplyChainDbManagement projectXSupplyChainDbManagement,
DataLoaderOptions options = null) : base(batchScheduler, options)
{
_projectXSupplyChainDbManagement = projectXSupplyChainDbManagement;
}
protected override async Task<ILookup<string, Exception>> LoadGroupedBatchAsync(IReadOnlyList<string> keys, CancellationToken cancellationToken)
{
var result = await _projectXSupplyChainDbManagement
.ExceptionRepository.GetExceptionByStockNumbers(keys, cancellationToken)
.ToLookupAsync(x => x.Location, cancellationToken);
return result;
}
}
Repo.cs
namespace Repositories
{
public interface IExceptionRepository
{
public IAsyncEnumerable<Entities.Sql.Exception> GetExceptionByStockNumbers(
IReadOnlyList<string> locations,
CancellationToken cancellationToken);
}
public class ExceptionRepository: IExceptionRepository
{
private readonly ProjectXSqlDbContext _projectXSqlDbContext;
public ExceptionRepository(ProjectXSqlDbContext projectXSqlDbContext)
{
_projectXSqlDbContext = projectXSqlDbContext;
}
public IAsyncEnumerable<Entities.Sql.Exception> GetExceptionByStockNumbers(
IReadOnlyList<string> locations,
CancellationToken cancellationToken)
{
var exceptions = _projectXSqlDbContext.Exceptions
.Where(_ => locations.Contains(_.Location))
.AsAsyncEnumerable()
// .ToDictionaryAsync(_ => _.Location, cancellationToken)
;
return exceptions;
}
}
}