1 : /******************************************************************************
2 : * $Id: ogrcouchdblayer.cpp 22283 2011-05-01 22:14:25Z rouault $
3 : *
4 : * Project: CouchDB Translator
5 : * Purpose: Implements OGRCouchDBLayer class.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2011, Even Rouault <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_couchdb.h"
31 : #include "json_object_private.h" // json_object_iter, complete type required
32 : #include "ogrgeojsonreader.h"
33 : #include "ogrgeojsonutils.h"
34 :
35 : CPL_CVSID("$Id: ogrcouchdblayer.cpp 22283 2011-05-01 22:14:25Z rouault $");
36 :
37 : /************************************************************************/
38 : /* OGRCouchDBLayer() */
39 : /************************************************************************/
40 :
41 16 : OGRCouchDBLayer::OGRCouchDBLayer(OGRCouchDBDataSource* poDS)
42 :
43 : {
44 16 : this->poDS = poDS;
45 :
46 16 : nNextInSeq = 0;
47 :
48 16 : poSRS = NULL;
49 :
50 16 : poFeatureDefn = NULL;
51 :
52 16 : nOffset = 0;
53 16 : bEOF = FALSE;
54 :
55 16 : poFeatures = NULL;
56 :
57 16 : bGeoJSONDocument = TRUE;
58 16 : }
59 :
60 : /************************************************************************/
61 : /* ~OGRCouchDBLayer() */
62 : /************************************************************************/
63 :
64 16 : OGRCouchDBLayer::~OGRCouchDBLayer()
65 :
66 : {
67 16 : if( poSRS != NULL )
68 8 : poSRS->Release();
69 :
70 16 : if( poFeatureDefn != NULL )
71 15 : poFeatureDefn->Release();
72 :
73 16 : json_object_put(poFeatures);
74 16 : }
75 :
76 : /************************************************************************/
77 : /* ResetReading() */
78 : /************************************************************************/
79 :
80 13 : void OGRCouchDBLayer::ResetReading()
81 :
82 : {
83 13 : nNextInSeq = 0;
84 13 : nOffset = 0;
85 13 : bEOF = FALSE;
86 13 : }
87 :
88 : /************************************************************************/
89 : /* GetLayerDefn() */
90 : /************************************************************************/
91 :
92 8 : OGRFeatureDefn * OGRCouchDBLayer::GetLayerDefn()
93 : {
94 8 : CPLAssert(poFeatureDefn);
95 8 : return poFeatureDefn;
96 : }
97 :
98 : /************************************************************************/
99 : /* GetNextFeature() */
100 : /************************************************************************/
101 :
102 47 : OGRFeature *OGRCouchDBLayer::GetNextFeature()
103 : {
104 : OGRFeature *poFeature;
105 :
106 47 : GetLayerDefn();
107 :
108 30 : while(TRUE)
109 : {
110 77 : if (nNextInSeq < nOffset ||
111 : nNextInSeq >= nOffset + (int)aoFeatures.size())
112 : {
113 18 : if (bEOF)
114 8 : return NULL;
115 :
116 10 : nOffset += aoFeatures.size();
117 10 : if (!FetchNextRows())
118 0 : return NULL;
119 : }
120 :
121 69 : poFeature = GetNextRawFeature();
122 69 : if (poFeature == NULL)
123 0 : return NULL;
124 :
125 69 : if((m_poFilterGeom == NULL
126 : || FilterGeometry( poFeature->GetGeometryRef() ) )
127 : && (m_poAttrQuery == NULL
128 : || m_poAttrQuery->Evaluate( poFeature )) )
129 : {
130 39 : return poFeature;
131 : }
132 : else
133 30 : delete poFeature;
134 : }
135 : }
136 :
137 : /************************************************************************/
138 : /* GetNextRawFeature() */
139 : /************************************************************************/
140 :
141 69 : OGRFeature *OGRCouchDBLayer::GetNextRawFeature()
142 : {
143 69 : if (nNextInSeq < nOffset ||
144 : nNextInSeq - nOffset >= (int)aoFeatures.size())
145 0 : return NULL;
146 :
147 69 : OGRFeature* poFeature = TranslateFeature(aoFeatures[nNextInSeq - nOffset]);
148 69 : if (poFeature != NULL && poFeature->GetFID() == OGRNullFID)
149 0 : poFeature->SetFID(nNextInSeq);
150 :
151 69 : nNextInSeq ++;
152 :
153 69 : return poFeature;
154 : }
155 :
156 : /************************************************************************/
157 : /* SetNextByIndex() */
158 : /************************************************************************/
159 :
160 0 : OGRErr OGRCouchDBLayer::SetNextByIndex( long nIndex )
161 : {
162 0 : if (nIndex < 0)
163 0 : return OGRERR_FAILURE;
164 0 : bEOF = FALSE;
165 0 : nNextInSeq = nIndex;
166 0 : return OGRERR_NONE;
167 : }
168 :
169 : /************************************************************************/
170 : /* TestCapability() */
171 : /************************************************************************/
172 :
173 0 : int OGRCouchDBLayer::TestCapability( const char * pszCap )
174 :
175 : {
176 0 : if ( EQUAL(pszCap, OLCStringsAsUTF8) )
177 0 : return TRUE;
178 0 : else if ( EQUAL(pszCap, OLCFastSetNextByIndex) )
179 0 : return TRUE;
180 0 : return FALSE;
181 : }
182 :
183 : /************************************************************************/
184 : /* GetSpatialRef() */
185 : /************************************************************************/
186 :
187 0 : OGRSpatialReference* OGRCouchDBLayer::GetSpatialRef()
188 : {
189 0 : GetLayerDefn();
190 :
191 0 : return poSRS;
192 : }
193 :
194 : /************************************************************************/
195 : /* TranslateFeature() */
196 : /************************************************************************/
197 :
198 71 : OGRFeature* OGRCouchDBLayer::TranslateFeature( json_object* poObj )
199 : {
200 71 : OGRFeature* poFeature = NULL;
201 71 : poFeature = new OGRFeature( GetLayerDefn() );
202 :
203 71 : json_object* poId = json_object_object_get(poObj, "_id");
204 71 : const char* pszId = json_object_get_string(poId);
205 71 : if (pszId)
206 : {
207 71 : poFeature->SetField(_ID_FIELD, pszId);
208 :
209 71 : int nFID = atoi(pszId);
210 71 : const char* pszFID = CPLSPrintf("%09d", nFID);
211 71 : if (strcmp(pszId, pszFID) == 0)
212 71 : poFeature->SetFID(nFID);
213 : }
214 :
215 71 : json_object* poRev = json_object_object_get(poObj, "_rev");
216 71 : const char* pszRev = json_object_get_string(poRev);
217 71 : if (pszRev)
218 71 : poFeature->SetField(_REV_FIELD, pszRev);
219 :
220 : /* -------------------------------------------------------------------- */
221 : /* Translate GeoJSON "properties" object to feature attributes. */
222 : /* -------------------------------------------------------------------- */
223 :
224 : json_object_iter it;
225 71 : it.key = NULL;
226 71 : it.val = NULL;
227 71 : it.entry = NULL;
228 71 : if( bGeoJSONDocument )
229 : {
230 19 : json_object* poObjProps = json_object_object_get( poObj, "properties" );
231 19 : if ( NULL != poObjProps &&
232 : json_object_get_type(poObjProps ) == json_type_object )
233 : {
234 76 : json_object_object_foreachC( poObjProps, it )
235 : {
236 57 : ParseFieldValue(poFeature, it.key, it.val);
237 : }
238 : }
239 : }
240 : else
241 : {
242 364 : json_object_object_foreachC( poObj, it )
243 : {
244 312 : if( strcmp(it.key, "_id") != 0 &&
245 : strcmp(it.key, "_rev") != 0 &&
246 : strcmp(it.key, "geometry") != 0 )
247 : {
248 156 : ParseFieldValue(poFeature, it.key, it.val);
249 : }
250 : }
251 : }
252 :
253 : /* -------------------------------------------------------------------- */
254 : /* Translate geometry sub-object of GeoJSON Feature. */
255 : /* -------------------------------------------------------------------- */
256 :
257 71 : json_object* poObjGeom = json_object_object_get( poObj, "geometry" );
258 71 : if (poObjGeom != NULL)
259 : {
260 71 : OGRGeometry* poGeometry = OGRGeoJSONReadGeometry( poObjGeom );
261 71 : if( NULL != poGeometry )
262 : {
263 71 : if (poSRS)
264 15 : poGeometry->assignSpatialReference(poSRS);
265 71 : poFeature->SetGeometryDirectly( poGeometry );
266 : }
267 : }
268 :
269 71 : return poFeature;
270 : }
271 :
272 : /************************************************************************/
273 : /* ParseFieldValue() */
274 : /************************************************************************/
275 :
276 213 : void OGRCouchDBLayer::ParseFieldValue(OGRFeature* poFeature,
277 : const char* pszKey,
278 : json_object* poValue)
279 : {
280 213 : int nField = poFeature->GetFieldIndex(pszKey);
281 213 : if (nField < 0)
282 : {
283 : CPLDebug("CouchDB",
284 : "Found field '%s' which is not in the layer definition. "
285 : "Ignoring its value",
286 0 : pszKey);
287 : }
288 213 : else if (poValue != NULL)
289 : {
290 213 : OGRFieldDefn* poFieldDefn = poFeature->GetFieldDefnRef(nField);
291 213 : CPLAssert(poFieldDefn != NULL);
292 213 : OGRFieldType eType = poFieldDefn->GetType();
293 :
294 213 : if( OFTInteger == eType )
295 : {
296 0 : poFeature->SetField( nField, json_object_get_int(poValue) );
297 : }
298 213 : else if( OFTReal == eType )
299 : {
300 142 : poFeature->SetField( nField, json_object_get_double(poValue) );
301 : }
302 71 : else if( OFTIntegerList == eType )
303 : {
304 0 : if ( json_object_get_type(poValue) == json_type_array )
305 : {
306 0 : int nLength = json_object_array_length(poValue);
307 0 : int* panVal = (int*)CPLMalloc(sizeof(int) * nLength);
308 0 : for(int i=0;i<nLength;i++)
309 : {
310 0 : json_object* poRow = json_object_array_get_idx(poValue, i);
311 0 : panVal[i] = json_object_get_int(poRow);
312 : }
313 0 : poFeature->SetField( nField, nLength, panVal );
314 0 : CPLFree(panVal);
315 : }
316 : }
317 71 : else if( OFTRealList == eType )
318 : {
319 0 : if ( json_object_get_type(poValue) == json_type_array )
320 : {
321 0 : int nLength = json_object_array_length(poValue);
322 0 : double* padfVal = (double*)CPLMalloc(sizeof(double) * nLength);
323 0 : for(int i=0;i<nLength;i++)
324 : {
325 0 : json_object* poRow = json_object_array_get_idx(poValue, i);
326 0 : padfVal[i] = json_object_get_double(poRow);
327 : }
328 0 : poFeature->SetField( nField, nLength, padfVal );
329 0 : CPLFree(padfVal);
330 : }
331 : }
332 71 : else if( OFTStringList == eType )
333 : {
334 0 : if ( json_object_get_type(poValue) == json_type_array )
335 : {
336 0 : int nLength = json_object_array_length(poValue);
337 0 : char** papszVal = (char**)CPLMalloc(sizeof(char*) * (nLength+1));
338 : int i;
339 0 : for(i=0;i<nLength;i++)
340 : {
341 0 : json_object* poRow = json_object_array_get_idx(poValue, i);
342 0 : const char* pszVal = json_object_get_string(poRow);
343 0 : if (pszVal == NULL)
344 0 : break;
345 0 : papszVal[i] = CPLStrdup(pszVal);
346 : }
347 0 : papszVal[i] = NULL;
348 0 : poFeature->SetField( nField, papszVal );
349 0 : CSLDestroy(papszVal);
350 : }
351 : }
352 : else
353 : {
354 71 : poFeature->SetField( nField, json_object_get_string(poValue) );
355 : }
356 : }
357 213 : }
358 :
359 :
360 : /************************************************************************/
361 : /* BuildFeatureDefnFromDoc() */
362 : /************************************************************************/
363 :
364 7 : void OGRCouchDBLayer::BuildFeatureDefnFromDoc(json_object* poDoc)
365 : {
366 : /* -------------------------------------------------------------------- */
367 : /* Read collection of properties. */
368 : /* -------------------------------------------------------------------- */
369 : json_object* poObjProps = json_object_object_get( poDoc,
370 7 : "properties" );
371 : json_object_iter it;
372 7 : it.key = NULL;
373 7 : it.val = NULL;
374 7 : it.entry = NULL;
375 7 : if( NULL != poObjProps && json_object_get_type(poObjProps) == json_type_object )
376 : {
377 4 : json_object_object_foreachC( poObjProps, it )
378 : {
379 3 : if( -1 == poFeatureDefn->GetFieldIndex( it.key ) )
380 : {
381 : OGRFieldDefn fldDefn( it.key,
382 3 : GeoJSONPropertyToFieldType( it.val ) );
383 3 : poFeatureDefn->AddFieldDefn( &fldDefn );
384 : }
385 : }
386 : }
387 : else
388 : {
389 6 : bGeoJSONDocument = FALSE;
390 :
391 42 : json_object_object_foreachC( poDoc, it )
392 : {
393 36 : if( strcmp(it.key, "_id") != 0 &&
394 : strcmp(it.key, "_rev") != 0 &&
395 : strcmp(it.key, "geometry") != 0 &&
396 : -1 == poFeatureDefn->GetFieldIndex( it.key ) )
397 : {
398 : OGRFieldDefn fldDefn( it.key,
399 18 : GeoJSONPropertyToFieldType( it.val ) );
400 18 : poFeatureDefn->AddFieldDefn( &fldDefn );
401 : }
402 : }
403 : }
404 :
405 7 : if( json_object_object_get( poDoc, "geometry" ) == NULL )
406 : {
407 0 : poFeatureDefn->SetGeomType(wkbNone);
408 : }
409 7 : }
410 :
411 :
412 : /************************************************************************/
413 : /* BuildFeatureDefnFromRows() */
414 : /************************************************************************/
415 :
416 7 : int OGRCouchDBLayer::BuildFeatureDefnFromRows(json_object* poAnswerObj)
417 : {
418 7 : if ( !json_object_is_type(poAnswerObj, json_type_object) )
419 : {
420 : CPLError(CE_Failure, CPLE_AppDefined,
421 0 : "Layer definition creation failed");
422 0 : return FALSE;
423 : }
424 :
425 7 : if (poDS->IsError(poAnswerObj, "Layer definition creation failed"))
426 : {
427 0 : return FALSE;
428 : }
429 :
430 7 : json_object* poRows = json_object_object_get(poAnswerObj, "rows");
431 7 : if (poRows == NULL ||
432 : !json_object_is_type(poRows, json_type_array))
433 : {
434 : CPLError(CE_Failure, CPLE_AppDefined,
435 0 : "Layer definition creation failed");
436 0 : return FALSE;
437 : }
438 :
439 7 : int nRows = json_object_array_length(poRows);
440 :
441 7 : json_object* poRow = NULL;
442 7 : for(int i=0;i<nRows;i++)
443 : {
444 7 : json_object* poTmpRow = json_object_array_get_idx(poRows, i);
445 7 : if (poTmpRow != NULL &&
446 : json_object_is_type(poTmpRow, json_type_object))
447 : {
448 7 : json_object* poId = json_object_object_get(poTmpRow, "id");
449 7 : const char* pszId = json_object_get_string(poId);
450 7 : if (pszId != NULL && pszId[0] != '_')
451 : {
452 7 : poRow = poTmpRow;
453 7 : break;
454 : }
455 : }
456 : }
457 :
458 7 : if ( poRow == NULL )
459 : {
460 0 : return FALSE;
461 : }
462 :
463 7 : json_object* poDoc = json_object_object_get(poRow, "doc");
464 7 : if ( poDoc == NULL )
465 0 : poDoc = json_object_object_get(poRow, "value");
466 7 : if ( poDoc == NULL ||
467 : !json_object_is_type(poDoc, json_type_object) )
468 : {
469 : CPLError(CE_Failure, CPLE_AppDefined,
470 0 : "Layer definition creation failed");
471 0 : return FALSE;
472 : }
473 :
474 7 : BuildFeatureDefnFromDoc(poDoc);
475 :
476 7 : return TRUE;
477 : }
478 :
479 : /************************************************************************/
480 : /* FetchNextRowsAnalyseDocs() */
481 : /************************************************************************/
482 :
483 11 : int OGRCouchDBLayer::FetchNextRowsAnalyseDocs(json_object* poAnswerObj)
484 : {
485 11 : if (poAnswerObj == NULL)
486 0 : return FALSE;
487 :
488 11 : if ( !json_object_is_type(poAnswerObj, json_type_object) )
489 : {
490 : CPLError(CE_Failure, CPLE_AppDefined,
491 0 : "FetchNextRowsAnalyseDocs() failed");
492 0 : json_object_put(poAnswerObj);
493 0 : return FALSE;
494 : }
495 :
496 11 : if (poDS->IsError(poAnswerObj, "FetchNextRowsAnalyseDocs() failed"))
497 : {
498 0 : json_object_put(poAnswerObj);
499 0 : return FALSE;
500 : }
501 :
502 11 : json_object* poRows = json_object_object_get(poAnswerObj, "rows");
503 11 : if (poRows == NULL ||
504 : !json_object_is_type(poRows, json_type_array))
505 : {
506 : CPLError(CE_Failure, CPLE_AppDefined,
507 0 : "FetchNextRowsAnalyseDocs() failed");
508 0 : json_object_put(poAnswerObj);
509 0 : return FALSE;
510 : }
511 :
512 11 : int nRows = json_object_array_length(poRows);
513 114 : for(int i=0;i<nRows;i++)
514 : {
515 103 : json_object* poRow = json_object_array_get_idx(poRows, i);
516 103 : if ( poRow == NULL ||
517 : !json_object_is_type(poRow, json_type_object) )
518 : {
519 : CPLError(CE_Failure, CPLE_AppDefined,
520 0 : "FetchNextRowsAnalyseDocs() failed");
521 0 : json_object_put(poAnswerObj);
522 0 : return FALSE;
523 : }
524 :
525 103 : json_object* poDoc = json_object_object_get(poRow, "doc");
526 103 : if ( poDoc == NULL )
527 0 : poDoc = json_object_object_get(poRow, "value");
528 103 : if ( poDoc == NULL ||
529 : !json_object_is_type(poDoc, json_type_object) )
530 : {
531 : CPLError(CE_Failure, CPLE_AppDefined,
532 0 : "FetchNextRowsAnalyseDocs() failed");
533 0 : json_object_put(poAnswerObj);
534 0 : return FALSE;
535 : }
536 :
537 103 : json_object* poId = json_object_object_get(poDoc, "_id");
538 103 : const char* pszId = json_object_get_string(poId);
539 103 : if (pszId != NULL && strncmp(pszId, "_design/", 8) != 0)
540 : {
541 93 : aoFeatures.push_back(poDoc);
542 : }
543 : }
544 :
545 11 : bEOF = nRows < GetFeaturesToFetch();
546 :
547 11 : poFeatures = poAnswerObj;
548 :
549 11 : return TRUE;
550 : }
|