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