WQL is both verbose and a bit unsightly.
This proposal offers a much more compact syntax which could also theoretically be integrated with the the card naming conventions in inclusion syntax. It is admittedly still a little unsightly.
some of the funky rules:
1. conditions inside a () expression may be separated by commas, or by any of the condition shortcuts:
name (first position only)
: content
<_, <-, <=, _>, =>, -> (references)
<...> type
; "and there exists"
2. if a bare string is encountered in the first position it is assumed to be a name.
3. '+' is a special 'binary' operator that may be used interchangeable with a name condition (in the first position). essentially: (X)+(Y) == (left:(X),right(Y)). if one side is omitted, it is assumed to refer to _self, except in the context immediated following ; in which case it refers to _this.
4. ';' creates a new context in which _this refers to the card returned by the outer context. it can be though of as "and there exists" operator. it is used in combination with the '+' operator (using the implicit _this) to specify the existence of "plus" cards.
here are examples of existing WQL syntax followed by
translation to compact syntax. in some case multiple variants are
specified, referring to different levels of short-cutting.
{"name": "Lewis Hoffman"}
Lewis Hoffman
{"type": "Fruit"}
<Fruit>
{"content": "Kiwi"}
:Kiwi
{"type":"Fruit", "content": "Kiwi"}
<Fruit>:Kiwi
{"content": ["eq", "Kiwi"] }
:eq Kiwi
{"content": ["=", "Kiwi"] }
:= Kiwi
{"type": ["in", "Release", "Point Releases"] }
(type:[in Release, Point Release])
<[Release, Point Releases]>
{"content": ["match", "Matt"] }
:~Matt
{"refer_to": "John Abbe"}
(refer_to:"John Abbe")
-> John Abbe
{"referred_to_by": "John Abbe"}
<- John Abbe
{"link_to": "John Abbe"}
_> John Abbe
# link, include, reference: _>, =>, ->
# (reference includes both, thus double line)
{"part": "website"}
part:website
# haven't used this one much, it don't need no shortcut
{"right": "email"}
*+email
{"left": "email"}
email+*
# this (condition)+(condition) syntax implies you must always specify left and right together in a pair. use the wildcard to say "no conditions", otherwise it will assume _self.
{"right_plus": "email"}
;+email
{"left_plus": "email"}
;email+
{"plus":"email"}
;+email || ;email+
# ';' creates a special context where the '+' operator may only specify one side, and the other side is assumed to refer to card that would be returned by the condition. if we use '_this' to stand in for the "other" side, a fully explicit version might be like this:
{"right_plus": "email"}
;(name:_this+email)
{"left_plus": "email"}
;(name:email+_this)
# having to specify the condition twice and join with || to do plus is admittedly a bit of a pain. however I actually 'want' the language to reflect that we're doing twice as much work on the backend in this case.
{"type":"Ticket","right_plus":["status",{"content":"closed"}]}
<Ticket>;+status:closed
{"type": "User", "not": {"plus": "nerdy nickname"}}
<User>;!+nerdy nickname;!nerdy nickname+
# here ;! needs to be a special operator.
# if it were a generic !, then it would have to be:
<User>!;+nerdy nickname,!;nerdy nickname+
{"type": "User", "sort": "name", "dir": "desc", "limit": 8}
<User>↓name≤8
# ha! if only I could figure out the keyboard shortcuts for unicode this would be cool.
{"left":{"found_by":"_self+pattern for action"},"right":"also send to"}
(↵+pattern for action)+also sent to
# the unicode is the pretty way to do this but we might want an easier to type substitute
(<..self+pattern for action)+also sent to
{"type":"committee", "plus":["chair",{"refer_to":"_self"}]}
<comittee>;+chair->_self
{"or":
{
"found_by":"_self+action email committee members",
"and":{"found_by":"_self+action email legislators"}
}
}
↵+action email committee members || ↵+action email legislators
{"referred_to_by":
{"left":{"found_by":"_self+pattern_for_action"},
"right":"send to"}
}
<- (↵+pattern_for_action)+sent to
# parens omitted as '+' has higher precedence/binding than '<-'
{"referred_to_by":{"left":"_self", "right":"Action Pattern"}}
<- +Action Pattern
{"type":"Stakeholder",
"referred_to_by":
{"included_by":
{"referred_to_by":
{"left":
{ "referred_to_by":
{"left":
{"referred_to_by":
{"left":"_self",
"right":"action pattern"
},
"right_plus":["action type",{"refer_to":"testimony"}]
},
"right":"bill"
}
},
"right":"committee"
}
}
}
}
<Stakeholder> <- ( <= ( <- ((<- (( <-
((+action pattern;+action type->testimony)+bill))+committee)))))
# hmm... So, in this giant case I'm not sure I can claim this is a lot more understandable.
# but it is a *lot* shorter! haha
since ':' is already in use, I'd propose '=' as the generic comparison, and ',' as generic separator.
so to fully genericise
<Ticket>;+status:open;+tag->wql
would be:
(type=Ticket,exists=(name=_this+status,content=open),exists=(name=_this+tag,refer_to=(name=wql)))
--Lewis Hoffman.....Wed Feb 03 14:16:34 -0800 2010
dammit!! ';' used to be '&', I changed it partly because it intuitively suggests the low precedence, but also because I wanted something url friendly. I forgot that BOTH '&' and ';' are used a param separators in URLs. and of course plus doesn't work right.
I'd love to be able to jam this syntax in urls without a bunch of %0D crap, but that is going to be a real challenge.
--Lewis Hoffman.....Wed Feb 03 14:25:35 -0800 2010
we almost never use the 1 arg "plus"; the 2 arg plus is one of the most common things we use. How would you represent that?
--Ethan McCutchen.....Wed Feb 03 16:05:18 -0800 2010
+discussed in support tickets
+relevant user stories