Thoughts on architecture for the GDA backend
Phil Longstaff
plongstaff at rogers.com
Mon Dec 17 16:40:54 EST 2007
Derek Atkins wrote:
Hi,
Phil Longstaff [1]<plongstaff at rogers.com> writes:
Except for a number of bugs (and a lot of testing, and a load/save UI),
the GDA backend basically works for the objects outside of the business
objects. I also want to add an audit trail for changes and version
support to detect when a db needs to be updated to a newer version.
So we've reached feature-parity with the 1.6 Postgres backend?
Excellent! Definitely good progress. What's the time frame to get
the business objects done?
Depends, of course, on how much time I can spend on the project. With
holidays coming up, I should be able to spend more time, and maybe get
the business objects done. I've never used them before, so there will
be a bit of a learning curve.
Some thoughts:
- the GDA backend pulls the data from the engine objects and builds an
INSERT/UPDATE query using the values. This requires the backend to know
what values/types need to be persistent.
In the current GnuCash architecture this is done by having the
backend provide a framework and then having "per-backend object
plugins" that define this persistence.
- create a new GObject interface which has methods for 1) getting a
dictionary of persistent data for the object 2) getting/setting
persistent data. The goal would be to have the engine object and its
class have a bigger role in defining the db table columns in order to
better encapsulate persistence information in the engine objects. The
backend would then be required to transfer the persistence information
for an object to/from the db or file.
Thoughts?
Do we really need this? Is the current plug-in framework not
sufficient? Or do you really believe that you can come up
with an interface that is backend agnostic? I'd like to see
a design proposal before going along this route, because if it's
not backend agnostic then it's no better than what we currently
have.
I'm thinking of something like a modified version of the memento design
pattern ([2]http://en.wikipedia.org/wiki/Memento_pattern). It may have
originally been designed to allow state modifications to be undone, but
it should also be usable here with the gnucash object being the object
whose state needs to be saved and the backend being the caretaker.
However, we wouldn't need an object to be the memento. We *would* need
name/type information to allow the memento state info to be
saved/restored.
In one sense, if every object kept made all of its information
available via kvp, it would be easy to store since there is a flexible
mechanism there, and there is no maintenance problem keeping the
backend up-to-date with the schema.
Take the account object as an example.
The XML backend calls xaccAccountGetName(), xaccAccountGetCommodity(),
... and then encodes each piece of information. The GDA backend calls
the same functions, formats the SQL INSERT or UPDATE request and passes
it to the db to be executed and save the object. If a new attribute is
added to the account engine object, each backend needs to be modified
to call a new function to get the attribute value, then each backend
needs to encode it properly in order to save it.
The Account engine object now has GObject properties defined for all of
its internal attributes. This allows g_object_get() and g_object_set()
to be called to get/set attribute values respectively, but also allows
g_object_class_list_properties() to be called to get a list of the
attributes including type information. A backend could call
g_object_class_list_properties() and then, for each attribute, call
g_object_get(), encode the value and save it. It would need to to know
how to encode each type (for XML, strings are easy, numbers are easy,
commodities are a namespace/name pair, etc., while for GDA, strings are
easy, numbers are easy, commodities are a GUID, etc.). One problem
with g_object_class_list_properties() is that the account has a number
of properties (such as ending balance) which don't need to be
persistent. Therefore, an IGncEnginePersistenceInfo interface with a
gnc_engine_object_get_persistence_parameters() function to return the
same kind of info as g_object_class_list_properties() would be added
(an alternative is to define GncObject or GncEngineObject as a subclass
of QofObject and subclass all engine objects from it - the
gnc_engine_object_get_persistence_parameters() could then be defined as
a method for GncEngineObject). Actually, it would be defined for the
engine object class objects, not the engine objects themselves.
I think it would reduce the size of each backend. In addition, since
the engine object classes would supply the information about what would
need to be saved, it would improve encapsulation and also maintenance
in the backends as new attributes are added. Each backend would need
to know how to save each attribute type, and how to convert from the
saved value if the attribute type has changed (e.g. recent sx change
from FreqSpec to Recurrence). The GDA backend would need to know how
to map attribute names to column names (I don't think '-' is allowed in
a column name, for example) and how to modify tables if the table
column structure doesn't match the types of the attributes to be saved
(attribute added or type changed).
Phil
References
1. mailto:plongstaff at rogers.com
2. http://en.wikipedia.org/wiki/Memento_pattern
More information about the gnucash-devel
mailing list