LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/couchdb - ogrcouchdblayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 226 151 66.8 %
Date: 2012-12-26 Functions: 17 11 64.7 %

       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                 : }

Generated by: LCOV version 1.7