Sent from my iPhone

> On Apr 14, 2016, at 12:09 PM, Marko Rodriguez <okramma...@gmail.com> wrote:
> 
> Hi Mark,
> 
>> A logo would be awesome! Thanks. 
> 
> Please see attached.
> 
>> I'd love to help with the tutorial. I think it will not only help the 
>> Gremlin community, but the library will get a lot better as a result. Just 
>> let me know where to start and what you'd like to see. 
> 
> We have a way of creating easily creating/publishing tutorials in TinkerPop3. 
> 
>       http://tinkerpop.apache.org/docs/3.1.1-incubating/tutorials/
> 
> I don't know how to do it, but Stephen does. How about you do this:
> 
>       1. You fork Apache TinkerPop tp31/.
>       2. You give Stephen and I rights to your forked repository.
>       3. Stephen will create the tutorial stub. (this will help me learn when 
> I see his commit).
>               - @stephen: call it gremlin-language-variants
>       4. You and I then go to town on creating the tutorial.
> 
> Please read over the ticket and comment as appropriate so we jive and are on 
> the same page going into this:
>       https://issues.apache.org/jira/browse/TINKERPOP-1232
> 
> Thank you Mark,
> Mark…………….o.
> 
> http://markorodriguez.com
> 
> <gremlinpy-logo.png>
> 
> 
> 
> 
> 
> 
> 
> 
> 
>> 
>>> On Thursday, April 14, 2016 at 10:47:14 AM UTC-4, Marko A. Rodriguez wrote:
>>> Hi Mark,
>>> 
>>> I think that any host language embedding should use its native idioms 
>>> while, at the same time, staying as true as possible to Gremlin-Java (not 
>>> Gremlin-Groovy -- though they are nearly identical). I would argue that 
>>> Gremlin-Java is the "true representation" of the language. So what do I 
>>> mean by native idioms?
>>> 
>>>     in_V vs inV     // if camel case isn't a thing in the native language
>>>     $g vs. g                // of course if thats how variables are 
>>> referenced
>>>     
>>> …huh, can't think of anything else :). But I hope you get the point. 
>>> 
>>> I notice in Gremlin-Py you do g.v(2) vs g.V(2). Why is that? 
>>> 
>>> *** Would you be interested in working on a tutorial (with me?) about the 3 
>>> ways to create a Gremlin language variant. Given your expertise in Python 
>>> and the existence of Gremlin-Py, I think we can both (1) make a good 
>>> tutorial to teach others down the line and (2) spruce up Gremlin-Py's 
>>> documentation and appearance (e.g. you need a Gremlin logo! -- Gremlin with 
>>> a Snake around his neck? -- want me to make you one?). ***
>>>     Please see: https://issues.apache.org/jira/browse/TINKERPOP-1232        
>>> 
>>> Thanks Mark,
>>> Marko.
>>> 
>>> http://markorodriguez.com
>>> 
>>> On Apr 14, 2016, at 8:28 AM, Mark Henderson <emeh...@gmail.com> wrote:
>>> 
>>> I think writing "Gremlin/Groovy" in a host language is pretty awesome as 
>>> long as it isn't too far off from writing actual Gremlin. I can revive my 
>>> PHP project if it would be helpful to the community. A JavaScript version 
>>> would probably be one that would get the most attention from developers 
>>> today, but JS, even with es6, doesn't have the flexibility (maybe with 
>>> Proxies) with its objects where you wouldn't have to write a full-on 1-to-1 
>>> api equivalent of Gremlin (let alone mimicking Groovy). It seems like a 
>>> Ruby version would be doable by implementing `method_missing` 
>>> 
>>> Thanks for adding Gremlinpy to the new site (I need to clean up the code a 
>>> bit *shame*)
>>> 
>>> On Thursday, April 14, 2016 at 9:34:40 AM UTC-4, Marko A. Rodriguez wrote:
>>> Hi Mark,
>>> 
>>> Exactly. I never saw Gremlin-Py until now and just noticed it on the Apache 
>>> TinkerPop homepage. That is good stuff. Moreover, as you say, there is a 
>>> distinction between:
>>> 
>>>     1. Writing Gremlin in a host language.
>>>     2. Communicating to a GremlinServer-compliant server in a host language.
>>> 
>>> The (1) is about query syntax and the (2) is about protocol stuffs.
>>> 
>>> Lots of the libraries either confound the two or just do (2) with (1) 
>>> simply being a Groovy String (cheesy).
>>> 
>>> I would like to see a lot more (1) of the community libraries as I think 
>>> this is one of the big selling points of Gremlin -- write in your native 
>>> language.
>>> 
>>> BTW, I added Gremlin-Py to the description in the "host language embedding" 
>>> section here: http://www.planettinkerpop.org/#gremlin (2 scrolls down).
>>> 
>>> Thanks for your thoughts,
>>> Marko.
>>> 
>>> http://markorodriguez.com
>>> 
>>> On Apr 14, 2016, at 7:06 AM, Mark Henderson <emeh...@gmail.com> wrote:
>>> 
>>> I've written "native object to Gremlin" libs in both PHP and Python and it 
>>> isn't too bad/not too far from Groovy. The biggest issues were around 
>>> indices [..] (when it had that format) and closures "{x -> ...}", but 
>>> otherwise both langs allowed for easy query building. 
>>> 
>>> It basically looked like this in PHP:
>>> 
>>> $g= Gremlin();
>>> $g->V()->has('"name"','mark');
>>> echo (str)$g;  //g.V().has("name",SOME_BOUND_VAR_1)
>>> 
>>> Works pretty much the same with the Python lib that I've been building 
>>> (https://github.com/emehrkay/gremlinpy). 
>>> 
>>> If we wanted to actually execute the query on every step, that wouldn't be 
>>> too difficult to implement with Gremlinpy. Gremlinpy is a simple linked 
>>> list, it looks at g.V().has('"name"', 'mark') as three token objects with a 
>>> shared pool of bound parameters. It creates the string query and parameters 
>>> dictionary when you cast the list to a string. The only change needed would 
>>> be to bind in a library like Gremlinclient 
>>> (https://github.com/davebshow/gremlinclient), build the query with every 
>>> step, and send it to the server.
>>> 
>>> res = g.V() # sends request
>>> res2 = g.V().has('"name"', 'mark') # second request
>>> ...
>>> 
>>> The remaining difficulty would be deciding what gets bound. Maybe you can 
>>> pass in a key val pair for what you want bound
>>> 
>>> res = g.V().has('"name"',{'NAME':'mark'})  # g.V().has("name",NAME)
>>> 
>>> 
>>> 
>>> On Tuesday, April 12, 2016 at 10:54:08 PM UTC-4, Dmill wrote:
>>> Yes a lot of the points you bring up are valid. 
>>> 
>>> One of the main problems with stringifying everything is that it does not 
>>> allow for some of the stuff I mentioned in my PS. That is to name "smart 
>>> merges". This query building behavior that makes use of scopes is 
>>> unfortunately the standard for frameworks in the industry. 
>>> This is mostly due to the SQL heritage and it's declarative nature ; 
>>> ordering of "steps" doesn't matter so it allows for easy "after the fact" 
>>> client side filtering. It's not uncommon to have a base query that gets 
>>> altered by some filtering data. In some cases it's a simple has() that 
>>> needs to be injected somewhere, in other cases it's a repeat() that needs 
>>> to be completely altered.
>>> Use cases can get a little complicated here but in it's simplest form 
>>> imagine having to add/remove entries to/from a match(). Of course that 
>>> scenario works well with a toString approach but for other steps, not so 
>>> well. Our experience has been that the builder needs to be aware of the 
>>> step's signatures to resolve merges.
>>> 
>>> So sure this is another problem entirely, in the end users can't really do 
>>> this with string queries either. But for widespread adoption it would be 
>>> best if the query builder could handle these scenarios. 
>>> 
>>> Also to bounce off of some of your comments : 
>>> 
>>> > $id -> "~id"
>>> > $label -> "~label"
>>> > g.V().out("%%x")
>>> > $g->V()->has($id,Number::long(36))  ==> g.V().has("id",36l)
>>> 
>>> All of the above are absolutely possible. But it's a lot to keep in mind 
>>> for users that are already trying to figure out how Gremlin works. Now they 
>>> also need to translate gremlin-groovy into gremlin-php. 
>>> One of the advantages of going the hard route and keeping track of all step 
>>> signatures instead of a toString approach is that you can significantly 
>>> reduce the above cases. The builder can resolve quite a few of these 
>>> automatically and when conflicts arise it can do it's best to resolve it 
>>> and throw/log a warning telling the user how he could explicit his query.
>>> 
>>> >For your Date example, you would have to have a special "toString()" for 
>>> >PHP dates to Java dates (or whichever backend ScriptEngine is being used).
>>> 
>>> There are no PHP Dates [insert desperate crying emoji here]. PHP sucks with 
>>> typing. It's got it's good points but this kind of stuff is not one of 
>>> them. Basically PHP Dates come in various forms, from Integer timestamps to 
>>> String and only the user really knows what he wants. We can provide this 
>>> functionality like you did with long() but it's another thing to keep in 
>>> mind.
>>> 
>>> One point we haven't gone over have been lambdas. We can't really toString 
>>> these. I guess this is where customStep() or script() come in play.
>>> 
>>> To wrap it up, a toString query builder is absolutely an option and could 
>>> cover a lot of the API. In fact in PHP we could magically make any API 
>>> method available, $g->something("~label", "lolo") would stringify to 
>>> g.something(label, "lolo") regardless of whether or not the step exists. 
>>> But this involves quite a few language specific alterations and doesn't 
>>> provide much (if any) functional benefit. 
>>> It would be so much easier for people to just write a gremlin-groovy string 
>>> as it's well documented and doesn't need any extra knowledge.
>>> If on the other hand the query builder has features like mentioned in the 
>>> PS or earlier in this post, it's well worth the effort. I believe most 
>>> people who build their own query builders do so to support some form of 
>>> extra feature they wouldn't have by using gremlin-groovy string queries. 
>>> But such a query builder enters the realm of non-trivial (although not 
>>> unachievable). A first step in helping people make these builders would be 
>>> to provide an easily parseable list of signatures for the most desirable 
>>> classes. Maybe something along the lines of a yaml file.
>>> 
>>> Anyways I'm just thinking out loud at this point.
>>> 
>>> 
>>> 
>>> 
>>> 
>>> On Tue, Apr 12, 2016 at 9:42 PM, Marko Rodriguez <okram...@gmail.com> wrote:
>>> Hi Dylan,
>>> 
>>> Your email is excellent. Thank you for breaking things down for me. Here 
>>> are some responses.
>>> 
>>> 1. Method overloading :
>>> 
>>> abstract class Query {
>>>    public function has(PropertyKey $key); //1
>>>    public function has(PropertyKey $key, Object $value); //2
>>>    public function has(Label $label, String $value); //3
>>>    public function has(VertexId $id, Long $value); //4
>>>    public function has(VertexId $id, Int $value); //5
>>>    public function has(VertexId $id, Predicate $p); //6
>>> }
>>> 
>>> The above is illegal in languages like PHP (or javascript?). Instead we're 
>>> stuck with :
>>> 
>>> abstract class Query {
>>>    public function has(Array $args);
>>> }
>>> 
>>> We're then left to figure out what is what in the array and sort out how we 
>>> need to stringify the output. 
>>> 
>>> I was thinking, why would you need to introspect into the array? Just 
>>> toString() each element in the array with a comma (,) in between. For 
>>> instance:
>>> 
>>> * has("age",32) ==> has(["age",32]) ==> has("age",32) // all String array 
>>> element need " " wrappers.
>>> * has("age") ==> has(["age"]) ==> has("age")
>>> * has("person","name","marko") ==> has(["person","name","marko"]) ==> 
>>> has("person","name","marko")
>>> 
>>> Thus, Gremlin-PHP have one has()-method and that method just iterates the 
>>> arguments and toString()'s thing accordingly with comma deliminators.
>>> 
>>> If the user does $g->V()->has("label", "user") do we add quotes to the 
>>> first argument or is it a label/id? What about the second argument, is it a 
>>> predicate? etc.  This gets complexe very quickly.
>>> 
>>> The universal rule --- if its a String add quotes. If its not, don't. 
>>> 
>>> $id -> "~id"
>>> $label -> "~label"
>>> 
>>> $g->V()->has($label,"user")
>>> 
>>> And what if I had $g->V()->has("id", 36) . PHP only supports Int so one of 
>>> the two signatures (4 or 5) needs to give as we have a major conflict. This 
>>> example is fictional for has() but I've run into this on a couple of other 
>>> methods, just can't remember which. 
>>> 
>>> Yea, that sucks. Well, you could do this:
>>> 
>>> $g->V()->has($id,Number::long(36))  ==> g.V().has("id",36l)
>>> 
>>> This would, of course, bind you to Gremlin-Groovy as the ultimate 
>>> ScriptEngine.
>>> 
>>> Another example would be  g.V().has(id, neq(m)) . We could imagine the 
>>> following PHP equivalent $g->V()->has(new Id(), Predicate::neq("m")) where 
>>> Id() is a class that helps us recognize this type, and neq() a static 
>>> method of Predicate. However "m" has to be passed as string and we have no 
>>> clue what m is... is this a string or a binding or a server side variable? 
>>> More on this in point 2.
>>> 
>>> Well, this is the same problem in Gremlin-Java. where() is ALWAYS bindings 
>>> and has() is ALWAYS objects. Thus:
>>> 
>>> $g->V()->where("a",Predicate::neq("m")) ==> g.V().where("a",neq("m")) // 
>>> again strings always get " "-wrappers.
>>> 
>>> To close things off here there's also the case of signatures like 
>>> out(String... edgeLabels) that need their own logic.
>>> 
>>> Again, just toString() each object in the array and insert commas between.
>>> 
>>> $g->V()->out(["created","knows"]) ==> g.V().out("created","knows")
>>> 
>>> 
>>> Conclusion: There's a lot of manual work that needs to go into separating 
>>> the logic between signatures and handling special cases. Part of this can 
>>> be automated if your language supports magic getters and setters by parsing 
>>> the javadocs for example. But not only is that an if, the rest will still 
>>> be manual. This step is maintenance heavy.
>>> 
>>> I see the biggest pains being:
>>> 
>>>     1. Having to implement each method.
>>>     2. Having to have helper classes for P, T, Order, Column, etc.
>>> 
>>> This is simply a matter of fat fingering stuff in and not anything 
>>> implementation-wise that is problematic -- ????….
>>> 
>>> 2. Conflicts
>>> 
>>> Because we're manipulating strings it's really hard to tell a few items 
>>> appart (binding vs server variable vs string; Theres a reason why I 
>>> separate binding and variable). 
>>> 
>>> For instance in the example above of gremlin : g.V().has(id, neq(m)) vs 
>>> PHP: $g->V()->has(new Id(), Predicate::neq("m")) we don't know what to make 
>>> of m. Is this a binding or a string or even a variable that was previously 
>>> set in the session? There is no clean way of working around this.
>>> 
>>> Firstly because bindings tend to be handled on a different layer than the 
>>> query builder.
>>> Secondly because methods that will help in avoiding the conflicts will also 
>>> lose typing data.
>>> For example : $g->V()->has(new Id(), Predicate::neq(Query::variable("m"))) 
>>> could generate the proper query by outputting m without quotes but we don't 
>>> know what type m is so in some cases it might be tricky to select the 
>>> proper signature.
>>> 
>>> Conclusion: there are a number of ways around this point. We use prefixes 
>>> B_m or V_m and a hack to ignore signatures altogether when in this 
>>> scenario. It's not that these aren't solve-able they just aren't trivial.
>>> 
>>> Hm. Yea, I'm not to smart about sever variables. Out of my butt you could 
>>> create a "crazy String" for those an then do replaceAll-style updates.
>>> 
>>> g.V().out("%%x")
>>> 
>>> replaceAll("%%x",x)
>>> 
>>> ?
>>> 
>>> 
>>> 3. API
>>> 
>>> Why we would need traversal, graph, vertex and edge APIs are quite self 
>>> explanatory for everyday work with Gremlin. I'm just going to expose why we 
>>> would also require some Java classes as well. 
>>> 
>>> Because JSON is lossy by nature we often have to cast variables to certain 
>>> types. For example by submitting these kind of scripts : 
>>> g.V(1).property("date", new Date(B_m)); with B_m = timestamp. This is just 
>>> another case that is difficult to cover. 
>>> 
>>> This adds onto the other points in making a gremlin language variant 
>>> non-trivial.
>>> 
>>> All of the above can be worked around by using an injection method that 
>>> just appends a string to the query : $g->customStep("V().has(id, neq(m))") 
>>> but that's besides the point.
>>> 
>>> 
>>> Ah. Classy. Note that in ?3.2.1? we might support script()-step.
>>> 
>>> g.V().script("out().map{ it.name }")
>>> 
>>> …to enable lambdas in remote'd traversals (Server or OLAP).
>>> 
>>> For your Date example, you would have to have a special "toString()" for 
>>> PHP dates to Java dates (or whichever backend ScriptEngine is being used).
>>> 
>>> $g->V()->property("data", phpDate)
>>> 
>>> Your Array-string-ifier would not just call toString() blindly on the 
>>> objects of the array arguments, but would do stuff like:
>>> 
>>> if(object instanceof String)
>>>   return \" + object.toString() + "\;
>>> else if(object instanceof Date)
>>>   return "new Date(…)";
>>> else
>>>   return object.toString()
>>> 
>>> 
>>> Final Conclusion: It's not a trivial task. Of course the examples above are 
>>> very verbose and achieving something closer to gremlin in style is possible 
>>> but there are always going to be "gotchas" users will need to keep in mind. 
>>>  A while back in TP2 I released a php library for this (the one we 
>>> currently use in our projects). I decided to remove it as it was too much 
>>> maintenance to get it to work across user causes so I decided to 
>>> concentrate on our own one (some choices made in 2. wouldn't have worked 
>>> for other cases)
>>> I'm convinced there's got to be a way of reconciling everything and getting 
>>> this to work flawlessly but it's going to require a lot of thought/work
>>> 
>>> 
>>> PS: I mentioned some other points like managing multiple versions of 
>>> gremlin (for two lines of releases) which is a real headache. 
>>> For performance it may be good to allow the builder to handle multiple 
>>> lines, which comes with it's load of complications as well. 
>>> And then there's the ability to "block" queries and either inject them into 
>>> each other or merge them together which simplifies unit testing and extends 
>>> functionality :
>>> 
>>> $query = $g->V()->out("likes")->flag("flagname")->has("age", 20);
>>> // Some logic here accesses new information and realizes the query needs 
>>> altering
>>> $query->getFlag("flagname")->out("hates", true) // true for merge
>>> $query->toString(); // g.V().out('likes', hates').has('age', 20)
>>> 
>>> But this point alone could warrant it's own email as it is relatively 
>>> complex. Though TP3 has simplified some cases thanks to union() and some 
>>> other steps.
>>> 
>>> Our builder supports all of the above so if you have any questions feel 
>>> free to ask me.
>>> 
>>> Phew that was long. I'll add this to the ticket in a bit.
>>> 
>>> 
>>> Yes, maintenance seems the biggest pain. Every new method to Gremlin-Java 
>>> requires updates to Gremlin-PHP ---- perhaps there is a programmatic way to 
>>> introspect the Java source file (or JavaDoc) and generate the code 
>>> automagically?
>>> 
>>> public GraphTraversal out(final String… edgeLabels) 
>>>     ==auto-write==>
>>> out(Array… edgeLabels) {
>>>   $string -> $string + ".out(" + StringHelper::toString(edgeLabels) + ")";
>>> }
>>> 
>>> 
>>> If you could do that, then the only code you actually have to 
>>> write/maintain (besides the introspector above) is StringHelper which does 
>>> all the fancy String conversion of arguments. 
>>> 
>>> ??.
>>> 
>>> Thanks Dylan for your time,
>>> Marko.
>>> 
>>> http://markorodriguez.com
>>> 
>>> 
>>> On Tue, Apr 12, 2016 at 4:37 PM, Marko Rodriguez <okram...@gmail.com> wrote:
>>> Hello everyone,
>>> 
>>> Please see the section entitled "Host Language Embedding" here:
>>>     http://www.planettinkerpop.org/#gremlin (3 sections down)
>>> 
>>> When I was writing up this section, I noticed that most of the language 
>>> drivers that are advertised on our homepage 
>>> (http://tinkerpop.incubator.apache.org/#graph-libraries) know how to talk 
>>> to Gremlin Server via web sockets, REST, etc., but rely on the user to 
>>> create a String of their graph traversal and submit it. For instance, here 
>>> is a snippet from the Gremlin-PHP documentation:
>>> 
>>> $db = new Connection([
>>>     'host' => 'localhost',
>>>     'graph' => 'graph',
>>>     'username' => 'pomme',
>>>     'password' => 'hardToCrack'
>>> ]);
>>> //you can set $db->timeout = 0.5; if you wish
>>> $db->open();
>>> $db->send('g.V(2)');
>>> //do something with result
>>> $db->close();
>>> 
>>> $db->send(String) is great, but it would be better if the user didn't have 
>>> to leave PHP.
>>> 
>>> Please see this ticket:
>>>     https://issues.apache.org/jira/browse/TINKERPOP-1232
>>> 
>>> I think for non-JVM languages, it would be nice if these drivers (PHP, 
>>> JavaScript, Python, etc.) didn't require the user to explicitly create 
>>> Gremlin-XXX Strings, but instead either used JINI or model-3 in the ticket 
>>> above. Lets look at model-3 as I think its the easiest and more general.
>>> 
>>> For instance, they would have a class in their native language that would 
>>> mirror the GraphTraversal API. *** I don't know any other languages well 
>>> enough, so I'm just going to do this in Groovy :), hopefully you get the 
>>> generalized point. ***
>>> 
>>> public class Test {
>>> 
>>>   String s;
>>> 
>>>   public Test(final String source) {
>>>     s = source;
>>>   }
>>> 
>>>   public Test() {
>>>     s = "";
>>>   }
>>> 
>>>   public Test V() {
>>>     s = s + ".V()";
>>>     return this;
>>>   }
>>> 
>>>   public Test outE(final String label) {
>>>     s = s + ".outE(\"${label}\")";
>>>     return this;
>>>   }
>>> 
>>>   public Test repeat(final Test test) {
>>>     s = s + ".repeat(${test.toString()})";
>>>     return this;
>>>   }
>>> 
>>>   public String toString() {
>>>     return s;
>>>   }
>>> }
>>> 
>>> Then, via fluency (function composition) and nesting, you could generate a 
>>> Gremlin-Groovy (or which ever ScriptEngine language) traversal String in 
>>> the backend.
>>> 
>>> gremlin> g = new Test("g");
>>> ==>g
>>> gremlin> g.V().outE("knows")
>>> ==>g.V().outE("knows")
>>> gremlin>
>>> gremlin> g = new Test("g");
>>> ==>g
>>> gremlin> g.V().repeat(new Test().outE("knows"))
>>> ==>g.V().repeat(.outE("knows"))
>>> gremlin>
>>> 
>>> ...
>> 
>> 
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Gremlin-users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to gremlin-users+unsubscr...@googlegroups.com.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/gremlin-users/e7eb7ab6-3455-4b71-ad39-18094f2e06aa%40googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
> 
> -- 
> You received this message because you are subscribed to a topic in the Google 
> Groups "Gremlin-users" group.
> To unsubscribe from this topic, visit 
> https://groups.google.com/d/topic/gremlin-users/kTXEzJE8wEs/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to 
> gremlin-users+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/gremlin-users/5882FC8F-7B5F-4F0C-AE93-72DB8D0B102D%40gmail.com.
> For more options, visit https://groups.google.com/d/optout.

Reply via email to