K2's implementation of OQL follows the ODMG standard, with the following additions and omissions:
OQL queries sent to K2 must be terminated by a semicolon.
Unnamed from clauses are not allowed, so you must provide a variable name for each collection in your from clause.
The group by, having, and order by clauses are not yet supported, but the functionality of the latter can be accomplished by using the sort function. For example, the following call to sort:
sort(list("HairColor", "Name"), list(true, false),
set(struct(Name: "Fred", HairColor: "Black"),
struct(Name: "Wilma", HairColor: "Red"),
struct(Name: "Barney", HairColor: "Blond"),
struct(Name: "Betty", HairColor: "Black")));
produces the following result:
list(struct(HairColor: "Black", Name: "Fred"),
struct(HairColor: "Black", Name: "Betty"),
struct(HairColor: "Blond", Name: "Barney"),
struct(HairColor: "Red", Name: "Wilma"))
The third parameter to sort must be a collection of
structs. The first parameter is a list of labels, in the order
in which they should be considered. The second parameter parallels the
first, and indicates whether or not the field should be sorted in
ascending order.
One major addition in K2's OQL is variants, or "tagged unions". These are used when we want to be able to represent data of varying type. The tag you specify is used to identify the type of data contained in the variant. For example, the two variants in this set:
set(variant(address: struct(Street: "123 Fake Street",
City: "Springfield",
State: "??")),
variant(phone: "(888) 555-1212"))
contain data of different types (one is a struct, the other a
string); However, since all variants are considered to be of the same
type, these variants can be put in the same collection, even though
collections in K2 (and OQL) must be homogeneous. This flexibility is
often required when modeling data sources which are not
well-structured.You extract the contents of a variant using another K2 addition to OQL, a case statement. This construct tests, for a variant value, which tag it contains, and evaluates a different statement for each. Note that since OQL is type-safe, all of the possible results of a case statement must have the same type. For example, if the above set were named ContactInfo, the following query:
select case (info) of
address: addr --> addr.Street + ", " + addr.City + " " + addr.State,
phone: ph --> ph
endcase
from ContactInfo info;
would produce the following result:
bag("123 Fake Street, Springfield ??",
"(888) 555-1212")