mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
* created the backend-api document
* removed the old Query code (bug #94318) git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@7290 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
123d988ed1
commit
a56e6be18b
@ -1,6 +1,11 @@
|
|||||||
2002-10-07 Derek Atkins <derek@ihtfp.com>
|
2002-10-07 Derek Atkins <derek@ihtfp.com>
|
||||||
* Rename "print invoice" to "printable invoice"
|
* Rename "print invoice" to "printable invoice"
|
||||||
|
|
||||||
|
* Applied Matt Martin's advanced-portfolio patch.
|
||||||
|
|
||||||
|
* created the backend-api document
|
||||||
|
* removed the old Query code (bug #94318)
|
||||||
|
|
||||||
2002-10-07 Christian Stimming <stimming@tuhh.de>
|
2002-10-07 Christian Stimming <stimming@tuhh.de>
|
||||||
|
|
||||||
* src/import-export/hbci/druid-hbci-initial.c: Fix and activate
|
* src/import-export/hbci/druid-hbci-initial.c: Fix and activate
|
||||||
|
160
src/doc/backend-api.txt
Normal file
160
src/doc/backend-api.txt
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
GnuCash Backend API (v2)
|
||||||
|
|
||||||
|
Derek Atkins
|
||||||
|
<derek@ihtfp.com>
|
||||||
|
|
||||||
|
Created: 2002-10-07
|
||||||
|
|
||||||
|
Problem:
|
||||||
|
--------
|
||||||
|
|
||||||
|
The current Backend API is hardcoded to dealing with Accounts,
|
||||||
|
Transactions, and Splits. The Backend Query API does not allow
|
||||||
|
caching of a Query (meaning the Backend has to recompile the Query
|
||||||
|
every time the query is executed). With the inclusion of a multitude
|
||||||
|
of new datatypes and plugable architure, the Backend API requires
|
||||||
|
modification to handle the new data.
|
||||||
|
|
||||||
|
|
||||||
|
"Dynamic" Data Types:
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The engine has a set of APIs to load new data types into the engine.
|
||||||
|
The Backends need this as well. Currently the engine supplies a set
|
||||||
|
of registration functions to register Backend handlers for new data
|
||||||
|
types. Each Backend defines a plug-in API and then data types can
|
||||||
|
register themselves. This is how extensibility works.
|
||||||
|
|
||||||
|
For example, the "file" Backend defines the API for plug-in data
|
||||||
|
types. It requires data types to implement four functions:
|
||||||
|
create_parser(), add_item(), get_count(), and write().
|
||||||
|
|
||||||
|
A new data-type, the GncFOO type, implements the required APIs and
|
||||||
|
registers itself with gncObjectRegisterBackend(). The file backend
|
||||||
|
can then either lookup the GncFOO object by name by calling
|
||||||
|
gncObjectLookupBackend(), or can iterate over all the registered
|
||||||
|
objects by using gncObjectForeachBackend(), depending on the
|
||||||
|
particular backend operation.
|
||||||
|
|
||||||
|
By using these functions, new data types can be registered and new
|
||||||
|
types of data stored using generic Backend API functions. The backend
|
||||||
|
implementing generic *_edit() or session_load() APIs could then lookup
|
||||||
|
data types by name or iterate over all known data types to determine
|
||||||
|
how to load or save data. Each backend can define the set of
|
||||||
|
interfaces it requires data-types to implement.
|
||||||
|
|
||||||
|
|
||||||
|
Handling Queries:
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The version-1 Backend provides a single run-query method that returns
|
||||||
|
a list of splits. This has proven to be limiting, and recompiling the
|
||||||
|
query into the backend format each time can be time consuming. To fix
|
||||||
|
this the backend query API needs to be broken into three pieces:
|
||||||
|
|
||||||
|
gpointer (*query_compile)(Backend* be, Query* query);
|
||||||
|
|
||||||
|
compiles a Query* into whatever Backend Language is necessary.
|
||||||
|
|
||||||
|
void (*query_free)(Backend* be, gpointer query);
|
||||||
|
|
||||||
|
frees the compiled Query (obtained from the query_compile method).
|
||||||
|
|
||||||
|
void (*query_run)(Backend* be, gpointer query);
|
||||||
|
|
||||||
|
executes the compiled Query and inserts the responses into the
|
||||||
|
engine. It will search for the type corresponding to the
|
||||||
|
Query search_for type: gncQueryGetSearchFor(). Note that the
|
||||||
|
search type CANNOT change between a compile and the execute,
|
||||||
|
but the query infrastructure maintains that invariant.
|
||||||
|
|
||||||
|
|
||||||
|
In this manner, a Backend (e.g. the Postgres backend) can compile the
|
||||||
|
Query into its own format (e.g. a SQL expression) and then use the
|
||||||
|
pre-compiled expression every run instead of rebuilding the
|
||||||
|
expression.
|
||||||
|
|
||||||
|
There is an implementation issue in the case of Queries across
|
||||||
|
multiple Books. Each book could theoretically be in a different
|
||||||
|
backend, which means we need to tie the compiled query to the book's
|
||||||
|
Backend for which it was compiled. This is an implementation detail,
|
||||||
|
and not even a challenging one, but it needs to be clearly
|
||||||
|
acknowledged up front.
|
||||||
|
|
||||||
|
Also note that this API can usurp the price_lookup() method, assuming
|
||||||
|
the GNCPriceLookup can be subsumed by the Query.
|
||||||
|
|
||||||
|
|
||||||
|
Handling Multiple Datatypes:
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
The current API specifically defines "edit" functions for Accounts and
|
||||||
|
Transactions. This rather rigid API does not allow for adding new
|
||||||
|
data types to the Backend. A better approach is to generalize the
|
||||||
|
begin_edit, rollback_edit, and commit_edit APIs into a general API
|
||||||
|
which is dynamically sub-typed at runtime:
|
||||||
|
|
||||||
|
void (*begin_edit)(Backend* be, GNCIdTypeConst data_type, gpointer object);
|
||||||
|
void (*rollback_edit)(Backend* be, GNCIdTypeConst data_type, gpointer object);
|
||||||
|
void (*commit_edit)(Backend* be, GNCIdTypeConst data_type, gpointer object);
|
||||||
|
|
||||||
|
This API looks just like the existing API for Accounts, Periods, and
|
||||||
|
Price entries, although it quite obviously does not match the
|
||||||
|
Transaction commit. Note that not all data-types need to implement
|
||||||
|
all three types (there is no rollback on Accounts, Prices, or
|
||||||
|
Periods). Note that certain data-types can _still_ be special (e.g.
|
||||||
|
the Period handling).
|
||||||
|
|
||||||
|
Question: why does the transaction commit have two transactions? In
|
||||||
|
particular, can't the backend "know" that the "original" transaction
|
||||||
|
is in "trans->orig". Besides, if the Backend is truly in charge of
|
||||||
|
the data, then the engine can make changes to the local copy and can
|
||||||
|
"back out" by accessing the backend (or commit by sending it to the
|
||||||
|
backend). Can't one assume that the "backend" knows how the engine is
|
||||||
|
implementing the rollback caching?
|
||||||
|
|
||||||
|
|
||||||
|
When to load data?
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Data loads into the engine at two times, at start time and at query
|
||||||
|
time. Loading data during queries is discussed above. This section
|
||||||
|
discusses data loaded at startup.
|
||||||
|
|
||||||
|
Currently the API has book_load() and price_load(). That's nice for
|
||||||
|
the book and price DB, but there may be other items that need to be
|
||||||
|
loaded at "start" time. A better approach would be to combine all
|
||||||
|
the _load() APIs into a single API:
|
||||||
|
|
||||||
|
void session_load(Backend*, GNCBook*);
|
||||||
|
|
||||||
|
This one API would load all the necessary "start-time" data, including
|
||||||
|
the Chart of Accounts, the Commodity Table, the Scheduled Transaction
|
||||||
|
List, the Pricedb, etc. There is no need to have multiple APIs for
|
||||||
|
each of the data types loaded at start-time. Dynamic data-types that
|
||||||
|
require data to be loaded at start-time can register a specific API
|
||||||
|
for the backend to execute the load.
|
||||||
|
|
||||||
|
|
||||||
|
Usefulness of sync_*()?
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
What is the point of sync_all(), sync_group(), and sync_price()?
|
||||||
|
Obviously one of them is necessary to implement "save-as", but there
|
||||||
|
is no need for multiple versions. New datatypes can just be plugged
|
||||||
|
in by the dynamic API. There is no reason to differentiate the book
|
||||||
|
from the pricedb, as they are still attached to each other.
|
||||||
|
Therefore, sync_all() should be left and sync_group() and sync_price()
|
||||||
|
should be removed.
|
||||||
|
|
||||||
|
|
||||||
|
Usefulness of export()?
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
The export() method is used to export a Chart of Accounts to a file.
|
||||||
|
Is it really necessary that this be in the backend? What does it mean
|
||||||
|
to "export" in anything else? Note that only the file backend even
|
||||||
|
IMPLEMENTS this method... How general is export?
|
||||||
|
|
||||||
|
|
||||||
|
============================== END OF DOCUMENT =====================
|
2974
src/engine/Query.c
2974
src/engine/Query.c
File diff suppressed because it is too large
Load Diff
@ -34,7 +34,6 @@
|
|||||||
#include "guid.h"
|
#include "guid.h"
|
||||||
#include "kvp_frame.h"
|
#include "kvp_frame.h"
|
||||||
|
|
||||||
#if 1
|
|
||||||
#include "QueryNew.h"
|
#include "QueryNew.h"
|
||||||
#include "QueryCore.h"
|
#include "QueryCore.h"
|
||||||
|
|
||||||
@ -218,241 +217,4 @@ void xaccQuerySetSortOrder(Query *q, GList *p1, GList *p2, GList *p3);
|
|||||||
time_t xaccQueryGetEarliestDateFound(Query * q);
|
time_t xaccQueryGetEarliestDateFound(Query * q);
|
||||||
time_t xaccQueryGetLatestDateFound(Query * q);
|
time_t xaccQueryGetLatestDateFound(Query * q);
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
typedef struct query_s Query;
|
|
||||||
|
|
||||||
/* Protect us if QueryNew.h is included first */
|
|
||||||
#ifndef GNC_QUERYNEW_H
|
|
||||||
typedef enum {
|
|
||||||
QUERY_AND=1,
|
|
||||||
QUERY_OR,
|
|
||||||
QUERY_NAND,
|
|
||||||
QUERY_NOR,
|
|
||||||
QUERY_XOR
|
|
||||||
} QueryOp;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BY_STANDARD=1,
|
|
||||||
BY_DATE,
|
|
||||||
BY_DATE_ROUNDED,
|
|
||||||
BY_DATE_ENTERED,
|
|
||||||
BY_DATE_ENTERED_ROUNDED,
|
|
||||||
BY_DATE_RECONCILED,
|
|
||||||
BY_DATE_RECONCILED_ROUNDED,
|
|
||||||
BY_NUM,
|
|
||||||
BY_AMOUNT,
|
|
||||||
BY_MEMO,
|
|
||||||
BY_DESC,
|
|
||||||
BY_RECONCILE,
|
|
||||||
BY_ACCOUNT_FULL_NAME,
|
|
||||||
BY_ACCOUNT_CODE,
|
|
||||||
BY_CORR_ACCOUNT_FULL_NAME,
|
|
||||||
BY_CORR_ACCOUNT_CODE,
|
|
||||||
BY_NONE
|
|
||||||
} sort_type_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
PD_ACCOUNT=1,
|
|
||||||
PD_AMOUNT,
|
|
||||||
PD_BALANCE,
|
|
||||||
PD_BOOK,
|
|
||||||
PD_CLEARED,
|
|
||||||
PD_DATE,
|
|
||||||
PD_GUID,
|
|
||||||
PD_KVP,
|
|
||||||
PD_STRING,
|
|
||||||
PD_MISC
|
|
||||||
} pd_type_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
PR_ACCOUNT=1,
|
|
||||||
PR_ACTION,
|
|
||||||
PR_BALANCE,
|
|
||||||
PR_BOOK,
|
|
||||||
PR_CLEARED,
|
|
||||||
PR_DATE,
|
|
||||||
PR_DESC,
|
|
||||||
PR_GUID,
|
|
||||||
PR_KVP,
|
|
||||||
PR_MEMO,
|
|
||||||
PR_NUM,
|
|
||||||
PR_PRICE,
|
|
||||||
PR_SHRS, /* FIXME: misnamed, should be PR_QUANT or PR_AMOUNT */
|
|
||||||
PR_VALUE,
|
|
||||||
PR_MISC,
|
|
||||||
} pr_type_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ACCT_MATCH_ALL=1,
|
|
||||||
ACCT_MATCH_ANY,
|
|
||||||
ACCT_MATCH_NONE
|
|
||||||
} acct_match_t;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
AMT_MATCH_ATLEAST=1,
|
|
||||||
AMT_MATCH_ATMOST,
|
|
||||||
AMT_MATCH_EXACTLY
|
|
||||||
} amt_match_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AMT_SGN_MATCH_EITHER=1,
|
|
||||||
AMT_SGN_MATCH_CREDIT,
|
|
||||||
AMT_SGN_MATCH_DEBIT
|
|
||||||
} amt_match_sgn_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BOOK_MATCH_ANY=1,
|
|
||||||
BOOK_MATCH_NONE
|
|
||||||
} book_match_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
CLEARED_NO = 1 << 0,
|
|
||||||
CLEARED_CLEARED = 1 << 1,
|
|
||||||
CLEARED_RECONCILED = 1 << 2,
|
|
||||||
CLEARED_FROZEN = 1 << 3,
|
|
||||||
CLEARED_VOIDED = 1 << 4
|
|
||||||
} cleared_match_t;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
STRING_MATCH_CASE = 1 << 0,
|
|
||||||
STRING_MATCH_REGEXP = 1 << 1
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BALANCE_BALANCED = 1 << 0,
|
|
||||||
BALANCE_UNBALANCED = 1 << 1
|
|
||||||
} balance_match_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
KVP_MATCH_LT=1,
|
|
||||||
KVP_MATCH_LTE,
|
|
||||||
KVP_MATCH_EQ,
|
|
||||||
KVP_MATCH_GTE,
|
|
||||||
KVP_MATCH_GT
|
|
||||||
} kvp_match_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
KVP_MATCH_SPLIT = 1 << 0,
|
|
||||||
KVP_MATCH_TRANS = 1 << 1,
|
|
||||||
KVP_MATCH_ACCOUNT = 1 << 2
|
|
||||||
} kvp_match_where_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
QUERY_MATCH_ALL=1, /* match all accounts */
|
|
||||||
QUERY_MATCH_ANY=2 /* match any account */
|
|
||||||
} query_run_t;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* compare two queries for equality. this is a simplistic
|
|
||||||
* implementation -- logical equivalences between different
|
|
||||||
* and/or trees are ignored. */
|
|
||||||
gboolean gncQueryEqual(Query *q1, Query *q2);
|
|
||||||
|
|
||||||
/* handy for debugging */
|
|
||||||
void xaccQueryPrint(Query *q);
|
|
||||||
|
|
||||||
/* (Un-)set the Query's search to look at the template account group used by
|
|
||||||
* scheduled transactions, as well. */
|
|
||||||
void xaccQuerySearchTemplateGroup( Query *, gboolean );
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
* match-adding API
|
|
||||||
*******************************************************************/
|
|
||||||
|
|
||||||
void xaccQueryAddAccountMatch(Query *, AccountList *,
|
|
||||||
acct_match_t how, QueryOp op);
|
|
||||||
void xaccQueryAddAccountGUIDMatch(Query *, AccountGUIDList *,
|
|
||||||
acct_match_t, QueryOp);
|
|
||||||
void xaccQueryAddSingleAccountMatch(Query *, Account *, QueryOp);
|
|
||||||
|
|
||||||
void xaccQueryAddBookMatch(Query * q, BookList *,
|
|
||||||
acct_match_t how, QueryOp op);
|
|
||||||
void xaccQueryAddBookGUIDMatch(Query *, BookGUIDList *,
|
|
||||||
acct_match_t how, QueryOp op);
|
|
||||||
void xaccQueryAddSingleBookMatch(Query *, GNCBook *, QueryOp);
|
|
||||||
|
|
||||||
void xaccQueryAddDescriptionMatch(Query * q, const char * matchstring,
|
|
||||||
int case_sens, int use_regexp, QueryOp op);
|
|
||||||
void xaccQueryAddNumberMatch(Query * q, const char * matchstring,
|
|
||||||
int case_sens, int use_regexp, QueryOp op);
|
|
||||||
void xaccQueryAddActionMatch(Query * q, const char * matchstring,
|
|
||||||
int case_sens, int use_regexp, QueryOp op);
|
|
||||||
|
|
||||||
/* ?????????? why are these depricated ??????????? */
|
|
||||||
void DxaccQueryAddValueMatch(Query * q, double amount,
|
|
||||||
amt_match_sgn_t amt_sgn,
|
|
||||||
amt_match_t how, QueryOp op);
|
|
||||||
void DxaccQueryAddSharePriceMatch(Query * q, double amount,
|
|
||||||
amt_match_t how, QueryOp op);
|
|
||||||
void DxaccQueryAddSharesMatch(Query * q, double amount,
|
|
||||||
amt_match_t how, QueryOp op);
|
|
||||||
|
|
||||||
/* The DateMatch queries match transactions whose posted date
|
|
||||||
* is in a date range. If use_start is TRUE, then a matching
|
|
||||||
* posted date will be greater than the start date. If
|
|
||||||
* use_end is TRUE, then a match occurs for posted dates earlier
|
|
||||||
* than the end date. If both flags are set, then *both*
|
|
||||||
* conditions must hold ('and'). If neither flag is set, then
|
|
||||||
* all transactions are matched.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void xaccQueryAddDateMatch(Query * q,
|
|
||||||
int use_start, int sday, int smonth, int syear,
|
|
||||||
int use_end, int eday, int emonth, int eyear,
|
|
||||||
QueryOp op);
|
|
||||||
void xaccQueryAddDateMatchTS(Query * q,
|
|
||||||
int use_start, Timespec sts,
|
|
||||||
int use_end, Timespec ets,
|
|
||||||
QueryOp op);
|
|
||||||
void xaccQueryAddDateMatchTT(Query * q,
|
|
||||||
int use_start, time_t stt,
|
|
||||||
int use_end, time_t ett,
|
|
||||||
QueryOp op);
|
|
||||||
void xaccQueryAddMemoMatch(Query * q, const char * matchstring,
|
|
||||||
int case_sens, int use_regexp, QueryOp op);
|
|
||||||
void xaccQueryAddClearedMatch(Query * q, cleared_match_t how, QueryOp op);
|
|
||||||
void xaccQueryAddBalanceMatch(Query * q, balance_match_t how, QueryOp op);
|
|
||||||
void xaccQueryAddGUIDMatch(Query * q, const GUID *guid,
|
|
||||||
GNCIdType id_type, QueryOp op);
|
|
||||||
/* given kvp value is on right side of comparison */
|
|
||||||
void xaccQueryAddKVPMatch(Query *q, GSList *path, const kvp_value *value,
|
|
||||||
kvp_match_t how, kvp_match_where_t where,
|
|
||||||
QueryOp op);
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
* sort-related functions
|
|
||||||
*******************************************************************/
|
|
||||||
|
|
||||||
void xaccQuerySetSortOrder(Query * q, sort_type_t primary,
|
|
||||||
sort_type_t secondary, sort_type_t tertiary);
|
|
||||||
sort_type_t xaccQueryGetPrimarySortOrder(Query * q);
|
|
||||||
sort_type_t xaccQueryGetSecondarySortOrder(Query * q);
|
|
||||||
sort_type_t xaccQueryGetTertiarySortOrder(Query * q);
|
|
||||||
|
|
||||||
void xaccQuerySetSortIncreasing(Query * q,
|
|
||||||
gboolean prim_increasing,
|
|
||||||
gboolean sec_increasing,
|
|
||||||
gboolean tert_increasing);
|
|
||||||
gboolean xaccQueryGetSortPrimaryIncreasing (Query *q);
|
|
||||||
gboolean xaccQueryGetSortSecondaryIncreasing (Query *q);
|
|
||||||
gboolean xaccQueryGetSortTertiaryIncreasing (Query *q);
|
|
||||||
|
|
||||||
void xaccQuerySetMaxSplits(Query * q, int n);
|
|
||||||
int xaccQueryGetMaxSplits(Query * q);
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
* compatibility interface with old Query API
|
|
||||||
*******************************************************************/
|
|
||||||
time_t xaccQueryGetEarliestDateFound(Query * q);
|
|
||||||
time_t xaccQueryGetLatestDateFound(Query * q);
|
|
||||||
|
|
||||||
#endif /* 0 */
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user