1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en_gb">
<head>
<title>QOF Query Usage Example</title>
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" type="text/css" href="qof.css">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h1>QOF Queries Over a Set of Objects</h1>
<div id="resource">
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="http://sourceforge.net/projects/qof/">SourceForge</a></li>
<li><a href="index.html#docs">Documentation</a></li>
<li><a href="http://qof-gen.sourceforge.net/">QOF-Generator</a></li>
<li><a href="gobj-example.c.html">GObject queries</a></li>
<li><a href="why-qof.html">Why QOF?</a></li>
<li><a href="http://www.data-freedom.org/">Data Freedom</a></li>
<li><a href="index.html#support">Support</a></li>
</ul>
</div>
<div><p><a href="http://qof-gen.sourceforge.net/">Generate your own</a>
examples using your own data and build a test application.</p>
</div>
<div><p>The example below shows how to perform an SQL query over
a collection of generic, programmer-defined objects. The example
comes in two parts: first, the definition of a generic object, and
second, the actual 'application program' that queries over the set of
objects.</p>
</div>
<div class="clear"> </div>
<h2>Defining a Queriable Object</h2>
<div><p>QOF provides a loose run-time typed object system. To make
an object queriable, you must use that system. However, it is our
hope that the system is sufficiently loose that it doesn't impose
any undesired, forced structure on your particular programming style.
We are trying to provide mechanism, not policy. Note that this
example is in C not C++.</p>
</div>
<div><p>
QOF has only two dependencies, and those are
<a href="http://developer.gnome.org/doc/API/glib/">GLib</a> and
libxml2.</p>
<p>GLib is a collection of basic algorithms and structures
for C programmers, such as linked lists, hash tables,
and more. Glib is a fairly small, fast and simple system,
and should not present difficulties to the experienced
programmer. In the example below, the list of results
from the query are returned as a linked list of GLib
objects. Please note that this example neither uses
nor requires GObjects or Gtk+ in any way.</p>
</div>
<pre>
/** @file my-object.c
* @brief Example definition of a queriable object.
* @author Copyright (c) 2003,2004 Linas Vepstas <linas@linas.org>
*
* This example program shows how to configure an arbitrary
* programmer-defined oject "MyObj" so that the Query routines
* can be used on it. It shows one part of the total:
* -- The object definition, showing how to hook into the query system.
*
* Please make note of how the 'book' is used. A 'book' can serve
* as a collection of collections. In the example below, the book
* will be used to hold all of the instances of 'my object' so that
* these can be found later. Note that the book doesn't need to
* exclusively hold only instances of 'my object', it can hold
* collections of other types as well.
*
* The above ability is one reason why 'book' holds such a central
* place in the QOF system. Note also: when the query is performed
* over all instances of 'my object', its not really over *all*
* instances; its only over those instances stored in the given book.
* Thus, the book is a kind of dataset, and by using books, one
* can have multiple disjoint datasets.
*/
#include <glib.h>
#include <qof/qof.h>
#include "my-object.h"
/* ===================================================== */
MyObj *
my_obj_new (QofBook *book)
{
MyObj *m = g_new0 (MyObj,1);
/* Make sure we keep track of every object;
* otherwise we won't be able to search over them.
* Do this by storing them in a collection.
*
* Although we use a 'collection' in this example, there is no
* requirement that this be done. One could use a global variable
* or something else. The only requirement is that the 'foreach'
* below is able to find every object.
*
* The collection 'data' pointer can be used to store any kind
* of user-defined data. Here, we use it to hold a linked
* list (the GList), but it could have held anything. Most
* other objects (e.g. GnuCash objects) probably don't use the
* data pointer in this way.
*/
QofCollection *coll = qof_book_get_collection (book, MYOBJ_ID);
GList *all_my_objs = qof_collection_get_data (coll);
all_my_objs = g_list_prepend (all_my_objs, m);
qof_collection_set_data (coll, all_my_objs);
return m;
}
/* Generic object getters */
int
my_obj_get_a (MyObj *m)
{
return m->a;
}
int
my_obj_get_b (MyObj *m)
{
return m->b;
}
const char *
my_obj_get_memo (MyObj *m)
{
return m->memo;
}
/* Loop over every instance of MyObj, and apply the callback to it.
* This routine must be defined for queries to be possible. */
void
my_obj_foreach (QofCollection *coll, QofEntityForeachCB cb, gpointer ud)
{
GList *n;
GList *all_my_objs = qof_collection_get_data (coll);
for (n=all_my_objs; n; n=n->next)
{
cb (n->data, ud);
}
}
/* Provide a default mechanism to sort MyObj.
* This is neeeded so that query results can be returned in
* some 'reasonable' order. If you don't want to sort,
* just have this function always return 0.
*/
int
my_obj_order (MyObj *a, MyObj *b)
{
if ( (a) && !(b) ) return -1;
if ( !(a) && (b) ) return +1;
if ( !(a) && !(b) ) return 0;
if ((a)->a > (b)->a) return +1;
if ((a)->a == (b)->a) return 0;
return -1;
}
/* ===================================================== */
/* Provide infrastructure to register my object with QOF */
static QofObject myobj_object_def =
{
interface_version: QOF_OBJECT_VERSION,
e_type: MYOBJ_ID,
type_label: "My Blinking Object",
book_begin: NULL,
book_end: NULL,
is_dirty: NULL,
mark_clean: NULL,
foreach: my_obj_foreach,
printable: NULL,
};
gboolean myObjRegister (void)
{
/* Associate an ASCII name to each getter, as well as the return type */
static QofParam params[] = {
{ MYOBJ_A, QOF_TYPE_INT32, (QofAccessFunc)my_obj_get_a, NULL },
{ MYOBJ_B, QOF_TYPE_INT32, (QofAccessFunc)my_obj_get_b, NULL },
{ MYOBJ_MEMO, QOF_TYPE_STRING, (QofAccessFunc)my_obj_get_memo, NULL },
{ NULL },
};
qof_class_register (MYOBJ_ID, (QofSortFunc)my_obj_order, params);
return qof_object_register (&myobj_object_def);
}
</pre>
<br><br>
<h2>The Main Application Program</h2>
The above defined a C object. Below follows an application program that
shows how to perform SQL queries over a collection of these objects.
<pre>
/** @file sql-example.c
* @breif Example program showing SQL to perform query over objects.
* @author Copyright (c) 2003, 2004 Linas Vepstas <linas@linas.org>
*
* This example program shows how to configure an arbitrary
* programmer-defined oject "MyObj" so that the Query routines
* can be used on it. It consists of four basic peices:
* -- The object definition, showing how to hook into the query system.
* (this part is in the "my-object.c" file)
* -- Generic application intialization, including the creation of
* a number of instances of MyObj.
* -- QOF intialization, required before QOF can be used.
* -- The definition and running of a query, and a printout of the
* results.
*/
#include <glib.h>
#include <qof/qof.h>
#include "my-object.h"
/* ===================================================== */
QofBook *
my_app_init (void)
{
QofBook *book;
/* Perform the application object registeration */
myObjRegister ();
/* Create a new top-level object container */
book = qof_book_new();
return book;
}
void
my_app_shutdown (QofBook *book)
{
/* Terminate our storage. This prevents the system from
* being used any further. */
qof_book_destroy (book);
}
void
my_app_create_data (QofBook *book)
{
MyObj *m;
/* Pretend our app has some objects; we will perform
* the search over these objects */
m = my_obj_new (book);
m->a = 1;
m->b = 1;
m->memo = "Hiho Silver!";
m = my_obj_new (book);
m->a = 1;
m->b = 42;
m->memo = "The Answer to the Question";
m = my_obj_new (book);
m->a = 99;
m->b = 1;
m->memo = "M M M My Sharona";
}
/* ===================================================== */
/* A routine that will build an actual query, run it, and
* print the results.
*/
void
my_app_run_query (QofSqlQuery *q, char *sql_str)
{
GList *results, *n;
/* Run the query */
results = qof_sql_query_run (q, sql_str);
printf ("------------------------------------------\n");
printf ("Query string is: %s\n", sql_str);
printf ("Query returned %d results:\n", g_list_length(results));
for (n=results; n; n=n->next)
{
MyObj *m = n->data;
printf ("Found a matching object, a=%d b=%d memo=\"%s\"\n",
m->a, m->b, m->memo);
}
printf ("\n");
}
void
my_app_do_some_queries (QofBook *book)
{
QofSqlQuery *q;
GList *n;
/* Print out the baseline: all of the instances in the system */
printf ("\n");
printf ("My Object collection contains the following objects:\n");
QofCollection *coll = qof_book_get_collection (book, MYOBJ_ID);
GList *all_my_objs = qof_collection_get_data (coll);
for (n=all_my_objs; n; n=n->next)
{
MyObj *m = n->data;
printf (" a=%d b=%d memo=\"%s\"\n",
m->a, m->b, m->memo);
}
printf ("\n");
/* Create a new query */
q = qof_sql_query_new ();
/* Set the book to be searched */
qof_sql_query_set_book(q, book);
/* Describe the query to be performed.
* We want to find all objects whose "memo" field matches
* a particular string, or all objects whose "b" field is 42.
*/
char * str = "SELECT * FROM " MYOBJ_ID
" WHERE (" MYOBJ_MEMO " = 'M M M My Sharona') OR "
" (" MYOBJ_B " = 42);";
my_app_run_query (q, str);
/* Do some more */
my_app_run_query (q, "SELECT * FROM MyObj WHERE MyObj_a = 1;");
my_app_run_query (q, "SELECT * FROM MyObj WHERE (MyObj_a = 1) AND (MyObj_b=42);");
my_app_run_query (q, "SELECT * FROM MyObj WHERE (MyObj_a = 3);");
my_app_run_query (q, "SELECT * FROM MyObj;");
my_app_run_query (q, "SELECT * FROM MyObj ORDER BY MyObj_a DESC;");
my_app_run_query (q, "SELECT * FROM MyObj ORDER BY MyObj_b DESC;");
my_app_run_query (q, "SELECT * FROM MyObj WHERE MyObj_a = 1 ORDER BY MyObj_b DESC;");
/* The query isn't needed any more; discard it */
qof_sql_query_destroy (q);
}
/* ===================================================== */
int
main (int argc, char *argv[])
{
QofBook *book;
/* Initialize the QOF framework */
gnc_engine_get_string_cache();
guid_init();
qof_object_initialize ();
qof_query_init ();
qof_book_register ();
/* Do application-specific things */
book = my_app_init();
my_app_create_data(book);
my_app_do_some_queries (book);
my_app_shutdown (book);
/* Perform a clean shutdown */
qof_query_shutdown ();
qof_object_shutdown ();
guid_shutdown ();
gnc_engine_string_cache_destroy ();
}
/* =================== END OF FILE ===================== */
</pre>
</body>
</html>
|