Skip to content

Commit

Permalink
Introduced two differents GraphQLDataFetcher (SingleDataFetcher, Mult…
Browse files Browse the repository at this point in the history
…ipleDataFetcher). Implemented a method to interpolate arguments of mongodb methods (e.g. find(), limit(), skip() etc.) with GraphQL query arguments. Code cleanup.
  • Loading branch information
FabrDas committed Oct 15, 2020
1 parent 8d290d8 commit 2775738
Show file tree
Hide file tree
Showing 7 changed files with 325 additions and 167 deletions.
115 changes: 0 additions & 115 deletions graphql/src/main/java/org/restheart/graphql/GraphQLDataFetcher.java

This file was deleted.

91 changes: 46 additions & 45 deletions graphql/src/main/java/org/restheart/graphql/GraphQLService.java
Expand Up @@ -2,14 +2,9 @@

import com.mongodb.MongoClient;
import graphql.GraphQL;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.*;
import io.undertow.server.HttpServerExchange;
import org.bson.BsonDocument;
import org.bson.BsonElement;
import org.bson.BsonValue;
import org.bson.Document;
import org.restheart.exchange.ByteArrayRequest;
import org.restheart.exchange.MongoResponse;
Expand All @@ -18,7 +13,6 @@
import org.restheart.plugins.Service;
import org.restheart.utils.JsonUtils;

import javax.print.Doc;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
Expand All @@ -34,18 +28,39 @@ public class GraphQLService implements Service<ByteArrayRequest, MongoResponse>
private GraphQL gql;
private GraphQLApp app;
private MongoClient mongoClient;
private String sdl;

@InjectMongoClient
public void init(MongoClient mclient) throws IOException, URISyntaxException {
this.mongoClient = mclient;
this.sdl ="type Query { " +
"first(_id: Int!): Document" +
"}" +
"type Document { " +
"_id: Int " +
"msg: String " +
"}";

//fetching APP definition from database
this.app = new GraphQLApp("Test APP");
Document appDesc = this.mongoClient.getDatabase("restheart")
.getCollection("apps").find().first();


Map<String, Query> queryDefinitions = new HashMap<>();

//creating queries definitions and putting them inside App definition
for (Document query: appDesc.getList("queries", Document.class)) {
String queryName = query.getString("name");
queryDefinitions.put(queryName,
QueryBuilder.newBuilder(query.getString("db"), queryName, query.getString("collection")
, query.getBoolean("multiple"))
.filter((Document) query.get("filter"))
.sort((Document) query.get("sort"))
.skip((Document) query.get("skip"))
.limit((Document) query.get("limit"))
.first((Document) query.get("first"))
.build());
}
this.app.setQueries(queryDefinitions);


//making executable the schema
GraphQLSchema graphQLSchema = buildSchema(appDesc.getString("schema"));
this.app.setSchema(graphQLSchema);
this.gql = GraphQL.newGraphQL(graphQLSchema).build();

}

Expand All @@ -59,50 +74,36 @@ private GraphQLSchema buildSchema(String sdl){
private RuntimeWiring buildWiring(){

TypeRuntimeWiring.Builder obj = newTypeWiring("Query");
//for each app query, create a dedicated data fetcher
for (String queryName : this.app.getQueries().keySet()) {
obj.dataFetcher(queryName, new GraphQLDataFetcher(this.mongoClient, this.app));
boolean isMultiple = this.app.getQueryByName(queryName).isMultiple();
//TODO: create a null pointer exception for isMultiple --> it is mandatory!
if (isMultiple){
obj.dataFetcher(queryName, MultipleGraphQLDataFetcher.getInstance());
}
else{
obj.dataFetcher(queryName, SingleGraphQLDataFetcher.getInstance());
}
}

MultipleGraphQLDataFetcher.setCurrentApp(this.app);
MultipleGraphQLDataFetcher.setMongoClient(this.mongoClient);
SingleGraphQLDataFetcher.setCurrentApp(this.app);
SingleGraphQLDataFetcher.setMongoClient(this.mongoClient);
return RuntimeWiring.newRuntimeWiring().type(obj).build();
}

@Override
public void handle(ByteArrayRequest request, MongoResponse response) throws Exception {

if (this.mongoClient == null) {
response.setInError(500, "MongoClient not initialized");
return;
}

if (!check(request)) {
response.setInError(400, "RICHIESTA ERRATA");
return;
}

//create APP
this.app = new GraphQLApp("Test APP");
Map<String, Query> queries = new HashMap<>();

//retrieve query definition
Document res = this.mongoClient.getDatabase("restheart")
.getCollection("queries").find().first();

//create Query Object by query definition
Query firstQuery = QueryBuilder.newBuilder(res.getString("db"),
res.getString("name"), res.getString("collection"))
.filter((Document) res.get("filter"))
.sort((Document) res.get("sort"))
.skip((Document) res.get("skip"))
.limit((Document) res.get("limit"))
.first((Document) res.get("first"))
.build();

//add query to app queries
queries.put(firstQuery.getName(), firstQuery);
app.setQueries(queries);

//assign and build app schema
GraphQLSchema graphQLSchema = buildSchema(sdl);
this.app.setSchema(graphQLSchema);
this.gql = GraphQL.newGraphQL(graphQLSchema).build();


var query = new String(request.getContent());

var result = this.gql.execute(query);
Expand Down
@@ -0,0 +1,106 @@
package org.restheart.graphql;

import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.SelectedField;
import org.restheart.exchange.InvalidMetadataException;
import org.restheart.exchange.QueryVariableNotBoundException;
import org.bson.Document;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static com.mongodb.client.model.Projections.fields;
import static com.mongodb.client.model.Projections.include;

public class MultipleGraphQLDataFetcher implements DataFetcher<List<Document>> {

private static MultipleGraphQLDataFetcher instance = null;

public static MultipleGraphQLDataFetcher getInstance(){
if (instance ==null){
instance = new MultipleGraphQLDataFetcher();
}
return instance;
}
private MultipleGraphQLDataFetcher() { }


private static GraphQLApp currentApp = null;
private static MongoClient mongoClient = null;


public static GraphQLApp getCurrentApp() {
return currentApp;
}

public static void setCurrentApp(GraphQLApp app) {
currentApp = app;
}

public static MongoClient getMongoClient() {
return mongoClient;
}

public static void setMongoClient(MongoClient mclient) {
mongoClient = mclient;
}

@Override
public List<Document> get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception {
String queryName = dataFetchingEnvironment.getField().getName();
try{
Query queryDef = currentApp.getQueryByName(queryName);
Map<String, Object> graphQLQueryArguments = dataFetchingEnvironment.getArguments();

Map<String, Document> interpolatedArguments = queryDef.interpolate(graphQLQueryArguments);

FindIterable<Document> query;

if (interpolatedArguments.containsKey("filter")){
query = mongoClient.getDatabase(queryDef.getDb())
.getCollection(queryDef.getCollection(), Document.class)
.find(interpolatedArguments.get("filter"));
}
else{
query = mongoClient.getDatabase(queryDef.getDb())
.getCollection(queryDef.getCollection(), Document.class)
.find();
}

if (interpolatedArguments.containsKey("sort")){
query = query.sort(interpolatedArguments.get("sort"));
}

if (interpolatedArguments.containsKey("skip")){
query = query.skip((int) interpolatedArguments.get("skip").get("skip"));
}

if (interpolatedArguments.containsKey("limit")){
query = query.limit((int) interpolatedArguments.get("limit").get("limit"));
}

// find projection fields
List<String> projField = new LinkedList<String>();
for (SelectedField field: dataFetchingEnvironment.getSelectionSet().getFields()) {
projField.add(field.getQualifiedName());
}
ArrayList<Document> result = new ArrayList<Document>();

query.projection(fields(include(projField))).into(result);

return result;

}catch (NullPointerException e){
System.out.println("No query found with name "+ queryName );
return null;
}catch (InvalidMetadataException | QueryVariableNotBoundException e) {
e.printStackTrace();
return null;
}
}
}

0 comments on commit 2775738

Please sign in to comment.