Table of Contents
WQL Basics
WQL, the Wagn Query Language, is a syntax for finding Wagn cards. If you haven't come across it before, there's a brief introduction on the WQL card. This card is for those who've figured out why and where to use it but want to learn how to write the stuff.
A WQL statement defines a list of cards by their properties, their relationships to other cards, or both.
WQL is employed both by web users (in JSON) and by developers (in Ruby). Developers should have no problem translating the examples from JSON ...
Building Blocks
WQL is built out of card definitions, properties, relationships, operators, and directives to arrange the results.
Card definitions identify a card or list of cards. Every WQL statement is, as a whole, a card definition, because it defines a list of cards.
Cards are defined by their properties (name, type, content) and their relationships (linked to from X, included on Y, connected to Z...). By default WQL performs exact searches, but with operators (match, lt, gt...) can execute more complex searches.
WQL also serves to help arrange the cards by ordering and limiting results.
A +cheat sheet lists these more concisely, but without the explanation given below here:
Properties
Each card definition can describe the following card properties:
- name
- type
- content
- id (each card has a unique id that remains the same even when the name is changed)
- count
Exact Searches
Each of these properties can be used as the key in a card definition. For example, here is a search for the card named Lewis Hoffman.
{"name": "Lewis Hoffman"}
(1)
This card happens to have the id 3, so it can also be found this way:
{"id": 3}
(1)
Both the name and id uniquely identify cards in Wagn, so they each return only one item. This type query however will return a list of several items.
{"type": "Fruit"}
Exact matches on content can return lists, too.
{"content": "Kiwi"}
To narrow searches, you can combine properties:
{"type":"Fruit", "content": "Kiwi"}
(0)
Count returns the number of items in a Search:
{"return":"count", "type": "Fruit"}
6
Operators
All the above examples represent exact searches (although Wagn does its best to be include variations such as capitalization and pluralization). The entire name is "Lewis Hoffman". Or the content is exactly and only "Kiwi". WQL allows more flexible ways to constrain properties, via operators.
WQL supports the following operators:
- match, ~
- gt, >
- lt, <
- eq, =
- ne, !=
- in
In the WQL examples above, all the values in our key/value pairs are just strings, which in WQL means the operator is implicitly "=". To use operators, the syntax is as follows:
PROPERTY:[OPERATOR, VALUE]
So, the above example of cards with content equalling Kiwi:
{"content": "Kiwi"}
is actually the short form of the following:
{"content": ["eq", "Kiwi"] }
or
{"content": ["=", "Kiwi"] }
The other operators are more interesting. The in operator lets you search on the same property more than once. For example, this gets all the cards that are either Releases or Point Releases:
{"type": ["in", "Release", "Point Releases"] }
This one gets all the cards which have "Matt" anywhere in their content, even as part of a word (e.g., in "formatting"):
{"content": ["match", "Matt"] }(309)
WQL ignores word boundaries so that when you use the match operator with a property, you get all of the power and flexibility of PostgreSQL pattern matching. Note: you have to double the backslash due to escaping, e.g., to search for the whole word Matt you would use "\\mMatt\\M".
By far the most common use of operators is to search for a whole word in card contents and names. So, if you use the operator as the key, it will search in card contents and names, and automatically restrict the search to whole words (with fuzzy matching for case and pluralization/conjugation), as with the following syntax:
OPERATOR:VALUE
and the following example:
{"match": "Matt" }(17)
Relationships
Here's where it gets interesting. Cards in Wagn are related to other cards in two main ways: references (links and includes), and connections (plus cards). Since these relationships are the source of most structure in Wagn, this is the the element of WQL that adds the most depth.
All of these relationships are specified in WQL by nesting card definitions. With the exception of certain "plus" relationships, they all take this form:
RELATIONSHIP: CARD_DEFINITION
References
Cards linking to or including other cards comprise references. (note -- insert links to feature cards inline here)
WQL supports the following reference keys:
- link_to - web links
- linked_to_by
- include - embedded cards
- included_by
- refer_to - web links or embedded cards
- referred_to_by
The simplest reference relationship is the link_to. Here's how you can use WQL to find all the cards linked to the "John Abbe" card:
{"link_to": "John Abbe"}
(744)
Notice that in this case our card definition is just the card name, "John Abbe". This is a short form of the more explicit expression:
{"link_to": {"name":"John Abbe"} }
Written that way, it's easier to see why we say there are nested card definitions: curly brackets inside curly brackets.
Plus cards
Frankly, if WQL ever gets a little mind-flexing, it's in using plus cards. But that's partly because plus cards are such a flexible way of doing things. If you haven't gotten the basic ideas behind plus cards, continuing to read here will likely be very confusing. If you get the gist of plus cards, this will all make sense. But don't feel bad if you have to peek again later.
WQL supports two main plus cards keys:
- part - value defines cards that are part of a given plus card
- plus - value defines plus cards of which a given card is part
For each of those, it also supports two side-specific keys:
- left, right
- left_plus, right_plus
Part queries are generally pretty simple. Remember, if it has a part, it is always a plus card! The following finds all the cards that have "website" as a part.
{"part": "website"}
(52)
"left" and "right" do similar things, but are a bit narrower. This will get all the plus cards of which "email" is the rightmost part:
{"right": "email"}
Plus queries can get a little more involved. This is because, while a card can only ever have two part cards, it can be plussed to countless other cards. And you often want to refer to them in pairs - the other part and the plus card. For example, you might want to find all of the cards connected to "status" (the other part) where the content of X+status (the plus card) is "closed". So the plus card actually takes two definitions. Here's the syntax:
"plus":[OTHER_PART, PLUS_CARD]
...and that example we mentioned:
{"plus":["status",{"content":"closed"}]}
(557)
In that one, "status" defines the part, and {"content":"closed"} defines the plus card.
If you give the "plus" key just one card definition like a normal card definition, then it will treat it as the other part.
"plus":OTHER_PART
For example, this finds all the cards connected to status (regardless of the value of the plus cards):
{"plus":"status"}
(1362)
Users and roles
WQL lets you query the relationship of users (technically, any card with an account) and roles, using these keys:
- member_of
- member
For example, this finds all of the cards with accounts who have the GC Staff role:
{"member_of":"GC Staff"}
And this finds all of the roles that Lewis Hoffman has:
{"member":"Lewis Hoffman"}
Users and cards
You can also query what cards a user (technically, any card with an account) has created or edited, and who has been editing a card, using these keys:
- edited_by — returns every card this card-with-account (CWA) has ever edited
- editor_of — returns all CWAs who have ever edited this card (was "edited", which is now deprecated)
- created_by — returns cards this CWA created
- creator_of — returns CWA who created this card
For example, this finds all of the cards edited by John Abbe:
{"edited_by": "John Abbe"}(8344)
And this finds all of the users who have edited Wiki on Wheels:
{"edited": "Wiki on Wheels"}
Contextual Relationships
Wagn uses Virtual cards to created patterns that can be re-used in multiple contexts. The following keys are available (Examples coming, see contextual names for now).
_self, _left, _right, _user
"Not"
You can use "not" to exclude cards specified by the card definition. For example, here are all the User cards with no nerdy nickname card attached yet:
{"type": "User", "not": {"plus": "nerdy nickname"}}
If the card definition has multiple keys (properties or relationships), then the negation operates on the entire definition. So this:
{"not": {A, B}}
....means "not (A and B)", which is equivalent to "not A OR not B" . For the equivalent of "neither A nor B", you can do the following:
{"not": {"or": {A, B}}}
"Or" and "and"
"Or" expects a series of simple key/value pairs, so if one of the conditions has multiple elements, you need to use the explicit "and", e.g. this:
{"or":
{"type": "Image",
"and": {"type": "User", "plus": "Image"} }
}
(306)
Nesting searches
Often you want to specify a search once, then narrow it or arrange it in different ways. This could lead to a multiplication of search cards to maintain, but you can avoid this by using found_by, a key which takes a single Search card as a value, and returns all of the cards that Search returns. Note that the order and view of those cards is lost, and you can only nest once this way. A typical use is *right forms, e.g.:
{"found_by": "_self", "sort": "update"}(0)
Arranging Results
Limits
Limit takes a number, which determines how many cards will be shown at once. This gets passed directly into the SQL.
Ordering
Sort orders the cards, and can take one of four values:
- update — in descending order from most recently edited/updated (this is the default, but we may change, e.g. to respect order of Pointer items, so it's best to be explicit)
- create — in ascending order from the card earliest created to the latest
- name — in ascending order, alphabetically (this used to be alpha, which still works)
- content — in ascending order, alphabetically. This works, but only in very simple cases because Basic cards always have HTML and can have Wagn markup, both of which do unexpected things to the order. Even Phrase and Plaintext cards can have HTML or Wagn markup, but this should be usable on those cardtypes if no one is pasting in HTML. (Numbers are treated as text, and Dates are not stored in a consistent form, so neither is generally usable with sort by content.)
Dir can be used to override the default direction:
- asc — ascending order
- desc — as in descending
Putting these all together, you can tell WQL:
{"type": "User", "sort": "name", "dir": "desc", "limit": "8"}
Item views
You can use view to specify which views will be applied to each card in the list of cards returned — the default view is closed, but you can change this to open, content, link, name, etc. If you are going to be including the search in many places, this saves you from having to specify it each time.
Modifying Results
Append and prepend let you convert search result cards into new cards. For example, here's a simple way to find all the cards in a Wagn grouped by their type.
{"type":"Cardtype", "append":"*type", "sort":"name"}(50)
Notice that each card returned is a virtual card, which means that it's not actually stored in the database. There is a Basic card, and a *type, but there is no actual Basic+*type -- it's formed via a search pattern established in *type+*right+*content. Since most WQL can only return cards in the database, something like this would not work:
{"left":{"type":"Cardtype"}, "right":"*type", "sort":"name"}
Append works because the appending is done after the results are returned.
In addition to virtual cards, you can use append/prepend to return "missing" cards — cards that haven't been created yet. For example, if you're using Wagn for an event and you want to invite people to fill in missing contact information, you might do something like this:
{"type": "User", "sort": "name", "append": "how to reach me"}(820)
In general, whenever all the results you want are actual cards, you should not use append/prepend, but rather use left / right.
Tips
- "in" doesn't work with "plus" yet, but if you want to search on two plus cards, you can use "plus" for one and "right_plus" for the other.
- When searching on the content of Toggles, search for 0 to find the nos and 1 to find the yeses.
- You can put comments in WQL with:
/* commented text */
Needs
- To date, all operators and sorts are treat numeric card values as text, which means, for example, that 11 comes before 2 (as it would alphabetically). We plan to support better number handling soon.
Also see Related Tickets


