Hi,

*** This email is primarily for Josh (and Kuppitz). However, if others are 
interested… ***

So I did a lot of thinking this weekend about structure/ and this morning, I 
prototyped both graph/ and rdbms/.

This is the way I’m currently thinking of things:

        1. There are 4 base types in structure/.
                - Primitive: string, long, float, int, … (will constrain these 
at some point).
                - TTuple<K,V>: key/value map.
                - TSequence<V>: an iterable of v objects.
                - TSymbol: like Ruby, I think we need “enum-like” symbols 
(e.g., #id, #label).
        
        2. Every structure has a “root.”
                - for graph its TGraph implements TSequence<TVertex>
                - for rdbms its a TDatabase implements TTuple<String,TTable>

        3. Roots implement Structure and thus, are what is generated by 
StructureFactory.mint().
                - defined using withStructure().
                - For graph, its accessible via V().
                - For rdbms, its accessible via db().

        4. There is a list of core instructions for dealing with these base 
objects.
                - value(K key): gets the TTuple value for the provided key.
                - values(K key): gets an iterator of the value for the provided 
key.
                - entries(): gets an iterator of T2Tuple objects for the 
incoming TTuple.
                - hasXXX(A,B): various has()-based filters for looking into a 
TTuple and a TSequence
                - db()/V()/etc.: jump to the “root” of the withStructure() 
structure.
                - drop()/add(): behave as one would expect and thus.

————

For RDBMS, we have three interfaces in rdbms/. 
(machine/machine-core/structure/rdbms)

        1. TDatabase implements TTuple<String,TTable> // the root structure 
that indexes the tables.
        2. TTable implements TSequence<TRow<?>> // a table is a sequence of rows
        3. TRow<V> implements TTuple<String,V>> // a row has string column names
        
I then created a new project at machine/structure/jdbc). The classes in here 
implement the above rdbms/ interfaces/

Here is an RDBMS session:

final Machine machine = LocalMachine.open();
final TraversalSource jdbc =
        Gremlin.traversal(machine).
                        withProcessor(PipesProcessor.class).
                        withStructure(JDBCStructure.class, 
Map.of(JDBCStructure.JDBC_CONNECTION, "jdbc:h2:/tmp/test"));
        
System.out.println(jdbc.db().toList());
System.out.println(jdbc.db().entries().toList());
System.out.println(jdbc.db().value("people").toList());
System.out.println(jdbc.db().values("people").toList());
System.out.println(jdbc.db().values("people").value("name").toList());
System.out.println(jdbc.db().values("people").entries().toList());

This yields:

[<database#conn1: url=jdbc:h2:/tmp/test user=>]
[PEOPLE:<table#PEOPLE>]
[<table#people>]
[<row#PEOPLE:1>, <row#PEOPLE:2>]
[marko, josh]
[NAME:marko, AGE:29, NAME:josh, AGE:32]

The bytecode of the last query is:

[db(<database#conn1: url=jdbc:h2:/tmp/test user=>), values(people), entries]

JDBCDatabase implements TDatabase, Structure. 
        *** JDBCDatabase is the root structure and is referenced by db() *** 
(CRUCIAL POINT)
        
Assume another table called ADDRESSES with two columns: name and city.

jdbc.db().values(“people”).as(“x”).db().values(“addresses”).has(“name”,eq(path(“x”).by(“name”))).value(“city”)
        
The above is equivalent to:

SELECT city FROM people,addresses WHERE people.name=addresses.name

If you want to do an inner join (a product), you do this:

        
jdbc.db().values(“people”).as(“x”).db().values(“addresses”).has(“name”,eq(path(“x”).by(“name”))).as(“y”).path(“x”,”y")

The above is equivalent to:

SELECT * FROM addresses INNER JOIN people ON people.name=addresses.name

NOTES:
        1. Instead of select(), we simply jump to the root via db() (or V() for 
graph).
        2. Instead of project(), we simply use value() or values().
        3. Instead of select() being overloaded with by() join syntax, we use 
has() and path().
                - like TP3 we will be smart about dropping path() data once its 
no longer referenced.
        4. We can also do LEFT and RIGHT JOINs (haven’t thought through FULL 
OUTER JOIN yet).
                - however, we don’t support ‘null' in TP so I don’t know if we 
want to support these null-producing joins. ?
        
LEFT JOIN:
        * If an address doesn’t exist for the person, emit a “null”-filled path.

jdbc.db().values(“people”).as(“x”).
  db().values(“addresses”).as(“y”).
    choose(has(“name”,eq(path(“x”).by(“name”))),
      identity(),
      path(“y”).by(null).as(“y”)).
  path(“x”,”y")

SELECT * FROM addresses LEFT JOIN people ON people.name=addresses.name

RIGHT JOIN:

jdbc.db().values(“people”).as(“x”).
  db().values(“addresses”).as(“y”).
    choose(has(“name”,eq(path(“x”).by(“name”))),
      identity(),
      path(“x”).by(null).as(“x”)).
  path(“x”,”y")


SUMMARY:

There are no “low level” instructions. Everything is based on the standard 
instructions that we know and love. Finally, if not apparent, the above 
bytecode chunks would ultimately get strategized into a single SQL query 
(breadth-first) instead of one-off queries (depth-first) to improve performance.

Neat?,
Marko.

http://rredux.com <http://rredux.com/>




Reply via email to