File: my-obj-example.c.html

package info (click to toggle)
qof 0.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 4,436 kB
  • ctags: 3,587
  • sloc: ansic: 33,810; sh: 9,356; xml: 487; makefile: 405; yacc: 184; lex: 123; sed: 16
file content (378 lines) | stat: -rw-r--r-- 11,522 bytes parent folder | download | duplicates (2)
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">&nbsp;</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 &lt;linas@linas.org&gt;
 *
 *  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 &lt;glib.h&gt;
#include &lt;qof/qof.h&gt;
#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-&gt;a;
}

int
my_obj_get_b (MyObj *m)
{
   return m-&gt;b;
}

const char *
my_obj_get_memo (MyObj *m)
{
   return m-&gt;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-&gt;next)
   {
      cb (n-&gt;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)-&gt;a &gt; (b)-&gt;a) return +1;
   if ((a)-&gt;a == (b)-&gt;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 &lt;linas@linas.org&gt;
 *
 *  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 &lt;glib.h&gt;
#include &lt;qof/qof.h&gt;
#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-&gt;a = 1;
   m-&gt;b = 1;
   m-&gt;memo = "Hiho Silver!";
   
   m = my_obj_new (book);
   m-&gt;a = 1;
   m-&gt;b = 42;
   m-&gt;memo = "The Answer to the Question";
   
   m = my_obj_new (book);
   m-&gt;a = 99;
   m-&gt;b = 1;
   m-&gt;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-&gt;next)
   {
      MyObj *m = n-&gt;data;
      printf ("Found a matching object, a=%d b=%d memo=\"%s\"\n", 
          m-&gt;a, m-&gt;b, m-&gt;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-&gt;next)
   {
      MyObj *m = n-&gt;data;
      printf ("    a=%d b=%d memo=\"%s\"\n", 
          m-&gt;a, m-&gt;b, m-&gt;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>