The Query Language
The LoganBerry Query Language can be used to express boolean queries. The basic component of such queries is an "attribute pattern". The format of an attribute pattern is as follows:
attribute-type(pattern-type): pattern
The attribute-type is a string indicating a LoganBerry attribute type; it is case sensitive. The pattern is a string that will be compared against the value of the given attribute in LoganBerry database entries; if it contains blanks or special characters then it should be enclosed in double quotes. The pattern-type is a string that specifies a particular pattern-matcher; this governs how the comparison between values and patterns is performed.
The pattern-type (and surrounding parentheses) can be omitted from an attribute pattern. In this case, a default pattern-matcher is used (currently the default is "DWIM").
A LoganBerry entry matches an attribute pattern if (1) the entry contains an attribute of the type given in the attribute pattern, and (2) the value of this attribute matches the pattern given in the attribute pattern (see "Pattern Matching" below).
Attribute patterns can be combined using AND, OR, and NOT as well as parentheses. The AND operator between attribute patterns is optional (for backward compatibility). The syntax for boolean queries is defined by the following formal grammar:
query ::= boolexpr | boolexpr query
boolexpr ::= term | term "OR" boolexpr
term ::= factor | factor "AND" term
factor ::= attribute-pattern | "NOT" factor | "(" boolexpr ")"
attribute-pattern ::= attribute-type ":" pattern |
attribute-type "(" pattern-type ")" ":" pattern
Here are some sample boolean queries over a mythical directory database consisting of names and phone numbers:
Name: Ben*
Name(wildcard): Ben*
Name(exact): "Ben Dover" Phone(exact): 123-4567
Name(exact): "Ben Dover" AND Phone(exact): 123-4567
Name: Sally OR Name: Saly OR Name: Salley OR Name: Silly
Name(soundex): Sally
(Name: "Moe D. Lawn" OR Name: "Frank N. Stein") AND Phone(prefix): "(415)"
Name: "Moe D. Lawn" OR Name: "Frank N. Stein" AND Phone(prefix): "(415)"
Phone: *
Phone: * OR NOT Phone: *
NOT (Name: "Patty O'Furniture" OR Name: "Mary Mae Bill" OR Name: "Justin Tyme")
NOT Name: "Patty O'Furniture" AND NOT Name: "Mary Mae Bill" AND NOT Name: "Justin Tyme"
The first two queries above produce identical results (assuming DWIM as the default pattern-matcher). Queries three and four are also identical. Queries five and six are not identical, but have similar intent. Queries seven and eight are different (because operators group right-to-left); use parenthesis to explicitly control the order of execution. Queries nine and ten produce identical results only if each database entry contains a Phone attribute, for instance if Phone is the primary key. The last two queries given above are identical, of course.
Pattern Matching
Each attribute pattern in a boolean query evaluates to either TRUE or FALSE based on whether or not the attribute value present in a LoganBerry entry matches the pattern given in the query. A variety of pattern matchers are available for use in queries including:
exact: Compares the value and pattern for equality.
prefix: Checks if the pattern is a prefix of the value. Prefix[v, "p"] is the same as Wildcard[v, "p*"], though faster.
wildcard: The pattern may contain zero or more wildcards (the character "*") that match anything.
re: The pattern is taken to be a regular expression as defined in RegularExpressionDoc.tioga.
soundex: Compares the value and pattern based on their Soundex codes. The Soundex encoding tends to group together variants of the same name; for instance, Johnson, Jansen, and Johansen have identical Soundex codes.
subrange: Checks if the value is in the range specified by the pattern. The pattern is taken to be two strings (or rope literals) separated by a "-"; a match occurs if pattern.beginningdvaluedpattern.end in lexicographic ordering or prefix(value)=pattern.end.
numrange: Checks if the value is in the numerical range specified by the pattern. The pattern should consist of two positive integers separated by a "-", e.g. "18-21".
daterange: Checks if the value is in the chronological range specified by the pattern. The pattern should consist of two date and times (as can be parsed by Tempus) separated by a "-", e.g. "today at noon-doomsday". The starting time is taken to be the earliest time that meets the specification whereas the ending time in the latest, e.g. "Yesterday-Today" means all of yesterday and all of today, not the beginning of yesterday to the beginning of today.
date: Checks if the value matches the pattern within the time precision of the pattern. The pattern, as well as the value, should be a date and time (as can be parsed by Tempus). A match can not occur unless the pattern is no more precise than the value. For example, a pattern of "Wednesday" will match a value of "Wednesday at 2 pm", but not vice versa.
DWIM: Tries to deduce an appropriate pattern matcher from the given pattern.
This list is almost certainly incomplete since new pattern-matching routines can be dynamically registered (via PatternMatch.mesa).