Query API

Christopher Browne cbbrowne@hex.net
Tue, 19 Dec 2000 01:10:44 -0600


On 18 Dec 2000 13:00:56 EST, the world broke into rejoicing as
Derek Atkins <warlord@MIT.EDU>  said:
> Christopher Browne <cbbrowne@hex.net> writes:
> > It shouldn't be a situation of the GUI submitting database queries;
> > instead, the GUI should submit _transaction_ queries to the engine, and
> > the engine can then do what it needs.

> This is a reasonable approach, although I think we still want
> (need?)  to be flexible enough to make some rather robust queries.
> For example, I can certainly see where you might want to search for
> transactions in an account between specific dates, or certain
> reports might want to make certain more extensive queries.  I'm not
> sure what the best way to do this would be; I'd like to be able to
> support batch queries across an RPC, but I don't know how to make
> the request.

This is absolutely sensible; it would be logical to provide a CORBA
interface to the Query scheme, perhaps thus:

module Query {
  enum SortBy { STANDARD, DATE, DATEENTERED, DATERECONCILED, NUM,
		AMOUNT, MEMO, DESC, RECONCILE, NONE };
  enum QueryOp { AND, OR, NAND, NOR, XOR };
  enum pdtypet { DATE, AMOUNT, ACCOUNT, STRING, CLEARED, MISC };
  enum acctmatcht { ACCT_MATCH_ALL, ACCT_MATCH_ANY, ACCT_MATCH_NONE } 
  enum amtmatcht { AMT_MATCH_ATLEAST, AMT_MATCH_ATMOST, 
		   AMT_MATCH_EXACTLY } ;
  
  enum amtmatchsgnt { AMT_SGN_MATCH_EITHER, AMT_SGN_MATCH_CREDIT, 
		      AMT_SGN_MATCH_DEBIT } ;

  enum clearing { CLEARED_NO, CLEARED_CLEARED, CLEARED_RECONCILED,
		  CLEARED_FROZEN };

  enum strmatching { STRING_MATCH_CASE, STRING_MATCH_REGEXP,
		     STRING_MATCH_INSENSITIVE };
  
  struct DatePredicateData {
    long          usestart;
    Timespec     start;
    long          useend;
    Timespec     end;
  } 
  struct AmountPredicateData {
    amtmatcht     how;
    amtmatchsgnt amt_sgn;
    double          amount;
  };
  struct AccountPredicateData {
    acctmatcht how;
    Accounts::AccountList accounts;
    // Note that this references a type from
    // module "Accounts"
  }
  struct StringPredicateData {
    strmatching behavior;  /* what kind of search? */
    string matchstring;
    // regex_t        compiled;  // Compilation isn't part of the interface
  } StringPredicateData;
  struct MiscPredicateData {
    long how;  /* Shouldn't this use one of the enums? */
    long data; /* What is this? */
  }; 
  struct ClearedPredicateData {
    long how;
  };

  union PredicateData switch (pdtypet) {
  case DATE:
    DatePredicateData date;
  case AMOUNT:
    AmountPredicateData amount;
  case ACCOUNT: 
    AccountPredicateData acct;
  case STRING:  
    StringPredicateData str;
  case CLEARED: 
    ClearedPredicateData cleared;
  case MISC: 
    MiscPredicateData misc;  
  }

  struct QueryTerm {
    Predicate p;  /* What is this type supposed to be? */
    PredicateData data;
    long sense;
  };

  /* Something is wrong with the following; I am somehow not correctly
     understanding what the Predicate type is...  I'll punt and
     pretend that a Query consists of a binary tree of QueryTerm
     elements... */

  struct Query {
    QueryTerm qt;
    QueryOp combinethus;
    Query subquery;
  }; 
  
  // Locally, there would be the whole host of "Query Construction"
  // functions to build up a complex query.

  void InvokeQuery (in query q, 
		    out Transactions::TransactionList txns);

  /* Note that this references, from the "Transactions" module, the
     "TransactionList" typedef, which would reflect a sequence of
     transactions... */
};

A few points that should be made conspicuous:

- Note that the "enums" do not declare specific values.  They CANNOT
  do so; CORBA works with some languages, e.g. Lisp, that would allow
  "enums" to be kept symbolic.

- Note that the only actual "function call" here, which, in CORBA, is
  called an "operator," is InvokeQuery.  It returns a _sequence_ that
  could include arbitrarily many transactions.  It is passed what
  amounts to a "tree;" a potentially-very-complex query.

  This is the _direct_ answer to your issue of "supporting batch
  queries" across RPC.  This allows passing in a complex query, and
  returning a complex response.

- Frankly, this probably shouldn't return the transactions, but rather
  return a list of transaction _references_ [e.g. - perhaps a sequence
  of GUIDs].  That way, if the goal is not to look up the
  transactions, we don't have to.  

  But it's easy enough to take that sequence of GUIDs, and pass them to
  void PullTransactions ( in GUIDList g; out TransactionList txns );

- Note that the interface does NOT provide the whole set of functions
  described in Query.h/Query.c; only the one that would be used to
  request the query.  

  Query.h describes a bunch of functions that may be used to help
  construct the query.  Those should run locally; there is _NO_ point
  to running them across a network.
--
(concatenate 'string "cbbrowne" "@ntlug.org")
<http://www.hex.net/~cbbrowne/>
"Never make any mistaeks." (Anonymous, in a mail discussion about to a
kernel bug report.)