New Hacker and QOF instance modification / undo
Neil Williams
linux at codehelp.co.uk
Fri Sep 2 05:55:43 EDT 2005
On Thursday 01 September 2005 11:19 pm, Mike B wrote:
> Hey everyone,
Welcome!
> I've just been playing around with the
> GNUCash source for the first time, and I'm having a
> little trouble. I haven't seen anything in the design
> documents about how account data is organized and how
> the object mapping interfaces with that, so I'm having
> trouble making the queries that I want to make.
As already mentioned, each object describes itself to the query object
framework. A static object description outlines what data the object can
accept and provide, how to iterate over each instance of that object and how
to mark an instance as dirty.
The mapping from the object data to a specific backend layout is full of
indirection because the object neither knows nor cares about the detail of
the backend and vice versa. Each application using QOF can provide it's own
objects and / or it's own backends.
> I think it's interesting that when someone like me is
> first getting into the GNUCash source, what I really
> want is a database schema and access to SQL queries.
(repeat ten times: gnucash has no database).
If you want to, you could download CashUtil
http://www.linux.codehelp.co.uk/cashutil/ (it needs CVS QOF to build
currently) as this does provide command line SQL queries. It's far from
complete but it's easier than compiling new SQL queries via the gnucash tree.
> I'm sure that I'll learn to appreciate the OR mapping
> layer, but right now I'm just confused.
That would be because you are looking for something that does not exist!
:-)
I was just as confused when I started with the gnucash source tree.
Josh wrote:
> > You should take a good look at QOF, however. It's not an OR mapping
> > layer so much as a mappable object model ... i.e., queries expressed
> > over in-memory QOF object-graphs can be translated into SQL. I'm still
> > not sure how it handles data-modificiation, though.
In QOF, object descriptions provide the object model map using a list of
parameters that have a name, data type, get function and set function. This
list is static within the application and referenced via a GHashTable in QOF.
There is no need to copy QofParam - it's always static and sufficient to keep
just a pointer.
The SQL translation is actually the reverse of how Josh described it. Incoming
SQL is converted to the QOF predicates (which can also be manipulated
directly) where the search is actually achieved. QOF can accept limited SQL
commands but only by converting them to a QofQuery that it understands. i.e.
SQL support is not native (and will be implemented via the GDA external
library in due course). There is currently no way to convert a series of
predicates into SQL but I'm working on that for CashUtil so that it can have
some rudimentary macro functions.
Data-modification is done via QofParam and param_setfcn - a pointer to the
actual object function that modifies the instance.
QofParam *param; // assuming a string param_type in this case
param->param_setfcn(QofEntity *ent, const char *string);
If this was the Account name parameter (from Account.c):
{ ACCOUNT_NAME_,
QOF_TYPE_STRING,
(QofAccessFunc)xaccAccountGetName,
(QofSetterFunc) xaccAccountSetName },
This would actually call:
void xaccAccountSetName (Account *account, const char *name)
The Account* is cast from the QofEntity*.
param->param_getfcn works in a similar way. There's also an important
distinction between parameters that are "calculated" and those that can be
"set". Parameters like the Account balance can be queried (using get) but
should never be set, so the param_setfcn is NULL. This rule is fundamental to
QOF and it is vital that all objects implement the distinction in a logical
manner.
Function pointers are required to set certain parameters (like gnc_numeric,
boolean and dates) that are not passed as pointers themselves:
Timespec cli_date;
void (*date_setter) (QofEntity*, Timespec);
date_setter = (void(*)(QofEntity*, Timespec))param->param_setfcn;
if(date_setter != NULL) { date_setter(ent, cli_date); }
(That took me ages to understand but thanks to Derek's patience, I got it
eventually!)
Example:
http://code.neil.williamsleesmill.me.uk/cashutil/group__UNDO.html#ga2
All data modification should occur between a begin_edit and commit_edit pair.
Once QOF undo is implemented, there'll be a further wrapper for a series of
data modifications that form a single "operation" from the user perspective.
(For those who are interested, the limited undo support for QOF as currently
implemented in CashUtil is documented using (a buggy) Doxygen output here:
http://code.neil.williamsleesmill.me.uk/cashutil/group__UNDO.html
> I think what I really need is an example that I don't
> have to follow through layers of indirection.
If you want to experiment with your own objects, try QOF-gen:
http://qof-gen.sourceforge.net/
Or PilotQOF (which uses simpler objects):
http://pilot-qof.sourceforge.net/
--
Neil Williams
=============
http://www.data-freedom.org/
http://www.nosoftwarepatents.com/
http://www.linux.codehelp.co.uk/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.gnucash.org/pipermail/gnucash-devel/attachments/20050902/bff61714/attachment.bin
More information about the gnucash-devel
mailing list