You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2020/03/27 15:23:43 UTC

[sling-whiteboard] 02/03: GraphQL query engine added, minimal 'current resource path' query works

This is an automated email from the ASF dual-hosted git repository.

bdelacretaz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git

commit e09c3df3b2828b5c8e9021abf7f1e15904c86033
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Fri Mar 27 16:18:30 2020 +0100

    GraphQL query engine added, minimal 'current resource path' query works
---
 graphql-scripting/pom.xml                          |  6 ++
 .../gql/internal/GraphQLResourceQuery.java         | 81 ++++++++++++++++++++++
 .../gql/internal/GraphQLScriptEngine.java          | 19 ++++-
 .../gql/internal/GraphQLResourceQueryTest.java     | 48 +++++++++++++
 .../sling/scripting/graphql/it/BasicContentIT.java | 10 +--
 .../graphql/it/GraphQLScriptingTestSupport.java    |  2 +-
 .../initial-content/apps/graphql/test/one/json.gql | 19 ++++-
 7 files changed, 176 insertions(+), 9 deletions(-)

diff --git a/graphql-scripting/pom.xml b/graphql-scripting/pom.xml
index 7852c61..c6ef7cb 100644
--- a/graphql-scripting/pom.xml
+++ b/graphql-scripting/pom.xml
@@ -180,6 +180,12 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <version>1.10.19</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.apache.sling</groupId>
       <artifactId>org.apache.sling.servlet-helpers</artifactId>
       <version>1.3.0</version>
diff --git a/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQuery.java b/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQuery.java
new file mode 100644
index 0000000..37217c3
--- /dev/null
+++ b/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQuery.java
@@ -0,0 +1,81 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.sling.scripting.gql.internal;
+
+import java.util.Date;
+
+import org.apache.sling.api.resource.Resource;
+
+import graphql.ExecutionResult;
+import graphql.GraphQL;
+import graphql.schema.DataFetcher;
+import graphql.schema.DataFetchingEnvironment;
+import graphql.schema.GraphQLSchema;
+import graphql.schema.idl.RuntimeWiring;
+import graphql.schema.idl.SchemaGenerator;
+import graphql.schema.idl.SchemaParser;
+import graphql.schema.idl.TypeDefinitionRegistry;
+import graphql.schema.idl.TypeRuntimeWiring;
+
+/** Run a GraphQL query in the context of a Sling Resource */
+class GraphQLResourceQuery {
+
+    static class EchoDataFetcher implements DataFetcher<Object> {
+        private final Object data;
+
+        EchoDataFetcher(Object data) {
+            this.data = data;
+        }
+        @Override
+        public Object get(DataFetchingEnvironment environment) throws Exception {
+            return data;
+        }
+    }
+
+    ExecutionResult executeQuery(Resource r, String query) {
+        final String schemaDef = 
+            "type Query { currentResource : SlingResource }\n"
+            + "type SlingResource { path: String }\n"
+        ;
+
+        final GraphQLSchema schema = buildSchema(schemaDef, r);
+        final GraphQL graphQL = GraphQL.newGraphQL(schema).build();
+        final ExecutionResult result = graphQL.execute(query);
+        return result;
+    }
+
+    private GraphQLSchema buildSchema(String sdl, Resource r) {
+        TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
+        RuntimeWiring runtimeWiring = buildWiring(r);
+        SchemaGenerator schemaGenerator = new SchemaGenerator();
+        return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
+    }
+
+    private RuntimeWiring buildWiring(Resource r) {
+        // TODO data should pass via the DataFetchingEnvironment...
+        final String path = r == null ? "NO_PATH" : r.getPath();
+        return RuntimeWiring.newRuntimeWiring()
+            .type(TypeRuntimeWiring.newTypeWiring("Query").dataFetcher("currentResource", new EchoDataFetcher("DummyCurrentResourceResult")).build())
+            .type(TypeRuntimeWiring.newTypeWiring("SlingResource").dataFetcher("path", new EchoDataFetcher(path)).build())
+            .build()
+        ;
+    }
+}
diff --git a/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLScriptEngine.java b/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLScriptEngine.java
index 812d002..4d4c43b 100644
--- a/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLScriptEngine.java
+++ b/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLScriptEngine.java
@@ -23,7 +23,6 @@ package org.apache.sling.scripting.gql.internal;
 import java.io.IOException;
 import java.io.Reader;
 import java.io.StringReader;
-import java.util.Date;
 
 import javax.script.AbstractScriptEngine;
 import javax.script.Bindings;
@@ -32,6 +31,10 @@ import javax.script.ScriptEngineFactory;
 import javax.script.ScriptException;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.scripting.SlingBindings;
+
+import graphql.ExecutionResult;
 
 public class GraphQLScriptEngine extends AbstractScriptEngine {
 
@@ -49,8 +52,18 @@ public class GraphQLScriptEngine extends AbstractScriptEngine {
     @Override
     public Object eval(Reader reader, ScriptContext context) throws ScriptException {
         try {
-            // TODO no execution so far...
-            IOUtils.copy(reader, context.getWriter());
+            final GraphQLResourceQuery q = new GraphQLResourceQuery();
+
+            final Resource resource = (Resource) context.getBindings(ScriptContext.ENGINE_SCOPE).get(SlingBindings.RESOURCE);
+            final ExecutionResult result = q.executeQuery(resource, IOUtils.toString(reader));
+            if(!result.getErrors().isEmpty()) {
+                throw new ScriptException(("GraphQL query failed:" + result.getErrors()));
+            }
+            final Object data = result.getData();
+            if(data == null) {
+                throw new ScriptException("No data");
+            }
+            IOUtils.copy(new StringReader(data.toString()), context.getWriter());
         } catch(IOException e) {
             throw new ScriptException(e);
         }
diff --git a/graphql-scripting/src/test/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQueryTest.java b/graphql-scripting/src/test/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQueryTest.java
new file mode 100644
index 0000000..9218b37
--- /dev/null
+++ b/graphql-scripting/src/test/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQueryTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.sling.scripting.gql.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.UUID;
+
+import org.apache.sling.api.resource.Resource;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import graphql.ExecutionResult;
+
+public class GraphQLResourceQueryTest {
+   @Test
+    public void basicTest() throws Exception {
+        final String path = "/some/path/" + UUID.randomUUID();
+        final Resource r = Mockito.mock(Resource.class);
+        Mockito.when(r.getPath()).thenReturn(path);
+
+        final GraphQLResourceQuery q = new GraphQLResourceQuery();
+        final ExecutionResult result = q.executeQuery(r, "{ currentResource { path } }");
+
+        if(!result.getErrors().isEmpty()) {
+            fail("Errors:" + result.getErrors());
+        }
+        final String expected = "{currentResource={path=" + path + "}}";
+        assertEquals(expected, result.getData().toString());
+    }
+}
diff --git a/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/BasicContentIT.java b/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/BasicContentIT.java
index b2ca6f1..750dd67 100644
--- a/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/BasicContentIT.java
+++ b/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/BasicContentIT.java
@@ -30,7 +30,8 @@ import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
 import org.ops4j.pax.exam.spi.reactors.PerClass;
 import org.ops4j.pax.exam.util.Filter;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.ops4j.pax.exam.cm.ConfigurationAdminOptions.factoryConfiguration;
 
 @RunWith(PaxExam.class)
@@ -53,9 +54,10 @@ public class BasicContentIT extends GraphQLScriptingTestSupport {
 
     @Test
     public void testJsonContent() throws Exception {
-        final String content = getContent("/graphql/one.json");
-        assertTrue("Expecting the right content:" + content, 
-            content.contains("One day this will be a GraphQL query"));
+        final String expected = "{currentResource={path=/content/graphql/one}}";
+        final String actual = getContent("/graphql/one.json");
+        assertNotNull(actual);
+        assertEquals(expected, actual.trim());
     }
 
 }
diff --git a/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java b/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java
index 9ae877b..6f22cc9 100644
--- a/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java
+++ b/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java
@@ -148,7 +148,7 @@ public abstract class GraphQLScriptingTestSupport extends TestSupport {
 
         if (expectedStatus > 0) {
             assertEquals("Expected status " + expectedStatus + " for " + method
-                + " at " + path, expectedStatus, response.getStatus());
+                + " at " + path + " - content=" + response.getOutputAsString(), expectedStatus, response.getStatus());
         }
 
         return response;
diff --git a/graphql-scripting/src/test/resources/initial-content/apps/graphql/test/one/json.gql b/graphql-scripting/src/test/resources/initial-content/apps/graphql/test/one/json.gql
index 32539ce..16bd6e4 100644
--- a/graphql-scripting/src/test/resources/initial-content/apps/graphql/test/one/json.gql
+++ b/graphql-scripting/src/test/resources/initial-content/apps/graphql/test/one/json.gql
@@ -1 +1,18 @@
-One day this will be a GraphQL query
\ No newline at end of file
+# * Licensed to the Apache Software Foundation (ASF) under one
+# * or more contributor license agreements.  See the NOTICE file
+# * distributed with this work for additional information
+# * regarding copyright ownership.  The ASF licenses this file
+# * to you under the Apache License, Version 2.0 (the
+# * "License"); you may not use this file except in compliance
+# * with the License.  You may obtain a copy of the License at
+# *
+# *   http://www.apache.org/licenses/LICENSE-2.0
+# *
+# * 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.
+
+{ currentResource { path } }
\ No newline at end of file