Skip to content

Commit

Permalink
Validators for JSON and Graphql Exporter (#1833)
Browse files Browse the repository at this point in the history
* Validators for JSON and Graphql Exporter

* Remove Singleton
  • Loading branch information
rishi-aga authored Feb 12, 2021
1 parent 39d1add commit 66be9ae
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2021, Yahoo Inc.
* Licensed under the Apache License, Version 2.0
* See LICENSE file in project root for terms.
*/
package com.yahoo.elide.async.export.validator;

import com.yahoo.elide.core.exceptions.BadRequestException;
import com.yahoo.elide.core.request.EntityProjection;

import java.util.Collection;

/**
* Validates none of the projections have relationships.
*/
public class NoRelationshipsProjectionValidator implements Validator {

@Override
public void validateProjection(Collection<EntityProjection> projections) {
for (EntityProjection projection : projections) {
if (!projection.getRelationships().isEmpty()) {
throw new BadRequestException(
"Export is not supported for Query that requires traversing Relationships.");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2021, Yahoo Inc.
* Licensed under the Apache License, Version 2.0
* See LICENSE file in project root for terms.
*/
package com.yahoo.elide.async.export.validator;

import com.yahoo.elide.core.exceptions.BadRequestException;
import com.yahoo.elide.core.request.EntityProjection;

import java.util.Collection;

/**
* Validates each projection in collection have one projection only.
*/
public class SingleRootProjectionValidator implements Validator {

@Override
public void validateProjection(Collection<EntityProjection> projections) {
if (projections.size() != 1) {
throw new BadRequestException("Export is only supported for single Query with one root projection.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
*/
package com.yahoo.elide.async.export.validator;

import graphql.language.Field;
import com.yahoo.elide.core.request.EntityProjection;

import java.util.Collection;

/**
* Utility interface used to validate Entity Projections.
Expand All @@ -14,8 +16,7 @@ public interface Validator {

/**
* Validates the EntityProjection.
* @param entityType Class of the Entity to be validated.
* @param field GraphQL Field.
* @param projections Collection of EntityProjections to validate.
*/
public void validateProjection(Class<?> entityType, Field field);
public void validateProjection(Collection<EntityProjection> projections);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

import com.yahoo.elide.Elide;
import com.yahoo.elide.async.export.formatter.TableExportFormatter;
import com.yahoo.elide.async.export.validator.NoRelationshipsProjectionValidator;
import com.yahoo.elide.async.models.AsyncAPI;
import com.yahoo.elide.async.models.TableExport;
import com.yahoo.elide.async.service.AsyncExecutorService;
import com.yahoo.elide.async.service.storageengine.ResultStorageEngine;
import com.yahoo.elide.core.RequestScope;
import com.yahoo.elide.core.datastore.DataStoreTransaction;
import com.yahoo.elide.core.exceptions.BadRequestException;
import com.yahoo.elide.core.request.EntityProjection;
import com.yahoo.elide.core.security.User;
import com.yahoo.elide.graphql.GraphQLRequestScope;
Expand All @@ -27,10 +27,10 @@
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.UUID;

/**
Expand All @@ -41,7 +41,8 @@ public class GraphQLTableExportOperation extends TableExportOperation {

public GraphQLTableExportOperation(TableExportFormatter formatter, AsyncExecutorService service,
AsyncAPI export, RequestScope scope, ResultStorageEngine engine) {
super(formatter, service, export, scope, engine);
super(formatter, service, export, scope, engine,
Arrays.asList(new NoRelationshipsProjectionValidator()));
}

@Override
Expand All @@ -53,9 +54,8 @@ public RequestScope getRequestScope(TableExport export, User user, String apiVer
}

@Override
public EntityProjection getProjection(TableExport export, RequestScope scope)
throws BadRequestException {
EntityProjection projection;
public Collection<EntityProjection> getProjections(TableExport export, RequestScope scope) {
GraphQLProjectionInfo projectionInfo;
try {
String graphQLDocument = export.getQuery();
Elide elide = getService().getElide();
Expand All @@ -65,20 +65,13 @@ public EntityProjection getProjection(TableExport export, RequestScope scope)
Map<String, Object> variables = QueryRunner.extractVariables(mapper, node);
String queryString = QueryRunner.extractQuery(node);

GraphQLProjectionInfo projectionInfo =
new GraphQLEntityProjectionMaker(elide.getElideSettings(), variables, scope.getApiVersion())
.make(queryString);

//TODO Call Validators.
Optional<Entry<String, EntityProjection>> optionalEntry =
projectionInfo.getProjections().entrySet().stream().findFirst();

projection = optionalEntry.isPresent() ? optionalEntry.get().getValue() : null;
projectionInfo = new GraphQLEntityProjectionMaker(elide.getElideSettings(), variables,
scope.getApiVersion()).make(queryString);

} catch (IOException e) {
throw new IllegalStateException(e);
}

return projection;
return projectionInfo.getProjections().values();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import com.yahoo.elide.Elide;
import com.yahoo.elide.async.export.formatter.TableExportFormatter;
import com.yahoo.elide.async.export.validator.NoRelationshipsProjectionValidator;
import com.yahoo.elide.async.models.AsyncAPI;
import com.yahoo.elide.async.models.TableExport;
import com.yahoo.elide.async.service.AsyncExecutorService;
Expand All @@ -22,6 +23,8 @@
import lombok.extern.slf4j.Slf4j;

import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.UUID;

Expand All @@ -35,7 +38,8 @@ public class JSONAPITableExportOperation extends TableExportOperation {

public JSONAPITableExportOperation(TableExportFormatter formatter, AsyncExecutorService service,
AsyncAPI export, RequestScope scope, ResultStorageEngine engine) {
super(formatter, service, export, scope, engine);
super(formatter, service, export, scope, engine,
Arrays.asList(new NoRelationshipsProjectionValidator()));
}

@Override
Expand All @@ -53,7 +57,7 @@ public RequestScope getRequestScope(TableExport export, User user, String apiVer
}

@Override
public EntityProjection getProjection(TableExport export, RequestScope scope) throws BadRequestException {
public Collection<EntityProjection> getProjections(TableExport export, RequestScope scope) {
EntityProjection projection = null;
try {
URIBuilder uri = new URIBuilder(export.getQuery());
Expand All @@ -64,6 +68,6 @@ public EntityProjection getProjection(TableExport export, RequestScope scope) th
} catch (URISyntaxException e) {
throw new BadRequestException(e.getMessage());
}
return projection;
return Collections.singletonList(projection);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import com.yahoo.elide.Elide;
import com.yahoo.elide.async.export.formatter.TableExportFormatter;
import com.yahoo.elide.async.export.validator.SingleRootProjectionValidator;
import com.yahoo.elide.async.export.validator.Validator;
import com.yahoo.elide.async.models.AsyncAPI;
import com.yahoo.elide.async.models.AsyncAPIResult;
import com.yahoo.elide.async.models.TableExport;
Expand All @@ -28,8 +30,12 @@
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import java.util.concurrent.Callable;
Expand All @@ -45,14 +51,16 @@ public abstract class TableExportOperation implements Callable<AsyncAPIResult> {
private TableExport exportObj;
private RequestScope scope;
private ResultStorageEngine engine;
private List<Validator> validators = new ArrayList<>(Arrays.asList(new SingleRootProjectionValidator()));

public TableExportOperation(TableExportFormatter formatter, AsyncExecutorService service,
AsyncAPI exportObj, RequestScope scope, ResultStorageEngine engine) {
AsyncAPI exportObj, RequestScope scope, ResultStorageEngine engine, List<Validator> validators) {
this.formatter = formatter;
this.service = service;
this.exportObj = (TableExport) exportObj;
this.scope = scope;
this.engine = engine;
this.validators.addAll(validators);
}

@Override
Expand All @@ -64,7 +72,9 @@ public AsyncAPIResult call() {
try (DataStoreTransaction tx = elide.getDataStore().beginTransaction()) {

RequestScope requestScope = getRequestScope(exportObj, scope.getUser(), apiVersion, tx);
EntityProjection projection = getProjection(exportObj, requestScope);
Collection<EntityProjection> projections = getProjections(exportObj, requestScope);
validateProjections(projections);
EntityProjection projection = projections.iterator().next();

Observable<PersistentResource> observableResults = export(exportObj, requestScope, projection);

Expand All @@ -85,7 +95,7 @@ public AsyncAPIResult call() {
exportResult.setUrl(new URL(generateDownloadURL(exportObj, (RequestScope) scope)));
exportResult.setRecordCount(recordNumber);
} catch (BadRequestException e) {
exportResult.setMessage("Bad Request body");
exportResult.setMessage(e.getMessage());
} catch (MalformedURLException e) {
exportResult.setMessage("Download url generation failure.");
} catch (Exception e) {
Expand Down Expand Up @@ -194,14 +204,16 @@ protected TableExport storeResults(TableExport exportObj, ResultStorageEngine re
return resultStorageEngine.storeResults(exportObj, result);
}

private void validateProjections(Collection<EntityProjection> projections) {
validators.forEach(validator -> validator.validateProjection(projections));
}

/**
* Generate Entity Projection from the query.
* @param exportObj TableExport type object.
* @param requestScope requestScope object.
* @return EntityProjection object.
* @throws BadRequestException BadRequestException.
* @return Collection of EntityProjection object.
*/
public abstract EntityProjection getProjection(TableExport exportObj, RequestScope requestScope)
throws BadRequestException;
public abstract Collection<EntityProjection> getProjections(TableExport exportObj, RequestScope requestScope);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2021, Verizon Media.
* Licensed under the Apache License, Version 2.0
* See LICENSE file in project root for terms.
*/
package com.yahoo.elide.async.models;

import com.yahoo.elide.annotation.Include;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Include(rootLevel = true, type = "group")
@Entity
public class ArtifactGroup {
@Id
private String name = "";

@OneToMany(mappedBy = "group")
private List<ArtifactProduct> products = new ArrayList<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2021, Verizon Media.
* Licensed under the Apache License, Version 2.0
* See LICENSE file in project root for terms.
*/
package com.yahoo.elide.async.models;

import com.yahoo.elide.annotation.Include;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Include(type = "product")
@Entity
public class ArtifactProduct {
@Id
private String name = "";

@ManyToOne
private ArtifactGroup group = null;
}
Loading

0 comments on commit 66be9ae

Please sign in to comment.