QOF: QOF Backend Design

QOF 0.7.5

QOF Backend Design

         Derek Atkins
       <derek@ihtfp.com>

       Neil Williams
       <linux@codehelp.co.uk>

Created: 2002-10-07 Updated: 2005-05-22

# Outline:

The Backend Query API allows caching of a Query (meaning the Backend does not have to recompile the Query every time the query is executed).

# New QOF Objects

The engine has a set of APIs to load new data types into the engine. The Backends use this as well. There is a noticeable difference between QOF and GnuCash: GnuCash extends the backend by defining routines for each object. QOF backends handle each object equally and generically.

A new object is declared using the base QOF types and zero or more references to other QOF objects. Each QOF backend must handle each base QOF type and references to other objects - usually by storing the type of the referenced object and the GUID of the referenced object as the value and the GUID of the original object as the key in a GHashTable or other lookup mechanism within the backend. See QofEntityReference.

# Handling Queries:

The backend query API is broken into three pieces:

## Compiling a QofQuery

        gpointer (*query_compile)(QofBackend* be, QofQuery* query);

compiles a QofQuery* into whatever QofBackend language is necessary.

## Free the query

        void (*query_free)(Backend* be, gpointer query);

frees the compiled Query (obtained from the query_compile method).

## Run the query

        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.

# 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.

        void session_load(QofBackend*, QofBook*);

This one API loads all the necessary "start-time" data, There is no need to have multiple APIs for each of the data types loaded at start-time.