Repository: incubator-rya
Updated Branches:
  refs/heads/master 4ac4e8674 -> 529f2d595


http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c4d4bfe7/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexIT.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexIT.java
 
b/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexIT.java
new file mode 100644
index 0000000..4ddb2a5
--- /dev/null
+++ 
b/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexIT.java
@@ -0,0 +1,326 @@
+/**
+ * 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.rya.indexing.mongo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.rya.api.RdfCloudTripleStoreConfiguration;
+import org.apache.rya.api.domain.RyaURI;
+import org.apache.rya.indexing.accumulo.ConfigUtils;
+import org.apache.rya.indexing.entity.model.Entity;
+import org.apache.rya.indexing.entity.model.Type;
+import org.apache.rya.indexing.entity.storage.EntityStorage;
+import org.apache.rya.indexing.entity.storage.TypeStorage;
+import org.apache.rya.indexing.entity.update.mongo.MongoEntityIndexer;
+import org.apache.rya.mongodb.MockMongoFactory;
+import org.apache.rya.mongodb.MongoDBRdfConfiguration;
+import org.apache.rya.sail.config.RyaSailFactory;
+import org.bson.Document;
+import org.junit.Before;
+import org.junit.Test;
+import org.openrdf.model.Statement;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.model.impl.ValueFactoryImpl;
+import org.openrdf.model.vocabulary.RDF;
+import org.openrdf.query.BindingSet;
+import org.openrdf.query.QueryLanguage;
+import org.openrdf.query.TupleQueryResult;
+import org.openrdf.query.impl.MapBindingSet;
+import org.openrdf.repository.sail.SailRepository;
+import org.openrdf.repository.sail.SailRepositoryConnection;
+import org.openrdf.sail.Sail;
+
+import com.google.common.collect.ImmutableSet;
+import com.mongodb.Block;
+import com.mongodb.MongoClient;
+import com.mongodb.client.MongoDatabase;
+
+import de.flapdoodle.embed.mongo.distribution.Version;
+
+public class MongoEntityIndexIT {
+    private static final ValueFactory VF = ValueFactoryImpl.getInstance();
+    private MongoDBRdfConfiguration conf;
+    private SailRepositoryConnection conn;
+    private MongoEntityIndexer indexer;
+    private MongoClient mongoClient;
+
+    @Before
+    public void setUp() throws Exception{
+        mongoClient = 
MockMongoFactory.with(Version.Main.PRODUCTION).newMongoClient();
+        conf = new MongoDBRdfConfiguration();
+        conf.set(MongoDBRdfConfiguration.MONGO_DB_NAME, "test");
+        conf.set(MongoDBRdfConfiguration.MONGO_COLLECTION_PREFIX, "rya");
+        conf.set(RdfCloudTripleStoreConfiguration.CONF_TBL_PREFIX, "rya");
+        conf.setBoolean(ConfigUtils.USE_MONGO, true);
+        conf.setMongoClient(mongoClient);
+        conf.setBoolean(ConfigUtils.USE_ENTITY, true);
+        final int port = mongoClient.getServerAddressList().get(0).getPort();
+        conf.set(MongoDBRdfConfiguration.MONGO_INSTANCE_PORT, 
Integer.toString(port));
+
+        final Sail sail = RyaSailFactory.getInstance(conf);
+        conn = new SailRepository(sail).getConnection();
+        conn.begin();
+
+        indexer = new MongoEntityIndexer();
+        indexer.setConf(conf);
+        indexer.init();
+    }
+
+    @Test
+    public void ensureInEntityStore_Test() throws Exception {
+        setupTypes();
+        addStatements();
+
+        final MongoDatabase db = mongoClient.getDatabase("test");
+        db.listCollections().forEach((Block<Document>)doc -> {
+            System.out.println(doc);
+        });
+
+
+        final EntityStorage entities = indexer.getEntityStorage(conf);
+        final RyaURI subject = new RyaURI("urn:alice");
+        final Optional<Entity> alice = entities.get(subject);
+        assertTrue(alice.isPresent());
+    }
+
+    @Test
+    public void sparqlQuery_Test() throws Exception {
+        setupTypes();
+        addStatements();
+        //conn.commit();
+
+        final String query = "SELECT * WHERE { " +
+                "<urn:strawberry> <" + RDF.TYPE + "> <urn:icecream> ."+
+                "<urn:strawberry> <urn:brand> ?brand . " +
+                "<urn:strawberry> <urn:flavor> ?flavor . " +
+            "}";
+
+        final TupleQueryResult rez = 
conn.prepareTupleQuery(QueryLanguage.SPARQL, query).evaluate();
+        final Set<BindingSet> results = new HashSet<>();
+        while(rez.hasNext()) {
+            final BindingSet bs = rez.next();
+            System.out.println(bs);
+            results.add(bs);
+        }
+        final MapBindingSet expected = new MapBindingSet();
+        expected.addBinding("flavor", 
ValueFactoryImpl.getInstance().createLiteral("Strawberry"));
+        expected.addBinding("brand", 
ValueFactoryImpl.getInstance().createLiteral("Awesome Icecream"));
+
+        assertEquals(1, results.size());
+        assertEquals(expected, results.iterator().next());
+    }
+
+    @Test
+    public void partialQuery_Test() throws Exception {
+        setupTypes();
+        addStatements();
+        conn.commit();
+
+        final String query = "SELECT * WHERE { " +
+                "<urn:george> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:george> <urn:name> ?name . " +
+                "<urn:george> <urn:eye> ?eye . " +
+            "}";
+
+        final TupleQueryResult rez = 
conn.prepareTupleQuery(QueryLanguage.SPARQL, query).evaluate();
+        final Set<BindingSet> results = new HashSet<>();
+        while(rez.hasNext()) {
+            final BindingSet bs = rez.next();
+            System.out.println(bs);
+            results.add(bs);
+        }
+        final ValueFactory vf = ValueFactoryImpl.getInstance();
+        final MapBindingSet expected = new MapBindingSet();
+        //expected.addBinding("name", 
vf.createURI("http://www.w3.org/2001/SMLSchema#string";, "George"));
+        expected.addBinding("name", vf.createLiteral("George"));
+        expected.addBinding("eye", vf.createLiteral("blue"));
+
+        assertEquals(1, results.size());
+        assertEquals(expected, results.iterator().next());
+    }
+
+    private void setupTypes() throws Exception {
+        final TypeStorage typeStore = indexer.getTypeStorage(conf);
+        // Add some Types to the storage.
+        final Type cat = new Type(new RyaURI("urn:cat"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:numLegs"))
+                    .add(new RyaURI("urn:eye"))
+                    .add(new RyaURI("urn:species"))
+                    .build());
+
+        final Type dog = new Type(new RyaURI("urn:dog"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:numLegs"))
+                    .add(new RyaURI("urn:eye"))
+                    .add(new RyaURI("urn:species"))
+                    .build());
+
+        final Type icecream = new Type(new RyaURI("urn:icecream"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:brand"))
+                    .add(new RyaURI("urn:flavor"))
+                    .add(new RyaURI("urn:cost"))
+                    .build());
+
+        final Type person = new Type(new RyaURI("urn:person"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:name"))
+                    .add(new RyaURI("urn:age"))
+                    .add(new RyaURI("urn:eye"))
+                    .build());
+
+        typeStore.create(cat);
+        typeStore.create(dog);
+        typeStore.create(icecream);
+        typeStore.create(person);
+    }
+
+    private void addStatements() throws Exception {
+        final List<Statement> stmnts = new ArrayList<>();
+
+        //alice
+        URI subject = VF.createURI("urn:alice");
+        URI predicate = VF.createURI("urn:name");
+        Value object = VF.createLiteral("Alice");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:eye");
+        object = VF.createLiteral("blue");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:age");
+        object = VF.createLiteral(30);
+        conn.add(VF.createStatement(subject, predicate, object));
+        conn.add(VF.createStatement(subject, RDF.TYPE, 
VF.createURI("urn:person")));
+
+        //bob
+        subject = VF.createURI("urn:bob");
+        predicate = VF.createURI("urn:name");
+        object = VF.createLiteral("Bob");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:eye");
+        object = VF.createLiteral("brown");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:age");
+        object = VF.createLiteral(57);
+        conn.add(VF.createStatement(subject, predicate, object));
+        conn.add(VF.createStatement(subject, RDF.TYPE, 
VF.createURI("urn:person")));
+
+        //charlie
+        subject = VF.createURI("urn:charlie");
+        predicate = VF.createURI("urn:name");
+        object = VF.createLiteral("Charlie");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:eye");
+        object = VF.createLiteral("hazel");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:age");
+        object = VF.createLiteral(25);
+        conn.add(VF.createStatement(subject, predicate, object));
+        conn.add(VF.createStatement(subject, RDF.TYPE, 
VF.createURI("urn:person")));
+
+        //david
+        subject = VF.createURI("urn:david");
+        predicate = VF.createURI("urn:name");
+        object = VF.createLiteral("David");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:eye");
+        object = VF.createLiteral("brown");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:age");
+        object = VF.createLiteral(30);
+        conn.add(VF.createStatement(subject, predicate, object));
+        conn.add(VF.createStatement(subject, RDF.TYPE, 
VF.createURI("urn:person")));
+
+        //eve
+        subject = VF.createURI("urn:eve");
+        predicate = VF.createURI("urn:name");
+        object = VF.createLiteral("Bob");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:age");
+        object = VF.createLiteral(25);
+        conn.add(VF.createStatement(subject, predicate, object));
+        conn.add(VF.createStatement(subject, RDF.TYPE, 
VF.createURI("urn:person")));
+
+        //frank
+        subject = VF.createURI("urn:frank");
+        predicate = VF.createURI("urn:name");
+        object = VF.createLiteral("Frank");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:eye");
+        object = VF.createLiteral("Hazel");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:age");
+        object = VF.createLiteral(57);
+        conn.add(VF.createStatement(subject, predicate, object));
+        conn.add(VF.createStatement(subject, RDF.TYPE, 
VF.createURI("urn:person")));
+
+        //george
+        subject = VF.createURI("urn:george");
+        predicate = VF.createURI("urn:name");
+        object = VF.createLiteral("George");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:eye");
+        object = VF.createLiteral("blue");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:age");
+        object = VF.createLiteral(30);
+        conn.add(VF.createStatement(subject, predicate, object));
+        conn.add(VF.createStatement(subject, RDF.TYPE, 
VF.createURI("urn:person")));
+
+        // Some Icecream typed objects.
+        //chocolate
+        subject = VF.createURI("urn:chocolate");
+        predicate = VF.createURI("urn:brand");
+        object = VF.createLiteral("Awesome Icecream");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:flavor");
+        object = VF.createLiteral("Chocolate");
+        conn.add(VF.createStatement(subject, predicate, object));
+        conn.add(VF.createStatement(subject, RDF.TYPE, 
VF.createURI("urn:icecream")));
+
+        //vanilla
+        subject = VF.createURI("urn:vanilla");
+        predicate = VF.createURI("urn:brand");
+        object = VF.createLiteral("Awesome Icecream");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:flavor");
+        object = VF.createLiteral("Vanilla");
+        conn.add(VF.createStatement(subject, predicate, object));
+        conn.add(VF.createStatement(subject, RDF.TYPE, 
VF.createURI("urn:icecream")));
+
+        //strawberry
+        subject = VF.createURI("urn:strawberry");
+        predicate = VF.createURI("urn:brand");
+        object = VF.createLiteral("Awesome Icecream");
+        conn.add(VF.createStatement(subject, predicate, object));
+        predicate = VF.createURI("urn:flavor");
+        object = VF.createLiteral("Strawberry");
+        conn.add(VF.createStatement(subject, predicate, object));
+        conn.add(VF.createStatement(subject, RDF.TYPE, 
VF.createURI("urn:icecream")));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c4d4bfe7/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexTest.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexTest.java
 
b/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexTest.java
new file mode 100644
index 0000000..f4aeaa1
--- /dev/null
+++ 
b/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexTest.java
@@ -0,0 +1,260 @@
+/**
+ * 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.rya.indexing.mongo;
+
+import java.util.List;
+
+import org.apache.rya.api.domain.RyaType;
+import org.apache.rya.api.domain.RyaURI;
+import org.apache.rya.indexing.accumulo.ConfigUtils;
+import org.apache.rya.indexing.entity.EntityIndexOptimizer;
+import org.apache.rya.indexing.entity.model.Entity;
+import org.apache.rya.indexing.entity.model.Property;
+import org.apache.rya.indexing.entity.model.Type;
+import org.apache.rya.indexing.entity.query.EntityQueryNode;
+import org.apache.rya.indexing.entity.storage.EntityStorage;
+import org.apache.rya.indexing.entity.storage.TypeStorage;
+import org.apache.rya.mongodb.MockMongoFactory;
+import org.apache.rya.mongodb.MongoDBRdfConfiguration;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openrdf.model.vocabulary.RDF;
+import org.openrdf.query.MalformedQueryException;
+import org.openrdf.query.algebra.QueryModelNode;
+import org.openrdf.query.algebra.StatementPattern;
+import org.openrdf.query.algebra.TupleExpr;
+import org.openrdf.query.algebra.helpers.QueryModelVisitorBase;
+import org.openrdf.query.algebra.helpers.StatementPatternCollector;
+import org.openrdf.query.parser.sparql.SPARQLParser;
+
+import com.google.common.collect.ImmutableSet;
+import com.mongodb.MongoClient;
+
+public class MongoEntityIndexTest {
+    private static final Type PERSON_TYPE =
+            new Type(new RyaURI("urn:person"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:name"))
+                    .add(new RyaURI("urn:age"))
+                    .add(new RyaURI("urn:eye"))
+                    .build());
+    private static final RyaURI RYA_PERSON_TYPE = new RyaURI("urn:person");
+
+    static MongoDBRdfConfiguration conf;
+    private static EntityIndexOptimizer optimizer;
+    private static EntityStorage entityStorage;
+
+    @BeforeClass
+    public static void beforeClass() throws Exception {
+        conf = new MongoDBRdfConfiguration();
+        conf.set(ConfigUtils.USE_MONGO, "true");
+        conf.set(MongoDBRdfConfiguration.MONGO_DB_NAME, "test");
+        conf.set(MongoDBRdfConfiguration.MONGO_COLLECTION_PREFIX, "rya_");
+        conf.setTablePrefix("another_");
+
+        final MongoClient client = 
MockMongoFactory.newFactory().newMongoClient();
+        conf.setMongoClient(client);
+
+        optimizer = new EntityIndexOptimizer();
+        optimizer.setConf(conf);
+
+        final TypeStorage typeStorage = optimizer.getTypeStorage();
+        typeStorage.create(PERSON_TYPE);
+
+        final Entity entity = Entity.builder()
+                .setSubject(new RyaURI("urn:SSN:111-11-1111"))
+                .setExplicitType(RYA_PERSON_TYPE)
+                .setProperty(RYA_PERSON_TYPE, new Property(new 
RyaURI("urn:age"), new RyaType("25")))
+                .setProperty(RYA_PERSON_TYPE, new Property(new 
RyaURI("urn:eye"), new RyaType("blue")))
+                .setProperty(RYA_PERSON_TYPE, new Property(new 
RyaURI("urn:name"), new RyaType("bob")))
+                .build();
+        entityStorage = optimizer.getEntityStorage();
+        entityStorage.create(entity);
+    }
+
+    @Test()
+    public void queryIsFullEntity() throws Exception {
+        // A pattern that has two different subjects.
+        final String query = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                "<urn:SSN:111-11-1111> <urn:name> ?name . " +
+                "<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
+            "}";
+
+        final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, 
getSPs(query), entityStorage);
+        assertOptimizer(query, expected);
+    }
+
+    @Test()
+    public void queryIsPartEntity() throws Exception {
+        // A pattern that has two different subjects.
+        final String query = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+            "}";
+
+        final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, 
getSPs(query), entityStorage);
+        assertOptimizer(query, expected);
+    }
+
+    @Test()
+    public void queryIsPartEntityandExtra() throws Exception {
+        // A pattern that has two different subjects.
+        final String query = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                "<urn:SSN:222-22-2222> <urn:age> ?age . " +
+                "<urn:SSN:222-22-2222> <urn:eye> ?eye . " +
+                "<urn:SSN:222-22-2222> <urn:name> ?name . " +
+            "}";
+
+        final String expectedQuery = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+            "}";
+
+        final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, 
getSPs(expectedQuery), entityStorage);
+        assertOptimizer(query, expected);
+    }
+
+    @Test()
+    public void queryIsFullEntityWithExtra() throws Exception {
+        // A pattern that has two different subjects.
+        final String query = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                "<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
+                "<urn:SSN:111-11-1111> <urn:name> ?name . " +
+                "<urn:SSN:222-22-2222> <urn:age> ?age . " +
+                "<urn:SSN:222-22-2222> <urn:eye> ?eye . " +
+                "<urn:SSN:222-22-2222> <urn:name> ?name . " +
+            "}";
+
+        final String expectedQuery = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                "<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
+                "<urn:SSN:111-11-1111> <urn:name> ?name . " +
+            "}";
+
+        final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, 
getSPs(expectedQuery), entityStorage);
+        assertOptimizer(query, expected);
+    }
+
+    @Test()
+    public void queryIsFullEntityWithOptional() throws Exception {
+        // A pattern that has two different subjects.
+        final String query = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                "<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
+                "<urn:SSN:111-11-1111> <urn:name> ?name . " +
+                "  OPTIONAL{" +
+                "    <urn:SSN:222-22-2222> <urn:age> ?age . " +
+                "    <urn:SSN:222-22-2222> <urn:eye> ?eye . " +
+                "    <urn:SSN:222-22-2222> <urn:name> ?name . " +
+                " } . " +
+            "}";
+
+        final String expectedQuery = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                "<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
+                "<urn:SSN:111-11-1111> <urn:name> ?name . " +
+            "}";
+
+        final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, 
getSPs(expectedQuery), entityStorage);
+        assertOptimizer(query, expected);
+    }
+
+    @Test()
+    public void queryIsSplitEntityWithOptional() throws Exception {
+        // A pattern that has two different subjects.
+        final String query = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                "<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
+                "  OPTIONAL{" +
+                "    <urn:SSN:111-11-1111> <urn:name> ?name . " +
+                " } . " +
+            "}";
+
+        final String expectedQuery = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                "<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
+            "}";
+
+        final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, 
getSPs(expectedQuery), entityStorage);
+        assertOptimizer(query, expected);
+    }
+
+    @Test()
+    public void queryEntityInOptional() throws Exception {
+        // A pattern that has two different subjects.
+        final String query = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                "<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
+                "  OPTIONAL{" +
+                "    <urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "    <urn:SSN:111-11-1111> <urn:name> ?name . " +
+                " } . " +
+            "}";
+
+        final String expectedQuery = "SELECT * WHERE { " +
+                "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                "<urn:SSN:111-11-1111> <urn:name> ?name . " +
+            "}";
+
+        final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, 
getSPs(expectedQuery), entityStorage);
+        assertOptimizer(query, expected);
+    }
+
+    private static List<StatementPattern> getSPs(final String sparql) throws 
MalformedQueryException {
+        final StatementPatternCollector spCollector = new 
StatementPatternCollector();
+        new SPARQLParser().parseQuery(sparql, 
null).getTupleExpr().visit(spCollector);
+        return spCollector.getStatementPatterns();
+    }
+
+    private void assertOptimizer(final String query, final EntityQueryNode 
expected) throws Exception {
+        final SPARQLParser parser = new SPARQLParser();
+        final TupleExpr expr = parser.parseQuery(query, null).getTupleExpr();
+
+        optimizer.optimize(expr, null, null);
+        expr.visit(new EntityFetchingAsserterVisitor(expected));
+    }
+
+    private class EntityFetchingAsserterVisitor extends 
QueryModelVisitorBase<Exception> {
+        private final EntityQueryNode expected;
+        public EntityFetchingAsserterVisitor(final EntityQueryNode expected) {
+            this.expected = expected;
+        }
+        @Override
+        protected void meetNode(final QueryModelNode node) throws Exception {
+            if(node instanceof EntityQueryNode) {
+                Assert.assertEquals(expected, node);
+            } else {
+                super.meetNode(node);
+            }
+        }
+    }
+}
+

Reply via email to