6.4. Using qof_book_merge with new and existing QOF objects

qof_class_register parameters. A successful merge operation relies on adequate support from new and existing QOF and GnuCash objects. A generic merge must rely on the specific objects to describe themselves and provide the functionality to get and set the relevant data. Each object needs to utilise a full set of qof_class parameters and a standard set of functions to get and set all and any parameters that cannot or should not be calculated.

The test-book-merge.c program demonstrates a full and complete qof_class parameter and function description:

static QofObject obj_object_def = {
  interface_version:     QOF_OBJECT_VERSION,
  e_type:                TEST_MODULE_NAME,
  type_label:            TEST_MODULE_DESC,
  create:                (gpointer)obj_create,
  book_begin:            NULL,
  book_end:              NULL,
  is_dirty:              NULL,
  mark_clean:            NULL,
  foreach:               qof_collection_foreach,
  printable:             NULL,
  version_cmp:           (int (*)(gpointer,gpointer)) qof_instance_version_cmp,
};

gboolean myobjRegister (void)
{
  static QofParam params[] = {
{ OBJ_NAME,	QOF_TYPE_STRING,	(QofAccessFunc)obj_getName,	(QofSetterFunc)obj_setName	},
{ OBJ_AMOUNT,   QOF_TYPE_NUMERIC,	(QofAccessFunc)obj_getAmount,   (QofSetterFunc)obj_setAmount	},
{ OBJ_GUID,	QOF_TYPE_GUID,		(QofAccessFunc)obj_getGUID,	(QofSetterFunc)obj_setGUID	},
{ OBJ_DATE,	QOF_TYPE_DATE,		(QofAccessFunc)obj_getDate,	(QofSetterFunc)obj_setDate	},
{ OBJ_DISCOUNT, QOF_TYPE_DOUBLE,	(QofAccessFunc)obj_getDiscount, (QofSetterFunc)obj_setDiscount  },
{ OBJ_ACTIVE,   QOF_TYPE_BOOLEAN,	(QofAccessFunc)obj_getActive,   (QofSetterFunc)obj_setActive	},
{ OBJ_VERSION,  QOF_TYPE_INT32,		(QofAccessFunc)obj_getVersion,  (QofSetterFunc)obj_setVersion   },
{ OBJ_MINOR,	QOF_TYPE_INT64,		(QofAccessFunc)obj_getMinor,	(QofSetterFunc)obj_setMinor	},
{ QOF_PARAM_BOOK, QOF_ID_BOOK,		(QofAccessFunc)qof_instance_get_book, NULL },
{ QOF_PARAM_GUID, QOF_TYPE_GUID,	(QofAccessFunc)qof_instance_get_guid, NULL },
{ NULL },
};

  qof_class_register (TEST_MODULE_NAME, NULL, params);

  return qof_object_register (&obj_object_def);
}
	

The prototypes for each get and set function illustrate the standard mechanisms for use by the merge operation:

/* getter functions */
void obj_setName(myobj*,	char*);
void obj_setGUID(myobj*,	const GUID*);
void obj_setAmount(myobj*,	gnc_numeric);
void obj_setDate(myobj*,	Timespec h);
void obj_setDiscount(myobj*,	double);
void obj_setActive(myobj*,	gboolean);
void obj_setVersion(myobj*,	gint32);
void obj_setMinor(myobj*,	gint64);

/* setter functions */
gnc_numeric	obj_getAmount(myobj*);
char*		obj_getName(myobj*);
const GUID*	obj_getGUID(myobj*);
Timespec   	obj_getDate(myobj*);
double		obj_getDiscount(myobj*);
gboolean	obj_getActive(myobj*);
gint32		obj_getVersion(myobj*);
gint64		obj_getMinor(myobj*);
	

Please note the return types and parameter types. To use the merge operation, your object should use the same prototype for each relevant QOF_TYPE.

In particular, please keep the same pattern for pointer parameters - strings should be char (or gchar) pointers, GUID should be constant pointers and all other types are passed and returned without using pointers.

Declaring functions that use additional parameters, unexpected pointers or other discrepancies is likely to cause a segmentation fault in the merge.

Any parameter that does NOT have a get and a corresponding set function will be ignored by the merge operation - this rule should be used to discriminate between parameters that should only ever be calculated (e.g. account balances) and parameters that must always be set by the backend, user or merge (e.g. account names).

Note that all objects require a foreach AND a create function in the object definition. If any object is not fully QOF compliant, ensure that either the foreach or create functions are NULL or you will get errors when qof_book_merge runs, even if no objects of that type exist in either book.