| 94 static DBUObject valuelist_result_create(DBUObjectResult *result, DBUClass *type, const CxAllocator *a) { |
94 static DBUObject valuelist_result_create(DBUObjectResult *result, DBUClass *type, const CxAllocator *a) { |
| 95 memset(result->userdata2, 0, result->int1); |
95 memset(result->userdata2, 0, result->int1); |
| 96 return result->userdata2; |
96 return result->userdata2; |
| 97 } |
97 } |
| 98 |
98 |
| 99 static int list_result_add(DBUObjectResult *result, DBUObject parent, void *obj, CxList *fk, const CxAllocator *a) { |
99 static int list_result_add(DBUObjectResult *result, DBUObject parent, DBUClass *type, void *obj, CxList *fk, const CxAllocator *a) { |
| 100 return cxListAdd(result->userdata1, obj); |
100 return cxListAdd(result->userdata1, obj); |
| 101 } |
101 } |
| 102 |
102 |
| 103 CxList* dbuObjectBuilderGetList(DBUObjectBuilder *builder) { |
103 CxList* dbuObjectBuilderGetList(DBUObjectBuilder *builder) { |
| 104 CxList *result_list = cxArrayListCreate(builder->allocator, NULL, CX_STORE_POINTERS, 8); |
104 CxList *result_list = cxArrayListCreate(builder->allocator, NULL, CX_STORE_POINTERS, 8); |
| 157 |
157 |
| 158 |
158 |
| 159 |
159 |
| 160 /* ------------------------- Object Builder -----------------------------*/ |
160 /* ------------------------- Object Builder -----------------------------*/ |
| 161 |
161 |
| 162 static int add_to_parent(DBUObjectResult *result, DBUObject parent, void *obj, CxList *fk, const CxAllocator *a) { |
162 static int add_to_parent(DBUObjectResult *result, DBUObject parent, DBUClass *type, void *obj, CxList *fklist, const CxAllocator *a) { |
| 163 DBUBuilderQuery *query = result->userdata1; |
163 DBUBuilderQuery *query = result->userdata1; |
| 164 |
164 DBUObjectBuilder *builder = result->userdata2; |
| |
165 CxIterator i = cxListIterator(fklist); |
| |
166 cx_foreach(DBUFK*, fk, i) { |
| |
167 // check if the elm can be added |
| |
168 DBUField *field = cxMapGet(fk->cls->obj_fields, type->name); |
| |
169 if(!field) { |
| |
170 continue; |
| |
171 } |
| |
172 |
| |
173 // find cached object for all foreign keys |
| |
174 DBUBuilderObjCache *parent_cached = cxMapGet(builder->cache, fk->cache_key); |
| |
175 if(!parent_cached) { |
| |
176 continue; |
| |
177 } |
| |
178 |
| |
179 if(field->builder.add) { |
| |
180 field->builder.add(&field->builder, parent_cached->obj, type, obj, NULL, a); |
| |
181 } |
| |
182 } |
| 165 |
183 |
| 166 return 0; |
184 return 0; |
| 167 } |
185 } |
| 168 |
186 |
| 169 int dbuObjectExec(DBUObjectBuilder *builder, DBUObjectResult *objresult) { |
187 int dbuObjectExec(DBUObjectBuilder *builder, DBUObjectResult *objresult) { |
| 178 if(!ret) { |
196 if(!ret) { |
| 179 CxIterator i = cxListIterator(builder->additionalQueries); |
197 CxIterator i = cxListIterator(builder->additionalQueries); |
| 180 cx_foreach(DBUBuilderQuery *, q, i) { |
198 cx_foreach(DBUBuilderQuery *, q, i) { |
| 181 DBUObjectResult result = { |
199 DBUObjectResult result = { |
| 182 .userdata1 = q, |
200 .userdata1 = q, |
| 183 .userdata2 = NULL, |
201 .userdata2 = builder, |
| 184 .int1 = CX_STORE_POINTERS, |
202 .int1 = CX_STORE_POINTERS, |
| 185 .create = result_create_obj, |
203 .create = result_create_obj, |
| 186 .add = add_to_parent |
204 .add = add_to_parent |
| 187 }; |
205 }; |
| 188 |
206 |
| 196 if(builder->cache) { |
214 if(builder->cache) { |
| 197 cxMapDestroy(builder->cache); |
215 cxMapDestroy(builder->cache); |
| 198 } |
216 } |
| 199 builder->cache = NULL; |
217 builder->cache = NULL; |
| 200 return ret; |
218 return ret; |
| |
219 } |
| |
220 |
| |
221 void dbufkelm_free(DBUFK *elm) { |
| |
222 free(elm->cache_key); |
| 201 } |
223 } |
| 202 |
224 |
| 203 int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *type, DBUObjectResult *objresult) { |
225 int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *type, DBUObjectResult *objresult) { |
| 204 DBUClass *cls = type; |
226 DBUClass *cls = type; |
| 205 |
227 |
| 268 } |
290 } |
| 269 } |
291 } |
| 270 |
292 |
| 271 const CxAllocator *a = builder->allocator; |
293 const CxAllocator *a = builder->allocator; |
| 272 |
294 |
| 273 CxList *fklist = cxArrayListCreateSimple(CX_STORE_POINTERS, 4); |
295 CxList *fklist = cxArrayListCreateSimple(sizeof(DBUFK), 4); |
| 274 fklist->collection.simple_destructor = free; |
296 fklist->collection.simple_destructor = (cx_destructor_func)dbufkelm_free; |
| 275 |
297 |
| 276 // get result |
298 // get result |
| 277 int err = 0; |
299 int err = 0; |
| 278 while(result->hasData(result)) { |
300 while(result->hasData(result)) { |
| |
301 |
| 279 // create main result obj |
302 // create main result obj |
| 280 void *obj = objresult->create(objresult, cls, a); |
303 void *obj = objresult->create(objresult, cls, a); |
| 281 if(!obj) { |
304 if(!obj) { |
| 282 break; |
305 break; |
| 283 } |
306 } |
| 324 cxstring text = result->getText(result, i); |
347 cxstring text = result->getText(result, i); |
| 325 field.field->initValue(field.field, a, current_obj, text.ptr, text.length); |
348 field.field->initValue(field.field, a, current_obj, text.ptr, text.length); |
| 326 |
349 |
| 327 // if obj caching is enabled and the current field contains |
350 // if obj caching is enabled and the current field contains |
| 328 // the primary key, add this object to the cache |
351 // the primary key, add this object to the cache |
| 329 if(builder->cache && field.field == current_cls->primary_key) { |
352 if(builder->cache) { |
| 330 if(field.field == current_cls->primary_key) { |
353 if(field.field == current_cls->primary_key) { |
| 331 cxmutstr cache_key = cx_asprintf("%.*s::%.*s", |
354 cxmutstr cache_key = cx_asprintf("%.*s::%.*s", |
| 332 (int)current_cls->name.length, current_cls->name.ptr, |
355 (int)current_cls->name.length, current_cls->name.ptr, |
| 333 (int)text.length, text.ptr); |
356 (int)text.length, text.ptr); |
| 334 if(!cache_key.ptr) { |
357 if(!cache_key.ptr) { |
| 335 err = 1; |
358 err = 1; |
| 336 break; |
359 break; |
| 337 } |
360 } |
| 338 int r = cxMapPut(builder->cache, cache_key, current_obj); |
361 DBUBuilderObjCache cache_elm; |
| |
362 cache_elm.class = current_cls; |
| |
363 cache_elm.obj = current_obj; |
| |
364 int r = cxMapPut(builder->cache, cache_key, &cache_elm); |
| 339 free(cache_key.ptr); |
365 free(cache_key.ptr); |
| 340 if(r) { |
366 if(r) { |
| 341 err = 1; |
367 err = 1; |
| 342 break; |
368 break; |
| 343 } |
369 } |
| 344 } else if(field.field->foreignKeyClass) { |
370 } else if(field.field->foreignKeyClass) { |
| 345 cxmutstr fkey = cx_asprintf("%.*s::%.*s", |
371 cxmutstr fkey = cx_asprintf("%.*s::%.*s", |
| 346 (int)field.field->foreignKeyClass->name.length, current_cls->name.ptr, |
372 (int)field.field->foreignKeyClass->name.length, field.field->foreignKeyClass->name.ptr, |
| 347 (int)text.length, text.ptr); |
373 (int)text.length, text.ptr); |
| 348 cxListAdd(fklist, fkey.ptr); |
374 DBUFK fkelm; |
| |
375 fkelm.cache_key = fkey.ptr; |
| |
376 fkelm.cls = field.field->foreignKeyClass; |
| |
377 cxListAdd(fklist, &fkelm); |
| 349 } |
378 } |
| 350 } |
379 } |
| 351 } |
380 } |
| 352 } |
381 } |
| 353 } |
382 } |
| 354 |
383 |
| 355 if(err) { |
384 if(err) { |
| 356 break; |
385 break; |
| 357 } |
386 } |
| 358 |
387 |
| 359 objresult->add(objresult, NULL, obj, fklist, a); |
388 objresult->add(objresult, NULL, cls, obj, fklist, a); |
| 360 |
389 |
| 361 cxListClear(fklist); |
390 cxListClear(fklist); |
| 362 |
391 |
| 363 // load next row |
392 // load next row |
| 364 result->nextRow(result); |
393 result->nextRow(result); |