]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/c-apps/oils_cstore.c
adding fleshing axis specifier interface "flesh_fields"
[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                                 osrfAppRegisterExtendedMethod(
274                                         MODULENAME,
275                                         method,
276                                         "dispatchCRUDMethod",
277                                         "",
278                                         1,
279                                         0,
280                                         (void*)method_meta
281                                 );
282                         }
283                 }
284                 kid = kid->next;
285         }
286
287         return 0;
288 }
289
290 /**
291  * Connects to the database 
292  */
293 int osrfAppChildInit() {
294
295         osrfLogDebug(OSRF_LOG_MARK, "Attempting to initialize libdbi...");
296         dbi_initialize(NULL);
297         osrfLogDebug(OSRF_LOG_MARK, "... libdbi initialized.");
298
299         char* driver    = osrf_settings_host_value("/apps/%s/app_settings/driver", MODULENAME);
300         char* user      = osrf_settings_host_value("/apps/%s/app_settings/database/user", MODULENAME);
301         char* host      = osrf_settings_host_value("/apps/%s/app_settings/database/host", MODULENAME);
302         char* port      = osrf_settings_host_value("/apps/%s/app_settings/database/port", MODULENAME);
303         char* db        = osrf_settings_host_value("/apps/%s/app_settings/database/db", MODULENAME);
304         char* pw        = osrf_settings_host_value("/apps/%s/app_settings/database/pw", MODULENAME);
305
306         osrfLogDebug(OSRF_LOG_MARK, "Attempting to load the database driver [%s]...", driver);
307         dbhandle = dbi_conn_new(driver);
308
309         if(!dbhandle) {
310                 osrfLogError(OSRF_LOG_MARK, "Error loading database driver [%s]", driver);
311                 return -1;
312         }
313         osrfLogDebug(OSRF_LOG_MARK, "Database driver [%s] seems OK", driver);
314
315         osrfLogInfo(OSRF_LOG_MARK, "%s connecting to database.  host=%s, "
316                 "port=%s, user=%s, pw=%s, db=%s", MODULENAME, host, port, user, pw, db );
317
318         if(host) dbi_conn_set_option(dbhandle, "host", host );
319         if(port) dbi_conn_set_option_numeric( dbhandle, "port", atoi(port) );
320         if(user) dbi_conn_set_option(dbhandle, "username", user);
321         if(pw) dbi_conn_set_option(dbhandle, "password", pw );
322         if(db) dbi_conn_set_option(dbhandle, "dbname", db );
323
324         free(user);
325         free(host);
326         free(port);
327         free(db);
328         free(pw);
329
330         const char* err;
331         if (dbi_conn_connect(dbhandle) < 0) {
332                 dbi_conn_error(dbhandle, &err);
333                 osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err);
334                 return -1;
335         }
336
337         osrfLogInfo(OSRF_LOG_MARK, "%s successfully connected to the database", MODULENAME);
338
339         int attr;
340         unsigned short type;
341         int i = 0; 
342         char* classname;
343         osrfStringArray* classes = osrfHashKeys( idlHash );
344         
345         while ( (classname = osrfStringArrayGetString(classes, i++)) ) {
346                 osrfHash* class = osrfHashGet( idlHash, classname );
347                 osrfHash* fields = osrfHashGet( class, "fields" );
348                 
349                 growing_buffer* sql_buf = buffer_init(32);
350                 buffer_fadd( sql_buf, "SELECT * FROM %s WHERE 1=0;", osrfHashGet(class, "tablename") );
351
352                 char* sql = buffer_data(sql_buf);
353                 buffer_free(sql_buf);
354                 osrfLogDebug(OSRF_LOG_MARK, "%s Investigatory SQL = %s", MODULENAME, sql);
355
356                 dbi_result result = dbi_conn_query(dbhandle, sql);
357                 free(sql);
358
359                 if (result) {
360
361                         int columnIndex = 1;
362                         const char* columnName;
363                         osrfHash* _f;
364                         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
365
366                                 osrfLogDebug(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
367
368                                 /* fetch the fieldmapper index */
369                                 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
370
371                                         osrfLogDebug(OSRF_LOG_MARK, "Found [%s] in IDL hash...", (char*)columnName);
372
373                                         /* determine the field type and storage attributes */
374                                         type = dbi_result_get_field_type(result, columnName);
375                                         attr = dbi_result_get_field_attribs(result, columnName);
376
377                                         switch( type ) {
378
379                                                 case DBI_TYPE_INTEGER :
380
381                                                         osrfHashSet(_f,"number", "primitive");
382
383                                                         if( attr & DBI_INTEGER_SIZE8 ) 
384                                                                 osrfHashSet(_f,"INT8", "datatype");
385                                                         else 
386                                                                 osrfHashSet(_f,"INT", "datatype");
387                                                         break;
388
389                                                 case DBI_TYPE_DECIMAL :
390                                                         osrfHashSet(_f,"number", "primitive");
391                                                         osrfHashSet(_f,"NUMERIC", "datatype");
392                                                         break;
393
394                                                 case DBI_TYPE_STRING :
395                                                         osrfHashSet(_f,"string", "primitive");
396                                                         osrfHashSet(_f,"TEXT", "datatype");
397                                                         break;
398
399                                                 case DBI_TYPE_DATETIME :
400                                                         osrfHashSet(_f,"string", "primitive");
401                                                         osrfHashSet(_f,"TIMESTAMP", "datatype");
402                                                         break;
403
404                                                 case DBI_TYPE_BINARY :
405                                                         osrfHashSet(_f,"string", "primitive");
406                                                         osrfHashSet(_f,"BYTEA", "datatype");
407                                         }
408
409                                         osrfLogDebug(
410                                                 OSRF_LOG_MARK,
411                                                 "Setting [%s] to primitive [%s] and datatype [%s]...",
412                                                 (char*)columnName,
413                                                 osrfHashGet(_f, "primitive"),
414                                                 osrfHashGet(_f, "datatype")
415                                         );
416                                 }
417                         }
418                         dbi_result_free(result);
419                 } else {
420                         osrfLogDebug(OSRF_LOG_MARK, "No data found for class [%s]...", (char*)classname);
421                 }
422         }
423
424         osrfStringArrayFree(classes);
425
426         return 0;
427 }
428
429
430 int dispatchCRUDMethod ( osrfMethodContext* ctx ) {
431         OSRF_METHOD_VERIFY_CONTEXT(ctx);
432
433         osrfHash* meta = (osrfHash*) ctx->method->userData;
434         osrfHash* class_obj = osrfHashGet( meta, "class" );
435
436         jsonObject * obj = NULL;
437         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "create"))
438                 obj = doCreate(class_obj, ctx->params);
439
440         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "retrieve"))
441                 obj = doRetrieve(class_obj, ctx->params);
442
443         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "update"))
444                 obj = doUpdate(class_obj, ctx->params);
445
446         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "delete"))
447                 obj = doDelete(class_obj, ctx->params);
448
449         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "search"))
450                 obj = doSearch(class_obj, ctx->params);
451
452         osrfAppRespondComplete( ctx, obj );
453
454         jsonObjectFree(obj);
455
456         return 0;
457 }
458
459 jsonObject* doCreate( osrfHash* meta, jsonObject* params ) { return NULL; }
460
461 jsonObject* doRetrieve( osrfHash* meta, jsonObject* params ) {
462
463         jsonObject* obj;
464
465         char* id = jsonObjectToSimpleString(jsonObjectGetIndex(params, 0));
466         jsonObject* order_hash = jsonObjectGetIndex(params, 1);
467
468         osrfLogDebug(
469                 OSRF_LOG_MARK,
470                 "%s retrieving %s object with id %s",
471                 MODULENAME,
472                 osrfHashGet(meta, "fieldmapper"),
473                 id
474         );
475
476         jsonObject* fake_params = jsonParseString("[]");
477         jsonObjectPush(fake_params, jsonParseString("{}"));
478
479         jsonObjectSetKey(
480                 jsonObjectGetIndex(fake_params, 0),
481                 osrfHashGet(meta, "primarykey"),
482                 jsonNewObject(id)
483         );
484
485         if (order_hash) jsonObjectPush(fake_params, jsonObjectClone(order_hash) );
486
487         jsonObject* list = doSearch(meta, fake_params);
488         obj = jsonObjectClone( jsonObjectGetIndex(list, 0) );
489
490         jsonObjectFree( list );
491         jsonObjectFree( fake_params );
492
493         return obj;
494 }
495
496 jsonObject* doSearch( osrfHash* meta, jsonObject* params ) {
497
498         jsonObject* _tmp;
499         jsonObject* obj;
500         jsonObject* search_hash = jsonObjectGetIndex(params, 0);
501         jsonObject* order_hash = jsonObjectGetIndex(params, 1);
502
503         growing_buffer* sql_buf = buffer_init(128);
504         buffer_fadd(sql_buf, "SELECT * FROM %s WHERE ", osrfHashGet(meta, "tablename") );
505
506         jsonObjectNode* node = NULL;
507         jsonObjectIterator* search_itr = jsonNewObjectIterator( search_hash );
508
509         int first = 1;
510         while ( (node = jsonObjectIteratorNext( search_itr )) ) {
511                 osrfHash* field = osrfHashGet( osrfHashGet(meta, "fields"), node->key );
512
513                 if (!field) continue;
514
515                 if (first) {
516                         first = 0;
517                 } else {
518                         buffer_add(sql_buf, " AND ");
519                 }
520
521                 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
522                         buffer_fadd(
523                                 sql_buf,
524                                 "%s = %d",
525                                 osrfHashGet(field, "name"),
526                                 atoi( jsonObjectToSimpleString(node->item) )
527                         );
528                 } else {
529                         char* key_string = jsonObjectToSimpleString(node->item);
530                         if ( dbi_conn_quote_string(dbhandle, &key_string) ) {
531                                 buffer_fadd(
532                                         sql_buf,
533                                         "%s = %s",
534                                         osrfHashGet(field, "name"),
535                                         key_string
536                                 );
537                                 free(key_string);
538                         } else {
539                                 osrfLogDebug(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, key_string);
540                                 free(key_string);
541                         }
542                 }
543         }
544
545         if (order_hash) {
546                 char* string;
547                 _tmp = jsonObjectGetKey( order_hash, "order_by" );
548                 if (_tmp) {
549                         string = jsonObjectToSimpleString(_tmp);
550                         buffer_fadd(
551                                 sql_buf,
552                                 " ORDER BY %s",
553                                 string
554                         );
555                         free(string);
556                 }
557
558                 _tmp = jsonObjectGetKey( order_hash, "limit" );
559                 if (_tmp) {
560                         string = jsonObjectToSimpleString(_tmp);
561                         buffer_fadd(
562                                 sql_buf,
563                                 " LIMIT %d",
564                                 atoi(string)
565                         );
566                         free(string);
567                 }
568
569                 _tmp = jsonObjectGetKey( order_hash, "offset" );
570                 if (_tmp) {
571                         string = jsonObjectToSimpleString(_tmp);
572                         buffer_fadd(
573                                 sql_buf,
574                                 " OFFSET %d",
575                                 atoi(string)
576                         );
577                         free(string);
578                 }
579         }
580
581         buffer_add(sql_buf, ";");
582
583         char* sql = buffer_data(sql_buf);
584         buffer_free(sql_buf);
585         
586         osrfLogDebug(OSRF_LOG_MARK, "%s SQL =  %s", MODULENAME, sql);
587         dbi_result result = dbi_conn_query(dbhandle, sql);
588
589         jsonObject* res_list = jsonParseString("[]");
590         if(result) {
591                 osrfLogDebug(OSRF_LOG_MARK, "Query returned with no errors");
592
593                 /* there should be one row at the most  */
594                 if (dbi_result_first_row(result)) {
595                         /* JSONify the result */
596                         osrfLogDebug(OSRF_LOG_MARK, "Query returned at least one row");
597                         do {
598                                 obj = oilsMakeJSONFromResult( result, meta );
599                                 jsonObjectPush(res_list, obj);
600                         } while (dbi_result_next_row(result));
601                 } else {
602                         osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
603                 }
604
605                 /* clean up the query */
606                 dbi_result_free(result); 
607
608         } else {
609                 osrfLogDebug(OSRF_LOG_MARK, "%s: Error retrieving %s with query [%s]", MODULENAME, osrfHashGet(meta, "fieldmapper"), sql);
610         }
611
612         free(sql);
613
614         if (order_hash) {
615                 _tmp = jsonObjectGetKey( order_hash, "flesh" );
616                 if (_tmp) {
617                         double x = jsonObjectGetNumber(_tmp);
618
619                         if ((int)x > 0) {
620
621                                 jsonObjectNode* cur;
622                                 jsonObjectIterator* itr = jsonNewObjectIterator( res_list );
623                                 while ((cur = jsonObjectIteratorNext( itr ))) {
624
625                                         osrfHash* links = osrfHashGet(meta, "links");
626                                         osrfHash* fields = osrfHashGet(meta, "fields");
627
628                                         int i = 0;
629                                         char* link_field;
630                                         osrfStringArray* link_fields;
631                                         
632                                         jsonObject* flesh_fields = jsonObjectGetKey( order_hash, "flesh_fields" );
633                                         if (flesh_fields) {
634                                                 jsonObjectNode* _f;
635                                                 jsonObjectIterator* _i = jsonNewObjectIterator( flesh_fields );
636                                                 link_fields = osrfNewStringArray(1);
637                                                 while ((_f = jsonObjectIteratorNext( _i ))) {
638                                                         osrfStringArrayAdd( link_fields, jsonObjectToSimpleString( _f->item ) );
639                                                 }
640                                         } else {
641                                                 link_fields = osrfHashKeys( links );
642                                         }
643
644                                         while ( (link_field = osrfStringArrayGetString(link_fields, i++)) ) {
645
646                                                 osrfLogDebug(OSRF_LOG_MARK, "Starting to flesh %s", link_field);
647
648                                                 osrfHash* kid_link = osrfHashGet(links, link_field);
649                                                 if (!kid_link) continue;
650
651                                                 osrfHash* field = osrfHashGet(fields, link_field);
652                                                 if (!field) continue;
653
654                                                 osrfHash* value_field = field;
655
656                                                 osrfHash* kid_idl = osrfHashGet(idlHash, osrfHashGet(kid_link, "class"));
657                                                 if (!kid_idl) continue;
658
659                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
660                                                         value_field = osrfHashGet( fields, osrfHashGet(meta, "primarykey") );
661                                                 }
662                                                         
663                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "might_have" ))) { // might_have
664                                                         value_field = osrfHashGet( fields, osrfHashGet(meta, "primarykey") );
665                                                 }
666
667                                                 osrfLogDebug(
668                                                         OSRF_LOG_MARK,
669                                                         "Link field: %s, remote class: %s, fkey: %s, reltype: %s",
670                                                         osrfHashGet(kid_link, "field"),
671                                                         osrfHashGet(kid_link, "class"),
672                                                         osrfHashGet(kid_link, "key"),
673                                                         osrfHashGet(kid_link, "reltype")
674                                                 );
675
676                                                 jsonObject* fake_params = jsonParseString("[]");
677                                                 jsonObjectPush(fake_params, jsonParseString("{}")); // search hash
678                                                 jsonObjectPush(fake_params, jsonParseString("{}")); // order/flesh hash
679
680                                                 osrfLogDebug(OSRF_LOG_MARK, "Creating dummy params object...");
681
682                                                 char* search_key =
683                                                 jsonObjectToSimpleString(
684                                                         jsonObjectGetIndex(
685                                                                 cur->item,
686                                                                 atoi( osrfHashGet(value_field, "array_position") )
687                                                         )
688                                                 );
689
690                                                 if (!search_key) {
691                                                         osrfLogDebug(OSRF_LOG_MARK, "Nothing to search for!");
692                                                         continue;
693                                                 }
694                                                         
695                                                 jsonObjectSetKey(
696                                                         jsonObjectGetIndex(fake_params, 0),
697                                                         osrfHashGet(kid_link, "key"),
698                                                         jsonNewObject( search_key )
699                                                 );
700
701                                                 free(search_key);
702
703
704                                                 jsonObjectSetKey(
705                                                         jsonObjectGetIndex(fake_params, 1),
706                                                         "flesh",
707                                                         jsonNewNumberObject( (double)((int)x - 1) )
708                                                 );
709
710                                                 if (flesh_fields) {
711                                                         jsonObjectSetKey(
712                                                                 jsonObjectGetIndex(fake_params, 1),
713                                                                 "flesh_fields",
714                                                                 jsonObjectClone( flesh_fields )
715                                                         );
716                                                 }
717
718                                                 if (jsonObjectGetKey(order_hash, "order_by")) {
719                                                         jsonObjectSetKey(
720                                                                 jsonObjectGetIndex(fake_params, 1),
721                                                                 "order_by",
722                                                                 jsonObjectClone(jsonObjectGetKey(order_hash, "order_by"))
723                                                         );
724                                                 }
725
726                                                 jsonObject* kids = doSearch(kid_idl, fake_params);
727
728                                                 osrfLogDebug(OSRF_LOG_MARK, "Search for %s return %d linked objects", osrfHashGet(kid_link, "class"), kids->size);
729                                                 
730                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_a" ))) {
731                                                         osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s", osrfHashGet(kid_link, "field"));
732                                                         jsonObjectSetIndex(
733                                                                 cur->item,
734                                                                 (unsigned long)atoi( osrfHashGet( field, "array_position" ) ),
735                                                                 jsonObjectClone( jsonObjectGetIndex(kids, 0) )
736                                                         );
737                                                         jsonObjectFree( kids );
738                                                 }
739
740                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
741                                                         osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s", osrfHashGet(kid_link, "field"));
742                                                         jsonObjectSetIndex(
743                                                                 cur->item,
744                                                                 (unsigned long)atoi( osrfHashGet( field, "array_position" ) ),
745                                                                 kids
746                                                         );
747                                                 }
748
749                                                 osrfLogDebug(OSRF_LOG_MARK, "Fleshing of %s complete", osrfHashGet(kid_link, "field"));
750
751                                                 jsonObjectFree( fake_params );
752                                         }
753                                         if (flesh_fields) osrfStringArrayFree(link_fields);
754                                 }
755                         }
756                 }
757         }
758
759         return res_list;
760 }
761
762
763 jsonObject* doUpdate( osrfHash* meta, jsonObject* params ) { return NULL; }
764
765 jsonObject* doDelete( osrfHash* meta, jsonObject* params ) { return NULL; }
766
767
768 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) {
769         if(!(result && meta)) return NULL;
770
771         jsonObject* object = jsonParseString("[]");
772         jsonObjectSetClass(object, osrfHashGet(meta, "classname"));
773
774         osrfHash* fields = osrfHashGet(meta, "fields");
775
776         osrfLogDebug(OSRF_LOG_MARK, "Setting object class to %s ", object->classname);
777
778         osrfHash* _f;
779         time_t _tmp_dt;
780         char dt_string[256];
781         struct tm gmdt;
782
783         int fmIndex;
784         int columnIndex = 1;
785         int attr;
786         unsigned short type;
787         const char* columnName;
788
789         /* cycle through the column list */
790         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
791
792                 osrfLogDebug(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
793
794                 fmIndex = -1; // reset the position
795                 
796                 /* determine the field type and storage attributes */
797                 type = dbi_result_get_field_type(result, columnName);
798                 attr = dbi_result_get_field_attribs(result, columnName);
799
800                 /* fetch the fieldmapper index */
801                 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
802                         char* virt = (char*)osrfHashGet(_f, "virtual");
803                         char* pos = (char*)osrfHashGet(_f, "array_position");
804
805                         if ( !virt || !pos || !(strcmp( virt, "true" )) ) continue;
806
807                         fmIndex = atoi( pos );
808                         osrfLogDebug(OSRF_LOG_MARK, "... Found column at position [%s]...", pos);
809                 }
810
811                 if (dbi_result_field_is_null(result, columnName)) {
812                         jsonObjectSetIndex( object, fmIndex, jsonNewObject(NULL) );
813                 } else {
814
815                         switch( type ) {
816
817                                 case DBI_TYPE_INTEGER :
818
819                                         if( attr & DBI_INTEGER_SIZE8 ) 
820                                                 jsonObjectSetIndex( object, fmIndex, 
821                                                         jsonNewNumberObject(dbi_result_get_longlong(result, columnName)));
822                                         else 
823                                                 jsonObjectSetIndex( object, fmIndex, 
824                                                         jsonNewNumberObject(dbi_result_get_long(result, columnName)));
825
826                                         break;
827
828                                 case DBI_TYPE_DECIMAL :
829                                         jsonObjectSetIndex( object, fmIndex, 
830                                                         jsonNewNumberObject(dbi_result_get_double(result, columnName)));
831                                         break;
832
833                                 case DBI_TYPE_STRING :
834
835
836                                         jsonObjectSetIndex(
837                                                 object,
838                                                 fmIndex,
839                                                 jsonNewObject( dbi_result_get_string(result, columnName) )
840                                         );
841
842                                         break;
843
844                                 case DBI_TYPE_DATETIME :
845
846                                         memset(dt_string, '\0', 256);
847                                         memset(&gmdt, '\0', sizeof(gmdt));
848                                         memset(&_tmp_dt, '\0', sizeof(_tmp_dt));
849
850                                         _tmp_dt = dbi_result_get_datetime(result, columnName);
851
852                                         localtime_r( &_tmp_dt, &gmdt );
853
854                                         if (!(attr & DBI_DATETIME_DATE)) {
855                                                 strftime(dt_string, 255, "%T", &gmdt);
856                                         } else if (!(attr & DBI_DATETIME_TIME)) {
857                                                 strftime(dt_string, 255, "%F", &gmdt);
858                                         } else {
859                                                 /* XXX ARG! My eyes! The goggles, they do nothing! */
860
861                                                 strftime(dt_string, 255, "%FT%T%z", &gmdt);
862                                         }
863
864                                         jsonObjectSetIndex( object, fmIndex, jsonNewObject(dt_string) );
865
866                                         break;
867
868                                 case DBI_TYPE_BINARY :
869                                         osrfLogError( OSRF_LOG_MARK, 
870                                                 "Can't do binary at column %s : index %d", columnName, columnIndex - 1);
871                         }
872                 }
873         }
874
875         return object;
876 }
877