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