1
2This directory contains code for the accounting engine.
3Its fairly clean but far from perfect, and it certainly
4lacks advanced features.
5
6There should be no GUI code in this subdirectory, and,
7ideally, it should build cleanly and independently of
8any GUI elements or assumptions.
9
10For design documentation, please see the file "design.txt",
11and also, look at the header files carefully. The documentation
12for each routine is in the header files for that routine.
13
14September 1998
15
1Gnucash Query API
2
3
4BASIC QUERY API: With this API you can create arbitrary logical
5queries to find sets of splits in an account group. To make simple
6queries (1 term, such as an account query), create the appropriate
7QueryTerm structure and stick it in a Query object using
8xaccInitQuery. The QueryTerm should be malloced but the Query object
9will handle freeing it. To make compound queries, make multiple
10simple queries and combine them using xaccMergeQuery and the logical
11operations of your choice.
12
13-----------------------------------------------------------------
14Query * xaccMallocQuery()
15
16Allocates and initializes a Query structure which must be freed by the
17user with xaccFreeQuery. A newly-allocated Query object matches
18nothing (xaccQueryGetSplits will return NULL).
19
20-----------------------------------------------------------------
21void xaccInitQuery(Query * q, QueryTerm * qt)
22
23Initializes an allocated Query object with initial term qt (possibly
24NULL). Any previous query terms are freed.
25
26-----------------------------------------------------------------
27void xaccFreeQuery(Query * q)
28
29Frees the resources associate with a Query object.
30
31-----------------------------------------------------------------
32void xaccQuerySetGroup(Query * q, AccountGroup * group)
33
34Set the Gnucash account group that the query applies to.
35xaccQuerySetGroup must be called before a Query object created with
36xaccMallocQuery can be used. Queries created with xaccQueryInvert and
37xaccQueryMerge inherit the account group of the arguments to those
38functions.
39
40-----------------------------------------------------------------
41Query * xaccQueryInvert(Query * q)
42
43Logically invert the query. xaccInvertQuery returns a newly allocated
44Query object such that the union of the splits matched by query q and
45query (p = xaccQueryInvert(q)) is the entire account group that q
46applies to.
47
48-----------------------------------------------------------------
49Query * xaccQueryMerge(Query * q1, Query * q2, QueryOp how)
50
51Combine queries q1 and q2 using logical operator 'how'. 'how' must be
52one of QUERY_AND, QUERY_OR, QUERY_NAND, QUERY_NOR, QUERY_XOR. The
53account groups of q1 and q2 must be the same. xaccQueryMerge returns
54a newly-allocated Query object or NULL on error.
55
56-----------------------------------------------------------------
57void xaccQueryClear(Query * q)
58
59Remove all query terms from q. q matches nothing after xaccQueryClear.
60
61-----------------------------------------------------------------
62void xaccQueryPurgeTerms(Query * q, pd_type_t type);
63
64Remove query terms of a particular type from q. The "type" of a term
65is determined by the type of data that gets passed to the predicate
66function. The currently-supported values of 'type' are PD_DATE,
67PD_AMOUNT, PD_ACCOUNT, PD_STRING, PD_CLEARED, PD_MISC. This function
68is really only used in one place: in window-register.c, to modify
69in-place a query to remove any date tests prior to adding new ones.
70This should probably be removed from the API in favor of an extra
71argument to xaccQueryMerge specifying what to do with existing terms
72of that type.
73
74
75-----------------------------------------------------------------
76int xaccQueryHasTerms(Query * q)
77
78Returns the number of terms in the canonical form of the query. Can
79be used as a predicate to see if the query has been initialized
80(return value > 0) or is "blank" (return value == 0).
81
82
83-----------------------------------------------------------------
84
85CONVENIENCE API: The remainder of the API (in particular, any function
86called xaccQueryAdd***Match) is a set of convenience functions for
87creating and modifying specific types of queries. All of these
88functions can be duplicated using the Basic API specified above,
89directly manipulating QueryTerm objects and creating and merging
90queries as needed. One slight advantage of the convenience API is
91that it uses a standard set of predicates that are more-or-less
92opaque. This may be important later.
93
94It's probably more useful to describe the various types of
95PredicateData than the convenience functions, which are pretty
96self-explanatory once you understand what the underlying process is.
97For example, AddMemoMatch and AddDescriptionMatch are essentially the
98same function because they both use PD_STRING predicate data; they
99just use a different predicate (one compares data.string.matchstring
100with the split's Memo, one compares with the parent transaction's
101Description).
102
103Each function in the convenience API takes a Query *, some arguments
104which fill in the fields of the appropriate PredicateData type, and a
105QueryOp. The Query object is modified in place, using the logical
106operation specified by the QueryOp to combine a single new QueryTerm
107with the existing Query. This works by making a new Query of one term
108and combining with the existing Query using xaccQueryMerge and the
109specified QueryOp. If you have an existing Query (a + b + c) and
110combine using QueryOp QUERY_AND in a convenience function representing
111predicate d, you will get (ad + bd + cd).
112
113
114STRUCTURE OF A QUERY: A Query is a logical function of any number of
115QueryTerms. A QueryTerm consists of a C function pointer (the
116Predicate) and a PredicateData structure containing data passed to the
117predicate function. The PredicateData structure is a constant
118associated with the Term and is identical for every Split that is
119tested.
120
121The terms of the Query may represent any logical function and are
122stored in canonical form, i.e. the function is expressed as a logical
123sum of logical products. So if you have QueryTerms a, b, c, d, e and
124you have the logical function a(b+c) + !(c(d+e)), it gets stored as
125ab + ac + !c + !c!e +!d!c + !d!e. This may not be optimal for evaluation
126of some functions but it's easy to store, easy to manipulate, and it
127doesn't require a complete algebra system to deal with.
128
129The representation is of a GList of GLists of QueryTerms. The
130"backbone" GList q->terms represents the OR-chain, and every item on
131the backbone is a GList of QueryTerms representing an AND-chain
132corresponding to a single product-term in the canonical
133representation. QueryTerms are duplicated when necessary to fill out
134the canonical form, and the same predicate may be evaluated multiple
135times per split for complex queries. This is a place where we could
136probably optimize.
137
138Evaluation of a Query (see xaccQueryGetSplits) is optimized as much as
139possible by short-circuited evaluation. The predicates in each
140AND-chain are sorted by predicate type, with Account queries sorted
141first to allow the evaluator to completely eliminate accounts from the
142search if there's no chance of them having splits that match.
143
144
145PREDICATE DATA TYPES: All the predicate data types are rolled up into
146the union type PredicateData. The "type" field specifies which type
147the union is. The values of type are:
148
149-----------------------------------------------------------------
150PD_DATE : match a date range. Specify a start date and an end date.
151
152Used in: xaccQueryAddDateMatch
153 xaccQueryAddDateMatchTT
154
155-----------------------------------------------------------------
156PD_AMOUNT : match a numeric amount. Specify an amount (always
157positive), a funds-flow direction (credit, debit, or either), and
158"how", specifying the type of amount comparison to be used :
159
160 AMT_MATCH_AT LEAST : split >= pd amount
161 AMT_MATCH_ATMOST : split >= pd amount
162 AMT_MATCH_EXACTLY : split == pd amount
163
164Used in: xaccQueryAddAmountMatch
165 xaccQueryAddSharePriceMatch
166 xaccQueryAddSharesMatch
167
168-----------------------------------------------------------------
169PD_ACCOUNT : match an account or set of accounts. Specify a set
170of accounts and "how":
171
172 ACCT_MATCH_ALL : a transaction must have at least one split
173 affecting each account in pd.acct.accounts.
174 ACCT_MATCH_ANY : a transaction must have at least one split
175 affecting any account in the set
176 ACCT_MATCH_NONE : a transaction may not affect any account in
177 the set.
178
179Used in: xaccQueryAddAccountMatch
180 xaccQueryAddSingleAccountMatch
181
182-----------------------------------------------------------------
183PD_STRING : match a string. Specify a string, bool signifying
184case sensitivity, bool signifying regexp or simple string.
185
186Used in: xaccQueryAddDescriptionMatch
187 xaccQueryAddNumberMatch
188 xaccQueryAddActionMatch
189 xaccQueryAddMemoMatch
190
191-----------------------------------------------------------------
192PD_CLEARED : match the Cleared state of the transaction. Specify
193a bit-mask that is an OR combination of one or more of the
194following:
195 CLEARED_NO (state == 'n')
196 CLEARED_CLEARED (state == 'c')
197 CLEARED_RECONCILED (state == 'y')
198
199Used in: xaccQueryAddClearedMatch
200
201-----------------------------------------------------------------
202PD_MISC : match some "other" user predicate. Not used at the moment.
203
204-----------------------------------------------------------------
205