Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Support parent/sibling selection in the query language #1

Open
adamschmideg opened this Issue · 4 comments

2 participants

@adamschmideg

First of all: great work! I like the light-weight database approach and the comprehensive documentation.

I understand it's possible to get the parents of a node:

  child = db.select('/user/handle');
  child.parent(); // -> gives the user node

My feature request is if it's possible to extend the query language so I can write child.select('..') to get the same result.

I also wonder how I could get the previous or next sibling of a node in an array.

@danski
Owner

Hey! Very pleasantly surprising to get a feature request before I properly announce the library (I'm working on a decent REPL and API docs before publishing fully).

I actually agree that this would be a neat feature, but it requires some fairly tough changes to the descent operation performed during query operation - while SpahQL currently uses the actual JS call stack for descent, instead we'd have to pass about an array stack which may be popped when encountering a parent operator (".."). I wonder if "+1" would be a valid next-sibling operator as well - what do you think?

// Parent selector
db.select("//status/..") //-> select all parent objects of a "status" key
// Sibling selector
db.select("/timeline/first/+1") //-> equivalent to "/timeline/1"
db.select("/timeline/last/-1") //-> select penultimate status
@danski
Owner

Actually, let's revise the sibling selectors. Applying a path component semantic for elements at the same depth seems wildly inconsistent. Here's some possibilities for you to comment on:

db.select("/timeline/first|sibling(+1)") // general pattern of KEY . PIPE . TRAVERSAL_FUNCTION . BRACKET_LEFT . ARGS . BRACKET_RIGHT . FILTER_QUERIES
db.select("/timeline/first+1") // potentially dangerous, as "+1" and "-1" are also valid string object keys
@adamschmideg

Sorry about my late response. I checked the in-browser REPL which is nice to play with, I also had a look at the source.

I think your PIPE syntax would be great, and it wouldn't break the current operation. Here is my slightly different syntax

db.select("/timeline/first/|next/name") // the next function takes no argument
db.select("/timeline/last/|sibling(-1)") // sibling takes an argument

It could be implemented in a general (an unsafe) way: db.select("/foo/|traversal/bar") would be equivalent with db.select("/foo").traversal().select("/bar"). This would make extension quite easy, the user just has to add their traversal function to the SpahQL prototype. So db.select("/foo/bar").select("|parent") would work out of the box.

@danski
Owner

I think including the slash for arbitrary traversal functions isn't quite right - let's assume for a moment that the slash doesn't exist in the language. The query:

/a/b//c

Could be seen as a macro for "descend" and "descendRecursive" traversals:

descend('a')|descend('b')|descendRecursive('c')

However we allow / and // as aliases for baked in descent functions - meaning the slashes have an inherent meaning relating to descent. A pipe is traversal-agnostic and essentially boils down to function-currying:

descend('a')|descend('b')|parent //-> pass output of each function into the next and return the final value
/a/b|parent //-> Truncated version of above

Bear in mind that pipes are not parts of a path component but would actually terminate parsing of the current query and tell the query parser to expect a new path query or traversal function, which will receive the result array from the previous token as input data. Here's an example with filters:

//*[/.type == 'array'] | firstChild //-> Find all arrays and return the first child
//*[/.type == 'array']/0 //-> Equivalent in current syntax

I'm still in two minds about whether or not to actually implement this, but I'm fairly certain the currying pattern is what you're after - which would mean no slashes before pipes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.