LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ngw - ogrngwlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 878 0.0 %
Date: 2024-05-07 17:03:27 Functions: 0 53 0.0 %

          Line data    Source code
       1             : /*******************************************************************************
       2             :  *  Project: NextGIS Web Driver
       3             :  *  Purpose: Implements NextGIS Web Driver
       4             :  *  Author: Dmitry Baryshnikov, dmitry.baryshnikov@nextgis.com
       5             :  *  Language: C++
       6             :  *******************************************************************************
       7             :  *  The MIT License (MIT)
       8             :  *
       9             :  *  Copyright (c) 2018-2020, NextGIS <info@nextgis.com>
      10             :  *
      11             :  *  Permission is hereby granted, free of charge, to any person obtaining a copy
      12             :  *  of this software and associated documentation files (the "Software"), to
      13             :  *deal in the Software without restriction, including without limitation the
      14             :  *rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      15             :  *sell copies of the Software, and to permit persons to whom the Software is
      16             :  *  furnished to do so, subject to the following conditions:
      17             :  *
      18             :  *  The above copyright notice and this permission notice shall be included in
      19             :  *all copies or substantial portions of the Software.
      20             :  *
      21             :  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      22             :  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      24             :  *  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 DEALINGS
      27             :  *IN THE SOFTWARE.
      28             :  *******************************************************************************/
      29             : 
      30             : #include "ogr_ngw.h"
      31             : 
      32             : /*
      33             :  * CheckRequestResult()
      34             :  */
      35           0 : static bool CheckRequestResult(bool bResult, const CPLJSONObject &oRoot,
      36             :                                const std::string &osErrorMessage)
      37             : {
      38           0 :     if (!bResult)
      39             :     {
      40           0 :         if (oRoot.IsValid())
      41             :         {
      42           0 :             std::string osErrorMessageInt = oRoot.GetString("message");
      43           0 :             if (!osErrorMessageInt.empty())
      44             :             {
      45           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "%s",
      46             :                          osErrorMessageInt.c_str());
      47           0 :                 return false;
      48             :             }
      49             :         }
      50           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", osErrorMessage.c_str());
      51             : 
      52           0 :         return false;
      53             :     }
      54             : 
      55           0 :     if (!oRoot.IsValid())
      56             :     {
      57           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", osErrorMessage.c_str());
      58           0 :         return false;
      59             :     }
      60             : 
      61           0 :     return true;
      62             : }
      63             : 
      64             : /*
      65             :  * OGRGeometryToWKT()
      66             :  */
      67           0 : static std::string OGRGeometryToWKT(OGRGeometry *poGeom)
      68             : {
      69           0 :     std::string osOut;
      70           0 :     if (nullptr == poGeom)
      71             :     {
      72           0 :         return osOut;
      73             :     }
      74             : 
      75           0 :     char *pszWkt = nullptr;
      76           0 :     if (poGeom->exportToWkt(&pszWkt) == OGRERR_NONE)
      77             :     {
      78           0 :         osOut = pszWkt;
      79             :     }
      80           0 :     CPLFree(pszWkt);
      81             : 
      82           0 :     return osOut;
      83             : }
      84             : 
      85             : /*
      86             :  * JSONToFeature()
      87             :  */
      88           0 : static OGRFeature *JSONToFeature(const CPLJSONObject &featureJson,
      89             :                                  OGRFeatureDefn *poFeatureDefn,
      90             :                                  bool bCheckIgnoredFields = false,
      91             :                                  bool bStoreExtensionData = false)
      92             : {
      93           0 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
      94           0 :     poFeature->SetFID(featureJson.GetLong("id"));
      95           0 :     CPLJSONObject oFields = featureJson.GetObj("fields");
      96           0 :     for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); ++iField)
      97             :     {
      98           0 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
      99           0 :         if (bCheckIgnoredFields && poFieldDefn->IsIgnored())
     100             :         {
     101           0 :             continue;
     102             :         }
     103           0 :         CPLJSONObject oJSONField = oFields[poFieldDefn->GetNameRef()];
     104           0 :         if (oJSONField.IsValid() &&
     105           0 :             oJSONField.GetType() != CPLJSONObject::Type::Null)
     106             :         {
     107           0 :             switch (poFieldDefn->GetType())
     108             :             {
     109           0 :                 case OFTInteger:
     110           0 :                     poFeature->SetField(iField, oJSONField.ToInteger());
     111           0 :                     break;
     112           0 :                 case OFTInteger64:
     113           0 :                     poFeature->SetField(iField, oJSONField.ToLong());
     114           0 :                     break;
     115           0 :                 case OFTReal:
     116           0 :                     poFeature->SetField(iField, oJSONField.ToDouble());
     117           0 :                     break;
     118           0 :                 case OFTBinary:
     119             :                     // Not supported.
     120           0 :                     break;
     121           0 :                 case OFTString:
     122             :                 case OFTIntegerList:
     123             :                 case OFTInteger64List:
     124             :                 case OFTRealList:
     125             :                 case OFTStringList:
     126           0 :                     poFeature->SetField(iField, oJSONField.ToString().c_str());
     127           0 :                     break;
     128           0 :                 case OFTDate:
     129             :                 case OFTTime:
     130             :                 case OFTDateTime:
     131             :                 {
     132           0 :                     int nYear = oJSONField.GetInteger("year");
     133           0 :                     int nMonth = oJSONField.GetInteger("month");
     134           0 :                     int nDay = oJSONField.GetInteger("day");
     135           0 :                     int nHour = oJSONField.GetInteger("hour");
     136           0 :                     int nMinute = oJSONField.GetInteger("minute");
     137           0 :                     int nSecond = oJSONField.GetInteger("second");
     138           0 :                     poFeature->SetField(iField, nYear, nMonth, nDay, nHour,
     139             :                                         nMinute, float(nSecond));
     140           0 :                     break;
     141             :                 }
     142           0 :                 default:
     143           0 :                     break;
     144             :             }
     145             :         }
     146             :     }
     147             : 
     148             :     bool bFillGeometry =
     149           0 :         !(bCheckIgnoredFields && poFeatureDefn->IsGeometryIgnored());
     150             : 
     151           0 :     if (bFillGeometry)
     152             :     {
     153           0 :         OGRGeometry *poGeometry = nullptr;
     154           0 :         OGRGeometryFactory::createFromWkt(featureJson.GetString("geom").c_str(),
     155             :                                           nullptr, &poGeometry);
     156           0 :         if (poGeometry != nullptr)
     157             :         {
     158             :             const OGRSpatialReference *poSpatialRef =
     159           0 :                 poFeatureDefn->GetGeomFieldDefn(0)->GetSpatialRef();
     160           0 :             if (poSpatialRef != nullptr)
     161             :             {
     162           0 :                 poGeometry->assignSpatialReference(poSpatialRef);
     163             :             }
     164           0 :             poFeature->SetGeomFieldDirectly(0, poGeometry);
     165             :         }
     166             :     }
     167             : 
     168             :     // Get extensions key and store it in native data.
     169           0 :     if (bStoreExtensionData)
     170             :     {
     171           0 :         CPLJSONObject oExtensions = featureJson.GetObj("extensions");
     172           0 :         if (oExtensions.IsValid() &&
     173           0 :             oExtensions.GetType() != CPLJSONObject::Type::Null)
     174             :         {
     175           0 :             poFeature->SetNativeData(
     176           0 :                 oExtensions.Format(CPLJSONObject::PrettyFormat::Plain).c_str());
     177           0 :             poFeature->SetNativeMediaType("application/json");
     178             :         }
     179             :     }
     180             : 
     181           0 :     return poFeature;
     182             : }
     183             : 
     184             : /*
     185             :  * FeatureToJson()
     186             :  */
     187           0 : static CPLJSONObject FeatureToJson(OGRFeature *poFeature)
     188             : {
     189           0 :     CPLJSONObject oFeatureJson;
     190           0 :     if (poFeature == nullptr)
     191             :     {
     192             :         // Should not happen.
     193           0 :         return oFeatureJson;
     194             :     }
     195             : 
     196           0 :     if (poFeature->GetFID() >= 0)
     197             :     {
     198           0 :         oFeatureJson.Add("id", poFeature->GetFID());
     199             :     }
     200             : 
     201           0 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
     202           0 :     std::string osGeomWKT = OGRGeometryToWKT(poGeom);
     203           0 :     if (!osGeomWKT.empty())
     204             :     {
     205           0 :         oFeatureJson.Add("geom", osGeomWKT);
     206             :     }
     207             : 
     208           0 :     OGRFeatureDefn *poFeatureDefn = poFeature->GetDefnRef();
     209           0 :     CPLJSONObject oFieldsJson("fields", oFeatureJson);
     210           0 :     for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); ++iField)
     211             :     {
     212           0 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
     213           0 :         if (poFeature->IsFieldNull(iField) == TRUE)
     214             :         {
     215           0 :             oFieldsJson.AddNull(poFieldDefn->GetNameRef());
     216           0 :             continue;
     217             :         }
     218             : 
     219           0 :         if (poFeature->IsFieldSet(iField) == TRUE)
     220             :         {
     221           0 :             switch (poFieldDefn->GetType())
     222             :             {
     223           0 :                 case OFTInteger:
     224           0 :                     oFieldsJson.Add(poFieldDefn->GetNameRef(),
     225             :                                     poFeature->GetFieldAsInteger(iField));
     226           0 :                     break;
     227           0 :                 case OFTInteger64:
     228           0 :                     oFieldsJson.Add(
     229             :                         poFieldDefn->GetNameRef(),
     230             :                         static_cast<GInt64>(
     231           0 :                             poFeature->GetFieldAsInteger64(iField)));
     232           0 :                     break;
     233           0 :                 case OFTReal:
     234           0 :                     oFieldsJson.Add(poFieldDefn->GetNameRef(),
     235             :                                     poFeature->GetFieldAsDouble(iField));
     236           0 :                     break;
     237           0 :                 case OFTBinary:
     238             :                     // Not supported.
     239           0 :                     break;
     240           0 :                 case OFTString:
     241             :                 case OFTIntegerList:
     242             :                 case OFTInteger64List:
     243             :                 case OFTRealList:
     244             :                 case OFTStringList:
     245           0 :                     oFieldsJson.Add(poFieldDefn->GetNameRef(),
     246             :                                     poFeature->GetFieldAsString(iField));
     247           0 :                     break;
     248           0 :                 case OFTDate:
     249             :                 case OFTTime:
     250             :                 case OFTDateTime:
     251             :                 {
     252             :                     int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
     253           0 :                     if (poFeature->GetFieldAsDateTime(
     254             :                             iField, &nYear, &nMonth, &nDay, &nHour, &nMinute,
     255           0 :                             &nSecond, &nTZFlag) == TRUE)
     256             :                     {
     257             :                         // TODO: Convert timestamp to UTC.
     258           0 :                         if (nTZFlag == 0 || nTZFlag == 100)
     259             :                         {
     260             :                             CPLJSONObject oDateJson(poFieldDefn->GetNameRef(),
     261           0 :                                                     oFieldsJson);
     262             : 
     263           0 :                             oDateJson.Add("year", nYear);
     264           0 :                             oDateJson.Add("month", nMonth);
     265           0 :                             oDateJson.Add("day", nDay);
     266           0 :                             oDateJson.Add("hour", nHour);
     267           0 :                             oDateJson.Add("minute", nMinute);
     268           0 :                             oDateJson.Add("second", nSecond);
     269             :                         }
     270             :                     }
     271           0 :                     break;
     272             :                 }
     273           0 :                 default:
     274           0 :                     break;
     275             :             }
     276             :         }
     277             :     }
     278             : 
     279           0 :     if (poFeature->GetNativeData())
     280             :     {
     281           0 :         CPLJSONDocument oExtensions;
     282           0 :         if (oExtensions.LoadMemory(poFeature->GetNativeData()))
     283             :         {
     284           0 :             oFeatureJson.Add("extensions", oExtensions.GetRoot());
     285             :         }
     286             :     }
     287             : 
     288           0 :     return oFeatureJson;
     289             : }
     290             : 
     291             : /*
     292             :  * FeatureToJsonString()
     293             :  */
     294           0 : static std::string FeatureToJsonString(OGRFeature *poFeature)
     295             : {
     296           0 :     return FeatureToJson(poFeature).Format(CPLJSONObject::PrettyFormat::Plain);
     297             : }
     298             : 
     299             : /*
     300             :  * FreeMap()
     301             :  */
     302           0 : static void FreeMap(std::map<GIntBig, OGRFeature *> &moFeatures)
     303             : {
     304             :     // cppcheck-suppress constVariableReference
     305           0 :     for (auto &oPair : moFeatures)
     306             :     {
     307           0 :         OGRFeature::DestroyFeature(oPair.second);
     308             :     }
     309             : 
     310           0 :     moFeatures.clear();
     311           0 : }
     312             : 
     313           0 : static bool CheckFieldNameUnique(OGRFeatureDefn *poFeatureDefn, int iField,
     314             :                                  const char *pszFieldName)
     315             : {
     316           0 :     for (int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
     317             :     {
     318           0 :         if (i == iField)
     319             :         {
     320           0 :             continue;
     321             :         }
     322             : 
     323           0 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(i);
     324           0 :         if (poFieldDefn && EQUAL(poFieldDefn->GetNameRef(), pszFieldName))
     325             :         {
     326           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     327             :                      "Field name %s already present in field %d.", pszFieldName,
     328             :                      i);
     329           0 :             return false;
     330             :         }
     331             :     }
     332           0 :     return true;
     333             : }
     334             : 
     335           0 : static std::string GetUniqueFieldName(OGRFeatureDefn *poFeatureDefn, int iField,
     336             :                                       const char *pszBaseName, int nAdd = 0,
     337             :                                       int nMax = 100)
     338             : {
     339           0 :     const char *pszNewName = CPLSPrintf("%s%d", pszBaseName, nAdd);
     340           0 :     for (int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
     341             :     {
     342           0 :         if (i == iField)
     343             :         {
     344           0 :             continue;
     345             :         }
     346             : 
     347           0 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(i);
     348           0 :         if (poFieldDefn && EQUAL(poFieldDefn->GetNameRef(), pszNewName))
     349             :         {
     350           0 :             if (nAdd + 1 == nMax)
     351             :             {
     352           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     353             :                          "Too many field names like '%s' + number.",
     354             :                          pszBaseName);
     355             : 
     356           0 :                 return pszBaseName;  // Let's solve this on server side.
     357             :             }
     358             :             return GetUniqueFieldName(poFeatureDefn, iField, pszBaseName,
     359           0 :                                       nAdd + 1);
     360             :         }
     361             :     }
     362             : 
     363           0 :     return pszNewName;
     364             : }
     365             : 
     366           0 : static void NormalizeFieldName(OGRFeatureDefn *poFeatureDefn, int iField,
     367             :                                OGRFieldDefn *poFieldDefn)
     368             : {
     369           0 :     if (EQUAL(poFieldDefn->GetNameRef(), "id"))
     370             :     {
     371             :         std::string osNewFieldName = GetUniqueFieldName(
     372           0 :             poFeatureDefn, iField, poFieldDefn->GetNameRef(), 0);
     373           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     374             :                  "Normalized/laundered field name: '%s' to '%s'",
     375             :                  poFieldDefn->GetNameRef(), osNewFieldName.c_str());
     376             : 
     377             :         // Set field name with normalized value.
     378           0 :         poFieldDefn->SetName(osNewFieldName.c_str());
     379             :     }
     380           0 : }
     381             : 
     382             : /*
     383             :  * TranslateSQLToFilter()
     384             :  */
     385           0 : std::string OGRNGWLayer::TranslateSQLToFilter(swq_expr_node *poNode)
     386             : {
     387           0 :     if (nullptr == poNode)
     388             :     {
     389           0 :         return "";
     390             :     }
     391             : 
     392           0 :     if (poNode->eNodeType == SNT_OPERATION)
     393             :     {
     394           0 :         if (poNode->nOperation == SWQ_AND && poNode->nSubExprCount == 2)
     395             :         {
     396             :             std::string osFilter1 =
     397           0 :                 TranslateSQLToFilter(poNode->papoSubExpr[0]);
     398             :             std::string osFilter2 =
     399           0 :                 TranslateSQLToFilter(poNode->papoSubExpr[1]);
     400             : 
     401           0 :             if (osFilter1.empty() || osFilter2.empty())
     402             :             {
     403           0 :                 return "";
     404             :             }
     405           0 :             return osFilter1 + "&" + osFilter2;
     406             :         }
     407           0 :         else if ((poNode->nOperation == SWQ_EQ ||
     408           0 :                   poNode->nOperation == SWQ_NE ||
     409           0 :                   poNode->nOperation == SWQ_GE ||
     410           0 :                   poNode->nOperation == SWQ_LE ||
     411           0 :                   poNode->nOperation == SWQ_LT ||
     412           0 :                   poNode->nOperation == SWQ_GT ||
     413           0 :                   poNode->nOperation == SWQ_LIKE ||
     414           0 :                   poNode->nOperation == SWQ_ILIKE) &&
     415           0 :                  poNode->nSubExprCount == 2 &&
     416           0 :                  poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
     417           0 :                  poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT)
     418             :         {
     419           0 :             if (poNode->papoSubExpr[0]->string_value == nullptr)
     420             :             {
     421           0 :                 return "";
     422             :             }
     423           0 :             char *pszNameEncoded = CPLEscapeString(
     424           0 :                 poNode->papoSubExpr[0]->string_value, -1, CPLES_URL);
     425           0 :             std::string osFieldName = "fld_" + std::string(pszNameEncoded);
     426           0 :             CPLFree(pszNameEncoded);
     427             : 
     428           0 :             switch (poNode->nOperation)
     429             :             {
     430           0 :                 case SWQ_EQ:
     431           0 :                     osFieldName += "__eq";
     432           0 :                     break;
     433           0 :                 case SWQ_NE:
     434           0 :                     osFieldName += "__ne";
     435           0 :                     break;
     436           0 :                 case SWQ_GE:
     437           0 :                     osFieldName += "__ge";
     438           0 :                     break;
     439           0 :                 case SWQ_LE:
     440           0 :                     osFieldName += "__le";
     441           0 :                     break;
     442           0 :                 case SWQ_LT:
     443           0 :                     osFieldName += "__lt";
     444           0 :                     break;
     445           0 :                 case SWQ_GT:
     446           0 :                     osFieldName += "__gt";
     447           0 :                     break;
     448           0 :                 case SWQ_LIKE:
     449           0 :                     osFieldName += "__like";
     450           0 :                     break;
     451           0 :                 case SWQ_ILIKE:
     452           0 :                     osFieldName += "__ilike";
     453           0 :                     break;
     454           0 :                 default:
     455           0 :                     CPLAssert(false);
     456             :                     break;
     457             :             }
     458             : 
     459           0 :             std::string osVal;
     460           0 :             switch (poNode->papoSubExpr[1]->field_type)
     461             :             {
     462           0 :                 case SWQ_INTEGER64:
     463             :                 case SWQ_INTEGER:
     464           0 :                     osVal = std::to_string(poNode->papoSubExpr[1]->int_value);
     465           0 :                     break;
     466           0 :                 case SWQ_FLOAT:
     467           0 :                     osVal = std::to_string(poNode->papoSubExpr[1]->float_value);
     468           0 :                     break;
     469           0 :                 case SWQ_STRING:
     470           0 :                     if (poNode->papoSubExpr[1]->string_value)
     471             :                     {
     472           0 :                         char *pszValueEncoded = CPLEscapeString(
     473           0 :                             poNode->papoSubExpr[1]->string_value, -1,
     474             :                             CPLES_URL);
     475           0 :                         osVal = pszValueEncoded;
     476           0 :                         CPLFree(pszValueEncoded);
     477             :                     }
     478           0 :                     break;
     479           0 :                 case SWQ_DATE:
     480             :                 case SWQ_TIME:
     481             :                 case SWQ_TIMESTAMP:
     482           0 :                     if (poNode->papoSubExpr[1]->string_value)
     483             :                     {
     484           0 :                         char *pszValueEncoded = CPLEscapeString(
     485           0 :                             poNode->papoSubExpr[1]->string_value, -1,
     486             :                             CPLES_URL);
     487           0 :                         osVal = pszValueEncoded;
     488           0 :                         CPLFree(pszValueEncoded);
     489             :                     }
     490           0 :                     break;
     491           0 :                 default:
     492           0 :                     break;
     493             :             }
     494           0 :             if (osFieldName.empty() || osVal.empty())
     495             :             {
     496           0 :                 CPLDebug("NGW", "Unsupported filter operation for server side");
     497           0 :                 return "";
     498             :             }
     499             : 
     500           0 :             return osFieldName + "=" + osVal;
     501             :         }
     502             :         else
     503             :         {
     504           0 :             CPLDebug("NGW", "Unsupported filter operation for server side");
     505           0 :             return "";
     506             :         }
     507             :     }
     508           0 :     return "";
     509             : }
     510             : 
     511             : /*
     512             :  * OGRNGWLayer()
     513             :  */
     514           0 : OGRNGWLayer::OGRNGWLayer(OGRNGWDataset *poDSIn,
     515           0 :                          const CPLJSONObject &oResourceJsonObject)
     516             :     : osResourceId(oResourceJsonObject.GetString("resource/id", "-1")),
     517             :       poDS(poDSIn), bFetchedPermissions(false), nFeatureCount(-1),
     518           0 :       oNextPos(moFeatures.begin()), nPageStart(0), bNeedSyncData(false),
     519           0 :       bNeedSyncStructure(false), bClientSideAttributeFilter(false)
     520             : {
     521           0 :     std::string osName = oResourceJsonObject.GetString("resource/display_name");
     522           0 :     poFeatureDefn = new OGRFeatureDefn(osName.c_str());
     523           0 :     poFeatureDefn->Reference();
     524             : 
     525           0 :     poFeatureDefn->SetGeomType(NGWAPI::NGWGeomTypeToOGRGeomType(
     526           0 :         oResourceJsonObject.GetString("vector_layer/geometry_type")));
     527             : 
     528           0 :     OGRSpatialReference *poSRS = new OGRSpatialReference;
     529           0 :     poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     530           0 :     int nEPSG = oResourceJsonObject.GetInteger(
     531             :         "vector_layer/srs/id",
     532             :         3857);  // Default NGW SRS is Web mercator EPSG:3857.
     533           0 :     if (poSRS->importFromEPSG(nEPSG) == OGRERR_NONE)
     534             :     {
     535           0 :         if (poFeatureDefn->GetGeomFieldCount() != 0)
     536             :         {
     537           0 :             poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
     538             :         }
     539             :     }
     540           0 :     poSRS->Release();
     541             : 
     542           0 :     CPLJSONArray oFields = oResourceJsonObject.GetArray("feature_layer/fields");
     543           0 :     FillFields(oFields);
     544           0 :     FillMetadata(oResourceJsonObject);
     545             : 
     546           0 :     SetDescription(poFeatureDefn->GetName());
     547           0 : }
     548             : 
     549             : /*
     550             :  * OGRNGWLayer()
     551             :  */
     552           0 : OGRNGWLayer::OGRNGWLayer(const std::string &osResourceIdIn,
     553             :                          OGRNGWDataset *poDSIn,
     554             :                          const NGWAPI::Permissions &stPermissionsIn,
     555             :                          OGRFeatureDefn *poFeatureDefnIn,
     556           0 :                          GIntBig nFeatureCountIn, const OGREnvelope &stExtentIn)
     557             :     : osResourceId(osResourceIdIn), poDS(poDSIn),
     558             :       stPermissions(stPermissionsIn), bFetchedPermissions(true),
     559             :       poFeatureDefn(poFeatureDefnIn), nFeatureCount(nFeatureCountIn),
     560           0 :       stExtent(stExtentIn), oNextPos(moFeatures.begin()), nPageStart(0),
     561             :       bNeedSyncData(false), bNeedSyncStructure(false),
     562           0 :       bClientSideAttributeFilter(false)
     563             : {
     564           0 :     poFeatureDefn->Reference();
     565           0 :     SetDescription(poFeatureDefn->GetName());
     566           0 : }
     567             : 
     568             : /*
     569             :  * OGRNGWLayer()
     570             :  */
     571           0 : OGRNGWLayer::OGRNGWLayer(OGRNGWDataset *poDSIn, const std::string &osNameIn,
     572             :                          OGRSpatialReference *poSpatialRef,
     573             :                          OGRwkbGeometryType eGType, const std::string &osKeyIn,
     574           0 :                          const std::string &osDescIn)
     575             :     : osResourceId("-1"), poDS(poDSIn), bFetchedPermissions(false),
     576           0 :       nFeatureCount(0), oNextPos(moFeatures.begin()), nPageStart(0),
     577             :       bNeedSyncData(false), bNeedSyncStructure(false),
     578           0 :       bClientSideAttributeFilter(false)
     579             : {
     580           0 :     poFeatureDefn = new OGRFeatureDefn(osNameIn.c_str());
     581           0 :     poFeatureDefn->Reference();
     582             : 
     583           0 :     poFeatureDefn->SetGeomType(eGType);
     584             : 
     585           0 :     if (poSpatialRef)
     586             :     {
     587           0 :         if (poFeatureDefn->GetGeomFieldCount() != 0)
     588             :         {
     589           0 :             poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSpatialRef);
     590             :         }
     591             :     }
     592             : 
     593           0 :     if (!osDescIn.empty())
     594             :     {
     595           0 :         OGRLayer::SetMetadataItem("description", osDescIn.c_str());
     596             :     }
     597           0 :     if (!osKeyIn.empty())
     598             :     {
     599           0 :         OGRLayer::SetMetadataItem("keyname", osKeyIn.c_str());
     600             :     }
     601             : 
     602           0 :     SetDescription(poFeatureDefn->GetName());
     603           0 : }
     604             : 
     605             : /*
     606             :  * ~OGRNGWLayer()
     607             :  */
     608           0 : OGRNGWLayer::~OGRNGWLayer()
     609             : {
     610           0 :     FreeFeaturesCache(true);
     611           0 :     if (poFeatureDefn != nullptr)
     612             :     {
     613           0 :         poFeatureDefn->Release();
     614             :     }
     615           0 : }
     616             : 
     617             : /*
     618             :  * FreeFeaturesCache()
     619             :  */
     620           0 : void OGRNGWLayer::FreeFeaturesCache(bool bForce)
     621             : {
     622           0 :     if (!soChangedIds.empty())
     623             :     {
     624           0 :         bNeedSyncData = true;
     625             :     }
     626             : 
     627           0 :     if (SyncFeatures() == OGRERR_NONE || bForce)  // Try sync first
     628             :     {
     629             :         // Free only if synced with server successfully or executed from
     630             :         // destructor.
     631           0 :         FreeMap(moFeatures);
     632             :     }
     633           0 : }
     634             : 
     635             : /*
     636             :  * GetResourceId()
     637             :  */
     638           0 : std::string OGRNGWLayer::GetResourceId() const
     639             : {
     640           0 :     return osResourceId;
     641             : }
     642             : 
     643             : /*
     644             :  * Delete()
     645             :  */
     646           0 : bool OGRNGWLayer::Delete()
     647             : {
     648           0 :     if (osResourceId == "-1")
     649             :     {
     650           0 :         return true;
     651             :     }
     652             : 
     653             :     // Headers free in DeleteResource method.
     654           0 :     return NGWAPI::DeleteResource(poDS->GetUrl(), osResourceId,
     655           0 :                                   poDS->GetHeaders());
     656             : }
     657             : 
     658             : /*
     659             :  * Rename()
     660             :  */
     661           0 : OGRErr OGRNGWLayer::Rename(const char *pszNewName)
     662             : {
     663           0 :     bool bResult = true;
     664           0 :     if (osResourceId != "-1")
     665             :     {
     666           0 :         bResult = NGWAPI::RenameResource(poDS->GetUrl(), osResourceId,
     667           0 :                                          pszNewName, poDS->GetHeaders());
     668             :     }
     669           0 :     if (bResult)
     670             :     {
     671           0 :         poFeatureDefn->SetName(pszNewName);
     672           0 :         SetDescription(poFeatureDefn->GetName());
     673             :     }
     674             :     else
     675             :     {
     676           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Rename layer to %s failed",
     677             :                  pszNewName);
     678             :     }
     679           0 :     return bResult ? OGRERR_NONE : OGRERR_FAILURE;
     680             : }
     681             : 
     682             : /*
     683             :  * ResetReading()
     684             :  */
     685           0 : void OGRNGWLayer::ResetReading()
     686             : {
     687           0 :     SyncToDisk();
     688           0 :     if (poDS->GetPageSize() > 0)
     689             :     {
     690           0 :         FreeFeaturesCache();
     691           0 :         nPageStart = 0;
     692             :     }
     693           0 :     oNextPos = moFeatures.begin();
     694           0 : }
     695             : 
     696             : /*
     697             :  * FillFeatures()
     698             :  */
     699           0 : bool OGRNGWLayer::FillFeatures(const std::string &osUrl)
     700             : {
     701           0 :     CPLDebug("NGW", "GetNextFeature: Url: %s", osUrl.c_str());
     702             : 
     703           0 :     CPLErrorReset();
     704           0 :     CPLJSONDocument oFeatureReq;
     705           0 :     char **papszHTTPOptions = poDS->GetHeaders();
     706           0 :     bool bResult = oFeatureReq.LoadUrl(osUrl, papszHTTPOptions);
     707           0 :     CSLDestroy(papszHTTPOptions);
     708             : 
     709           0 :     CPLJSONObject oRoot = oFeatureReq.GetRoot();
     710           0 :     if (!CheckRequestResult(bResult, oRoot, "GetFeatures request failed"))
     711             :     {
     712           0 :         return false;
     713             :     }
     714             : 
     715           0 :     CPLJSONArray aoJSONFeatures = oRoot.ToArray();
     716           0 :     for (int i = 0; i < aoJSONFeatures.Size(); ++i)
     717             :     {
     718           0 :         OGRFeature *poFeature = JSONToFeature(aoJSONFeatures[i], poFeatureDefn,
     719           0 :                                               true, poDS->IsExtInNativeData());
     720           0 :         moFeatures[poFeature->GetFID()] = poFeature;
     721             :     }
     722             : 
     723           0 :     return true;
     724             : }
     725             : 
     726             : /*
     727             :  * SetNextByIndex()
     728             :  */
     729           0 : OGRErr OGRNGWLayer::SetNextByIndex(GIntBig nIndex)
     730             : {
     731           0 :     SyncToDisk();
     732           0 :     if (nIndex < 0)
     733             :     {
     734           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     735             :                  "Feature index must be greater or equal 0. Got " CPL_FRMT_GIB,
     736             :                  nIndex);
     737           0 :         return OGRERR_FAILURE;
     738             :     }
     739           0 :     if (poDS->GetPageSize() > 0)
     740             :     {
     741             :         // Check if index is in current cache
     742           0 :         if (nPageStart > nIndex && nIndex <= nPageStart - poDS->GetPageSize())
     743             :         {
     744           0 :             if (moFeatures.empty() ||
     745           0 :                 static_cast<GIntBig>(moFeatures.size()) <= nIndex)
     746             :             {
     747           0 :                 oNextPos = moFeatures.end();
     748             :             }
     749             :             else
     750             :             {
     751           0 :                 oNextPos = moFeatures.begin();
     752           0 :                 std::advance(oNextPos, static_cast<size_t>(nIndex));
     753             :             }
     754             :         }
     755             :         else
     756             :         {
     757           0 :             ResetReading();
     758           0 :             nPageStart = nIndex;
     759             :         }
     760             :     }
     761             :     else
     762             :     {
     763           0 :         if (moFeatures.empty() && GetMaxFeatureCount(false) > 0)
     764             :         {
     765           0 :             std::string osUrl;
     766           0 :             if (poDS->HasFeaturePaging())
     767             :             {
     768           0 :                 osUrl = NGWAPI::GetFeaturePage(
     769           0 :                     poDS->GetUrl(), osResourceId, 0, 0, osFields, osWhere,
     770           0 :                     osSpatialFilter, poDS->Extensions(),
     771           0 :                     poFeatureDefn->IsGeometryIgnored() == TRUE);
     772             :             }
     773             :             else
     774             :             {
     775           0 :                 osUrl = NGWAPI::GetFeature(poDS->GetUrl(), osResourceId);
     776             :             }
     777             : 
     778           0 :             FillFeatures(osUrl);
     779             :         }
     780             : 
     781           0 :         if (moFeatures.empty() ||
     782           0 :             static_cast<GIntBig>(moFeatures.size()) <= nIndex)
     783             :         {
     784           0 :             oNextPos = moFeatures.end();
     785             :         }
     786             :         else
     787             :         {
     788           0 :             oNextPos = moFeatures.begin();
     789           0 :             std::advance(oNextPos, static_cast<size_t>(nIndex));
     790             :         }
     791             :     }
     792           0 :     return OGRERR_NONE;
     793             : }
     794             : 
     795             : /*
     796             :  * GetNextFeature()
     797             :  */
     798           0 : OGRFeature *OGRNGWLayer::GetNextFeature()
     799             : {
     800           0 :     std::string osUrl;
     801             : 
     802           0 :     if (poDS->GetPageSize() > 0)
     803             :     {
     804           0 :         if (oNextPos == moFeatures.end() &&
     805           0 :             nPageStart < GetMaxFeatureCount(false))
     806             :         {
     807           0 :             FreeFeaturesCache();
     808             : 
     809           0 :             osUrl = NGWAPI::GetFeaturePage(
     810           0 :                 poDS->GetUrl(), osResourceId, nPageStart, poDS->GetPageSize(),
     811           0 :                 osFields, osWhere, osSpatialFilter, poDS->Extensions(),
     812           0 :                 poFeatureDefn->IsGeometryIgnored() == TRUE);
     813           0 :             nPageStart += poDS->GetPageSize();
     814             :         }
     815             :     }
     816           0 :     else if (moFeatures.empty() && GetMaxFeatureCount(false) > 0)
     817             :     {
     818           0 :         if (poDS->HasFeaturePaging())
     819             :         {
     820           0 :             osUrl = NGWAPI::GetFeaturePage(
     821           0 :                 poDS->GetUrl(), osResourceId, 0, 0, osFields, osWhere,
     822           0 :                 osSpatialFilter, poDS->Extensions(),
     823           0 :                 poFeatureDefn->IsGeometryIgnored() == TRUE);
     824             :         }
     825             :         else
     826             :         {
     827           0 :             osUrl = NGWAPI::GetFeature(poDS->GetUrl(), osResourceId);
     828             :         }
     829             :     }
     830             : 
     831           0 :     bool bFinalRead = true;
     832           0 :     if (!osUrl.empty())
     833             :     {
     834           0 :         if (!FillFeatures(osUrl))
     835             :         {
     836           0 :             return nullptr;
     837             :         }
     838             : 
     839           0 :         oNextPos = moFeatures.begin();
     840             : 
     841           0 :         if (poDS->GetPageSize() < 1)
     842             :         {
     843             :             // Without paging we read all features at once.
     844           0 :             m_nFeaturesRead = moFeatures.size();
     845             :         }
     846             :         else
     847             :         {
     848           0 :             if (poDS->GetPageSize() - moFeatures.size() == 0)
     849             :             {
     850           0 :                 m_nFeaturesRead = nPageStart;
     851           0 :                 bFinalRead = false;
     852             :             }
     853             :             else
     854             :             {
     855           0 :                 m_nFeaturesRead =
     856           0 :                     nPageStart - poDS->GetPageSize() + moFeatures.size();
     857             :             }
     858             :         }
     859             :     }
     860             : 
     861           0 :     while (oNextPos != moFeatures.end())
     862             :     {
     863           0 :         OGRFeature *poFeature = oNextPos->second;
     864           0 :         ++oNextPos;
     865             : 
     866           0 :         if (poFeature == nullptr)  // Feature may be deleted.
     867             :         {
     868           0 :             continue;
     869             :         }
     870             : 
     871             :         // Check local filters only for new features which not send to server
     872             :         // yet or if attribute filter process on client side.
     873           0 :         if (poFeature->GetFID() < 0 || bClientSideAttributeFilter)
     874             :         {
     875           0 :             if ((m_poFilterGeom == nullptr ||
     876           0 :                  FilterGeometry(poFeature->GetGeometryRef())) &&
     877           0 :                 (m_poAttrQuery == nullptr ||
     878           0 :                  m_poAttrQuery->Evaluate(poFeature)))
     879             :             {
     880           0 :                 return poFeature->Clone();
     881             :             }
     882             :         }
     883             :         else
     884             :         {
     885           0 :             return poFeature->Clone();
     886             :         }
     887             :     }
     888             : 
     889           0 :     if (poDS->GetPageSize() > 0 && !bFinalRead)
     890             :     {
     891           0 :         return GetNextFeature();
     892             :     }
     893           0 :     return nullptr;
     894             : }
     895             : 
     896             : /*
     897             :  * GetFeature()
     898             :  */
     899           0 : OGRFeature *OGRNGWLayer::GetFeature(GIntBig nFID)
     900             : {
     901             :     // Check feature in cache.
     902           0 :     if (moFeatures[nFID] != nullptr)
     903             :     {
     904           0 :         return moFeatures[nFID]->Clone();
     905             :     }
     906             :     std::string osUrl =
     907           0 :         NGWAPI::GetFeature(poDS->GetUrl(), osResourceId) + std::to_string(nFID);
     908           0 :     CPLErrorReset();
     909           0 :     CPLJSONDocument oFeatureReq;
     910           0 :     char **papszHTTPOptions = poDS->GetHeaders();
     911           0 :     bool bResult = oFeatureReq.LoadUrl(osUrl, papszHTTPOptions);
     912           0 :     CSLDestroy(papszHTTPOptions);
     913             : 
     914           0 :     CPLJSONObject oRoot = oFeatureReq.GetRoot();
     915           0 :     if (!CheckRequestResult(bResult, oRoot,
     916           0 :                             "GetFeature " + std::to_string(nFID) +
     917             :                                 " response is invalid"))
     918             :     {
     919           0 :         return nullptr;
     920             :     }
     921             : 
     922             :     // Don't store feature in cache. This can broke sequence read.
     923           0 :     return JSONToFeature(oRoot, poFeatureDefn, true, poDS->IsExtInNativeData());
     924             : }
     925             : 
     926             : /*
     927             :  * GetLayerDefn()
     928             :  */
     929           0 : OGRFeatureDefn *OGRNGWLayer::GetLayerDefn()
     930             : {
     931           0 :     return poFeatureDefn;
     932             : }
     933             : 
     934             : /*
     935             :  * TestCapability()
     936             :  */
     937           0 : int OGRNGWLayer::TestCapability(const char *pszCap)
     938             : {
     939           0 :     FetchPermissions();
     940           0 :     if (EQUAL(pszCap, OLCRandomRead))
     941           0 :         return TRUE;
     942           0 :     else if (EQUAL(pszCap, OLCSequentialWrite))
     943           0 :         return stPermissions.bDataCanWrite && poDS->IsUpdateMode();
     944           0 :     else if (EQUAL(pszCap, OLCRandomWrite))
     945           0 :         return stPermissions.bDataCanWrite && poDS->IsUpdateMode();
     946           0 :     else if (EQUAL(pszCap, OLCFastFeatureCount))
     947           0 :         return m_poFilterGeom == nullptr && m_poAttrQuery == nullptr;
     948           0 :     else if (EQUAL(pszCap, OLCFastGetExtent))
     949           0 :         return TRUE;
     950           0 :     else if (EQUAL(pszCap, OLCAlterFieldDefn))  // Only field name and alias can
     951             :                                                 // be altered.
     952           0 :         return stPermissions.bDatastructCanWrite && poDS->IsUpdateMode();
     953           0 :     else if (EQUAL(pszCap, OLCDeleteFeature))
     954           0 :         return stPermissions.bDataCanWrite && poDS->IsUpdateMode();
     955           0 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
     956           0 :         return TRUE;
     957           0 :     else if (EQUAL(pszCap, OLCFastSetNextByIndex))
     958           0 :         return TRUE;
     959           0 :     else if (EQUAL(pszCap, OLCCreateField))
     960           0 :         return osResourceId == "-1" &&
     961           0 :                poDS->IsUpdateMode();  // Can create fields only in new layer not
     962             :                                       // synced with server.
     963           0 :     else if (EQUAL(pszCap, OLCIgnoreFields))
     964           0 :         return poDS->HasFeaturePaging();  // Ignore fields, paging support and
     965             :                                           // attribute/spatial filters were
     966             :                                           // introduced in NGW v3.1
     967           0 :     else if (EQUAL(pszCap, OLCFastSpatialFilter))
     968           0 :         return poDS->HasFeaturePaging();
     969           0 :     else if (EQUAL(pszCap, OLCRename))
     970           0 :         return poDS->IsUpdateMode();
     971           0 :     else if (EQUAL(pszCap, OLCZGeometries))
     972           0 :         return TRUE;
     973           0 :     return FALSE;
     974             : }
     975             : 
     976             : /*
     977             :  * FillMetadata()
     978             :  */
     979           0 : void OGRNGWLayer::FillMetadata(const CPLJSONObject &oRootObject)
     980             : {
     981           0 :     std::string osCreateDate = oRootObject.GetString("resource/creation_date");
     982           0 :     if (!osCreateDate.empty())
     983             :     {
     984           0 :         OGRLayer::SetMetadataItem("creation_date", osCreateDate.c_str());
     985             :     }
     986           0 :     std::string osDescription = oRootObject.GetString("resource/description");
     987           0 :     if (!osDescription.empty())
     988             :     {
     989           0 :         OGRLayer::SetMetadataItem("description", osDescription.c_str());
     990             :     }
     991           0 :     std::string osKeyName = oRootObject.GetString("resource/keyname");
     992           0 :     if (!osKeyName.empty())
     993             :     {
     994           0 :         OGRLayer::SetMetadataItem("keyname", osKeyName.c_str());
     995             :     }
     996           0 :     std::string osResourceType = oRootObject.GetString("resource/cls");
     997           0 :     if (!osResourceType.empty())
     998             :     {
     999           0 :         OGRLayer::SetMetadataItem("resource_type", osResourceType.c_str());
    1000             :     }
    1001             :     std::string osResourceParentId =
    1002           0 :         oRootObject.GetString("resource/parent/id");
    1003           0 :     if (!osResourceParentId.empty())
    1004             :     {
    1005           0 :         OGRLayer::SetMetadataItem("parent_id", osResourceParentId.c_str());
    1006             :     }
    1007           0 :     OGRLayer::SetMetadataItem("id", osResourceId.c_str());
    1008             : 
    1009             :     std::vector<CPLJSONObject> items =
    1010           0 :         oRootObject.GetObj("resmeta/items").GetChildren();
    1011             : 
    1012           0 :     for (const CPLJSONObject &item : items)
    1013             :     {
    1014           0 :         std::string osSuffix = NGWAPI::GetResmetaSuffix(item.GetType());
    1015           0 :         OGRLayer::SetMetadataItem((item.GetName() + osSuffix).c_str(),
    1016           0 :                                   item.ToString().c_str(), "NGW");
    1017             :     }
    1018           0 : }
    1019             : 
    1020             : /*
    1021             :  * FillFields()
    1022             :  */
    1023           0 : void OGRNGWLayer::FillFields(const CPLJSONArray &oFields)
    1024             : {
    1025           0 :     for (int i = 0; i < oFields.Size(); ++i)
    1026             :     {
    1027           0 :         CPLJSONObject oField = oFields[i];
    1028           0 :         std::string osFieldName = oField.GetString("keyname");
    1029             :         OGRFieldType eFieldtype =
    1030           0 :             NGWAPI::NGWFieldTypeToOGRFieldType(oField.GetString("datatype"));
    1031           0 :         OGRFieldDefn oFieldDefn(osFieldName.c_str(), eFieldtype);
    1032           0 :         std::string osFieldId = oField.GetString("id");
    1033           0 :         std::string osFieldAlias = oField.GetString("display_name");
    1034           0 :         oFieldDefn.SetAlternativeName(osFieldAlias.c_str());
    1035           0 :         poFeatureDefn->AddFieldDefn(&oFieldDefn);
    1036           0 :         std::string osFieldIsLabel = oField.GetString("label_field");
    1037           0 :         std::string osFieldGridVisible = oField.GetString("grid_visibility");
    1038             : 
    1039           0 :         std::string osFieldAliasName = "FIELD_" + std::to_string(i) + "_ALIAS";
    1040           0 :         std::string osFieldIdName = "FIELD_" + std::to_string(i) + "_ID";
    1041             :         std::string osFieldIsLabelName =
    1042           0 :             "FIELD_" + std::to_string(i) + "_LABEL_FIELD";
    1043             :         std::string osFieldGridVisibleName =
    1044           0 :             "FIELD_" + std::to_string(i) + "_GRID_VISIBILITY";
    1045             : 
    1046           0 :         OGRLayer::SetMetadataItem(osFieldAliasName.c_str(),
    1047             :                                   osFieldAlias.c_str(), "");
    1048           0 :         OGRLayer::SetMetadataItem(osFieldIdName.c_str(), osFieldId.c_str(), "");
    1049           0 :         OGRLayer::SetMetadataItem(osFieldIsLabelName.c_str(),
    1050             :                                   osFieldIsLabel.c_str(), "");
    1051           0 :         OGRLayer::SetMetadataItem(osFieldGridVisibleName.c_str(),
    1052             :                                   osFieldGridVisible.c_str(), "");
    1053             :     }
    1054           0 : }
    1055             : 
    1056             : /*
    1057             :  * GetMaxFeatureCount()
    1058             :  */
    1059           0 : GIntBig OGRNGWLayer::GetMaxFeatureCount(bool bForce)
    1060             : {
    1061           0 :     if (nFeatureCount < 0 || bForce)
    1062             :     {
    1063           0 :         CPLErrorReset();
    1064           0 :         CPLJSONDocument oCountReq;
    1065           0 :         char **papszHTTPOptions = poDS->GetHeaders();
    1066           0 :         bool bResult = oCountReq.LoadUrl(
    1067           0 :             NGWAPI::GetFeatureCount(poDS->GetUrl(), osResourceId),
    1068             :             papszHTTPOptions);
    1069           0 :         CSLDestroy(papszHTTPOptions);
    1070           0 :         if (bResult)
    1071             :         {
    1072           0 :             CPLJSONObject oRoot = oCountReq.GetRoot();
    1073           0 :             if (oRoot.IsValid())
    1074             :             {
    1075           0 :                 nFeatureCount = oRoot.GetLong("total_count");
    1076           0 :                 nFeatureCount += GetNewFeaturesCount();
    1077             :             }
    1078             :         }
    1079             :     }
    1080           0 :     return nFeatureCount;
    1081             : }
    1082             : 
    1083             : /*
    1084             :  * GetFeatureCount()
    1085             :  */
    1086           0 : GIntBig OGRNGWLayer::GetFeatureCount(int bForce)
    1087             : {
    1088           0 :     if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
    1089             :     {
    1090           0 :         return GetMaxFeatureCount(CPL_TO_BOOL(bForce));
    1091             :     }
    1092             :     else
    1093             :     {
    1094           0 :         return OGRLayer::GetFeatureCount(bForce);
    1095             :     }
    1096             : }
    1097             : 
    1098             : /*
    1099             :  * GetExtent()
    1100             :  */
    1101           0 : OGRErr OGRNGWLayer::GetExtent(OGREnvelope *psExtent, int bForce)
    1102             : {
    1103           0 :     if (!stExtent.IsInit() || CPL_TO_BOOL(bForce))
    1104             :     {
    1105           0 :         char **papszHTTPOptions = poDS->GetHeaders();
    1106           0 :         bool bResult = NGWAPI::GetExtent(poDS->GetUrl(), osResourceId,
    1107           0 :                                          papszHTTPOptions, 3857, stExtent);
    1108           0 :         CSLDestroy(papszHTTPOptions);
    1109           0 :         if (!bResult)
    1110             :         {
    1111           0 :             return OGRERR_FAILURE;
    1112             :         }
    1113             :     }
    1114           0 :     *psExtent = stExtent;
    1115           0 :     return OGRERR_NONE;
    1116             : }
    1117             : 
    1118             : /*
    1119             :  * GetExtent()
    1120             :  */
    1121           0 : OGRErr OGRNGWLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
    1122             : {
    1123           0 :     return OGRLayer::GetExtent(iGeomField, psExtent, bForce);
    1124             : }
    1125             : 
    1126             : /*
    1127             :  * FetchPermissions()
    1128             :  */
    1129           0 : void OGRNGWLayer::FetchPermissions()
    1130             : {
    1131           0 :     if (bFetchedPermissions || osResourceId == "-1")
    1132             :     {
    1133           0 :         return;
    1134             :     }
    1135             : 
    1136           0 :     if (poDS->IsUpdateMode())
    1137             :     {
    1138           0 :         char **papszHTTPOptions = poDS->GetHeaders();
    1139             :         stPermissions =
    1140           0 :             NGWAPI::CheckPermissions(poDS->GetUrl(), osResourceId,
    1141           0 :                                      papszHTTPOptions, poDS->IsUpdateMode());
    1142           0 :         CSLDestroy(papszHTTPOptions);
    1143             :     }
    1144             :     else
    1145             :     {
    1146           0 :         stPermissions.bDataCanRead = true;
    1147           0 :         stPermissions.bResourceCanRead = true;
    1148           0 :         stPermissions.bDatastructCanRead = true;
    1149           0 :         stPermissions.bMetadataCanRead = true;
    1150             :     }
    1151           0 :     bFetchedPermissions = true;
    1152             : }
    1153             : 
    1154             : /*
    1155             :  * CreateField()
    1156             :  */
    1157           0 : OGRErr OGRNGWLayer::CreateField(const OGRFieldDefn *poField,
    1158             :                                 CPL_UNUSED int bApproxOK)
    1159             : {
    1160           0 :     CPLAssert(nullptr != poField);
    1161             : 
    1162           0 :     if (osResourceId ==
    1163             :         "-1")  // Can create field only on new layers (not synced with server).
    1164             :     {
    1165           0 :         if (!CheckFieldNameUnique(poFeatureDefn, -1, poField->GetNameRef()))
    1166             :         {
    1167           0 :             return OGRERR_FAILURE;
    1168             :         }
    1169             :         // Field name 'id' is forbidden.
    1170           0 :         OGRFieldDefn oModFieldDefn(poField);
    1171           0 :         NormalizeFieldName(poFeatureDefn, -1, &oModFieldDefn);
    1172           0 :         poFeatureDefn->AddFieldDefn(&oModFieldDefn);
    1173           0 :         return OGRERR_NONE;
    1174             :     }
    1175           0 :     return OGRLayer::CreateField(poField, bApproxOK);
    1176             : }
    1177             : 
    1178             : /*
    1179             :  * DeleteField()
    1180             :  */
    1181           0 : OGRErr OGRNGWLayer::DeleteField(int iField)
    1182             : {
    1183           0 :     if (osResourceId ==
    1184             :         "-1")  // Can delete field only on new layers (not synced with server).
    1185             :     {
    1186           0 :         return poFeatureDefn->DeleteFieldDefn(iField);
    1187             :     }
    1188           0 :     return OGRLayer::DeleteField(iField);
    1189             : }
    1190             : 
    1191             : /*
    1192             :  * ReorderFields()
    1193             :  */
    1194           0 : OGRErr OGRNGWLayer::ReorderFields(int *panMap)
    1195             : {
    1196           0 :     if (osResourceId == "-1")  // Can reorder fields only on new layers (not
    1197             :                                // synced with server).
    1198             :     {
    1199           0 :         return poFeatureDefn->ReorderFieldDefns(panMap);
    1200             :     }
    1201           0 :     return OGRLayer::ReorderFields(panMap);
    1202             : }
    1203             : 
    1204             : /*
    1205             :  * AlterFieldDefn()
    1206             :  */
    1207           0 : OGRErr OGRNGWLayer::AlterFieldDefn(int iField, OGRFieldDefn *poNewFieldDefn,
    1208             :                                    int nFlagsIn)
    1209             : {
    1210           0 :     CPLAssert(nullptr != poNewFieldDefn);
    1211             : 
    1212           0 :     OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
    1213           0 :     if (poFieldDefn)
    1214             :     {
    1215             :         // Check new field name is not equal for another fields.
    1216           0 :         if (!CheckFieldNameUnique(poFeatureDefn, iField,
    1217             :                                   poNewFieldDefn->GetNameRef()))
    1218             :         {
    1219           0 :             return OGRERR_FAILURE;
    1220             :         }
    1221           0 :         if (osResourceId == "-1")  // Can alter field only on new layers (not
    1222             :                                    // synced with server).
    1223             :         {
    1224             :             // Field name 'id' forbidden.
    1225           0 :             OGRFieldDefn oModFieldDefn(poNewFieldDefn);
    1226           0 :             NormalizeFieldName(poFeatureDefn, iField, &oModFieldDefn);
    1227             : 
    1228           0 :             poFieldDefn->SetName(oModFieldDefn.GetNameRef());
    1229           0 :             poFieldDefn->SetType(oModFieldDefn.GetType());
    1230           0 :             poFieldDefn->SetSubType(oModFieldDefn.GetSubType());
    1231           0 :             poFieldDefn->SetWidth(oModFieldDefn.GetWidth());
    1232           0 :             poFieldDefn->SetPrecision(oModFieldDefn.GetPrecision());
    1233             :         }
    1234           0 :         else if (nFlagsIn &
    1235             :                  ALTER_NAME_FLAG)  // Can only rename field, not change it type.
    1236             :         {
    1237             :             // Field name 'id' forbidden.
    1238           0 :             OGRFieldDefn oModFieldDefn(poNewFieldDefn);
    1239           0 :             NormalizeFieldName(poFeatureDefn, iField, &oModFieldDefn);
    1240             : 
    1241           0 :             bNeedSyncStructure = true;
    1242           0 :             poFieldDefn->SetName(oModFieldDefn.GetNameRef());
    1243             :         }
    1244             :     }
    1245           0 :     return OGRLayer::AlterFieldDefn(iField, poNewFieldDefn, nFlagsIn);
    1246             : }
    1247             : 
    1248             : /*
    1249             :  * SetMetadata()
    1250             :  */
    1251           0 : CPLErr OGRNGWLayer::SetMetadata(char **papszMetadata, const char *pszDomain)
    1252             : {
    1253           0 :     bNeedSyncStructure = true;
    1254           0 :     return OGRLayer::SetMetadata(papszMetadata, pszDomain);
    1255             : }
    1256             : 
    1257             : /*
    1258             :  * SetMetadataItem()
    1259             :  */
    1260           0 : CPLErr OGRNGWLayer::SetMetadataItem(const char *pszName, const char *pszValue,
    1261             :                                     const char *pszDomain)
    1262             : {
    1263           0 :     bNeedSyncStructure = true;
    1264           0 :     return OGRLayer::SetMetadataItem(pszName, pszValue, pszDomain);
    1265             : }
    1266             : 
    1267             : /*
    1268             :  * CreateNGWResourceJson()
    1269             :  */
    1270           0 : std::string OGRNGWLayer::CreateNGWResourceJson()
    1271             : {
    1272           0 :     CPLJSONObject oResourceJson;
    1273             : 
    1274             :     // Add resource json item.
    1275           0 :     CPLJSONObject oResource("resource", oResourceJson);
    1276           0 :     oResource.Add("cls", "vector_layer");
    1277           0 :     CPLJSONObject oResourceParent("parent", oResource);
    1278           0 :     oResourceParent.Add("id",
    1279           0 :                         static_cast<GIntBig>(std::stol(poDS->GetResourceId())));
    1280           0 :     oResource.Add("display_name", GetName());
    1281           0 :     const char *pszKeyName = GetMetadataItem("keyname");
    1282           0 :     if (pszKeyName)
    1283             :     {
    1284           0 :         oResource.Add("keyname", pszKeyName);
    1285             :     }
    1286           0 :     const char *pszDescription = GetMetadataItem("description");
    1287           0 :     if (pszDescription)
    1288             :     {
    1289           0 :         oResource.Add("description", pszDescription);
    1290             :     }
    1291             : 
    1292             :     // Add vector_layer json item.
    1293           0 :     CPLJSONObject oVectorLayer("vector_layer", oResourceJson);
    1294           0 :     CPLJSONObject oVectorLayerSrs("srs", oVectorLayer);
    1295             : 
    1296           0 :     OGRSpatialReference *poSpatialRef = GetSpatialRef();
    1297           0 :     int nEPSG = 3857;
    1298           0 :     if (poSpatialRef)
    1299             :     {
    1300           0 :         poSpatialRef->AutoIdentifyEPSG();
    1301           0 :         const char *pszEPSG = poSpatialRef->GetAuthorityCode(nullptr);
    1302           0 :         if (pszEPSG != nullptr)
    1303             :         {
    1304           0 :             nEPSG = atoi(pszEPSG);
    1305             :         }
    1306             :     }
    1307           0 :     oVectorLayerSrs.Add("id", nEPSG);
    1308             :     // In OGRNGWDataset::ICreateLayer we limit supported geometry types.
    1309           0 :     oVectorLayer.Add("geometry_type",
    1310           0 :                      NGWAPI::OGRGeomTypeToNGWGeomType(GetGeomType()));
    1311           0 :     CPLJSONArray oVectorLayerFields;
    1312           0 :     for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); ++iField)
    1313             :     {
    1314           0 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
    1315             : 
    1316           0 :         CPLJSONObject oField;
    1317           0 :         oField.Add("keyname", poFieldDefn->GetNameRef());
    1318           0 :         oField.Add("datatype",
    1319           0 :                    NGWAPI::OGRFieldTypeToNGWFieldType(poFieldDefn->GetType()));
    1320           0 :         std::string osFieldAliasName = poFieldDefn->GetAlternativeNameRef();
    1321             :         // Get alias from metadata.
    1322           0 :         if (osFieldAliasName.empty())
    1323             :         {
    1324           0 :             osFieldAliasName = "FIELD_" + std::to_string(iField) + "_ALIAS";
    1325             :             const char *pszFieldAlias =
    1326           0 :                 GetMetadataItem(osFieldAliasName.c_str());
    1327           0 :             if (pszFieldAlias)
    1328             :             {
    1329           0 :                 oField.Add("display_name", pszFieldAlias);
    1330             :             }
    1331             :         }
    1332             :         else
    1333             :         {
    1334           0 :             oField.Add("display_name", osFieldAliasName);
    1335             :         }
    1336           0 :         oVectorLayerFields.Add(oField);
    1337             :     }
    1338           0 :     oVectorLayer.Add("fields", oVectorLayerFields);
    1339             : 
    1340             :     // Add resmeta json item.
    1341           0 :     NGWAPI::FillResmeta(oResourceJson, GetMetadata("NGW"));
    1342             : 
    1343           0 :     return oResourceJson.Format(CPLJSONObject::PrettyFormat::Plain);
    1344             : }
    1345             : 
    1346             : /*
    1347             :  * SyncFeatures()
    1348             :  */
    1349           0 : OGRErr OGRNGWLayer::SyncFeatures()
    1350             : {
    1351           0 :     if (!bNeedSyncData)
    1352             :     {
    1353           0 :         return OGRERR_NONE;
    1354             :     }
    1355             : 
    1356           0 :     CPLJSONArray oFeatureJsonArray;
    1357           0 :     std::vector<GIntBig> aoPatchedFIDs;
    1358           0 :     for (GIntBig nFID : soChangedIds)
    1359             :     {
    1360           0 :         if (moFeatures[nFID] != nullptr)
    1361             :         {
    1362           0 :             oFeatureJsonArray.Add(FeatureToJson(moFeatures[nFID]));
    1363           0 :             aoPatchedFIDs.push_back(nFID);
    1364             :         }
    1365             :     }
    1366             : 
    1367           0 :     if (!aoPatchedFIDs.empty())
    1368             :     {
    1369             :         auto osIDs = NGWAPI::PatchFeatures(
    1370           0 :             poDS->GetUrl(), osResourceId,
    1371           0 :             oFeatureJsonArray.Format(CPLJSONObject::PrettyFormat::Plain),
    1372           0 :             poDS->GetHeaders());
    1373           0 :         if (!osIDs.empty())
    1374             :         {
    1375           0 :             bNeedSyncData = false;
    1376           0 :             nFeatureCount += GetNewFeaturesCount();
    1377           0 :             soChangedIds.clear();
    1378           0 :             if (osIDs.size() !=
    1379           0 :                 aoPatchedFIDs.size())  // Expected equal identifier count.
    1380             :             {
    1381           0 :                 CPLDebug("ngw", "Patched feature count is not equal. Reload "
    1382             :                                 "features from server.");
    1383           0 :                 FreeMap(moFeatures);
    1384             :             }
    1385             :             else  // Just update identifiers.
    1386             :             {
    1387           0 :                 int nCounter = 0;
    1388           0 :                 for (GIntBig nFID : aoPatchedFIDs)
    1389             :                 {
    1390           0 :                     GIntBig nNewFID = osIDs[nCounter++];
    1391           0 :                     OGRFeature *poFeature = moFeatures[nFID];
    1392           0 :                     poFeature->SetFID(nNewFID);
    1393           0 :                     moFeatures.erase(nFID);
    1394           0 :                     moFeatures[nNewFID] = poFeature;
    1395             :                 }
    1396             :             }
    1397             :         }
    1398             :         else
    1399             :         {
    1400             :             // Error message should set in NGWAPI::PatchFeatures function.
    1401           0 :             if (CPLGetLastErrorNo() != 0)
    1402             :             {
    1403           0 :                 return OGRERR_FAILURE;
    1404             :             }
    1405             :         }
    1406             :     }
    1407           0 :     return OGRERR_NONE;
    1408             : }
    1409             : 
    1410             : /*
    1411             :  * SyncToDisk()
    1412             :  */
    1413           0 : OGRErr OGRNGWLayer::SyncToDisk()
    1414             : {
    1415           0 :     if (osResourceId == "-1")  // Create vector layer at NextGIS Web.
    1416             :     {
    1417           0 :         bNeedSyncData = !moFeatures.empty();
    1418             :         std::string osResourceIdInt = NGWAPI::CreateResource(
    1419           0 :             poDS->GetUrl(), CreateNGWResourceJson(), poDS->GetHeaders());
    1420           0 :         if (osResourceIdInt == "-1")
    1421             :         {
    1422             :             // Error message should set in CreateResource.
    1423           0 :             return OGRERR_FAILURE;
    1424             :         }
    1425           0 :         osResourceId = std::move(osResourceIdInt);
    1426           0 :         OGRLayer::SetMetadataItem("id", osResourceId.c_str());
    1427           0 :         FetchPermissions();
    1428           0 :         bNeedSyncStructure = false;
    1429             :     }
    1430           0 :     else if (bNeedSyncStructure)  // Update vector layer at NextGIS Web.
    1431             :     {
    1432           0 :         if (!NGWAPI::UpdateResource(poDS->GetUrl(), GetResourceId(),
    1433           0 :                                     CreateNGWResourceJson(),
    1434           0 :                                     poDS->GetHeaders()))
    1435             :         {
    1436             :             // Error message should set in UpdateResource.
    1437           0 :             return OGRERR_FAILURE;
    1438             :         }
    1439           0 :         bNeedSyncStructure = false;
    1440             :     }
    1441             : 
    1442             :     // Sync features.
    1443           0 :     return SyncFeatures();
    1444             : }
    1445             : 
    1446             : /*
    1447             :  * DeleteFeature()
    1448             :  */
    1449           0 : OGRErr OGRNGWLayer::DeleteFeature(GIntBig nFID)
    1450             : {
    1451           0 :     CPLErrorReset();
    1452           0 :     if (nFID < 0)
    1453             :     {
    1454           0 :         if (moFeatures[nFID] != nullptr)
    1455             :         {
    1456           0 :             OGRFeature::DestroyFeature(moFeatures[nFID]);
    1457           0 :             moFeatures[nFID] = nullptr;
    1458           0 :             nFeatureCount--;
    1459           0 :             soChangedIds.erase(nFID);
    1460           0 :             return OGRERR_NONE;
    1461             :         }
    1462           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1463             :                  "Feature with id " CPL_FRMT_GIB " not found.", nFID);
    1464           0 :         return OGRERR_FAILURE;
    1465             :     }
    1466             :     else
    1467             :     {
    1468           0 :         FetchPermissions();
    1469           0 :         if (stPermissions.bDataCanWrite && poDS->IsUpdateMode())
    1470             :         {
    1471             :             bool bResult =
    1472           0 :                 NGWAPI::DeleteFeature(poDS->GetUrl(), osResourceId,
    1473           0 :                                       std::to_string(nFID), poDS->GetHeaders());
    1474           0 :             if (bResult)
    1475             :             {
    1476           0 :                 if (moFeatures[nFID] != nullptr)
    1477             :                 {
    1478           0 :                     OGRFeature::DestroyFeature(moFeatures[nFID]);
    1479           0 :                     moFeatures[nFID] = nullptr;
    1480             :                 }
    1481           0 :                 nFeatureCount--;
    1482           0 :                 soChangedIds.erase(nFID);
    1483           0 :                 return OGRERR_NONE;
    1484             :             }
    1485           0 :             return OGRERR_FAILURE;
    1486             :         }
    1487           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1488             :                  "Delete feature " CPL_FRMT_GIB " operation is not permitted.",
    1489             :                  nFID);
    1490           0 :         return OGRERR_FAILURE;
    1491             :     }
    1492             : }
    1493             : 
    1494             : /*
    1495             :  * DeleteAllFeatures()
    1496             :  */
    1497           0 : bool OGRNGWLayer::DeleteAllFeatures()
    1498             : {
    1499           0 :     if (osResourceId == "-1")
    1500             :     {
    1501           0 :         soChangedIds.clear();
    1502           0 :         bNeedSyncData = false;
    1503           0 :         FreeFeaturesCache();
    1504           0 :         nFeatureCount = 0;
    1505           0 :         return true;
    1506             :     }
    1507             :     else
    1508             :     {
    1509           0 :         FetchPermissions();
    1510           0 :         if (stPermissions.bDataCanWrite && poDS->IsUpdateMode())
    1511             :         {
    1512           0 :             bool bResult = NGWAPI::DeleteFeature(poDS->GetUrl(), osResourceId,
    1513           0 :                                                  "", poDS->GetHeaders());
    1514           0 :             if (bResult)
    1515             :             {
    1516           0 :                 soChangedIds.clear();
    1517           0 :                 bNeedSyncData = false;
    1518           0 :                 FreeFeaturesCache();
    1519           0 :                 nFeatureCount = 0;
    1520             :             }
    1521           0 :             return bResult;
    1522             :         }
    1523             :     }
    1524           0 :     CPLErrorReset();
    1525           0 :     CPLError(CE_Failure, CPLE_AppDefined,
    1526             :              "Delete all features operation is not permitted.");
    1527           0 :     return false;
    1528             : }
    1529             : 
    1530             : /*
    1531             :  * ISetFeature()
    1532             :  */
    1533           0 : OGRErr OGRNGWLayer::ISetFeature(OGRFeature *poFeature)
    1534             : {
    1535           0 :     if (poDS->IsBatchMode())
    1536             :     {
    1537           0 :         if (moFeatures[poFeature->GetFID()] == nullptr)
    1538             :         {
    1539           0 :             if (poFeature->GetFID() < 0)
    1540             :             {
    1541           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1542             :                          "Cannot update not existing feature " CPL_FRMT_GIB,
    1543             :                          poFeature->GetFID());
    1544           0 :                 return OGRERR_FAILURE;
    1545             :             }
    1546             :         }
    1547             :         else
    1548             :         {
    1549           0 :             OGRFeature::DestroyFeature(moFeatures[poFeature->GetFID()]);
    1550             :         }
    1551           0 :         moFeatures[poFeature->GetFID()] = poFeature->Clone();
    1552           0 :         soChangedIds.insert(poFeature->GetFID());
    1553             : 
    1554           0 :         if (soChangedIds.size() > static_cast<size_t>(poDS->GetBatchSize()))
    1555             :         {
    1556           0 :             bNeedSyncData = true;
    1557             :         }
    1558             : 
    1559           0 :         return SyncToDisk();
    1560             :     }
    1561             :     else
    1562             :     {
    1563             :         OGRErr eResult =
    1564           0 :             SyncToDisk();  // For create new layer if not yet created.
    1565           0 :         if (eResult == OGRERR_NONE)
    1566             :         {
    1567           0 :             if (poFeature->GetFID() < 0)
    1568             :             {
    1569           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1570             :                          "Cannot update not existing feature " CPL_FRMT_GIB,
    1571             :                          poFeature->GetFID());
    1572           0 :                 return OGRERR_FAILURE;
    1573             :             }
    1574             : 
    1575           0 :             bool bResult = NGWAPI::UpdateFeature(
    1576           0 :                 poDS->GetUrl(), osResourceId,
    1577           0 :                 std::to_string(poFeature->GetFID()),
    1578           0 :                 FeatureToJsonString(poFeature), poDS->GetHeaders());
    1579           0 :             if (bResult)
    1580             :             {
    1581           0 :                 CPLDebug("NGW", "ISetFeature with FID " CPL_FRMT_GIB,
    1582             :                          poFeature->GetFID());
    1583             : 
    1584           0 :                 OGRFeature::DestroyFeature(moFeatures[poFeature->GetFID()]);
    1585           0 :                 moFeatures[poFeature->GetFID()] = poFeature->Clone();
    1586           0 :                 return OGRERR_NONE;
    1587             :             }
    1588             :             else
    1589             :             {
    1590             :                 // CPLError should be set in NGWAPI::UpdateFeature.
    1591           0 :                 return OGRERR_FAILURE;
    1592             :             }
    1593             :         }
    1594             :         else
    1595             :         {
    1596           0 :             return eResult;
    1597             :         }
    1598             :     }
    1599             : }
    1600             : 
    1601             : /*
    1602             :  * ICreateFeature()
    1603             :  */
    1604           0 : OGRErr OGRNGWLayer::ICreateFeature(OGRFeature *poFeature)
    1605             : {
    1606           0 :     if (poDS->IsBatchMode())
    1607             :     {
    1608           0 :         GIntBig nNewFID = -1;
    1609           0 :         if (!soChangedIds.empty())
    1610             :         {
    1611           0 :             nNewFID = *(soChangedIds.begin()) - 1;
    1612             :         }
    1613           0 :         poFeature->SetFID(nNewFID);
    1614           0 :         moFeatures[nNewFID] = poFeature->Clone();
    1615           0 :         soChangedIds.insert(nNewFID);
    1616           0 :         nFeatureCount++;
    1617             : 
    1618           0 :         if (soChangedIds.size() > static_cast<size_t>(poDS->GetBatchSize()))
    1619             :         {
    1620           0 :             bNeedSyncData = true;
    1621             :         }
    1622             : 
    1623           0 :         return SyncToDisk();
    1624             :     }
    1625             :     else
    1626             :     {
    1627             :         OGRErr eResult =
    1628           0 :             SyncToDisk();  // For create new layer if not yet created.
    1629           0 :         if (eResult == OGRERR_NONE)
    1630             :         {
    1631           0 :             GIntBig nNewFID = NGWAPI::CreateFeature(
    1632           0 :                 poDS->GetUrl(), osResourceId, FeatureToJsonString(poFeature),
    1633           0 :                 poDS->GetHeaders());
    1634           0 :             if (nNewFID >= 0)
    1635             :             {
    1636           0 :                 poFeature->SetFID(nNewFID);
    1637           0 :                 moFeatures[nNewFID] = poFeature->Clone();
    1638           0 :                 nFeatureCount++;
    1639           0 :                 return OGRERR_NONE;
    1640             :             }
    1641             :             else
    1642             :             {
    1643             :                 // CPLError should be set in NGWAPI::CreateFeature.
    1644           0 :                 return OGRERR_FAILURE;
    1645             :             }
    1646             :         }
    1647             :         else
    1648             :         {
    1649           0 :             return eResult;
    1650             :         }
    1651             :     }
    1652             : }
    1653             : 
    1654             : /*
    1655             :  * SetIgnoredFields()
    1656             :  */
    1657           0 : OGRErr OGRNGWLayer::SetIgnoredFields(CSLConstList papszFields)
    1658             : {
    1659           0 :     OGRErr eResult = OGRLayer::SetIgnoredFields(papszFields);
    1660           0 :     if (eResult != OGRERR_NONE)
    1661             :     {
    1662           0 :         return eResult;
    1663             :     }
    1664             : 
    1665           0 :     if (nullptr == papszFields)
    1666             :     {
    1667           0 :         osFields.clear();
    1668             :     }
    1669             :     else
    1670             :     {
    1671           0 :         for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); ++iField)
    1672             :         {
    1673           0 :             OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
    1674           0 :             if (poFieldDefn->IsIgnored())
    1675             :             {
    1676           0 :                 continue;
    1677             :             }
    1678             : 
    1679           0 :             if (osFields.empty())
    1680             :             {
    1681           0 :                 osFields = poFieldDefn->GetNameRef();
    1682             :             }
    1683             :             else
    1684             :             {
    1685           0 :                 osFields += "," + std::string(poFieldDefn->GetNameRef());
    1686             :             }
    1687             :         }
    1688             : 
    1689           0 :         if (!osFields.empty())
    1690             :         {
    1691           0 :             char *pszValuesEncoded = CPLEscapeString(
    1692           0 :                 osFields.c_str(), static_cast<int>(osFields.size()), CPLES_URL);
    1693           0 :             osFields = pszValuesEncoded;
    1694           0 :             CPLFree(pszValuesEncoded);
    1695             :         }
    1696             :     }
    1697             : 
    1698           0 :     if (poDS->GetPageSize() < 1)
    1699             :     {
    1700           0 :         FreeFeaturesCache();
    1701             :     }
    1702           0 :     ResetReading();
    1703           0 :     return OGRERR_NONE;
    1704             : }
    1705             : 
    1706             : /*
    1707             :  * SetSpatialFilter()
    1708             :  */
    1709           0 : void OGRNGWLayer::SetSpatialFilter(OGRGeometry *poGeom)
    1710             : {
    1711           0 :     OGRLayer::SetSpatialFilter(poGeom);
    1712             : 
    1713           0 :     if (nullptr == m_poFilterGeom)
    1714             :     {
    1715           0 :         CPLDebug("NGW", "Spatial filter unset");
    1716           0 :         osSpatialFilter.clear();
    1717             :     }
    1718             :     else
    1719             :     {
    1720           0 :         OGREnvelope sEnvelope;
    1721           0 :         m_poFilterGeom->getEnvelope(&sEnvelope);
    1722             : 
    1723           0 :         OGREnvelope sBigEnvelope;
    1724           0 :         sBigEnvelope.MinX = -40000000.0;
    1725           0 :         sBigEnvelope.MinY = -40000000.0;
    1726           0 :         sBigEnvelope.MaxX = 40000000.0;
    1727           0 :         sBigEnvelope.MaxY = 40000000.0;
    1728             : 
    1729             :         // Case for infinity filter
    1730           0 :         if (sEnvelope.Contains(sBigEnvelope) == TRUE)
    1731             :         {
    1732           0 :             CPLDebug("NGW", "Spatial filter unset as filter envelope covers "
    1733             :                             "whole features.");
    1734           0 :             osSpatialFilter.clear();
    1735             :         }
    1736             :         else
    1737             :         {
    1738           0 :             if (sEnvelope.MinX == sEnvelope.MaxX &&
    1739           0 :                 sEnvelope.MinY == sEnvelope.MaxY)
    1740             :             {
    1741           0 :                 OGRPoint p(sEnvelope.MinX, sEnvelope.MinY);
    1742           0 :                 InstallFilter(&p);
    1743             :             }
    1744             : 
    1745           0 :             osSpatialFilter = OGRGeometryToWKT(m_poFilterGeom);
    1746           0 :             CPLDebug("NGW", "Spatial filter: %s", osSpatialFilter.c_str());
    1747           0 :             char *pszSpatFilterEncoded = CPLEscapeString(
    1748             :                 osSpatialFilter.c_str(),
    1749           0 :                 static_cast<int>(osSpatialFilter.size()), CPLES_URL);
    1750           0 :             osSpatialFilter = pszSpatFilterEncoded;
    1751           0 :             CPLFree(pszSpatFilterEncoded);
    1752             :         }
    1753             :     }
    1754             : 
    1755           0 :     if (poDS->GetPageSize() < 1)
    1756             :     {
    1757           0 :         FreeFeaturesCache();
    1758             :     }
    1759           0 :     ResetReading();
    1760           0 : }
    1761             : 
    1762             : /*
    1763             :  * SetSpatialFilter()
    1764             :  */
    1765           0 : void OGRNGWLayer::SetSpatialFilter(int iGeomField, OGRGeometry *poGeom)
    1766             : {
    1767           0 :     OGRLayer::SetSpatialFilter(iGeomField, poGeom);
    1768           0 : }
    1769             : 
    1770             : /*
    1771             :  * SetAttributeFilter()
    1772             :  */
    1773           0 : OGRErr OGRNGWLayer::SetAttributeFilter(const char *pszQuery)
    1774             : {
    1775           0 :     OGRErr eResult = OGRERR_NONE;
    1776           0 :     if (nullptr == pszQuery)
    1777             :     {
    1778           0 :         eResult = OGRLayer::SetAttributeFilter(pszQuery);
    1779           0 :         osWhere.clear();
    1780           0 :         bClientSideAttributeFilter = false;
    1781             :     }
    1782           0 :     else if (STARTS_WITH_CI(pszQuery,
    1783             :                             "NGW:"))  // Already formatted for NGW REST API
    1784             :     {
    1785           0 :         osWhere = pszQuery + strlen("NGW:");
    1786           0 :         bClientSideAttributeFilter = false;
    1787             :     }
    1788             :     else
    1789             :     {
    1790           0 :         eResult = OGRLayer::SetAttributeFilter(pszQuery);
    1791           0 :         if (eResult == OGRERR_NONE && m_poAttrQuery != nullptr)
    1792             :         {
    1793             :             swq_expr_node *poNode =
    1794           0 :                 reinterpret_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
    1795           0 :             osWhere = TranslateSQLToFilter(poNode);
    1796           0 :             if (osWhere.empty())
    1797             :             {
    1798           0 :                 bClientSideAttributeFilter = true;
    1799           0 :                 CPLDebug(
    1800             :                     "NGW",
    1801             :                     "Attribute filter '%s' will be evaluated on client side.",
    1802             :                     pszQuery);
    1803             :             }
    1804             :             else
    1805             :             {
    1806           0 :                 bClientSideAttributeFilter = false;
    1807           0 :                 CPLDebug("NGW", "Attribute filter: %s", osWhere.c_str());
    1808             :             }
    1809             :         }
    1810             :     }
    1811             : 
    1812           0 :     if (poDS->GetPageSize() < 1)
    1813             :     {
    1814           0 :         FreeFeaturesCache();
    1815             :     }
    1816           0 :     ResetReading();
    1817           0 :     return eResult;
    1818             : }
    1819             : 
    1820             : /*
    1821             :  * SetSelectedFields()
    1822             :  */
    1823           0 : OGRErr OGRNGWLayer::SetSelectedFields(const std::set<std::string> &aosFields)
    1824             : {
    1825           0 :     CPLStringList aosIgnoreFields;
    1826           0 :     for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); ++iField)
    1827             :     {
    1828           0 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
    1829           0 :         if (aosFields.find(poFieldDefn->GetNameRef()) != aosFields.end())
    1830             :         {
    1831           0 :             continue;
    1832             :         }
    1833           0 :         aosIgnoreFields.AddString(poFieldDefn->GetNameRef());
    1834             :     }
    1835           0 :     return SetIgnoredFields(aosIgnoreFields.List());
    1836             : }
    1837             : 
    1838             : /*
    1839             :  * Clone()
    1840             :  */
    1841           0 : OGRNGWLayer *OGRNGWLayer::Clone() const
    1842             : {
    1843           0 :     return new OGRNGWLayer(osResourceId, poDS, stPermissions,
    1844           0 :                            poFeatureDefn->Clone(), nFeatureCount, stExtent);
    1845             : }
    1846             : 
    1847             : /*
    1848             :  * GetNewFeaturesCount()
    1849             :  */
    1850           0 : GIntBig OGRNGWLayer::GetNewFeaturesCount() const
    1851             : {
    1852           0 :     if (soChangedIds.empty())
    1853             :     {
    1854           0 :         return 0;
    1855             :     }
    1856             : 
    1857           0 :     if (*soChangedIds.begin() >= 0)
    1858             :     {
    1859           0 :         return 0;
    1860             :     }
    1861             : 
    1862             :     // The lowest negative identifier equal new feature count
    1863           0 :     return *soChangedIds.begin() * -1;
    1864             : }

Generated by: LCOV version 1.14