Open question for the Neo4j.rb community:
ActiveNode models allow for query chaining like so:
object.foo.bar.baz
This is a powerful way to traverse entities which builds Cypher queries under the covers. It is also currently possible to name your variables for later use like so:
object.foo(:f).bar.baz(:b).pluck(:f, 'collect(b)')
This helps you dive a bit deeper without needing to write Cypher. In fact with this syntax you can also specify a relationship variable and some options:
object.foo(:f, :r).bar(nil, nil, labels: false).baz(:b).pluck(:f, 'collect(b)')
While this is great, giving arguments to associations can often confuse people. I've been playing around with a syntax like the following, which would be equivelent to the above:
object.foo.as(:f, :r).bar.with(labels: false).baz.as(:b).pluck(:f, 'collect(b)')
If we adopt a syntax like this, it could help us simplify a chunk of our code. Obviously it's a bit more typing, but it also has the advantage of being a bit more descriptive. It also shouldn't be too hard (hopefully) to convert an existing project.
One issue that I've noted is that when you have a has_one
association, there is one case where this doesn't work automatically:
object.foo.as(:f)
If foo
is a has_one
association it will return an object instead of returning a proxy, meaning that we can't chain the as
. In cases where we're accessing the has_one
association further on it the chain, there's no problem because we're expecting that there could be more than one object. An example:
object.has_many_association.foo.as(:f)
To solve this, I've thought of a couple of syntaxes:
object.foo_proxy
object.proxy_for(:foo)
The first one matches the ActiveRecord
style of having some methods defined based on the association's name. The second is probably more descriptive, but is more verbose. Maybe that's fine if this is a rare case.
There's also another case where htis syntax is perhaps more awkward:
# With current syntax:
employee.manager(rel_length: 1)
# With new syntax:
employee.manager_proxy.with(rel_length: 1).first
Obviously the new syntax would be longer in this case, but perhaps it's more clear that you're working with a proxy when you explicitly call out for a proxy.
What do you think?
I think you're mostly right that generally with the
has_one
you're returning an object, but you actually might want to chain based off of that object and not have it first make a query to get thehas_one
association object. Like:To chain that, you could do:
Though
association_proxy
hasn't been explicitly set out as part of the public API, but maybe it should be.As far as the has one with
rel_length
, I what if you wanted to find the best friend of your best friend's best friend?