diff --git a/LTS-CHANGELOG.adoc b/LTS-CHANGELOG.adoc index 4df4b4c181..56a103ba6d 100644 --- a/LTS-CHANGELOG.adoc +++ b/LTS-CHANGELOG.adoc @@ -17,12 +17,17 @@ include::content/docs/variables.adoc-include[] The LTS changelog lists releases which are only accessible via a commercial subscription. All fixes and changes in LTS releases will be released the next minor release. Changes from LTS 1.4.x will be included in release 1.5.0. +[[v1.10.25]] +== 1.10.25 (17.01.2024) + +icon:check[] GraphQL: Fetching of micronode fields has been improved to allow batch loading. + [[v1.10.24]] == 1.10.24 (10.01.2024) icon:check[] REST: The documentation of the generic parameter `fields` has been fixed. Now `fields` works over the Language entities as well, the values are `uuid`,`name`,`languageTag`,`nativeName`. -icon:check[] GraphQL. Some of (micro)schema fields related queries rely on the target (micro)schema having at least one field, crashing in HTTP 500 otherwise. This has now been fixed. +icon:check[] GraphQL: Some of (micro)schema fields related queries rely on the target (micro)schema having at least one field, crashing in HTTP 500 otherwise. This has now been fixed. [[v1.10.23]] == 1.10.23 (20.12.2023) diff --git a/changelog/src/changelog/entries/2024/01/7663.SUP-16244.bugfix b/changelog/src/changelog/entries/2024/01/7663.SUP-16244.bugfix new file mode 100644 index 0000000000..09717ff4f7 --- /dev/null +++ b/changelog/src/changelog/entries/2024/01/7663.SUP-16244.bugfix @@ -0,0 +1 @@ +GraphQL: Fetching of micronode fields has been improved to allow batch loading. \ No newline at end of file diff --git a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/ContentDao.java b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/ContentDao.java index b60194cff7..afef826a1d 100644 --- a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/ContentDao.java +++ b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/ContentDao.java @@ -26,6 +26,7 @@ import com.gentics.mesh.core.data.HibNodeFieldContainerEdge; import com.gentics.mesh.core.data.branch.HibBranch; import com.gentics.mesh.core.data.diff.FieldContainerChange; +import com.gentics.mesh.core.data.node.HibMicronode; import com.gentics.mesh.core.data.node.HibNode; import com.gentics.mesh.core.data.node.field.list.HibMicronodeFieldList; import com.gentics.mesh.core.data.node.field.nesting.HibMicronodeField; @@ -1143,4 +1144,18 @@ default Result getFieldEdges(HibNode fieldN * @return map of list UUIDs to lists of string field values */ Map> getStringListFieldValues(List listUuids); + + /** + * Get the Micronode list field values for the given list UUIDs + * @param listUuids list UUIDs + * @return map of list UUIDs to lists of micronode field values + */ + Map> getMicronodeListFieldValues(List listUuids); + + /** + * Load the micronodes for the given collection of micronode fields + * @param micronodeFields micronode fields + * @return map of field to micronode + */ + Map getMicronodes(Collection micronodeFields); } diff --git a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/DaoTransformable.java b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/DaoTransformable.java index ecdb18ccee..20c164a73c 100644 --- a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/DaoTransformable.java +++ b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/DaoTransformable.java @@ -17,6 +17,12 @@ * Rest model type */ public interface DaoTransformable { + /** + * Invoked before transforming the elements in the page to their REST models + * @param page page of elements + * @param ac action context + */ + default void beforeTransformToRestSync(Page> page, InternalActionContext ac) {} /** * Transform the element into the matching rest model response asynchronously. diff --git a/mdm/common/src/main/java/com/gentics/mesh/core/data/page/PageTransformer.java b/mdm/common/src/main/java/com/gentics/mesh/core/data/page/PageTransformer.java index 5cf5edf74a..0aa3a92d41 100644 --- a/mdm/common/src/main/java/com/gentics/mesh/core/data/page/PageTransformer.java +++ b/mdm/common/src/main/java/com/gentics/mesh/core/data/page/PageTransformer.java @@ -37,6 +37,13 @@ public PageTransformer(Map transformToRestSync(Page> page, InternalActionContext ac, int level) { + if (page.getSize() > 0) { + HibCoreElement element = page.getWrappedList().get(0); + ElementType type = element.getTypeInfo().getType(); + DaoTransformable, RestModel> dao = daos.get(type); + dao.beforeTransformToRestSync(page, ac); + } + List responses = transformToRestSync(page.stream(), ac, level).collect(Collectors.toList()); ListResponse listResponse = new ListResponse<>(); page.setPaging(listResponse); diff --git a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/ContentDaoWrapperImpl.java b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/ContentDaoWrapperImpl.java index 8948c06a72..991b9848cd 100644 --- a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/ContentDaoWrapperImpl.java +++ b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/ContentDaoWrapperImpl.java @@ -3,17 +3,18 @@ import static com.gentics.mesh.core.data.relationship.GraphRelationships.HAS_FIELD_CONTAINER; import static com.gentics.mesh.core.data.util.HibClassConverter.toGraph; +import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.inject.Inject; - import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang3.StringUtils; @@ -391,4 +392,14 @@ public Map> getHtmlListFieldValues(List listUuids) public Map> getStringListFieldValues(List listUuids) { throw new NotImplementedException("Prefetching of list values is not implemented"); } + + @Override + public Map> getMicronodeListFieldValues(List listUuids) { + throw new NotImplementedException("Prefetching of list values is not implemented"); + } + + @Override + public Map getMicronodes(Collection micronodeFields) { + return micronodeFields.stream().distinct().collect(Collectors.toMap(Function.identity(), HibMicronodeField::getMicronode)); + } } diff --git a/verticles/graphql/src/main/java/com/gentics/mesh/graphql/GraphQLHandler.java b/verticles/graphql/src/main/java/com/gentics/mesh/graphql/GraphQLHandler.java index 1fa36d2bf4..9cb342f8bb 100644 --- a/verticles/graphql/src/main/java/com/gentics/mesh/graphql/GraphQLHandler.java +++ b/verticles/graphql/src/main/java/com/gentics/mesh/graphql/GraphQLHandler.java @@ -114,6 +114,8 @@ public void handleQuery(GraphQLContext gc, String body) { dataLoaderRegistry.register(FieldDefinitionProvider.NUMBER_LIST_VALUES_DATA_LOADER_KEY, DataLoader.newDataLoader(typeProvider.getFieldDefProvider().NUMBER_LIST_VALUE_LOADER, dlOptions)); dataLoaderRegistry.register(FieldDefinitionProvider.HTML_LIST_VALUES_DATA_LOADER_KEY, DataLoader.newDataLoader(typeProvider.getFieldDefProvider().HTML_LIST_VALUE_LOADER, dlOptions)); dataLoaderRegistry.register(FieldDefinitionProvider.STRING_LIST_VALUES_DATA_LOADER_KEY, DataLoader.newDataLoader(typeProvider.getFieldDefProvider().STRING_LIST_VALUE_LOADER, dlOptions)); + dataLoaderRegistry.register(FieldDefinitionProvider.MICRONODE_LIST_VALUES_DATA_LOADER_KEY, DataLoader.newDataLoader(typeProvider.getFieldDefProvider().MICRONODE_LIST_VALUE_LOADER, dlOptions)); + dataLoaderRegistry.register(FieldDefinitionProvider.MICRONODE_DATA_LOADER_KEY, DataLoader.newDataLoader(typeProvider.getFieldDefProvider().MICRONODE_LOADER, dlOptions)); ExecutionInput executionInput = ExecutionInput .newExecutionInput() diff --git a/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/field/FieldDefinitionProvider.java b/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/field/FieldDefinitionProvider.java index 6441b05d5c..35a612276e 100644 --- a/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/field/FieldDefinitionProvider.java +++ b/verticles/graphql/src/main/java/com/gentics/mesh/graphql/type/field/FieldDefinitionProvider.java @@ -124,6 +124,16 @@ public class FieldDefinitionProvider extends AbstractTypeProvider { */ public static final String STRING_LIST_VALUES_DATA_LOADER_KEY = "stringListLoader"; + /** + * Key for the data loader for micronode list field values + */ + public static final String MICRONODE_LIST_VALUES_DATA_LOADER_KEY = "micronodeUuidListLoader"; + + /** + * Key for the data loader for micronode field values + */ + public static final String MICRONODE_DATA_LOADER_KEY = "micronodeLoader"; + protected final MicronodeFieldTypeProvider micronodeFieldTypeProvider; protected final WebRootLinkReplacerImpl linkReplacer; @@ -211,6 +221,28 @@ private static CompletionStage>> listValueDataLoader(List> MICRONODE_LIST_VALUE_LOADER = (keys, environment) -> { + ContentDao contentDao = Tx.get().contentDao(); + return listValueDataLoader(keys, contentDao::getMicronodeListFieldValues, Functions.identity()); + }; + + /** + * DataLoader implementation for micronodes + */ + public BatchLoaderWithContext MICRONODE_LOADER = (keys, environment) -> { + ContentDao contentDao = Tx.get().contentDao(); + Map micronodes = contentDao.getMicronodes(keys); + + Promise> promise = Promise.promise(); + List result = keys.stream().map(field -> micronodes.get(field)).collect(Collectors.toList()); + promise.complete(result); + + return promise.future().toCompletionStage(); + }; + @Inject public FieldDefinitionProvider(MeshOptions options, MicronodeFieldTypeProvider micronodeFieldTypeProvider, WebRootLinkReplacerImpl linkReplacer) { super(options); @@ -666,7 +698,14 @@ public Optional createListDef(GraphQLContext context, Li if (micronodeList == null) { return null; } - return micronodeList.getList().stream().map(item -> item.getMicronode()).collect(Collectors.toList()); + + String micronodeListUuid = micronodeList.getUuid(); + if (contentDao.supportsPrefetchingListFieldValues() && !StringUtils.isEmpty(micronodeListUuid)) { + DataLoader> micronodeListValueLoader = env.getDataLoader(FieldDefinitionProvider.MICRONODE_LIST_VALUES_DATA_LOADER_KEY); + return micronodeListValueLoader.load(micronodeListUuid); + } else { + return micronodeList.getList().stream().map(item -> item.getMicronode()).collect(Collectors.toList()); + } default: return null; } @@ -713,7 +752,9 @@ public Optional createMicronodeDef(GraphQLContext contex HibFieldContainer container = env.getSource(); HibMicronodeField micronodeField = container.getMicronode(schema.getName()); if (micronodeField != null) { - return micronodeField.getMicronode(); + + DataLoader micronodeLoader = env.getDataLoader(MICRONODE_DATA_LOADER_KEY); + return micronodeLoader.load(micronodeField); } return null; }).build());