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>
|
||||
* 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>
|
||||
|
||||
* 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 "kvp_frame.h"
|
||||
|
||||
#if 1
|
||||
#include "QueryNew.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 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
|
||||
|
Loading…
Reference in New Issue
Block a user