-
Notifications
You must be signed in to change notification settings - Fork 108
Description
Issue Description
The current implementation of the InputValueSerializer in the DGS Codegen library does not support custom serialization for Date fields. This limitation makes it challenging to handle Date objects properly when constructing GraphQL queries, especially when dates need to be serialized to ISO 8601 format.
Steps to Reproduce
- Create a GraphQL query request that includes
Datefields in the input. - Attempt to serialize the query using
GraphQLQueryRequest.serialize(). - Observe that
Datefields are not converted to ISO 8601 format.
Expected Behavior
The InputValueSerializer should provide a way to handle custom serialization for Date fields, allowing dates to be converted to ISO 8601 strings during the serialization process.
Current Workaround
Currently, users need to preprocess the input map manually before creating the GraphQLQueryRequest. This involves traversing the input map and converting Date objects to ISO 8601 strings using a utility method. While effective, this approach adds additional complexity and is not ideal.
Example of the Current Workaround
import com.fasterxml.jackson.databind.util.StdDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class GraphQLUtil {
private static final StdDateFormat dateFormat = new StdDateFormat();
public static Map<String, Object> preprocessInput(Map<String, Object> input) {
Map<String, Object> processedInput = new HashMap<>();
for (Map.Entry<String, Object> entry : input.entrySet()) {
Object value = entry.getValue();
if (value instanceof Date) {
processedInput.put(entry.getKey(), dateFormat.format((Date) value));
} else {
processedInput.put(entry.getKey(), value);
}
}
return processedInput;
}
}import java.util.HashMap;
import java.util.Map;
public final class GraphQLQueryRequest {
@NotNull
private final GraphQLQuery query;
@Nullable
private final BaseProjectionNode projection;
@NotNull
private final InputValueSerializer inputValueSerializer;
@NotNull
private final ProjectionSerializer projectionSerializer;
public GraphQLQueryRequest(@NotNull GraphQLQuery query, @Nullable BaseProjectionNode projection, @Nullable Map<Class<?>, ? extends Coercing<?, ?>> scalars) {
Intrinsics.checkNotNullParameter(query, "query");
super();
this.query = query;
this.projection = projection;
this.inputValueSerializer = new InputValueSerializer(scalars != null ? scalars : MapsKt.emptyMap());
this.projectionSerializer = new ProjectionSerializer(this.inputValueSerializer);
}
// Additional constructor to handle only query and projection
public GraphQLQueryRequest(@NotNull GraphQLQuery query, @Nullable BaseProjectionNode projection) {
this(query, projection, null);
}
@NotNull
public final GraphQLQuery getQuery() {
return this.query;
}
@Nullable
public final BaseProjectionNode getProjection() {
return this.projection;
}
@NotNull
public final InputValueSerializer getInputValueSerializer() {
return this.inputValueSerializer;
}
@NotNull
public final ProjectionSerializer getProjectionSerializer() {
return this.projectionSerializer;
}
@NotNull
public final String serialize() {
OperationDefinition.Builder operationDef = OperationDefinition.newOperationDefinition();
String queryName = this.query.getName();
if (queryName != null) {
operationDef.name(queryName);
}
String operationType = this.query.getOperationType();
if (operationType != null) {
operationDef.operation(Operation.valueOf(operationType.toUpperCase(Locale.ROOT)));
}
if (!this.query.getVariableDefinitions().isEmpty()) {
operationDef.variableDefinitions(this.query.getVariableDefinitions());
}
Field.Builder selection = Field.newField(this.query.getOperationName());
if (!this.query.getInput().isEmpty()) {
Map<String, Object> inputMap = this.query.getInput();
Map<String, Object> processedInputMap = GraphQLUtil.preprocessInput(inputMap);
List<Argument> arguments = new ArrayList<>();
for (Map.Entry<String, Object> entry : processedInputMap.entrySet()) {
arguments.add(new Argument(entry.getKey(), this.inputValueSerializer.toValue(entry.getValue())));
}
selection.arguments(arguments);
}
if (this.projection != null) {
SelectionSet selectionSet = this.projection instanceof BaseSubProjectionNode
? this.projectionSerializer.toSelectionSet(((BaseSubProjectionNode) this.projection).root())
: this.projectionSerializer.toSelectionSet(this.projection);
if (!selectionSet.getSelections().isEmpty()) {
selection.selectionSet(selectionSet);
}
}
operationDef.selectionSet(SelectionSet.newSelectionSet().selection(selection.build()).build());
return AstPrinter.printAst(operationDef.build());
}
}Proposed Solution
Enhance the InputValueSerializer to support custom serializers for specific types, including Date. This could be achieved by allowing users to register custom serializers for different classes, which would then be used during the serialization process.
Additional Context
Adding support for custom serializers will improve the flexibility and usability of the DGS Codegen library, making it easier to work with various data types, including Date, in a more seamless and intuitive manner.