Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
lukashornych committed Dec 17, 2023
2 parents 5289bad + 735cf89 commit 0687832
Show file tree
Hide file tree
Showing 22 changed files with 1,984 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public interface CatalogDataApiRootDescriptor extends CatalogRootDescriptor {
.description("""
Finds and returns single entity from unspecified collection by shared arguments between collections.
""")
.type(nullableRef(EntityDescriptor.THIS_GLOBAL))
// type can be entity of any collection
.build();

EndpointDescriptor LIST_UNKNOWN_ENTITY = EndpointDescriptor.builder()
Expand All @@ -80,7 +80,7 @@ public interface CatalogDataApiRootDescriptor extends CatalogRootDescriptor {
.description("""
Finds and returns list of entities from unspecified collections by shared arguments between collections.
""")
.type(nullableListRef(EntityDescriptor.THIS_GLOBAL))
// type can be list of entities of any collection
.build();

EndpointDescriptor GET_ENTITY = EndpointDescriptor.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@
import io.evitadb.externalApi.api.model.ObjectDescriptor;
import io.evitadb.externalApi.api.model.PropertyDescriptor;

import java.util.List;
import java.util.Locale;

import static io.evitadb.externalApi.api.catalog.dataApi.model.CatalogDataApiRootDescriptor.LOCALE_ENUM;
import static io.evitadb.externalApi.api.model.ObjectPropertyDataTypeDescriptor.nonNullListRef;
import static io.evitadb.externalApi.api.model.ObjectPropertyDataTypeDescriptor.nullableRef;
Expand Down Expand Up @@ -123,20 +120,27 @@ The moment is either extracted from the query as well (if present) or current da
.type(nonNull(PriceInnerRecordHandling.class))
.build();

ObjectDescriptor THIS_REFERENCE = ObjectDescriptor.builder()
.name("EntityReference")
ObjectDescriptor THIS_CLASSIFIER = ObjectDescriptor.builder()
.name("Entity")
.description("""
Pointer to a full entity.
Generic the most basic entity.
Common ancestor for all specific entities which correspond to specific collections.
""")
.staticFields(List.of(PRIMARY_KEY, TYPE, VERSION))
.staticField(PRIMARY_KEY)
.staticField(TYPE)
.staticField(VERSION)
.build();
ObjectDescriptor THIS_GLOBAL = ObjectDescriptor.extend(THIS_REFERENCE)
.name("Entity")
/**
* Used only to distinguish from entity classifier for clarity, that this is a final object that just references an
* entity, not that an entity should extend this.
*/
ObjectDescriptor THIS_REFERENCE = ObjectDescriptor.extend(THIS_CLASSIFIER)
.name("EntityReference")
.description("""
Catalog-wise entity with only common data across all entity collections.
Pointer to a full entity.
""")
.build();
ObjectDescriptor THIS = ObjectDescriptor.extend(THIS_REFERENCE)
ObjectDescriptor THIS = ObjectDescriptor.extend(THIS_CLASSIFIER)
.name("*")
.build();
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@
import javax.annotation.Nonnull;
import java.util.Currency;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import static io.evitadb.utils.CollectionUtils.createHashMap;
import static io.evitadb.utils.CollectionUtils.createHashSet;

/**
Expand All @@ -52,14 +54,15 @@ public class CatalogGraphQLSchemaBuildingContext extends GraphQLSchemaBuildingCo
@Getter @Nonnull private final Set<Locale> supportedLocales;
@Getter @Nonnull private final Set<Currency> supportedCurrencies;
@Getter @Nonnull private final Set<EntitySchemaContract> entitySchemas;
@Getter @Nonnull private final Map<String, GraphQLObjectType> entityTypeToEntityObject;

public CatalogGraphQLSchemaBuildingContext(@Nonnull GraphQLConfig config,
@Nonnull Evita evita,
@Nonnull CatalogContract catalog) {
super(config, evita);
this.catalog = catalog;
this.supportedLocales = createHashSet(20);
this.supportedCurrencies = createHashSet(20);
this.supportedLocales = createHashSet(10);
this.supportedCurrencies = createHashSet(10);

this.entitySchemas = evita.queryCatalog(catalog.getName(), session -> {
final Set<String> collections = session.getAllEntityTypes();
Expand All @@ -73,14 +76,16 @@ public CatalogGraphQLSchemaBuildingContext(@Nonnull GraphQLConfig config,
});
return schemas;
});
this.entityTypeToEntityObject = createHashMap(this.entitySchemas.size());
}

@Nonnull
public CatalogSchemaContract getSchema() {
return catalog.getSchema();
}

public void registerEntityObject(@Nonnull GraphQLObjectType entityObject) {
public void registerEntityObject(@Nonnull String entityType, @Nonnull GraphQLObjectType entityObject) {
registerType(entityObject);
entityTypeToEntityObject.putIfAbsent(entityType, entityObject);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import io.evitadb.externalApi.graphql.api.catalog.dataApi.builder.constraint.RequireConstraintSchemaBuilder;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.DeleteEntitiesMutationHeaderDescriptor;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.GetEntityHeaderDescriptor;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.GlobalEntityDescriptor;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.ListEntitiesHeaderDescriptor;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.ListUnknownEntitiesHeaderDescriptor;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.QueryEntitiesHeaderDescriptor;
Expand Down Expand Up @@ -263,7 +264,8 @@ private BuiltFieldDescriptor buildCollectionsField() {
@Nullable
private BuiltFieldDescriptor buildGetUnknownEntityField() {
final GraphQLFieldDefinition.Builder getUnknownEntityFieldBuilder = CatalogDataApiRootDescriptor.GET_UNKNOWN_ENTITY
.to(staticEndpointBuilderTransformer);
.to(staticEndpointBuilderTransformer)
.type(typeRef(GlobalEntityDescriptor.THIS.name()));

// build globally unique attribute filters
final List<GlobalAttributeSchemaContract> globalAttributes = buildingContext.getCatalog()
Expand Down Expand Up @@ -314,6 +316,7 @@ private BuiltFieldDescriptor buildGetUnknownEntityField() {
private BuiltFieldDescriptor buildListUnknownEntityField() {
final Builder listUnknownEntityFieldBuilder = CatalogDataApiRootDescriptor.LIST_UNKNOWN_ENTITY
.to(staticEndpointBuilderTransformer)
.type(nonNull(list(nonNull(typeRef(GlobalEntityDescriptor.THIS.name())))))
.argument(ListUnknownEntitiesHeaderDescriptor.LIMIT.to(argumentBuilderTransformer));

// build globally unique attribute filters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public CatalogContract getCatalog() {
}

public void registerEntityObject(@Nonnull GraphQLObjectType entityObject) {
catalogCtx.registerEntityObject(entityObject);
catalogCtx.registerEntityObject(schema.getName(), entityObject);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import graphql.schema.DataFetcher;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLInputType;
import graphql.schema.GraphQLInterfaceType;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLOutputType;
import graphql.schema.GraphQLType;
Expand All @@ -51,6 +52,7 @@
import io.evitadb.externalApi.graphql.api.catalog.dataApi.builder.constraint.GraphQLConstraintSchemaBuildingContext;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.builder.constraint.OrderConstraintSchemaBuilder;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.builder.constraint.RequireConstraintSchemaBuilder;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.GlobalEntityDescriptor;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.GraphQLEntityDescriptor;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.entity.AssociatedDataFieldHeaderDescriptor;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.entity.AttributesFieldHeaderDescriptor;
Expand All @@ -60,6 +62,7 @@
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.entity.PricesFieldHeaderDescriptor;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.model.entity.ReferenceFieldHeaderDescriptor;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.resolver.dataFetcher.BigDecimalDataFetcher;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.resolver.dataFetcher.EntityDtoTypeResolver;
import io.evitadb.externalApi.graphql.api.catalog.dataApi.resolver.dataFetcher.entity.*;
import io.evitadb.externalApi.graphql.api.dataType.DataTypesConverter;
import io.evitadb.externalApi.graphql.api.model.ObjectDescriptorToGraphQLInterfaceTransformer;
Expand Down Expand Up @@ -130,6 +133,12 @@ public EntityObjectBuilder(@Nonnull CatalogGraphQLSchemaBuildingContext building
}

public void buildCommonTypes() {
final GraphQLInterfaceType entityClassifier = EntityDescriptor.THIS_CLASSIFIER.to(interfaceBuilderTransformer).build();
buildingContext.registerType(entityClassifier);
buildingContext.registerTypeResolver(
entityClassifier,
new EntityDtoTypeResolver(buildingContext.getEntityTypeToEntityObject())
);
buildingContext.registerType(EntityDescriptor.THIS_REFERENCE.to(objectBuilderTransformer).build());
buildingContext.registerType(buildPriceObject());
buildingContext.registerType(buildGlobal());
Expand All @@ -155,7 +164,8 @@ public GraphQLObjectType build(@Nonnull CollectionGraphQLSchemaBuildingContext c
final GraphQLObjectType.Builder entityObjectBuilder = entityDescriptor
.to(objectBuilderTransformer)
.name(objectName)
.description(entitySchema.getDescription());
.description(entitySchema.getDescription())
.withInterface(typeRef(GraphQLEntityDescriptor.THIS_CLASSIFIER.name()));

// build locale fields
if (!entitySchema.getLocales().isEmpty()) {
Expand Down Expand Up @@ -236,21 +246,27 @@ public GraphQLObjectType build(@Nonnull CollectionGraphQLSchemaBuildingContext c
private GraphQLObjectType buildGlobal() {
final CatalogSchemaContract catalogSchema = buildingContext.getSchema();

final GraphQLObjectType.Builder globalEntityObjectBuilder = GraphQLEntityDescriptor.THIS_GLOBAL.to(objectBuilderTransformer);
final GraphQLObjectType.Builder globalEntityObjectBuilder = GlobalEntityDescriptor.THIS.to(objectBuilderTransformer);

if (!buildingContext.getSupportedLocales().isEmpty()) {
globalEntityObjectBuilder.field(GraphQLEntityDescriptor.LOCALES.to(fieldBuilderTransformer));
globalEntityObjectBuilder.field(GraphQLEntityDescriptor.ALL_LOCALES.to(fieldBuilderTransformer));
globalEntityObjectBuilder.field(GlobalEntityDescriptor.LOCALES.to(fieldBuilderTransformer));
globalEntityObjectBuilder.field(GlobalEntityDescriptor.ALL_LOCALES.to(fieldBuilderTransformer));
}

if (!catalogSchema.getAttributes().isEmpty()) {
buildingContext.registerFieldToObject(
GraphQLEntityDescriptor.THIS_GLOBAL,
GlobalEntityDescriptor.THIS,
globalEntityObjectBuilder,
buildGlobalEntityAttributesField()
);
}

buildingContext.registerDataFetcher(
GlobalEntityDescriptor.THIS,
GlobalEntityDescriptor.TARGET_ENTITY,
new TargetEntityDataFetcher()
);

return globalEntityObjectBuilder.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
*
* _ _ ____ ____
* _____ _(_) |_ __ _| _ \| __ )
* / _ \ \ / / | __/ _` | | | | _ \
* | __/\ V /| | || (_| | |_| | |_) |
* \___| \_/ |_|\__\__,_|____/|____/
*
* Copyright (c) 2023
*
* Licensed under the Business Source License, Version 1.1 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://github.com/FgForrest/evitaDB/blob/main/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.evitadb.externalApi.graphql.api.catalog.dataApi.model;

import io.evitadb.externalApi.api.model.ObjectDescriptor;
import io.evitadb.externalApi.api.model.PropertyDescriptor;

import static io.evitadb.externalApi.api.model.ObjectPropertyDataTypeDescriptor.nonNullRef;

/**
* Represents global entity with only fields that are present in all entities across all collection.s
*
* @author Lukáš Hornych, FG Forrest a.s. (c) 2023
*/
public interface GlobalEntityDescriptor extends GraphQLEntityDescriptor {

PropertyDescriptor TARGET_ENTITY = PropertyDescriptor.builder()
.name("targetEntity")
.description("""
Contains a reference to actual collection-specific entity represented by this global entity holder.
""")
.type(nonNullRef(THIS_CLASSIFIER))
.build();

ObjectDescriptor THIS = ObjectDescriptor.extend(THIS_CLASSIFIER)
.name("GlobalEntity")
.description("""
Catalog-wise entity with only common data across all entity collections.
""")
.staticField(TARGET_ENTITY)
.build();
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Each entity must be part of at most single hierarchy (tree).
// type is expected to be a list of non-hierarchical version of this entity
.build();

ObjectDescriptor THIS_NON_HIERARCHICAL = ObjectDescriptor.extend(THIS_REFERENCE)
ObjectDescriptor THIS_NON_HIERARCHICAL = ObjectDescriptor.extend(THIS_CLASSIFIER)
.name("NonHierarchical*")
.build();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
*
* _ _ ____ ____
* _____ _(_) |_ __ _| _ \| __ )
* / _ \ \ / / | __/ _` | | | | _ \
* | __/\ V /| | || (_| | |_| | |_) |
* \___| \_/ |_|\__\__,_|____/|____/
*
* Copyright (c) 2023
*
* Licensed under the Business Source License, Version 1.1 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://github.com/FgForrest/evitaDB/blob/main/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.evitadb.externalApi.graphql.api.catalog.dataApi.resolver.dataFetcher;

import graphql.TypeResolutionEnvironment;
import graphql.schema.GraphQLObjectType;
import graphql.schema.TypeResolver;
import io.evitadb.api.requestResponse.data.EntityClassifier;
import io.evitadb.externalApi.graphql.exception.GraphQLQueryResolvingInternalError;
import lombok.RequiredArgsConstructor;

import javax.annotation.Nonnull;
import java.util.Map;
import java.util.Optional;

/**
* Resolve specific entity DTO for entity interface based on fetched original entity object.
*
* @author Lukáš Hornych, FG Forrest a.s. (c) 2022
*/
@RequiredArgsConstructor
public class EntityDtoTypeResolver implements TypeResolver {

private final Map<String, GraphQLObjectType> entityTypeToEntityDtoMapping;

@Nonnull
@Override
public GraphQLObjectType getType(@Nonnull TypeResolutionEnvironment env) {
final EntityClassifier entity = env.getObject();
return Optional.ofNullable(entityTypeToEntityDtoMapping.get(entity.getType()))
.orElseThrow(() -> new GraphQLQueryResolvingInternalError("Missing entity dto for entity type `" + entity.getType() + "`."));
}
}
Loading

0 comments on commit 0687832

Please sign in to comment.