General Query Framework, a proposal

Derek Atkins warlord@MIT.EDU
28 Jan 2002 19:50:28 -0500


--=-=-=

I've been thinking a lot recently about generalizing the Query
infrastructure.   The current Query is specifically limited to
searching for Splits (and Transactions), and all the Query
methods are specifically tied to the Split.  I'd like to
propose a new Query framework that breaks down queries into
multiple levels:

1) a set of core queriable types.  A core type provides a name and a
query predicate function that is used to compare object types.  Core
query types include:

        string
        numeric
        date
        guid

2) a set of gnucash objects.  These are the queriable types (things
that you may want to search on/for in the system).  Each object
defines its name and a list of queriable parameters, the parameter
type (which must be a core query type), and the getter function for
the parameter.  Queriable gnucash objects would include:

        splits
        transactions
        accounts?
        entries
        customers
        vendors
        jobs
        invoices?
        orders?

The key to this new system is plugability.  Each core type and each
gnucash object is registered with the Query subsystem.  Users of the
query subject then build a set of query terms and can combine them to
run searches.

I believe that this current framework as current defined can handle
all the existing queries except for those based on the Reconcile flag.
I'm not sure how to cope with reconcile, yet, except perhaps to make
each "reconcile" type its own core type (i.e. the "split-recn" type).

The attached files are the current (incomplete) header files.  Please
let me know what you think so far.

Thanks!

-derek


--=-=-=
Content-Disposition: attachment; filename=QueryNew.h
Content-Description: top-level query infrastructure

/*
 * QueryNew.h -- API for finding Gnucash objects
 * Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
 *
 */

#ifndef GNC_QUERYNEW_H
#define GNC_QUERYNEW_H

/* A Query */
typedef struct querynew_s QueryNew;

/* Query Term Operators, for combining Query Terms */
typedef enum {
  QUERY_AND=1,
  QUERY_OR,
  QUERY_NAND,
  QUERY_NOR,
  QUERY_XOR
} QueryOp;


/* Standard Query Term comparitors, for how to process a query term */
typedef enum {
  COMPARE_LT = 1,
  COMPARE_LTE,
  COMPARE_EQUAL,
  COMPARE_GT,
  COMPARE_GTE
} query_compare_t;


/* Type of Query Core Objects (String, Date, Numeric, GUID, etc. */
typedef const char * QueryCoreType;

/*
 * List of known core query types... 
 * Each core query type defines it's set of optional "comparitor qualifiers".
 */
#define QUERYCORE_STRING	"string"
typedef enum {
  STRING_MATCH_CASEINSENSITIVE	= 1,
  STRING_MATCH_REGEXP
} string_match_t;

#define QUERYCORE_DATE		"date"
typedef enum {
  DATE_MATCH_ROUNDED = 1
} date_match_t;

#define QUERYCORE_NUMERIC	"numeric"
typedef enum {
  NUMERIC_MATCH_ABS = 1,
  NUMERIC_MATCH_NEG_ONLY,
  NUMERIC_MATCH_POS_ONLY
} numeric_match_t;

#define QUERYCORE_GUID		"guid"
typedef enum {
  GUID_MATCH_ALL = 1,
  GUID_MATCH_ANY
  GUID_MATCH_NONE
} guid_match_t;


/* XXX: How do we deal with RECNcells? */

#endif /* GNC_QUERYNEW_H */

--=-=-=
Content-Disposition: attachment; filename=QueryCore.h
Content-Description: Core Query Object registration

/*
 * QueryCore.h -- API for providing core Query objects
 * Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
 *
 */

#ifndef GNC_QUERYCORE_H
#define GNC_QUERYCORE_H

#include "QueryNew.h"

/* 
 * An arbitrary Query Predicate.  Given the gnucash object, see how
 * it compares to the predicate data given the match_options
 */

typedef int (*QueryPredicate) (gpointer object,
			       query_compare_t how,
			       gint match_options,
			       gpointer *pdata);

/* This function registers a new Core Object with the QueryNew
 * subsystem.  It registers the "core_name" object to use the
 * given query_predicate function
 */

void gncQueryRegisterCoreObject (char const *core_name,
				 QueryPredicate pred);


/* An example:
 *
 * gncQueryRegisterCoreObject (QUERYCORE_STRING, string_match_predicate);
 */


#endif /* GNC_QUERYCORE_H */

--=-=-=
Content-Disposition: attachment; filename=QueryObject.h
Content-Description: Gnucash Queriable Object Registration

/*
 * QueryObject.h -- API for searching Gnucash objects
 * Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
 *
 */

#ifndef GNC_QUERYOBJECT_H
#define GNC_QUERYOBJECT_H

#include "QueryNew.h"

/* Define an arbitrary function pointer for access functions.  This is
 * because C doesn't have templates, so we just cast a lot.  Real
 * functions must be of the form:
 * 
 * <param_type> function (object_type *obj);
 */
typedef void (*QueryAccess)(void);

/* This structure is for each queriable parameter in an object */
typedef struct query_object_def {
  const char *	parameter;
  QueryCoreType	param_type;
  QueryAccess	param_fcn;
} QueryObjectDef;


/* This function registers a new Gnucash Object with the QueryNew
 * subsystem.  It registers the "obj_name" object which provides the
 * "methods" set of queriable parameters.  The "methods" array must
 * be a NULL-terminated array.
 */
void gncQueryRegisterObject (const char * obj_name,
			     const QueryObjectDef *methods[]);

/* An example:
 *
 * #define MY_QUERY_OBJ_MEMO	"memo"
 * #define MY_QUERY_OBJ_VALUE	"value"
 * #define MY_QUERY_OBJ_DATE	"date"
 *
 * static QueryObjectDef myQueryObject[] = {
 * { MY_QUERY_OBJ_MEMO, QUERYCORE_STRING, myMemoGetter },
 * { MY_QUERY_OBJ_VALUE, QUERYCORE_NUMERIC, myValueGetter },
 * { MY_QUERY_OBJ_DATE, QUERYCORE_DATE, myDateGetter },
 * NULL };
 *
 * gncQueryRegisterObject ("myObjectName", &myQueryObject);
 */

#endif /* GNC_QUERYOBJECT_H */

--=-=-=



-- 
       Derek Atkins, SB '93 MIT EE, SM '95 MIT Media Laboratory
       Member, MIT Student Information Processing Board  (SIPB)
       URL: http://web.mit.edu/warlord/    PP-ASEL-IA     N1NWH
       warlord@MIT.EDU                        PGP key available

--=-=-=--