]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/c-apps/oils_cstore.c
make search methods streaming
[Evergreen.git] / Open-ILS / src / c-apps / oils_cstore.c
1 #include "opensrf/osrf_application.h"
2 #include "opensrf/osrf_settings.h"
3 #include "opensrf/utils.h"
4 #include "objson/object.h"
5 #include "opensrf/log.h"
6 #include "oils_utils.h"
7 #include "oils_constants.h"
8 #include "oils_event.h"
9 #include <dbi/dbi.h>
10
11 #include <time.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <libxml/globals.h>
15 #include <libxml/xmlerror.h>
16 #include <libxml/parser.h>
17 #include <libxml/tree.h>
18 #include <libxml/debugXML.h>
19 #include <libxml/xmlmemory.h>
20
21 #define OILS_AUTH_CACHE_PRFX "oils_cstore_"
22 #define MODULENAME "open-ils.cstore"
23 #define PERSIST_NS "http://open-ils.org/spec/opensrf/IDL/persistance/v1"
24 #define OBJECT_NS "http://open-ils.org/spec/opensrf/IDL/objects/v1"
25 #define BASE_NS "http://opensrf.org/spec/IDL/base/v1"
26
27 int osrfAppChildInit();
28 int osrfAppInitialize();
29
30 int dispatchCRUDMethod ( osrfMethodContext* );
31 jsonObject* doCreate ( osrfHash*, jsonObject* );
32 jsonObject* doRetrieve ( osrfHash*, jsonObject* );
33 jsonObject* doUpdate ( osrfHash*, jsonObject* );
34 jsonObject* doDelete ( osrfHash*, jsonObject* );
35 jsonObject* doSearch ( osrfHash*, jsonObject* );
36 jsonObject* oilsMakeJSONFromResult( dbi_result, osrfHash* );
37
38 dbi_conn dbhandle; /* our db connection */
39 xmlDocPtr idlDoc = NULL; // parse and store the IDL here
40
41
42 /* parse and store the IDL here */
43 osrfHash* idlHash;
44
45 int osrfAppInitialize() {
46
47         idlHash = osrfNewHash();
48         osrfHash* usrData = NULL;
49
50         osrfLogInfo(OSRF_LOG_MARK, "Initializing the CStore Server...");
51         osrfLogInfo(OSRF_LOG_MARK, "Finding XML file...");
52
53         char * idl_filename = osrf_settings_host_value("/apps/%s/app_settings/IDL", MODULENAME);
54         osrfLogInfo(OSRF_LOG_MARK, "Found file:");
55         osrfLogInfo(OSRF_LOG_MARK, idl_filename);
56
57         osrfLogInfo(OSRF_LOG_MARK, "Parsing the IDL XML...");
58         idlDoc = xmlReadFile( idl_filename, NULL, XML_PARSE_XINCLUDE );
59         
60         if (!idlDoc) {
61                 osrfLogError(OSRF_LOG_MARK, "Could not load or parse the IDL XML file!");
62                 exit(1);
63         }
64
65         osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed");
66
67         osrfStringArray* global_methods = osrfNewStringArray(1);
68
69         //osrfStringArrayAdd( global_methods, "create" );
70         osrfStringArrayAdd( global_methods, "retrieve" );
71         //osrfStringArrayAdd( global_methods, "update" );
72         //osrfStringArrayAdd( global_methods, "delete" );
73         osrfStringArrayAdd( global_methods, "search" );
74
75         xmlNodePtr docRoot = xmlDocGetRootElement(idlDoc);
76         xmlNodePtr kid = docRoot->children;
77         while (kid) {
78                 if (!strcmp( (char*)kid->name, "class" )) {
79
80                         usrData = osrfNewHash();
81                         osrfHashSet( usrData, xmlGetProp(kid, "id"), "classname");
82                         osrfHashSet( usrData, xmlGetNsProp(kid, "tablename", PERSIST_NS), "tablename");
83                         osrfHashSet( usrData, xmlGetNsProp(kid, "fieldmapper", OBJECT_NS), "fieldmapper");
84
85                         osrfHashSet( idlHash, usrData, (char*)osrfHashGet(usrData, "classname") );
86
87                         osrfLogInfo(OSRF_LOG_MARK, "Generating class methods for %s", osrfHashGet(usrData, "fieldmapper") );
88
89                         osrfHash* _tmp;
90                         osrfHash* links = osrfNewHash();
91                         osrfHash* fields = osrfNewHash();
92
93                         osrfHashSet( usrData, fields, "fields" );
94                         osrfHashSet( usrData, links, "links" );
95
96                         xmlNodePtr _cur = kid->children;
97
98                         while (_cur) {
99                                 char* string_tmp = NULL;
100
101                                 if (!strcmp( (char*)_cur->name, "fields" )) {
102
103                                         if( (string_tmp = (char*)xmlGetNsProp(_cur, "primary", PERSIST_NS)) ) {
104                                                 osrfHashSet(
105                                                         usrData,
106                                                         strdup( string_tmp ),
107                                                         "primarykey"
108                                                 );
109                                         }
110                                         string_tmp = NULL;
111
112                                         xmlNodePtr _f = _cur->children;
113
114                                         while(_f) {
115                                                 if (strcmp( (char*)_f->name, "field" )) {
116                                                         _f = _f->next;
117                                                         continue;
118                                                 }
119
120                                                 _tmp = osrfNewHash();
121
122                                                 if( (string_tmp = (char*)xmlGetNsProp(_f, "array_position", OBJECT_NS)) ) {
123                                                         osrfHashSet(
124                                                                 _tmp,
125                                                                 strdup( string_tmp ),
126                                                                 "array_position"
127                                                         );
128                                                 }
129                                                 string_tmp = NULL;
130
131                                                 if( (string_tmp = (char*)xmlGetNsProp(_f, "virtual", PERSIST_NS)) ) {
132                                                         osrfHashSet(
133                                                                 _tmp,
134                                                                 strdup( string_tmp ),
135                                                                 "virtual"
136                                                         );
137                                                 }
138                                                 string_tmp = NULL;
139
140                                                 if( (string_tmp = (char*)xmlGetProp(_f, "name")) ) {
141                                                         osrfHashSet(
142                                                                 _tmp,
143                                                                 strdup( string_tmp ),
144                                                                 "name"
145                                                         );
146                                                 }
147
148                                                 osrfLogInfo(OSRF_LOG_MARK, "Found field %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
149
150                                                 osrfHashSet(
151                                                         fields,
152                                                         _tmp,
153                                                         strdup( string_tmp )
154                                                 );
155                                                 _f = _f->next;
156                                         }
157                                 }
158
159                                 if (!strcmp( (char*)_cur->name, "links" )) {
160                                         xmlNodePtr _l = _cur->children;
161
162                                         while(_l) {
163                                                 if (strcmp( (char*)_l->name, "link" )) {
164                                                         _l = _l->next;
165                                                         continue;
166                                                 }
167
168                                                 _tmp = osrfNewHash();
169
170                                                 if( (string_tmp = (char*)xmlGetProp(_l, "reltype")) ) {
171                                                         osrfHashSet(
172                                                                 _tmp,
173                                                                 strdup( string_tmp ),
174                                                                 "reltype"
175                                                         );
176                                                 }
177                                                 osrfLogInfo(OSRF_LOG_MARK, "Adding link with reltype %s", string_tmp );
178                                                 string_tmp = NULL;
179
180                                                 if( (string_tmp = (char*)xmlGetProp(_l, "key")) ) {
181                                                         osrfHashSet(
182                                                                 _tmp,
183                                                                 strdup( string_tmp ),
184                                                                 "key"
185                                                         );
186                                                 }
187                                                 osrfLogInfo(OSRF_LOG_MARK, "Link fkey is %s", string_tmp );
188                                                 string_tmp = NULL;
189
190                                                 if( (string_tmp = (char*)xmlGetProp(_l, "class")) ) {
191                                                         osrfHashSet(
192                                                                 _tmp,
193                                                                 strdup( string_tmp ),
194                                                                 "class"
195                                                         );
196                                                 }
197                                                 osrfLogInfo(OSRF_LOG_MARK, "Link fclass is %s", string_tmp );
198                                                 string_tmp = NULL;
199
200                                                 osrfStringArray* map = osrfNewStringArray(0);
201
202                                                 if( (string_tmp = (char*)xmlGetProp(_l, "map") )) {
203                                                         char* map_list = strdup( string_tmp );
204                                                         osrfLogInfo(OSRF_LOG_MARK, "Link mapping list is %s", string_tmp );
205
206                                                         if (strlen( map_list ) > 0) {
207                                                                 char* st_tmp;
208                                                                 char* _map_class = strtok_r(map_list, " ", &st_tmp);
209                                                                 osrfStringArrayAdd(map, strdup(_map_class));
210                                                 
211                                                                 while ((_map_class = strtok_r(NULL, " ", &st_tmp))) {
212                                                                         osrfStringArrayAdd(map, strdup(_map_class));
213                                                                 }
214                                                         }
215                                                 }
216                                                 osrfHashSet( _tmp, map, "map");
217
218                                                 if( (string_tmp = (char*)xmlGetProp(_l, "field")) ) {
219                                                         osrfHashSet(
220                                                                 _tmp,
221                                                                 strdup( string_tmp ),
222                                                                 "field"
223                                                         );
224                                                 }
225
226                                                 osrfHashSet(
227                                                         links,
228                                                         _tmp,
229                                                         strdup( string_tmp )
230                                                 );
231
232                                                 osrfLogInfo(OSRF_LOG_MARK, "Found link %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
233
234                                                 _l = _l->next;
235                                         }
236                                 }
237
238                                 _cur = _cur->next;
239                         }
240
241                         int i = 0; 
242                         char* method_type;
243                         char* st_tmp;
244                         char* _fm;
245                         char* part;
246                         osrfHash* method_meta;
247                         while ( (method_type = osrfStringArrayGetString(global_methods, i++)) ) {
248
249                                 if (!osrfHashGet(usrData, "fieldmapper")) continue;
250
251                                 method_meta = osrfNewHash();
252                                 osrfHashSet(method_meta, usrData, "class");
253
254                                 _fm = strdup( (char*)osrfHashGet(usrData, "fieldmapper") );
255                                 part = strtok_r(_fm, ":", &st_tmp);
256
257                                 growing_buffer* method_name =  buffer_init(64);
258                                 buffer_fadd(method_name, "%s.direct.%s", MODULENAME, part);
259
260                                 while ((part = strtok_r(NULL, ":", &st_tmp))) {
261                                         buffer_fadd(method_name, ".%s", part);
262                                 }
263                                 buffer_fadd(method_name, ".%s", method_type);
264
265
266                                 char* method = buffer_data(method_name);
267                                 buffer_free(method_name);
268                                 free(_fm);
269
270                                 osrfHashSet( method_meta, method, "methodname" );
271                                 osrfHashSet( method_meta, method_type, "methodtype" );
272
273                                 int flags = 0;
274                                 if (!(strcmp( method_type, "search" ))) {
275                                         flags = flags | OSRF_METHOD_STREAM;
276                                 }
277
278                                 osrfAppRegisterExtendedMethod(
279                                         MODULENAME,
280                                         method,
281                                         "dispatchCRUDMethod",
282                                         "",
283                                         1,
284                                         flags,
285                                         (void*)method_meta
286                                 );
287                         }
288                 }
289                 kid = kid->next;
290         }
291
292         return 0;
293 }
294
295 /**
296  * Connects to the database 
297  */
298 int osrfAppChildInit() {
299
300         osrfLogDebug(OSRF_LOG_MARK, "Attempting to initialize libdbi...");
301         dbi_initialize(NULL);
302         osrfLogDebug(OSRF_LOG_MARK, "... libdbi initialized.");
303
304         char* driver    = osrf_settings_host_value("/apps/%s/app_settings/driver", MODULENAME);
305         char* user      = osrf_settings_host_value("/apps/%s/app_settings/database/user", MODULENAME);
306         char* host      = osrf_settings_host_value("/apps/%s/app_settings/database/host", MODULENAME);
307         char* port      = osrf_settings_host_value("/apps/%s/app_settings/database/port", MODULENAME);
308         char* db        = osrf_settings_host_value("/apps/%s/app_settings/database/db", MODULENAME);
309         char* pw        = osrf_settings_host_value("/apps/%s/app_settings/database/pw", MODULENAME);
310
311         osrfLogDebug(OSRF_LOG_MARK, "Attempting to load the database driver [%s]...", driver);
312         dbhandle = dbi_conn_new(driver);
313
314         if(!dbhandle) {
315                 osrfLogError(OSRF_LOG_MARK, "Error loading database driver [%s]", driver);
316                 return -1;
317         }
318         osrfLogDebug(OSRF_LOG_MARK, "Database driver [%s] seems OK", driver);
319
320         osrfLogInfo(OSRF_LOG_MARK, "%s connecting to database.  host=%s, "
321                 "port=%s, user=%s, pw=%s, db=%s", MODULENAME, host, port, user, pw, db );
322
323         if(host) dbi_conn_set_option(dbhandle, "host", host );
324         if(port) dbi_conn_set_option_numeric( dbhandle, "port", atoi(port) );
325         if(user) dbi_conn_set_option(dbhandle, "username", user);
326         if(pw) dbi_conn_set_option(dbhandle, "password", pw );
327         if(db) dbi_conn_set_option(dbhandle, "dbname", db );
328
329         free(user);
330         free(host);
331         free(port);
332         free(db);
333         free(pw);
334
335         const char* err;
336         if (dbi_conn_connect(dbhandle) < 0) {
337                 dbi_conn_error(dbhandle, &err);
338                 osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err);
339                 return -1;
340         }
341
342         osrfLogInfo(OSRF_LOG_MARK, "%s successfully connected to the database", MODULENAME);
343
344         int attr;
345         unsigned short type;
346         int i = 0; 
347         char* classname;
348         osrfStringArray* classes = osrfHashKeys( idlHash );
349         
350         while ( (classname = osrfStringArrayGetString(classes, i++)) ) {
351                 osrfHash* class = osrfHashGet( idlHash, classname );
352                 osrfHash* fields = osrfHashGet( class, "fields" );
353                 
354                 growing_buffer* sql_buf = buffer_init(32);
355                 buffer_fadd( sql_buf, "SELECT * FROM %s WHERE 1=0;", osrfHashGet(class, "tablename") );
356
357                 char* sql = buffer_data(sql_buf);
358                 buffer_free(sql_buf);
359                 osrfLogDebug(OSRF_LOG_MARK, "%s Investigatory SQL = %s", MODULENAME, sql);
360
361                 dbi_result result = dbi_conn_query(dbhandle, sql);
362                 free(sql);
363
364                 if (result) {
365
366                         int columnIndex = 1;
367                         const char* columnName;
368                         osrfHash* _f;
369                         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
370
371                                 osrfLogDebug(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
372
373                                 /* fetch the fieldmapper index */
374                                 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
375
376                                         osrfLogDebug(OSRF_LOG_MARK, "Found [%s] in IDL hash...", (char*)columnName);
377
378                                         /* determine the field type and storage attributes */
379                                         type = dbi_result_get_field_type(result, columnName);
380                                         attr = dbi_result_get_field_attribs(result, columnName);
381
382                                         switch( type ) {
383
384                                                 case DBI_TYPE_INTEGER :
385
386                                                         osrfHashSet(_f,"number", "primitive");
387
388                                                         if( attr & DBI_INTEGER_SIZE8 ) 
389                                                                 osrfHashSet(_f,"INT8", "datatype");
390                                                         else 
391                                                                 osrfHashSet(_f,"INT", "datatype");
392                                                         break;
393
394                                                 case DBI_TYPE_DECIMAL :
395                                                         osrfHashSet(_f,"number", "primitive");
396                                                         osrfHashSet(_f,"NUMERIC", "datatype");
397                                                         break;
398
399                                                 case DBI_TYPE_STRING :
400                                                         osrfHashSet(_f,"string", "primitive");
401                                                         osrfHashSet(_f,"TEXT", "datatype");
402                                                         break;
403
404                                                 case DBI_TYPE_DATETIME :
405                                                         osrfHashSet(_f,"string", "primitive");
406                                                         osrfHashSet(_f,"TIMESTAMP", "datatype");
407                                                         break;
408
409                                                 case DBI_TYPE_BINARY :
410                                                         osrfHashSet(_f,"string", "primitive");
411                                                         osrfHashSet(_f,"BYTEA", "datatype");
412                                         }
413
414                                         osrfLogDebug(
415                                                 OSRF_LOG_MARK,
416                                                 "Setting [%s] to primitive [%s] and datatype [%s]...",
417                                                 (char*)columnName,
418                                                 osrfHashGet(_f, "primitive"),
419                                                 osrfHashGet(_f, "datatype")
420                                         );
421                                 }
422                         }
423                         dbi_result_free(result);
424                 } else {
425                         osrfLogDebug(OSRF_LOG_MARK, "No data found for class [%s]...", (char*)classname);
426                 }
427         }
428
429         osrfStringArrayFree(classes);
430
431         return 0;
432 }
433
434
435 int dispatchCRUDMethod ( osrfMethodContext* ctx ) {
436         OSRF_METHOD_VERIFY_CONTEXT(ctx);
437
438         osrfHash* meta = (osrfHash*) ctx->method->userData;
439         osrfHash* class_obj = osrfHashGet( meta, "class" );
440
441         jsonObject * obj = NULL;
442         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "create"))
443                 obj = doCreate(class_obj, ctx->params);
444
445         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "retrieve"))
446                 obj = doRetrieve(class_obj, ctx->params);
447
448         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "update"))
449                 obj = doUpdate(class_obj, ctx->params);
450
451         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "delete"))
452                 obj = doDelete(class_obj, ctx->params);
453
454         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "search")) {
455                 obj = doSearch(class_obj, ctx->params);
456                 jsonObjectIterator* itr = jsonNewObjectIterator( obj );
457                 while ((cur = jsonObjectIteratorNext( itr ))) {
458                         osrfAppRespond( ctx, cur );
459                 }
460                 jsonObjectIteratorFree(itr);
461                 
462         } else {
463                 osrfAppRespondComplete( ctx, obj );
464         }
465
466         jsonObjectFree(obj);
467
468         return 0;
469 }
470
471 jsonObject* doCreate( osrfHash* meta, jsonObject* params ) { return NULL; }
472
473 jsonObject* doRetrieve( osrfHash* meta, jsonObject* params ) {
474
475         jsonObject* obj;
476
477         char* id = jsonObjectToSimpleString(jsonObjectGetIndex(params, 0));
478         jsonObject* order_hash = jsonObjectGetIndex(params, 1);
479
480         osrfLogDebug(
481                 OSRF_LOG_MARK,
482                 "%s retrieving %s object with id %s",
483                 MODULENAME,
484                 osrfHashGet(meta, "fieldmapper"),
485                 id
486         );
487
488         jsonObject* fake_params = jsonParseString("[]");
489         jsonObjectPush(fake_params, jsonParseString("{}"));
490
491         jsonObjectSetKey(
492                 jsonObjectGetIndex(fake_params, 0),
493                 osrfHashGet(meta, "primarykey"),
494                 jsonNewObject(id)
495         );
496
497         if (order_hash) jsonObjectPush(fake_params, jsonObjectClone(order_hash) );
498
499         jsonObject* list = doSearch(meta, fake_params);
500         obj = jsonObjectClone( jsonObjectGetIndex(list, 0) );
501
502         jsonObjectFree( list );
503         jsonObjectFree( fake_params );
504
505         return obj;
506 }
507
508 jsonObject* doSearch( osrfHash* meta, jsonObject* params ) {
509
510         jsonObject* _tmp;
511         jsonObject* obj;
512         jsonObject* search_hash = jsonObjectGetIndex(params, 0);
513         jsonObject* order_hash = jsonObjectGetIndex(params, 1);
514
515         growing_buffer* sql_buf = buffer_init(128);
516         buffer_fadd(sql_buf, "SELECT * FROM %s WHERE ", osrfHashGet(meta, "tablename") );
517
518         jsonObjectNode* node = NULL;
519         jsonObjectIterator* search_itr = jsonNewObjectIterator( search_hash );
520
521         int first = 1;
522         while ( (node = jsonObjectIteratorNext( search_itr )) ) {
523                 osrfHash* field = osrfHashGet( osrfHashGet(meta, "fields"), node->key );
524
525                 if (!field) continue;
526
527                 if (first) {
528                         first = 0;
529                 } else {
530                         buffer_add(sql_buf, " AND ");
531                 }
532
533                 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
534                         buffer_fadd(
535                                 sql_buf,
536                                 "%s = %d",
537                                 osrfHashGet(field, "name"),
538                                 atoi( jsonObjectToSimpleString(node->item) )
539                         );
540                 } else {
541                         char* key_string = jsonObjectToSimpleString(node->item);
542                         if ( dbi_conn_quote_string(dbhandle, &key_string) ) {
543                                 buffer_fadd(
544                                         sql_buf,
545                                         "%s = %s",
546                                         osrfHashGet(field, "name"),
547                                         key_string
548                                 );
549                                 free(key_string);
550                         } else {
551                                 osrfLogDebug(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, key_string);
552                                 free(key_string);
553                         }
554                 }
555         }
556
557         jsonObjectIteratorFree(itr);
558
559         if (order_hash) {
560                 char* string;
561                 _tmp = jsonObjectGetKey( order_hash, "order_by" );
562                 if (_tmp) {
563                         string = jsonObjectToSimpleString(_tmp);
564                         buffer_fadd(
565                                 sql_buf,
566                                 " ORDER BY %s",
567                                 string
568                         );
569                         free(string);
570                 }
571
572                 _tmp = jsonObjectGetKey( order_hash, "limit" );
573                 if (_tmp) {
574                         string = jsonObjectToSimpleString(_tmp);
575                         buffer_fadd(
576                                 sql_buf,
577                                 " LIMIT %d",
578                                 atoi(string)
579                         );
580                         free(string);
581                 }
582
583                 _tmp = jsonObjectGetKey( order_hash, "offset" );
584                 if (_tmp) {
585                         string = jsonObjectToSimpleString(_tmp);
586                         buffer_fadd(
587                                 sql_buf,
588                                 " OFFSET %d",
589                                 atoi(string)
590                         );
591                         free(string);
592                 }
593         }
594
595         buffer_add(sql_buf, ";");
596
597         char* sql = buffer_data(sql_buf);
598         buffer_free(sql_buf);
599         
600         osrfLogDebug(OSRF_LOG_MARK, "%s SQL =  %s", MODULENAME, sql);
601         dbi_result result = dbi_conn_query(dbhandle, sql);
602
603         jsonObject* res_list = jsonParseString("[]");
604         if(result) {
605                 osrfLogDebug(OSRF_LOG_MARK, "Query returned with no errors");
606
607                 /* there should be one row at the most  */
608                 if (dbi_result_first_row(result)) {
609                         /* JSONify the result */
610                         osrfLogDebug(OSRF_LOG_MARK, "Query returned at least one row");
611                         do {
612                                 obj = oilsMakeJSONFromResult( result, meta );
613                                 jsonObjectPush(res_list, obj);
614                         } while (dbi_result_next_row(result));
615                 } else {
616                         osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
617                 }
618
619                 /* clean up the query */
620                 dbi_result_free(result); 
621
622         } else {
623                 osrfLogDebug(OSRF_LOG_MARK, "%s: Error retrieving %s with query [%s]", MODULENAME, osrfHashGet(meta, "fieldmapper"), sql);
624         }
625
626         free(sql);
627
628         if (order_hash) {
629                 _tmp = jsonObjectGetKey( order_hash, "flesh" );
630                 if (_tmp) {
631                         double x = jsonObjectGetNumber(_tmp);
632
633                         if ((int)x > 0) {
634
635                                 jsonObjectNode* cur;
636                                 jsonObjectIterator* itr = jsonNewObjectIterator( res_list );
637                                 while ((cur = jsonObjectIteratorNext( itr ))) {
638
639                                         osrfHash* links = osrfHashGet(meta, "links");
640                                         osrfHash* fields = osrfHashGet(meta, "fields");
641
642                                         int i = 0;
643                                         char* link_field;
644                                         osrfStringArray* link_fields;
645                                         
646                                         jsonObject* flesh_fields = jsonObjectGetKey( order_hash, "flesh_fields" );
647                                         if (flesh_fields) {
648                                                 jsonObjectNode* _f;
649                                                 jsonObjectIterator* _i = jsonNewObjectIterator( flesh_fields );
650                                                 link_fields = osrfNewStringArray(1);
651                                                 while ((_f = jsonObjectIteratorNext( _i ))) {
652                                                         osrfStringArrayAdd( link_fields, jsonObjectToSimpleString( _f->item ) );
653                                                 }
654                                         } else {
655                                                 link_fields = osrfHashKeys( links );
656                                         }
657
658                                         while ( (link_field = osrfStringArrayGetString(link_fields, i++)) ) {
659
660                                                 osrfLogDebug(OSRF_LOG_MARK, "Starting to flesh %s", link_field);
661
662                                                 osrfHash* kid_link = osrfHashGet(links, link_field);
663                                                 if (!kid_link) continue;
664
665                                                 osrfHash* field = osrfHashGet(fields, link_field);
666                                                 if (!field) continue;
667
668                                                 osrfHash* value_field = field;
669
670                                                 osrfHash* kid_idl = osrfHashGet(idlHash, osrfHashGet(kid_link, "class"));
671                                                 if (!kid_idl) continue;
672
673                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
674                                                         value_field = osrfHashGet( fields, osrfHashGet(meta, "primarykey") );
675                                                 }
676                                                         
677                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "might_have" ))) { // might_have
678                                                         value_field = osrfHashGet( fields, osrfHashGet(meta, "primarykey") );
679                                                 }
680
681                                                 osrfLogDebug(
682                                                         OSRF_LOG_MARK,
683                                                         "Link field: %s, remote class: %s, fkey: %s, reltype: %s",
684                                                         osrfHashGet(kid_link, "field"),
685                                                         osrfHashGet(kid_link, "class"),
686                                                         osrfHashGet(kid_link, "key"),
687                                                         osrfHashGet(kid_link, "reltype")
688                                                 );
689
690                                                 jsonObject* fake_params = jsonParseString("[]");
691                                                 jsonObjectPush(fake_params, jsonParseString("{}")); // search hash
692                                                 jsonObjectPush(fake_params, jsonParseString("{}")); // order/flesh hash
693
694                                                 osrfLogDebug(OSRF_LOG_MARK, "Creating dummy params object...");
695
696                                                 char* search_key =
697                                                 jsonObjectToSimpleString(
698                                                         jsonObjectGetIndex(
699                                                                 cur->item,
700                                                                 atoi( osrfHashGet(value_field, "array_position") )
701                                                         )
702                                                 );
703
704                                                 if (!search_key) {
705                                                         osrfLogDebug(OSRF_LOG_MARK, "Nothing to search for!");
706                                                         continue;
707                                                 }
708                                                         
709                                                 jsonObjectSetKey(
710                                                         jsonObjectGetIndex(fake_params, 0),
711                                                         osrfHashGet(kid_link, "key"),
712                                                         jsonNewObject( search_key )
713                                                 );
714
715                                                 free(search_key);
716
717
718                                                 jsonObjectSetKey(
719                                                         jsonObjectGetIndex(fake_params, 1),
720                                                         "flesh",
721                                                         jsonNewNumberObject( (double)((int)x - 1) )
722                                                 );
723
724                                                 if (flesh_fields) {
725                                                         jsonObjectSetKey(
726                                                                 jsonObjectGetIndex(fake_params, 1),
727                                                                 "flesh_fields",
728                                                                 jsonObjectClone( flesh_fields )
729                                                         );
730                                                 }
731
732                                                 if (jsonObjectGetKey(order_hash, "order_by")) {
733                                                         jsonObjectSetKey(
734                                                                 jsonObjectGetIndex(fake_params, 1),
735                                                                 "order_by",
736                                                                 jsonObjectClone(jsonObjectGetKey(order_hash, "order_by"))
737                                                         );
738                                                 }
739
740                                                 jsonObject* kids = doSearch(kid_idl, fake_params);
741
742                                                 osrfLogDebug(OSRF_LOG_MARK, "Search for %s return %d linked objects", osrfHashGet(kid_link, "class"), kids->size);
743                                                 
744                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_a" ))) {
745                                                         osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s", osrfHashGet(kid_link, "field"));
746                                                         jsonObjectSetIndex(
747                                                                 cur->item,
748                                                                 (unsigned long)atoi( osrfHashGet( field, "array_position" ) ),
749                                                                 jsonObjectClone( jsonObjectGetIndex(kids, 0) )
750                                                         );
751                                                         jsonObjectFree( kids );
752                                                 }
753
754                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
755                                                         osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s", osrfHashGet(kid_link, "field"));
756                                                         jsonObjectSetIndex(
757                                                                 cur->item,
758                                                                 (unsigned long)atoi( osrfHashGet( field, "array_position" ) ),
759                                                                 kids
760                                                         );
761                                                 }
762
763                                                 osrfLogDebug(OSRF_LOG_MARK, "Fleshing of %s complete", osrfHashGet(kid_link, "field"));
764
765                                                 jsonObjectFree( fake_params );
766                                         }
767                                         if (flesh_fields) osrfStringArrayFree(link_fields);
768                                 }
769                                 jsonObjectIteratorFree(itr);
770                         }
771                 }
772         }
773
774         return res_list;
775 }
776
777
778 jsonObject* doUpdate( osrfHash* meta, jsonObject* params ) { return NULL; }
779
780 jsonObject* doDelete( osrfHash* meta, jsonObject* params ) { return NULL; }
781
782
783 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) {
784         if(!(result && meta)) return NULL;
785
786         jsonObject* object = jsonParseString("[]");
787         jsonObjectSetClass(object, osrfHashGet(meta, "classname"));
788
789         osrfHash* fields = osrfHashGet(meta, "fields");
790
791         osrfLogDebug(OSRF_LOG_MARK, "Setting object class to %s ", object->classname);
792
793         osrfHash* _f;
794         time_t _tmp_dt;
795         char dt_string[256];
796         struct tm gmdt;
797
798         int fmIndex;
799         int columnIndex = 1;
800         int attr;
801         unsigned short type;
802         const char* columnName;
803
804         /* cycle through the column list */
805         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
806
807                 osrfLogDebug(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
808
809                 fmIndex = -1; // reset the position
810                 
811                 /* determine the field type and storage attributes */
812                 type = dbi_result_get_field_type(result, columnName);
813                 attr = dbi_result_get_field_attribs(result, columnName);
814
815                 /* fetch the fieldmapper index */
816                 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
817                         char* virt = (char*)osrfHashGet(_f, "virtual");
818                         char* pos = (char*)osrfHashGet(_f, "array_position");
819
820                         if ( !virt || !pos || !(strcmp( virt, "true" )) ) continue;
821
822                         fmIndex = atoi( pos );
823                         osrfLogDebug(OSRF_LOG_MARK, "... Found column at position [%s]...", pos);
824                 }
825
826                 if (dbi_result_field_is_null(result, columnName)) {
827                         jsonObjectSetIndex( object, fmIndex, jsonNewObject(NULL) );
828                 } else {
829
830                         switch( type ) {
831
832                                 case DBI_TYPE_INTEGER :
833
834                                         if( attr & DBI_INTEGER_SIZE8 ) 
835                                                 jsonObjectSetIndex( object, fmIndex, 
836                                                         jsonNewNumberObject(dbi_result_get_longlong(result, columnName)));
837                                         else 
838                                                 jsonObjectSetIndex( object, fmIndex, 
839                                                         jsonNewNumberObject(dbi_result_get_long(result, columnName)));
840
841                                         break;
842
843                                 case DBI_TYPE_DECIMAL :
844                                         jsonObjectSetIndex( object, fmIndex, 
845                                                         jsonNewNumberObject(dbi_result_get_double(result, columnName)));
846                                         break;
847
848                                 case DBI_TYPE_STRING :
849
850
851                                         jsonObjectSetIndex(
852                                                 object,
853                                                 fmIndex,
854                                                 jsonNewObject( dbi_result_get_string(result, columnName) )
855                                         );
856
857                                         break;
858
859                                 case DBI_TYPE_DATETIME :
860
861                                         memset(dt_string, '\0', 256);
862                                         memset(&gmdt, '\0', sizeof(gmdt));
863                                         memset(&_tmp_dt, '\0', sizeof(_tmp_dt));
864
865                                         _tmp_dt = dbi_result_get_datetime(result, columnName);
866
867                                         localtime_r( &_tmp_dt, &gmdt );
868
869                                         if (!(attr & DBI_DATETIME_DATE)) {
870                                                 strftime(dt_string, 255, "%T", &gmdt);
871                                         } else if (!(attr & DBI_DATETIME_TIME)) {
872                                                 strftime(dt_string, 255, "%F", &gmdt);
873                                         } else {
874                                                 /* XXX ARG! My eyes! The goggles, they do nothing! */
875
876                                                 strftime(dt_string, 255, "%FT%T%z", &gmdt);
877                                         }
878
879                                         jsonObjectSetIndex( object, fmIndex, jsonNewObject(dt_string) );
880
881                                         break;
882
883                                 case DBI_TYPE_BINARY :
884                                         osrfLogError( OSRF_LOG_MARK, 
885                                                 "Can't do binary at column %s : index %d", columnName, columnIndex - 1);
886                         }
887                 }
888         }
889
890         return object;
891 }
892