WalnutQueryDoc.tioga
Spreitzer, July 25, 1985 8:26:25 pm PDT
Rick Beach, July 13, 1986 12:39:45 pm PDT
WALNUTQUERY
CEDAR 6.1 — FOR INTERNAL XEROX USE ONLY
WalnutQuery
Mike Spreitzer
© Copyright 1985, 1986 Xerox Corporation. All rights reserved.
Abstract: WalnutQuery provides an extremely simple way to query Walnut. It enumerates the messages, and applies a Boolean test to each.
Created by: Mike Spreitzer
Maintained by: Mike Spreitzer <Spreitzer.pa>
Keywords: Walnut, Query, Message, Message Set, Text Search, Time Compare
XEROX  Xerox Corporation
   Palo Alto Research Center
   3333 Coyote Hill Road
   Palo Alto, California 94304

For Internal Xerox Use Only
1. Introduction
The WalnutQuery package provides a means for querying messages in your Walnut database. At present there is only an Interpreter interface.
WalnutQuery has one operation: FilterToMsgSet. It takes an expression denoting a Boolean-valued function of a message, and a message set name to receive the accepted messages. It enumerates your Walnut messages (using the smallest applicable message set or the entire database), and tests each message with the filter; all the messages that pass the filter are put into the message set you named. The supplied message set is first created, if it did not already exist. The messages are not added to the message set untill after the enumeration is complete—this way, you can continue to use Walnut while the enumeration is in progress.
The enumeration can take a number of minutes, especially if it must enumerate your entire Walnut database. The best performance seen so far is about 500 messages tested per minute. You should not do an Expunge while FilterToMsgSet is in progress; any other Walnut operations should be OK. Changes to your Walnut database made after you start FilterToMsgSet will not be seen.
2. Filters
A filter is denoted by a Cedar value, normally a LIST constructed with REF ANY, ROPE (REF TEXT is acceptable wherever ROPE is), ATOM, and so on. Here is the encoding:
LIST[$dateRange, start: ROPE, end: ROPE]
Passes those messages that have a header field named "Date" whose value is a time between (inclusive) those given. Times are parsed by Convert.TimeFromRope.
LIST[$textMatch, where: ROPE, option1, ... optionN: ATOM, pattern: ROPE]
This does text searching in a header field (as named by where (captialization unimportant)) or the message body (when where = NIL). The message passes iff the pattern is found in the indicated place. For header fields, only the first one, if any, with the given name is tried. Possible options are:
$literal  treat the pattern as a literal; this is default.
$pattern  interpret metacharacters in the pattern (as in the Edit Tool).
$word  the matched text must not have surrounding alphabetic characters.
$addBoundsthe pattern must match the entire subject (header field or message body).
$anywheremeans neither $word nor $addBounds; this is the default.
$ignoreCaseignore case; this is the default.
$testCase  don't ignore case.
LIST[$inMsgSet, msgSetName: ROPE]
Passes the messages in the named message set.
filter: WalnutQuery.Test
A way to specify an arbitrary filter.
LIST[$not, filter: REF ANY]
This passes a message if and only if the argument would not.
LIST[$and, filter1, ... filterN: REF ANY]
This passes a message iff all the argument filters do.
LIST[$or, filter1, ... filterN: REF ANY]
This passes a message iff any argument filters does.
LIST[$xor, filter1, filter2: REF ANY]
This passes a message iff exactly one of the two filters does.
LIST[$iff, filter1, filter2: REF ANY]
This passes a message iff both of the filters agree.
3. Installation and Invocation
WalnutQuery exports a Cedar interface, and it contains the FilterToMsgSet operation. It can be invoked from the Command Tool with the ← command. WalnutQuery provides no Command Tool commands, nor any buttons or viewers anywhere. To install WalnutQuery, in any directory:

% Bringover -p [Cedar]<CedarChest6.1>Top>WalnutQuery.DF
% @WalnutQuery.Load
If Walnut hasn't been run yet, this will produce warnings about unbound imports, but nothing bad will happen. You can only use WalnutQuery while you actually have a Walnut viewer.
4. Performance
Here are some examples (where the log file is 5214229 bytes (10185 pages) long, and there are 576 deleted msgs, (2353 total msgs)):

% ← WalnutQuery.FilterToMsgSet[LIST[$dateRange, "24-July-85", "25-July-85"], "Yesterday"]
ok
{00:07:28 seconds, 2118358 words, 275 page faults}
% ← WalnutQuery.FilterToMsgSet[LIST[$textMatch, NIL, $literal, "cedar"], "AllCedar"]
ok
{00:09:18 seconds, 4846382 words, 14 page faults}
5. Progress monitoring
There is a way to get WalnutQuery to indicate how far it's gotten, and how far it's got to go, in terms of number of messages. If you give FilterToMsgSet a WalnutQuery.Status, it will fill in the total number of messages in your Walnut database, and continuously update the number that have been processed while enumerating the messages.
An easy way to get a visual display of this is to use ViewRec. WalnutQuery.NewViewedStatus does this for you: it creates a Status, and calls ViewRec on it.

%
← &status ← WalnutQuery.NewViewedStatus[]
=> ^[phase: idle, msgSet: NIL, total: 0, enumerated: 0, accepted: 0, added: 0]
% ← WalnutQuery.FilterToMsgSet[LIST[$and, LIST[$inMsgSet, "ARPALaserLovers"], LIST[$not, LIST[$textMatch, "Redistributed", "XeroxLaserLovers^.wbst"]]], "NotInTemp", &status]
=> ok
%