Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQL projects output field #1547

Open
wants to merge 3 commits into
base: hotfix-1.10.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions LTS-CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ 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.18]]
== 1.10.18 (TBD)

icon:check[] GraphQL: New filterable field 'projects' has been added to the output of the result of `schemas` and `microschemas` requests, depicting the projects that the (micro)schema is attached to.

[[v1.10.17]]
== 1.10.17 (TBD)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public Result<? extends HibNodeFieldContainer> findDraftFieldContainers(HibSchem

@Override
public Result<HibProject> findLinkedProjects(HibSchema schema) {
return new TraversalResult<>(getRoots(schema).stream().map(root -> root.getProject()));
return new TraversalResult<>(getRoots(schema).stream().map(root -> root.getProject()).filter(Objects::nonNull));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the test AW MP database there was a case when a ODB edge existed, but lead to nothing.

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public static Collection<Object[]> paramData() {
Arrays.asList("role-user-group-query", true, false, "draft"),
Arrays.asList("group-query", true, false, "draft"),
Arrays.asList("schema-query", true, false, "draft"),
// Arrays.asList("schema-projects-query", true, false, "draft"),
Arrays.asList("schema-projects-query", true, false, "draft"),
Arrays.asList("microschema-query", true, false, "draft"),
Arrays.asList("paging-query", true, false, "draft"),
Arrays.asList("tagFamily-query", true, false, "draft"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,93 @@
{
microschema(name:"vcard") {
vcard: microschema(name:"vcard") {
projects {
# [$.data.microschema.projects.elements.size()=1]
# [$.data.vcard.projects.elements.size()=1]
elements {
# [$.data.microschema.projects.elements[0].name=dummy]
# [$.data.vcard.projects.elements[0].name=dummy]
name
# [$.data.microschema.projects.elements[0].uuid=<is-uuid>]
# [$.data.vcard.projects.elements[0].uuid=<is-uuid>]
uuid
# [$.data.microschema.projects.elements[0].etag=<is-not-null>]
# [$.data.vcard.projects.elements[0].etag=<is-not-null>]
etag
# [$.data.microschema.projects.elements[0].created=<is-not-null>]
# [$.data.vcard.projects.elements[0].created=<is-not-null>]
created
# [$.data.microschema.projects.elements[0].edited=<is-not-null>]
# [$.data.vcard.projects.elements[0].edited=<is-not-null>]
edited
}
}
}
all: microschemas {
elements {
projects {
# [$.data.all.elements[0].projects.elements.size()=1]
elements {
# [$.data.all.elements[0].projects.elements[0].name=dummy]
name
# [$.data.all.elements[0].projects.elements[0].uuid=<is-uuid>]
uuid
# [$.data.all.elements[0].projects.elements[0].etag=<is-not-null>]
etag
# [$.data.all.elements[0].projects.elements[0].created=<is-not-null>]
created
# [$.data.all.elements[0].projects.elements[0].edited=<is-not-null>]
edited
}
}
}
}
vcard_bogus: microschema(name:"vcard") {
projects(filter: {name: {equals: "bogus"}}) {
# [$.data.vcard_bogus.projects.elements.size()=0]
elements {
uuid
}
}
}
all_bogus: microschemas {
elements {
projects(filter: {name: {equals: "bogus"}}) {
# [$.data.all_bogus.elements[0].projects.elements.size()=0]
elements {
uuid
}
}
}
}
vcard_dummy: microschema(name:"vcard") {
projects(filter: {name: {equals: "dummy"}}) {
# [$.data.vcard_dummy.projects.elements.size()=1]
elements {
# [$.data.vcard_dummy.projects.elements[0].name=dummy]
name
# [$.data.vcard_dummy.projects.elements[0].uuid=<is-uuid>]
uuid
# [$.data.vcard_dummy.projects.elements[0].etag=<is-not-null>]
etag
# [$.data.vcard_dummy.projects.elements[0].created=<is-not-null>]
created
# [$.data.vcard_dummy.projects.elements[0].edited=<is-not-null>]
edited
}
}
}
all_dummy: microschemas {
elements {
projects(filter: {name: {equals: "dummy"}}) {
# [$.data.all_dummy.elements[0].projects.elements.size()=1]
elements {
# [$.data.all_dummy.elements[0].projects.elements[0].name=dummy]
name
# [$.data.all_dummy.elements[0].projects.elements[0].uuid=<is-uuid>]
uuid
# [$.data.all_dummy.elements[0].projects.elements[0].etag=<is-not-null>]
etag
# [$.data.all_dummy.elements[0].projects.elements[0].created=<is-not-null>]
created
# [$.data.all_dummy.elements[0].projects.elements[0].edited=<is-not-null>]
edited
}
}
}
}
}
# [$.errors=<is-undefined>]
87 changes: 80 additions & 7 deletions tests/tests-core/src/main/resources/graphql/schema-projects-query
Original file line number Diff line number Diff line change
@@ -1,20 +1,93 @@
{
schema(name:"content") {
content: schema(name:"content") {
projects {
# [$.data.schema.projects.elements.size()=1]
# [$.data.content.projects.elements.size()=1]
elements {
# [$.data.schema.projects.elements[0].name=dummy]
# [$.data.content.projects.elements[0].name=dummy]
name
# [$.data.schema.projects.elements[0].uuid=<is-uuid>]
# [$.data.content.projects.elements[0].uuid=<is-uuid>]
uuid
# [$.data.schema.projects.elements[0].uuid=<is-not-null>]
# [$.data.content.projects.elements[0].uuid=<is-not-null>]
etag
# [$.data.schema.projects.elements[0].uuid=<is-not-null>]
# [$.data.content.projects.elements[0].uuid=<is-not-null>]
created
# [$.data.schema.projects.elements[0].uuid=<is-not-null>]
# [$.data.content.projects.elements[0].uuid=<is-not-null>]
edited
}
}
}
all: schemas {
elements {
projects {
# [$.data.all.elements[0].projects.elements.size()=1]
elements {
# [$.data.all.elements[0].projects.elements[0].name=dummy]
name
# [$.data.all.elements[0].projects.elements[0].uuid=<is-uuid>]
uuid
# [$.data.all.elements[0].projects.elements[0].uuid=<is-not-null>]
etag
# [$.data.all.elements[0].projects.elements[0].uuid=<is-not-null>]
created
# [$.data.all.elements[0].projects.elements[0].uuid=<is-not-null>]
edited
}
}
}
}
content_bogus: schema(name:"content") {
projects (filter: {name: {equals: "bogus"}}) {
# [$.data.content_bogus.projects.elements.size()=0]
elements {
name
}
}
}
all_bogus: schemas {
elements {
projects (filter: {name: {equals: "bogus"}}) {
# [$.data.all_bogus.elements[0].projects.elements.size()=0]
elements {
name
}
}
}
}
content_dummy: schema(name:"content") {
projects (filter: {name: {equals: "dummy"}}) {
# [$.data.content_dummy.projects.elements.size()=1]
elements {
# [$.data.content_dummy.projects.elements[0].name=dummy]
name
# [$.data.content_dummy.projects.elements[0].uuid=<is-uuid>]
uuid
# [$.data.content_dummy.projects.elements[0].uuid=<is-not-null>]
etag
# [$.data.content_dummy.projects.elements[0].uuid=<is-not-null>]
created
# [$.data.content_dummy.projects.elements[0].uuid=<is-not-null>]
edited
}
}
}
all_dummy: schemas {
elements {
projects (filter: {name: {equals: "dummy"}}) {
# [$.data.all_dummy.elements[0].projects.elements.size()=1]
elements {
# [$.data.all_dummy.elements[0].projects.elements[0].name=dummy]
name
# [$.data.all_dummy.elements[0].projects.elements[0].uuid=<is-uuid>]
uuid
# [$.data.all_dummy.elements[0].projects.elements[0].uuid=<is-not-null>]
etag
# [$.data.all_dummy.elements[0].projects.elements[0].uuid=<is-not-null>]
created
# [$.data.all_dummy.elements[0].projects.elements[0].uuid=<is-not-null>]
edited
}
}
}
}
}
# [$.errors=<is-undefined>]
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.gentics.mesh.graphql.filter;

import java.util.ArrayList;
import java.util.List;

import com.gentics.graphqlfilter.filter.FilterField;
import com.gentics.graphqlfilter.filter.MappedFilter;
import com.gentics.graphqlfilter.filter.StartMainFilter;
import com.gentics.graphqlfilter.filter.StringFilter;
import com.gentics.mesh.core.data.project.HibProject;

import graphql.schema.GraphQLInputType;
import graphql.schema.GraphQLTypeReference;

/**
* Start project GraphQL filter
*/
public class ProjectFilter extends StartMainFilter<HibProject> {

private static final String NAME = "ProjectFilter";

private static ProjectFilter instance;
public static synchronized ProjectFilter filter() {
if (instance == null) {
instance = new ProjectFilter();
}
return instance;
}

private final boolean byRef;

private ProjectFilter() {
this(false);
}

private ProjectFilter(boolean byRef) {
super(NAME, "Filters projects");
this.byRef = byRef;
}

@Override
public GraphQLInputType getType() {
if (byRef) {
return GraphQLTypeReference.typeRef(NAME);
} else {
return super.getType();
}
}

@Override
protected List<FilterField<HibProject, ?>> getFilters() {
List<FilterField<HibProject, ?>> filters = new ArrayList<>();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible filtering fields for the project: name, UUID, user tracking.

filters.add(CommonFields.hibUuidFilter());
filters.addAll(CommonFields.hibUserTrackingFilter());
filters.add(new MappedFilter<>("name", "Filters by name", StringFilter.filter(), HibProject::getName));
return filters;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
Expand All @@ -21,6 +22,7 @@
import org.apache.commons.lang3.StringUtils;

import com.gentics.graphqlfilter.filter.StartFilter;
import com.gentics.graphqlfilter.filter.StartMainFilter;
import com.gentics.mesh.core.action.DAOActions;
import com.gentics.mesh.core.data.HibBaseElement;
import com.gentics.mesh.core.data.HibCoreElement;
Expand Down Expand Up @@ -510,8 +512,30 @@ protected GraphQLFieldDefinition newElementField(String name, String description
* @return
*/
protected GraphQLFieldDefinition newElementField(String name, String description, DAOActions<?, ?> actions,
String elementType, boolean hidePermissionsErrors) {
return newFieldDefinition()
String elementType, boolean hidePermissionsErrors) {
return newElementField(name, description, actions, elementType, hidePermissionsErrors, new GraphQLArgument[] {});
}

/**
* Create a new elements field which automatically allows to resolve the element using it's name or uuid, with the optional extra arguments (filters etc).
*
* @param name
* Name of the field
* @param description
* Description of the field
* @param actions
* DAO Actions for the type of elements
* @param elementType
* Type name of the element which can be loaded
* @param hidePermissionsErrors
* Does not show errors if the permission is missing. Useful for sensitive data (ex. fetching users by name)
* @param extraArgs
* Extra filters
* @return
*/
protected GraphQLFieldDefinition newElementField(String name, String description, DAOActions<?, ?> actions,
String elementType, boolean hidePermissionsErrors, GraphQLArgument... extraArgs) {
Builder fieldBuilder = newFieldDefinition()
.name(name)
.description(description)
.argument(createUuidArg("Uuid of the " + name + "."))
Expand All @@ -526,7 +550,11 @@ protected GraphQLFieldDefinition newElementField(String name, String description
} else {
return handleUuidNameArgs(env, null, actions);
}
}).build();
});
if (extraArgs != null) {
Arrays.stream(extraArgs).filter(Objects::nonNull).forEach(fieldBuilder::argument);
}
return fieldBuilder.build();
}

/**
Expand Down Expand Up @@ -571,12 +599,16 @@ protected DynamicStreamPageImpl<NodeContent> fetchFilteredNodes(DataFetchingEnvi
}

protected DynamicStreamPageImpl<NodeContent> applyNodeFilter(DataFetchingEnvironment env, Stream<? extends NodeContent> stream) {
return applyFilter(env, stream, NodeFilter.filter(env.getContext()));
}

protected <T, F extends StartMainFilter<? super T>> DynamicStreamPageImpl<T> applyFilter(DataFetchingEnvironment env, Stream<? extends T> stream, F filter) {
Map<String, ?> filterArgument = env.getArgument("filter");
PagingParameters pagingInfo = getPagingInfo(env);
GraphQLContext gc = env.getContext();

if (filterArgument != null) {
return new DynamicStreamPageImpl<>(stream, pagingInfo, NodeFilter.filter(gc).createPredicate(filterArgument));
return new DynamicStreamPageImpl<>(stream, pagingInfo, filter.createPredicate(filterArgument));
} else {
return new DynamicStreamPageImpl<>(stream, pagingInfo);
}
Expand Down
Loading