orientechnologies / orientdb

OrientDB is the most versatile DBMS supporting Graph, Document, Reactive, Full-Text and Geospatial models in one Multi-Model product. OrientDB can run distributed (Multi-Master), supports SQL, ACID Transactions, Full-Text indexing and Reactive Queries.
https://orientdb.dev
Apache License 2.0
4.75k stars 871 forks source link

new bugs with traverse after fix #10281 #10292

Open mikhalov opened 2 months ago

mikhalov commented 2 months ago

OrientDB Version: 3.2.32 Java Version: 17 OS: Windows

After the fix https://github.com/orientechnologies/orientdb/issues/10281, several new bugs were discovered:

First Bug: It is still impossible to access a variable or result in the context using $current as was possible in the old API.

Second Bug: There is a bug when trying to access the result of a traversal using $path.out('Owns'). Specifically, the issue occurs when you attempt to reference the out('Owns') on the result of the traverse operation stored in the $path variable. This causes an error and does not work as expected.

Also, I am including tests for both bugs using the old and new APIs:

import com.orientechnologies.orient.core.command.OCommandRequest;
import com.orientechnologies.orient.core.config.OGlobalConfiguration;
import com.orientechnologies.orient.core.db.ODatabaseDocumentInternal;
import com.orientechnologies.orient.core.db.ODatabaseSession;
import com.orientechnologies.orient.core.db.ODatabaseType;
import com.orientechnologies.orient.core.db.OrientDB;
import com.orientechnologies.orient.core.db.OrientDBConfig;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.metadata.schema.OSchema;
import com.orientechnologies.orient.core.record.OEdge;
import com.orientechnologies.orient.core.record.OVertex;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.executor.OResultSet;
import com.orientechnologies.orient.core.sql.query.OConcurrentLegacyResultSet;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;
import com.tinkerpop.blueprints.impls.orient.OrientBaseGraph;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
import com.tinkerpop.frames.FramedGraphFactory;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class OrientDBTraversalTest {

    private ODatabaseSession db;

    @BeforeEach
    public void setup() {
        var builder = OrientDBConfig.builder()
                .addConfig(OGlobalConfiguration.CREATE_DEFAULT_USERS, true);
        final OrientDB orientDB = new OrientDB("memory:",
                OrientBaseGraph.ADMIN,
                OrientBaseGraph.ADMIN,
                builder.build());
        orientDB.create("test", ODatabaseType.MEMORY);
        db = orientDB.open("test", "admin", "admin");
        OSchema schema = db.getMetadata().getSchema();
        if (!schema.existsClass("Person")) {
            db.command("CREATE CLASS Person EXTENDS V");
        }
        if (!schema.existsClass("Pet")) {
            db.command("CREATE CLASS Pet EXTENDS V");
        }
        if (!schema.existsClass("Owns")) {
            db.command("CREATE CLASS Owns EXTENDS E");
        }

        OVertex person = db.newVertex("Person");
        person.setProperty("name", "John Doe");
        person.save();

        OVertex pet = db.newVertex("Pet");
        pet.setProperty("name", "Buddy");
        pet.save();

        OEdge ownsEdge = person.addEdge(pet, "Owns");
        ownsEdge.save();
    }

    @Test
    void newApiVariable() {
        String query = """
                select $path.out('Owns')[0].name as name from (
                    select $current as person
                    from (select from Person where name = 'John Doe')
                )
                let $path = (traverse out('Owns') from $current.person)""";
        try (OResultSet resultSet = db.query(query)) {
            assertTrue(resultSet.hasNext());

            while (resultSet.hasNext()) {
                System.out.println(resultSet.next().toJSON());
            }
        }
    }

    @Test
    void newApiLet() {
        String query = """
                select $path1.name as name from (
                    select $current as person
                    from (select from Person where name = 'John Doe')
                )
                let $path = (traverse out('Owns') from $current),
                    $path1 = $path.out('Owns')""";
        try (OResultSet resultSet = db.query(query)) {
            assertTrue(resultSet.hasNext());

            while (resultSet.hasNext()) {
                System.out.println(resultSet.next().toJSON());
            }
        }
    }

    @Test
    void oldApiVariable() {
        final FramedGraphFactory framedGraphFactory = new FramedGraphFactory();
        String query = """
                select $path.out('Owns')[0].name as name from (
                    select $current as person
                    from (select from Person where name = 'John Doe')
                )
                let $path = (traverse out('Owns') from $current.person)""";
        final ODatabaseDocumentTx rawGraph = framedGraphFactory.create(new OrientGraph((ODatabaseDocumentInternal) db))
                .getBaseGraph()
                .getRawGraph();
        final OCommandRequest cmdQuery = rawGraph.command(new OSQLSynchQuery<ODocument>(query));
        final OConcurrentLegacyResultSet<Object> resultSet = cmdQuery.execute();
        assertTrue(resultSet.iterator().hasNext());
        final ODocument first = (ODocument) resultSet.getFirst();
        assertEquals("Buddy", first.getProperty("name"));
    }

    @Test
    void oldApiLet() {
        final FramedGraphFactory framedGraphFactory = new FramedGraphFactory();
        String query = """
                select $current as person,
                       $path1.name as petName,
                       $path
                from (select from Person where name = 'John Doe')
                let $path = (traverse out('Owns') from $current),
                    $path1 = first($path.out('Owns'))""";
        final ODatabaseDocumentTx rawGraph = framedGraphFactory.create(new OrientGraph((ODatabaseDocumentInternal) db))
                .getBaseGraph()
                .getRawGraph();
        final OCommandRequest cmdQuery = rawGraph.command(new OSQLSynchQuery<ODocument>(query));
        final OConcurrentLegacyResultSet<Object> resultSet = cmdQuery.execute();
        assertTrue(resultSet.iterator().hasNext());
        final ODocument first = (ODocument) resultSet.getFirst();
        assertEquals("Buddy", first.getProperty("petName"));
    }

    @AfterEach
    public void tearDown() {
        db.command("DELETE VERTEX Person");
        db.command("DELETE VERTEX Pet");
        db.command("DELETE EDGE Owns");

        db.close();
    }
}
tglman commented 2 months ago

Hi,

Thanks to report this, will check it.

mikhalov commented 1 month ago

@tglman Checked the fix in the new release, but one case is still failing:

@Test
    void newApiVariable() {
        String query = """
                select $path.out('Owns')[0].name as name from (
                    select $current as person
                    from (select from Person where name = 'John Doe')
                )
                let
                $person = person,
                $path = (traverse out('Owns') from $current.$person)""";
        try (OResultSet resultSet = db.query(query)) {
            assertTrue(resultSet.hasNext());

            while (resultSet.hasNext()) {
                System.out.println(resultSet.next().toJSON());
            }
        }
    }

com.orientechnologies.orient.core.exception.OCommandExecutionException: Cannot use variable as query target: $current.$person

tglman commented 4 weeks ago

Hi,

Did you try to just use $person as target ?

Regards

mikhalov commented 2 weeks ago

@tglman, hi I tried, but I'm still getting an exception, even with the test I shared above.