Gnucash Query API BASIC QUERY API: With this API you can create arbitrary logical queries to find sets of splits in an account group. To make simple queries (1 term, such as an account query), create the appropriate QueryTerm structure and stick it in a Query object using xaccInitQuery. The QueryTerm should be malloced but the Query object will handle freeing it. To make compound queries, make multiple simple queries and combine them using xaccMergeQuery and the logical operations of your choice. ----------------------------------------------------------------- Query * xaccMallocQuery() Allocates and initializes a Query structure which must be freed by the user with xaccFreeQuery. A newly-allocated Query object matches nothing (xaccQueryGetSplits will return NULL). ----------------------------------------------------------------- void xaccInitQuery(Query * q, QueryTerm * qt) Initializes an allocated Query object with initial term qt (possibly NULL). Any previous query terms are freed. ----------------------------------------------------------------- void xaccFreeQuery(Query * q) Frees the resources associate with a Query object. ----------------------------------------------------------------- void xaccQuerySetGroup(Query * q, AccountGroup * group) Set the Gnucash account group that the query applies to. xaccQuerySetGroup must be called before a Query object created with xaccMallocQuery can be used. Queries created with xaccQueryInvert and xaccQueryMerge inherit the account group of the arguments to those functions. ----------------------------------------------------------------- Query * xaccQueryInvert(Query * q) Logically invert the query. xaccInvertQuery returns a newly allocated Query object such that the union of the splits matched by query q and query (p = xaccQueryInvert(q)) is the entire account group that q applies to. ----------------------------------------------------------------- Query * xaccQueryMerge(Query * q1, Query * q2, QueryOp how) Combine queries q1 and q2 using logical operator 'how'. 'how' must be one of QUERY_AND, QUERY_OR, QUERY_NAND, QUERY_NOR, QUERY_XOR. The account groups of q1 and q2 must be the same. xaccQueryMerge returns a newly-allocated Query object or NULL on error. ----------------------------------------------------------------- void xaccQueryClear(Query * q) Remove all query terms from q. q matches nothing after xaccQueryClear. ----------------------------------------------------------------- void xaccQueryPurgeTerms(Query * q, pd_type_t type); Remove query terms of a particular type from q. The "type" of a term is determined by the type of data that gets passed to the predicate function. The currently-supported values of 'type' are PD_DATE, PD_AMOUNT, PD_ACCOUNT, PD_STRING, PD_CLEARED, PD_MISC. This function is really only used in one place: in window-register.c, to modify in-place a query to remove any date tests prior to adding new ones. This should probably be removed from the API in favor of an extra argument to xaccQueryMerge specifying what to do with existing terms of that type. ----------------------------------------------------------------- int xaccQueryHasTerms(Query * q) Returns the number of terms in the canonical form of the query. Can be used as a predicate to see if the query has been initialized (return value > 0) or is "blank" (return value == 0). ----------------------------------------------------------------- CONVENIENCE API: The remainder of the API (in particular, any function called xaccQueryAdd***Match) is a set of convenience functions for creating and modifying specific types of queries. All of these functions can be duplicated using the Basic API specified above, directly manipulating QueryTerm objects and creating and merging queries as needed. One slight advantage of the convenience API is that it uses a standard set of predicates that are more-or-less opaque. This may be important later. It's probably more useful to describe the various types of PredicateData than the convenience functions, which are pretty self-explanatory once you understand what the underlying process is. For example, AddMemoMatch and AddDescriptionMatch are essentially the same function because they both use PD_STRING predicate data; they just use a different predicate (one compares data.string.matchstring with the split's Memo, one compares with the parent transaction's Description). Each function in the convenience API takes a Query *, some arguments which fill in the fields of the appropriate PredicateData type, and a QueryOp. The Query object is modified in place, using the logical operation specified by the QueryOp to combine a single new QueryTerm with the existing Query. This works by making a new Query of one term and combining with the existing Query using xaccQueryMerge and the specified QueryOp. If you have an existing Query (a + b + c) and combine using QueryOp QUERY_AND in a convenience function representing predicate d, you will get (ad + bd + cd). STRUCTURE OF A QUERY: A Query is a logical function of any number of QueryTerms. A QueryTerm consists of a C function pointer (the Predicate) and a PredicateData structure containing data passed to the predicate function. The PredicateData structure is a constant associated with the Term and is identical for every Split that is tested. The terms of the Query may represent any logical function and are stored in canonical form, i.e. the function is expressed as a logical sum of logical products. So if you have QueryTerms a, b, c, d, e and you have the logical function a(b+c) + !(c(d+e)), it gets stored as ab + ac + !c + !c!e +!d!c + !d!e. This may not be optimal for evaluation of some functions but it's easy to store, easy to manipulate, and it doesn't require a complete algebra system to deal with. The representation is of a GList of GLists of QueryTerms. The "backbone" GList q->terms represents the OR-chain, and every item on the backbone is a GList of QueryTerms representing an AND-chain corresponding to a single product-term in the canonical representation. QueryTerms are duplicated when necessary to fill out the canonical form, and the same predicate may be evaluated multiple times per split for complex queries. This is a place where we could probably optimize. Evaluation of a Query (see xaccQueryGetSplits) is optimized as much as possible by short-circuited evaluation. The predicates in each AND-chain are sorted by predicate type, with Account queries sorted first to allow the evaluator to completely eliminate accounts from the search if there's no chance of them having splits that match. PREDICATE DATA TYPES: All the predicate data types are rolled up into the union type PredicateData. The "type" field specifies which type the union is. The values of type are: ----------------------------------------------------------------- PD_DATE : match a date range. Specify a start date and an end date. Used in: xaccQueryAddDateMatch xaccQueryAddDateMatchTT ----------------------------------------------------------------- PD_AMOUNT : match a numeric amount. Specify an amount (always positive), a funds-flow direction (credit, debit, or either), and "how", specifying the type of amount comparison to be used : AMT_MATCH_AT LEAST : split >= pd amount AMT_MATCH_ATMOST : split >= pd amount AMT_MATCH_EXACTLY : split == pd amount Used in: xaccQueryAddAmountMatch xaccQueryAddSharePriceMatch xaccQueryAddSharesMatch ----------------------------------------------------------------- PD_ACCOUNT : match an account or set of accounts. Specify a set of accounts and "how": ACCT_MATCH_ALL : a transaction must have at least one split affecting each account in pd.acct.accounts. ACCT_MATCH_ANY : a transaction must have at least one split affecting any account in the set ACCT_MATCH_NONE : a transaction may not affect any account in the set. Used in: xaccQueryAddAccountMatch xaccQueryAddSingleAccountMatch ----------------------------------------------------------------- PD_STRING : match a string. Specify a string, bool signifying case sensitivity, bool signifying regexp or simple string. Used in: xaccQueryAddDescriptionMatch xaccQueryAddNumberMatch xaccQueryAddActionMatch xaccQueryAddMemoMatch ----------------------------------------------------------------- PD_CLEARED : match the Cleared state of the transaction. Specify a bit-mask that is an OR combination of one or more of the following: CLEARED_NO (state == 'n') CLEARED_CLEARED (state == 'c') CLEARED_RECONCILED (state == 'y') Used in: xaccQueryAddClearedMatch ----------------------------------------------------------------- PD_MISC : match some "other" user predicate. Not used at the moment. -----------------------------------------------------------------