Reputation: 95
I'm using the new interface (ITypeModule) introduced on the latest version of the hotchocolate framework (v12) to dynamically create all types of my schema. (https://chillicream.com/blog/2021/09/27/hot-chocolate-12#dynamic-schemas)
It's working well. But now I'm struggling to find out how to add filtering on my types using this stategy (since I can't use anotations and neither the descriptor like its done on the documentation (https://chillicream.com/docs/hotchocolate/fetching-data/filtering)
What I've tried so far:
My dependency injection:
// code omitted
builder.Services
.AddGraphQLServer()
.AddTypeModule<DynamicTenantSchemaTypeModule>()
.AddFiltering();
On the ITypeModule implementation (DynamicTenantSchemaTypeModule):
//code omitted
public async ValueTask<IReadOnlyCollection<ITypeSystemMember>> CreateTypesAsync(IDescriptorContext context, CancellationToken cancellationToken)
{
var types = new List<ITypeSystemMember>();
var queryType = new ObjectTypeDefinition("Query");
var schemas = await _documentSchemaRepository.GetSchemasAsync();
foreach (var schema in schemas)
{
var schemaNamePascalCase = schema.Name!.ToPascalCase();
var schemaNamePluralCamelCase = schema.PluralName!.ToCamelCase();
var objectTypeDefinition = new ObjectTypeDefinition(schemaNamePascalCase);
await AddFieldsAsync(types, schema, objectTypeDefinition, schema.Properties);
queryType.Fields.Add(new ObjectFieldDefinition(schemaNamePluralCamelCase)
{
Type = TypeReference.Parse($"[{schemaNamePascalCase}]"),
Resolver = async (ctx) =>
{
var documents = await _documentRepository.GetDocumentsAsync(schema.Id);
return documents;
}
}
.ToDescriptor(context)
.UseFiltering()
.ToDefinition());
types.Add(ObjectType.CreateUnsafe(objectTypeDefinition));
}
types.Add(ObjectType.CreateUnsafe(queryType));
return types;
}
//code omitted
But it throws the following exception:
HotChocolate.SchemaException: For more details look at the `Errors` property.
1. No default filter convention found. Call `AddFiltering()` on the schema builder.
at HotChocolate.Data.FilterDescriptorContextExtensions.<>c__DisplayClass1_0.<GetFilterConvention>b__0()
at HotChocolate.Types.Descriptors.DescriptorContext.GetConventionOrDefault[T](Func`1 defaultConvention, String scope)
at HotChocolate.Data.FilterDescriptorContextExtensions.GetFilterConvention(IDescriptorContext context, String scope)
at HotChocolate.Types.FilterObjectFieldDescriptorExtensions.<>c__DisplayClass5_0.<UseFiltering>b__1(IDescriptorContext c, ObjectFieldDefinition definition)
at HotChocolate.Types.Descriptors.DescriptorBase`1.<>c__DisplayClass19_0.<OnBeforeCreate>b__0(IDescriptorContext c, IDefinition d)
at HotChocolate.Types.Descriptors.DescriptorBase`1.CreateDefinition()
at HotChocolate.Types.Descriptors.DescriptorExtensions.ToDefinition[T](IDescriptor`1 descriptor)
Any ideas on how to add the filtering middleware correctly? Thanks!
Upvotes: 2
Views: 2552
Reputation: 4489
So far I got the filtering work on some field which I don't know where it comes from
descriptor.UseFiltering<MyFilterConvention>(f =>
{
f.Name(schemaNamePascalCase + "OperationFilterInput");
});
MyFilterConvention
by deriving from HotChocolate.Data.Filters.FilterConvention
classprotected override void Configure(IFilterConventionDescriptor descriptor)
{
descriptor.AddDefaults();
descriptor.Provider(new QueryableFilterProvider(x =>
x.AddDefaultFieldHandlers()));
}
This is the result for object Foo
foos (
where: FooOperationFilterInput
): [Foo]
input FooOperationFilterInput {
and: [FooOperationFilterInput!]
or: [FooOperationFilterInput!]
scope: StringOperationFilterInput
}
input StringOperationFilterInput {
and: [StringOperationFilterInput!]
or: [StringOperationFilterInput!]
eq: String
neq: String
... the rest is omitted for brevity ...
}
Upvotes: 1