Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: PlanetLabs scene driver
4 : * Purpose: Implements OGRPLScenesDataV1Layer
5 : * Author: Even Rouault, even dot rouault at spatialys.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2017, Planet Labs
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "ogr_plscenes.h"
14 : #include "ogrlibjsonutils.h"
15 : #include "ogrgeojsongeometry.h"
16 : #include "ogrgeojsonwriter.h"
17 : #include <algorithm>
18 :
19 : #ifdef EMBED_RESOURCE_FILES
20 : #include "embedded_resources.h"
21 : #endif
22 :
23 : /************************************************************************/
24 : /* GetFieldCount() */
25 : /************************************************************************/
26 :
27 2781 : int OGRPLScenesDataV1FeatureDefn::GetFieldCount() const
28 : {
29 2781 : if (OGRFeatureDefn::GetFieldCount() == 0 && m_poLayer != nullptr)
30 8 : m_poLayer->EstablishLayerDefn();
31 2781 : return OGRFeatureDefn::GetFieldCount();
32 : }
33 :
34 : /************************************************************************/
35 : /* OGRPLScenesDataV1Layer() */
36 : /************************************************************************/
37 :
38 12 : OGRPLScenesDataV1Layer::OGRPLScenesDataV1Layer(OGRPLScenesDataV1Dataset *poDS,
39 12 : const char *pszName)
40 : : m_poDS(poDS), m_bFeatureDefnEstablished(false),
41 12 : m_poSRS(new OGRSpatialReference(SRS_WKT_WGS84_LAT_LONG)),
42 : m_nTotalFeatures(-1), m_nNextFID(1), m_bEOF(false),
43 : m_bStillInFirstPage(true),
44 12 : m_nPageSize(atoi(CPLGetConfigOption("PLSCENES_PAGE_SIZE", "250"))),
45 : m_bInFeatureCountOrGetExtent(false), m_poPageObj(nullptr),
46 : m_poFeatures(nullptr), m_nFeatureIdx(0), m_poAttributeFilter(nullptr),
47 36 : m_bFilterMustBeClientSideEvaluated(false)
48 : {
49 12 : m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
50 :
51 : // Cannot be moved to initializer list because of use of this, which MSVC
52 : // 2008 doesn't like
53 12 : m_poFeatureDefn = new OGRPLScenesDataV1FeatureDefn(this, pszName);
54 :
55 12 : SetDescription(pszName);
56 12 : m_poFeatureDefn->SetGeomType(wkbMultiPolygon);
57 12 : m_poFeatureDefn->Reference();
58 12 : m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSRS);
59 12 : OGRPLScenesDataV1Layer::ResetReading();
60 12 : }
61 :
62 : /************************************************************************/
63 : /* ~OGRPLScenesDataV1Layer() */
64 : /************************************************************************/
65 :
66 24 : OGRPLScenesDataV1Layer::~OGRPLScenesDataV1Layer()
67 : {
68 12 : m_poFeatureDefn->DropRefToLayer();
69 12 : m_poFeatureDefn->Release();
70 12 : m_poSRS->Release();
71 12 : if (m_poPageObj != nullptr)
72 3 : json_object_put(m_poPageObj);
73 12 : if (m_poAttributeFilter != nullptr)
74 2 : json_object_put(m_poAttributeFilter);
75 24 : }
76 :
77 : /************************************************************************/
78 : /* GetLayerDefn() */
79 : /************************************************************************/
80 :
81 51 : OGRFeatureDefn *OGRPLScenesDataV1Layer::GetLayerDefn()
82 : {
83 51 : return m_poFeatureDefn;
84 : }
85 :
86 : /************************************************************************/
87 : /* RegisterField() */
88 : /************************************************************************/
89 :
90 321 : void OGRPLScenesDataV1Layer::RegisterField(OGRFieldDefn *poFieldDefn,
91 : const char *pszQueryableJSonName,
92 : const char *pszPrefixedJSonName)
93 : {
94 321 : const int nIdx = m_poFeatureDefn->GetFieldCount();
95 321 : m_oMapPrefixedJSonFieldNameToFieldIdx[pszPrefixedJSonName] = nIdx;
96 321 : if (pszQueryableJSonName)
97 : {
98 174 : m_oMapFieldIdxToQueryableJSonFieldName[nIdx] = pszQueryableJSonName;
99 : }
100 321 : m_poFeatureDefn->AddFieldDefn(poFieldDefn);
101 321 : }
102 :
103 : /************************************************************************/
104 : /* EstablishLayerDefn() */
105 : /************************************************************************/
106 :
107 31 : void OGRPLScenesDataV1Layer::EstablishLayerDefn()
108 : {
109 31 : if (m_bFeatureDefnEstablished)
110 26 : return;
111 5 : m_bFeatureDefnEstablished = true;
112 :
113 5 : const char *pzText = nullptr;
114 5 : const char *pszConfFile = nullptr;
115 : #if !defined(USE_ONLY_EMBEDDED_RESOURCE_FILES)
116 5 : pszConfFile = CPLFindFile("gdal", "plscenesconf.json");
117 5 : if (pszConfFile == nullptr)
118 : #endif
119 : {
120 : #ifdef EMBED_RESOURCE_FILES
121 : static const bool bOnce [[maybe_unused]] = []()
122 : {
123 : CPLDebug("PLScenes", "Using embedded plscenes.conf");
124 : return true;
125 : }();
126 : pzText = PLScenesGetConfJson();
127 : #else
128 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find plscenesconf.json");
129 0 : return;
130 : #endif
131 : }
132 :
133 5 : GByte *pabyRet = nullptr;
134 : #ifdef EMBED_RESOURCE_FILES
135 : if (!pzText)
136 : #endif
137 : {
138 5 : if (!VSIIngestFile(nullptr, pszConfFile, &pabyRet, nullptr, -1))
139 : {
140 0 : return;
141 : }
142 5 : pzText = reinterpret_cast<char *>(pabyRet);
143 : }
144 :
145 5 : json_object *poRoot = nullptr;
146 5 : if (!OGRJSonParse(pzText, &poRoot))
147 : {
148 0 : VSIFree(pabyRet);
149 0 : return;
150 : }
151 5 : VSIFree(pabyRet);
152 :
153 5 : json_object *poV1Data = CPL_json_object_object_get(poRoot, "v1_data");
154 10 : if (poV1Data == nullptr ||
155 5 : json_object_get_type(poV1Data) != json_type_object)
156 : {
157 0 : CPLError(CE_Failure, CPLE_AppDefined,
158 : "Cannot find v1_data object in plscenesconf.json");
159 0 : json_object_put(poRoot);
160 0 : return;
161 : }
162 :
163 : json_object *poItemType =
164 5 : CPL_json_object_object_get(poV1Data, GetDescription());
165 10 : if (poItemType == nullptr ||
166 5 : json_object_get_type(poItemType) != json_type_object)
167 : {
168 0 : CPLError(CE_Failure, CPLE_AppDefined,
169 : "Cannot find v1_data.%s object in plscenesconf.json",
170 0 : GetDescription());
171 0 : json_object_put(poRoot);
172 0 : return;
173 : }
174 :
175 5 : json_object *poFields = CPL_json_object_object_get(poItemType, "fields");
176 10 : if (poFields == nullptr ||
177 5 : json_object_get_type(poFields) != json_type_array)
178 : {
179 0 : CPLError(CE_Failure, CPLE_AppDefined,
180 : "Cannot find v1_data.%s.fields object in plscenesconf.json",
181 0 : GetDescription());
182 0 : json_object_put(poRoot);
183 0 : return;
184 : }
185 :
186 : {
187 10 : OGRFieldDefn oFieldDefn("id", OFTString);
188 5 : RegisterField(&oFieldDefn, "id", "id");
189 : }
190 5 : const auto nFields = json_object_array_length(poFields);
191 174 : for (auto i = decltype(nFields){0}; i < nFields; i++)
192 : {
193 169 : json_object *poField = json_object_array_get_idx(poFields, i);
194 169 : if (poField && json_object_get_type(poField) == json_type_object)
195 : {
196 169 : json_object *poName = CPL_json_object_object_get(poField, "name");
197 169 : json_object *poType = CPL_json_object_object_get(poField, "type");
198 169 : if (poName && json_object_get_type(poName) == json_type_string &&
199 338 : poType && json_object_get_type(poType) == json_type_string)
200 : {
201 169 : const char *pszName = json_object_get_string(poName);
202 169 : const char *pszType = json_object_get_string(poType);
203 169 : OGRFieldType eType(OFTString);
204 169 : OGRFieldSubType eSubType(OFSTNone);
205 169 : if (EQUAL(pszType, "datetime"))
206 15 : eType = OFTDateTime;
207 154 : else if (EQUAL(pszType, "double"))
208 95 : eType = OFTReal;
209 59 : else if (EQUAL(pszType, "int"))
210 15 : eType = OFTInteger;
211 44 : else if (EQUAL(pszType, "string"))
212 39 : eType = OFTString;
213 5 : else if (EQUAL(pszType, "boolean"))
214 : {
215 5 : eType = OFTInteger;
216 5 : eSubType = OFSTBoolean;
217 : }
218 : else
219 : {
220 0 : CPLError(CE_Warning, CPLE_AppDefined,
221 : "Unrecognized field type %s for field %s", pszType,
222 : pszName);
223 : }
224 169 : OGRFieldDefn oFieldDefn(pszName, eType);
225 169 : oFieldDefn.SetSubType(eSubType);
226 169 : RegisterField(&oFieldDefn, pszName,
227 338 : (CPLString("properties.") + pszName).c_str());
228 : }
229 : }
230 : }
231 :
232 : {
233 10 : OGRFieldDefn oFieldDefn("self_link", OFTString);
234 5 : RegisterField(&oFieldDefn, nullptr, "_links._self");
235 : }
236 :
237 : {
238 10 : OGRFieldDefn oFieldDefn("assets_link", OFTString);
239 5 : RegisterField(&oFieldDefn, nullptr, "_links.assets");
240 : }
241 :
242 : {
243 10 : OGRFieldDefn oFieldDefn("permissions", OFTStringList);
244 5 : RegisterField(&oFieldDefn, nullptr, "_permissions");
245 : }
246 :
247 5 : if (m_poDS->DoesFollowLinks())
248 : {
249 : json_object *poAssets =
250 2 : CPL_json_object_object_get(poItemType, "assets");
251 4 : if (poAssets == nullptr ||
252 2 : json_object_get_type(poAssets) != json_type_array)
253 : {
254 0 : CPLError(
255 : CE_Failure, CPLE_AppDefined,
256 : "Cannot find v1_data.%s.assets object in plscenesconf.json",
257 0 : GetDescription());
258 0 : json_object_put(poRoot);
259 0 : return;
260 : }
261 :
262 2 : const auto nAssets = json_object_array_length(poAssets);
263 24 : for (auto i = decltype(nAssets){0}; i < nAssets; i++)
264 : {
265 22 : json_object *poAsset = json_object_array_get_idx(poAssets, i);
266 22 : if (poAsset && json_object_get_type(poAsset) == json_type_string)
267 : {
268 22 : const char *pszAsset = json_object_get_string(poAsset);
269 22 : m_oSetAssets.insert(pszAsset);
270 :
271 : {
272 44 : CPLString osName("asset_");
273 22 : osName += pszAsset;
274 22 : osName += "_self_link";
275 44 : OGRFieldDefn oFieldDefn(osName, OFTString);
276 22 : RegisterField(
277 : &oFieldDefn, nullptr,
278 : CPLSPrintf("/assets.%s._links._self", pszAsset));
279 : }
280 : {
281 44 : CPLString osName("asset_");
282 22 : osName += pszAsset;
283 22 : osName += "_activate_link";
284 44 : OGRFieldDefn oFieldDefn(osName, OFTString);
285 22 : RegisterField(
286 : &oFieldDefn, nullptr,
287 : CPLSPrintf("/assets.%s._links.activate", pszAsset));
288 : }
289 : {
290 44 : CPLString osName("asset_");
291 22 : osName += pszAsset;
292 22 : osName += "_permissions";
293 44 : OGRFieldDefn oFieldDefn(osName, OFTStringList);
294 22 : RegisterField(
295 : &oFieldDefn, nullptr,
296 : CPLSPrintf("/assets.%s._permissions", pszAsset));
297 : }
298 : {
299 44 : CPLString osName("asset_");
300 22 : osName += pszAsset;
301 22 : osName += "_expires_at";
302 44 : OGRFieldDefn oFieldDefn(osName, OFTDateTime);
303 22 : RegisterField(
304 : &oFieldDefn, nullptr,
305 : CPLSPrintf("/assets.%s.expires_at", pszAsset));
306 : }
307 : {
308 44 : CPLString osName("asset_");
309 22 : osName += pszAsset;
310 22 : osName += "_location";
311 44 : OGRFieldDefn oFieldDefn(osName, OFTString);
312 22 : RegisterField(&oFieldDefn, nullptr,
313 : CPLSPrintf("/assets.%s.location", pszAsset));
314 : }
315 : {
316 44 : CPLString osName("asset_");
317 22 : osName += pszAsset;
318 22 : osName += "_status";
319 44 : OGRFieldDefn oFieldDefn(osName, OFTString);
320 22 : RegisterField(&oFieldDefn, nullptr,
321 : CPLSPrintf("/assets.%s.status", pszAsset));
322 : }
323 : }
324 : }
325 : }
326 :
327 5 : json_object_put(poRoot);
328 : }
329 :
330 : /************************************************************************/
331 : /* GetMetadata() */
332 : /************************************************************************/
333 :
334 0 : char **OGRPLScenesDataV1Layer::GetMetadata(const char *pszDomain)
335 : {
336 0 : if (pszDomain == nullptr || EQUAL(pszDomain, ""))
337 : {
338 0 : EstablishLayerDefn();
339 : }
340 0 : return OGRLayer::GetMetadata(pszDomain);
341 : }
342 :
343 : /************************************************************************/
344 : /* GetMetadataItem() */
345 : /************************************************************************/
346 :
347 0 : const char *OGRPLScenesDataV1Layer::GetMetadataItem(const char *pszName,
348 : const char *pszDomain)
349 : {
350 0 : if (pszDomain == nullptr || EQUAL(pszDomain, ""))
351 : {
352 0 : EstablishLayerDefn();
353 : }
354 0 : return OGRLayer::GetMetadataItem(pszName, pszDomain);
355 : }
356 :
357 : /************************************************************************/
358 : /* GetNextPage() */
359 : /************************************************************************/
360 :
361 20 : bool OGRPLScenesDataV1Layer::GetNextPage()
362 : {
363 20 : if (m_poPageObj != nullptr)
364 12 : json_object_put(m_poPageObj);
365 20 : m_poPageObj = nullptr;
366 20 : m_poFeatures = nullptr;
367 20 : m_nFeatureIdx = 0;
368 :
369 20 : if (m_osRequestURL.empty())
370 : {
371 2 : m_bEOF = true;
372 2 : return false;
373 : }
374 :
375 : json_object *poObj;
376 18 : if (m_osRequestURL.find(m_poDS->GetBaseURL() + "quick-search?_page_size") ==
377 : 0)
378 : {
379 16 : CPLString osFilter(m_poDS->GetFilter());
380 16 : if (osFilter.empty())
381 : {
382 16 : json_object *poFilterRoot = json_object_new_object();
383 16 : json_object *poItemTypes = json_object_new_array();
384 16 : json_object_array_add(poItemTypes,
385 16 : json_object_new_string(GetName()));
386 16 : json_object_object_add(poFilterRoot, "item_types", poItemTypes);
387 16 : json_object *poFilter = json_object_new_object();
388 16 : json_object_object_add(poFilterRoot, "filter", poFilter);
389 16 : json_object_object_add(poFilter, "type",
390 : json_object_new_string("AndFilter"));
391 16 : json_object *poConfig = json_object_new_array();
392 16 : json_object_object_add(poFilter, "config", poConfig);
393 :
394 16 : if (m_poFilterGeom != nullptr)
395 : {
396 1 : json_object *poGeomFilter = json_object_new_object();
397 1 : json_object_array_add(poConfig, poGeomFilter);
398 1 : json_object_object_add(
399 : poGeomFilter, "type",
400 : json_object_new_string("GeometryFilter"));
401 1 : json_object_object_add(poGeomFilter, "field_name",
402 : json_object_new_string("geometry"));
403 2 : OGRGeoJSONWriteOptions oOptions;
404 : json_object *poGeoJSONGeom =
405 1 : OGRGeoJSONWriteGeometry(m_poFilterGeom, oOptions);
406 1 : json_object_object_add(poGeomFilter, "config", poGeoJSONGeom);
407 : }
408 16 : if (m_poAttributeFilter != nullptr)
409 : {
410 6 : json_object_get(m_poAttributeFilter);
411 6 : json_object_array_add(poConfig, m_poAttributeFilter);
412 : }
413 :
414 16 : osFilter = json_object_to_json_string_ext(poFilterRoot, 0);
415 16 : json_object_put(poFilterRoot);
416 : }
417 : poObj =
418 16 : m_poDS->RunRequest(m_osRequestURL, FALSE, "POST", true, osFilter);
419 : }
420 : else
421 : {
422 2 : poObj = m_poDS->RunRequest(m_osRequestURL);
423 : }
424 18 : if (poObj == nullptr)
425 : {
426 2 : m_bEOF = true;
427 2 : return false;
428 : }
429 :
430 16 : json_object *poFeatures = CPL_json_object_object_get(poObj, "features");
431 29 : if (poFeatures == nullptr ||
432 29 : json_object_get_type(poFeatures) != json_type_array ||
433 13 : json_object_array_length(poFeatures) == 0)
434 : {
435 : // If this is a single item, then wrap it in a features array
436 : json_object *poProperties =
437 3 : CPL_json_object_object_get(poObj, "properties");
438 3 : if (poProperties != nullptr)
439 : {
440 2 : m_poPageObj = json_object_new_object();
441 2 : poFeatures = json_object_new_array();
442 2 : json_object_array_add(poFeatures, poObj);
443 2 : json_object_object_add(m_poPageObj, "features", poFeatures);
444 2 : poObj = m_poPageObj;
445 : }
446 : else
447 : {
448 1 : json_object_put(poObj);
449 1 : m_bEOF = true;
450 1 : return false;
451 : }
452 : }
453 :
454 15 : m_poPageObj = poObj;
455 15 : m_poFeatures = poFeatures;
456 :
457 : // Get URL of next page
458 15 : m_osNextURL = "";
459 15 : json_object *poLinks = CPL_json_object_object_get(poObj, "_links");
460 15 : if (poLinks && json_object_get_type(poLinks) == json_type_object)
461 : {
462 6 : json_object *poNext = CPL_json_object_object_get(poLinks, "_next");
463 6 : if (poNext && json_object_get_type(poNext) == json_type_string)
464 : {
465 6 : m_osNextURL = json_object_get_string(poNext);
466 : }
467 : }
468 :
469 15 : return true;
470 : }
471 :
472 : /************************************************************************/
473 : /* ResetReading() */
474 : /************************************************************************/
475 :
476 38 : void OGRPLScenesDataV1Layer::ResetReading()
477 : {
478 38 : m_bEOF = false;
479 :
480 38 : if (m_poFeatures != nullptr && m_bStillInFirstPage)
481 2 : m_nFeatureIdx = 0;
482 : else
483 36 : m_poFeatures = nullptr;
484 38 : m_nNextFID = 1;
485 38 : m_bStillInFirstPage = true;
486 38 : m_osRequestURL = m_poDS->GetBaseURL() +
487 38 : CPLSPrintf("quick-search?_page_size=%d", m_nPageSize);
488 38 : }
489 :
490 : /************************************************************************/
491 : /* SetSpatialFilter() */
492 : /************************************************************************/
493 :
494 2 : void OGRPLScenesDataV1Layer::SetSpatialFilter(OGRGeometry *poGeomIn)
495 : {
496 2 : m_poFeatures = nullptr;
497 :
498 2 : if (poGeomIn)
499 : {
500 1 : OGREnvelope sEnvelope;
501 1 : poGeomIn->getEnvelope(&sEnvelope);
502 1 : if (sEnvelope.MinX == sEnvelope.MaxX &&
503 1 : sEnvelope.MinY == sEnvelope.MaxY)
504 : {
505 2 : OGRPoint p(sEnvelope.MinX, sEnvelope.MinY);
506 2 : InstallFilter(&p);
507 : }
508 : else
509 0 : InstallFilter(poGeomIn);
510 : }
511 : else
512 1 : InstallFilter(poGeomIn);
513 :
514 2 : ResetReading();
515 2 : }
516 :
517 : /************************************************************************/
518 : /* OGRPLScenesDataV1ParseDateTime() */
519 : /************************************************************************/
520 :
521 4 : static bool OGRPLScenesDataV1ParseDateTime(const char *pszValue, int &nYear,
522 : int &nMonth, int &nDay, int &nHour,
523 : int &nMinute, int &nSecond)
524 : {
525 4 : return (sscanf(pszValue, "%04d/%02d/%02d %02d:%02d:%02d", &nYear, &nMonth,
526 4 : &nDay, &nHour, &nMinute, &nSecond) >= 3 ||
527 0 : sscanf(pszValue, "%04d-%02d-%02dT%02d:%02d:%02d", &nYear, &nMonth,
528 4 : &nDay, &nHour, &nMinute, &nSecond) >= 3);
529 : }
530 :
531 : /************************************************************************/
532 : /* IsSimpleComparison() */
533 : /************************************************************************/
534 :
535 26 : bool OGRPLScenesDataV1Layer::IsSimpleComparison(const swq_expr_node *poNode)
536 : {
537 52 : return poNode->eNodeType == SNT_OPERATION &&
538 26 : (poNode->nOperation == SWQ_EQ || poNode->nOperation == SWQ_NE ||
539 13 : poNode->nOperation == SWQ_LT || poNode->nOperation == SWQ_LE ||
540 10 : poNode->nOperation == SWQ_GT || poNode->nOperation == SWQ_GE) &&
541 23 : poNode->nSubExprCount == 2 &&
542 23 : poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
543 75 : poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT &&
544 0 : m_oMapFieldIdxToQueryableJSonFieldName.find(
545 23 : poNode->papoSubExpr[0]->field_index) !=
546 49 : m_oMapFieldIdxToQueryableJSonFieldName.end();
547 : }
548 :
549 : /************************************************************************/
550 : /* GetOperatorText() */
551 : /************************************************************************/
552 :
553 6 : static const char *GetOperatorText(swq_op nOp)
554 : {
555 6 : if (nOp == SWQ_LT)
556 2 : return "lt";
557 4 : if (nOp == SWQ_LE)
558 1 : return "lte";
559 3 : if (nOp == SWQ_GT)
560 2 : return "gt";
561 1 : if (nOp == SWQ_GE)
562 1 : return "gte";
563 0 : CPLAssert(false);
564 : return "";
565 : }
566 :
567 : /************************************************************************/
568 : /* BuildFilter() */
569 : /************************************************************************/
570 :
571 45 : json_object *OGRPLScenesDataV1Layer::BuildFilter(swq_expr_node *poNode)
572 : {
573 45 : if (poNode->eNodeType == SNT_OPERATION && poNode->nOperation == SWQ_AND &&
574 15 : poNode->nSubExprCount == 2)
575 : {
576 : // For AND, we can deal with a failure in one of the branch
577 : // since client-side will do that extra filtering
578 15 : json_object *poFilter1 = BuildFilter(poNode->papoSubExpr[0]);
579 15 : json_object *poFilter2 = BuildFilter(poNode->papoSubExpr[1]);
580 15 : if (poFilter1 && poFilter2)
581 : {
582 13 : json_object *poFilter = json_object_new_object();
583 13 : json_object_object_add(poFilter, "type",
584 : json_object_new_string("AndFilter"));
585 13 : json_object *poConfig = json_object_new_array();
586 13 : json_object_object_add(poFilter, "config", poConfig);
587 13 : json_object_array_add(poConfig, poFilter1);
588 13 : json_object_array_add(poConfig, poFilter2);
589 13 : return poFilter;
590 : }
591 2 : else if (poFilter1)
592 1 : return poFilter1;
593 : else
594 1 : return poFilter2;
595 : }
596 30 : else if (poNode->eNodeType == SNT_OPERATION &&
597 30 : poNode->nOperation == SWQ_OR && poNode->nSubExprCount == 2)
598 : {
599 : // For OR, we need both members to be valid
600 2 : json_object *poFilter1 = BuildFilter(poNode->papoSubExpr[0]);
601 2 : json_object *poFilter2 = BuildFilter(poNode->papoSubExpr[1]);
602 2 : if (poFilter1 && poFilter2)
603 : {
604 1 : json_object *poFilter = json_object_new_object();
605 1 : json_object_object_add(poFilter, "type",
606 : json_object_new_string("OrFilter"));
607 1 : json_object *poConfig = json_object_new_array();
608 1 : json_object_object_add(poFilter, "config", poConfig);
609 1 : json_object_array_add(poConfig, poFilter1);
610 1 : json_object_array_add(poConfig, poFilter2);
611 1 : return poFilter;
612 : }
613 : else
614 : {
615 1 : if (poFilter1)
616 0 : json_object_put(poFilter1);
617 1 : if (poFilter2)
618 1 : json_object_put(poFilter2);
619 1 : return nullptr;
620 : }
621 : }
622 28 : else if (poNode->eNodeType == SNT_OPERATION &&
623 28 : poNode->nOperation == SWQ_NOT && poNode->nSubExprCount == 1)
624 : {
625 2 : json_object *poFilter1 = BuildFilter(poNode->papoSubExpr[0]);
626 2 : if (poFilter1)
627 : {
628 1 : json_object *poFilter = json_object_new_object();
629 1 : json_object_object_add(poFilter, "type",
630 : json_object_new_string("NotFilter"));
631 1 : json_object_object_add(poFilter, "config", poFilter1);
632 1 : return poFilter;
633 : }
634 : else
635 : {
636 1 : return nullptr;
637 : }
638 : }
639 26 : else if (IsSimpleComparison(poNode))
640 : {
641 22 : int nYear = 0, nMonth = 0, nDay = 0, nHour = 0, nMinute = 0,
642 22 : nSecond = 0;
643 22 : const int nFieldIdx = poNode->papoSubExpr[0]->field_index;
644 22 : if (poNode->nOperation == SWQ_NE)
645 : {
646 1 : poNode->nOperation = SWQ_EQ;
647 1 : json_object *poFilter1 = BuildFilter(poNode);
648 1 : poNode->nOperation = SWQ_NE;
649 1 : if (poFilter1)
650 : {
651 1 : json_object *poFilter = json_object_new_object();
652 1 : json_object_object_add(poFilter, "type",
653 : json_object_new_string("NotFilter"));
654 1 : json_object_object_add(poFilter, "config", poFilter1);
655 18 : return poFilter;
656 : }
657 : else
658 : {
659 0 : return nullptr;
660 : }
661 : }
662 11 : else if (poNode->nOperation == SWQ_EQ &&
663 11 : (m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetType() ==
664 10 : OFTInteger ||
665 10 : m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetType() ==
666 32 : OFTReal) &&
667 2 : (poNode->papoSubExpr[1]->field_type == SWQ_INTEGER ||
668 1 : poNode->papoSubExpr[1]->field_type == SWQ_FLOAT))
669 : {
670 2 : json_object *poFilter = json_object_new_object();
671 2 : if (m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetType() == OFTReal)
672 : {
673 1 : json_object_object_add(poFilter, "type",
674 : json_object_new_string("RangeFilter"));
675 1 : json_object_object_add(
676 : poFilter, "field_name",
677 : json_object_new_string(
678 1 : m_oMapFieldIdxToQueryableJSonFieldName[nFieldIdx]));
679 1 : json_object *poConfig = json_object_new_object();
680 1 : const double EPS = 1e-8;
681 1 : json_object_object_add(
682 : poConfig, "gte",
683 1 : (poNode->papoSubExpr[1]->field_type == SWQ_INTEGER)
684 0 : ? json_object_new_double(
685 0 : poNode->papoSubExpr[1]->int_value - EPS)
686 1 : : json_object_new_double(
687 1 : poNode->papoSubExpr[1]->float_value - EPS));
688 1 : json_object_object_add(
689 : poConfig, "lte",
690 1 : (poNode->papoSubExpr[1]->field_type == SWQ_INTEGER)
691 0 : ? json_object_new_double(
692 0 : poNode->papoSubExpr[1]->int_value + EPS)
693 1 : : json_object_new_double(
694 1 : poNode->papoSubExpr[1]->float_value + EPS));
695 1 : json_object_object_add(poFilter, "config", poConfig);
696 : }
697 : else
698 : {
699 1 : json_object_object_add(
700 : poFilter, "type", json_object_new_string("NumberInFilter"));
701 1 : json_object_object_add(
702 : poFilter, "field_name",
703 : json_object_new_string(
704 1 : m_oMapFieldIdxToQueryableJSonFieldName[nFieldIdx]));
705 1 : json_object *poConfig = json_object_new_array();
706 1 : json_object_array_add(
707 : poConfig,
708 1 : (poNode->papoSubExpr[1]->field_type == SWQ_INTEGER)
709 1 : ? json_object_new_int64(
710 1 : poNode->papoSubExpr[1]->int_value)
711 0 : : json_object_new_double(
712 0 : poNode->papoSubExpr[1]->float_value));
713 1 : json_object_object_add(poFilter, "config", poConfig);
714 : }
715 2 : return poFilter;
716 : }
717 9 : else if (poNode->nOperation == SWQ_EQ &&
718 9 : m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetType() ==
719 28 : OFTString &&
720 9 : poNode->papoSubExpr[1]->field_type == SWQ_STRING)
721 : {
722 9 : json_object *poFilter = json_object_new_object();
723 9 : json_object_object_add(poFilter, "type",
724 : json_object_new_string("StringInFilter"));
725 9 : json_object_object_add(
726 : poFilter, "field_name",
727 : json_object_new_string(
728 9 : m_oMapFieldIdxToQueryableJSonFieldName[nFieldIdx]));
729 9 : json_object *poConfig = json_object_new_array();
730 9 : json_object_array_add(
731 : poConfig,
732 9 : json_object_new_string(poNode->papoSubExpr[1]->string_value));
733 9 : json_object_object_add(poFilter, "config", poConfig);
734 9 : return poFilter;
735 : }
736 28 : else if ((poNode->nOperation == SWQ_LT ||
737 8 : poNode->nOperation == SWQ_LE ||
738 7 : poNode->nOperation == SWQ_GT ||
739 11 : poNode->nOperation == SWQ_GE) &&
740 10 : (m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetType() ==
741 8 : OFTInteger ||
742 8 : m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetType() ==
743 20 : OFTReal) &&
744 2 : (poNode->papoSubExpr[1]->field_type == SWQ_INTEGER ||
745 0 : poNode->papoSubExpr[1]->field_type == SWQ_FLOAT))
746 : {
747 2 : json_object *poFilter = json_object_new_object();
748 2 : json_object_object_add(poFilter, "type",
749 : json_object_new_string("RangeFilter"));
750 2 : json_object_object_add(
751 : poFilter, "field_name",
752 : json_object_new_string(
753 2 : m_oMapFieldIdxToQueryableJSonFieldName[nFieldIdx]));
754 2 : json_object *poConfig = json_object_new_object();
755 2 : json_object_object_add(
756 : poConfig, GetOperatorText(poNode->nOperation),
757 2 : (poNode->papoSubExpr[1]->field_type == SWQ_INTEGER)
758 2 : ? json_object_new_int64(poNode->papoSubExpr[1]->int_value)
759 0 : : json_object_new_double(
760 0 : poNode->papoSubExpr[1]->float_value));
761 2 : json_object_object_add(poFilter, "config", poConfig);
762 2 : return poFilter;
763 : }
764 23 : else if ((poNode->nOperation == SWQ_LT ||
765 7 : poNode->nOperation == SWQ_LE ||
766 6 : poNode->nOperation == SWQ_GT ||
767 9 : poNode->nOperation == SWQ_GE) &&
768 8 : m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetType() ==
769 4 : OFTDateTime &&
770 20 : poNode->papoSubExpr[1]->field_type == SWQ_TIMESTAMP &&
771 4 : OGRPLScenesDataV1ParseDateTime(
772 4 : poNode->papoSubExpr[1]->string_value, nYear, nMonth, nDay,
773 : nHour, nMinute, nSecond))
774 : {
775 4 : json_object *poFilter = json_object_new_object();
776 4 : json_object_object_add(poFilter, "type",
777 : json_object_new_string("DateRangeFilter"));
778 4 : json_object_object_add(
779 : poFilter, "field_name",
780 : json_object_new_string(
781 4 : m_oMapFieldIdxToQueryableJSonFieldName[nFieldIdx]));
782 4 : json_object *poConfig = json_object_new_object();
783 4 : json_object_object_add(poConfig,
784 : GetOperatorText(poNode->nOperation),
785 : json_object_new_string(CPLSPrintf(
786 : "%04d-%02d-%02dT%02d:%02d:%02dZ", nYear,
787 : nMonth, nDay, nHour, nMinute, nSecond)));
788 4 : json_object_object_add(poFilter, "config", poConfig);
789 4 : return poFilter;
790 : }
791 : }
792 12 : else if (poNode->eNodeType == SNT_OPERATION &&
793 4 : poNode->nOperation == SWQ_IN && poNode->nSubExprCount >= 2 &&
794 11 : poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
795 0 : m_oMapFieldIdxToQueryableJSonFieldName.find(
796 3 : poNode->papoSubExpr[0]->field_index) !=
797 7 : m_oMapFieldIdxToQueryableJSonFieldName.end())
798 : {
799 2 : const int nFieldIdx = poNode->papoSubExpr[0]->field_index;
800 2 : if (m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetType() == OFTString)
801 : {
802 1 : json_object *poFilter = json_object_new_object();
803 1 : json_object_object_add(poFilter, "type",
804 : json_object_new_string("StringInFilter"));
805 1 : json_object_object_add(
806 : poFilter, "field_name",
807 : json_object_new_string(
808 1 : m_oMapFieldIdxToQueryableJSonFieldName[nFieldIdx]));
809 1 : json_object *poConfig = json_object_new_array();
810 1 : json_object_object_add(poFilter, "config", poConfig);
811 2 : for (int i = 1; i < poNode->nSubExprCount; i++)
812 : {
813 1 : if (poNode->papoSubExpr[i]->eNodeType != SNT_CONSTANT ||
814 1 : poNode->papoSubExpr[i]->field_type != SWQ_STRING)
815 : {
816 0 : json_object_put(poFilter);
817 0 : m_bFilterMustBeClientSideEvaluated = true;
818 2 : return nullptr;
819 : }
820 1 : json_object_array_add(
821 : poConfig, json_object_new_string(
822 1 : poNode->papoSubExpr[i]->string_value));
823 : }
824 1 : return poFilter;
825 : }
826 1 : else if (m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetType() ==
827 : OFTInteger)
828 : {
829 1 : json_object *poFilter = json_object_new_object();
830 1 : json_object_object_add(poFilter, "type",
831 : json_object_new_string("NumberInFilter"));
832 1 : json_object_object_add(
833 : poFilter, "field_name",
834 : json_object_new_string(
835 1 : m_oMapFieldIdxToQueryableJSonFieldName[nFieldIdx]));
836 1 : json_object *poConfig = json_object_new_array();
837 1 : json_object_object_add(poFilter, "config", poConfig);
838 3 : for (int i = 1; i < poNode->nSubExprCount; i++)
839 : {
840 2 : if (poNode->papoSubExpr[i]->eNodeType != SNT_CONSTANT ||
841 2 : poNode->papoSubExpr[i]->field_type != SWQ_INTEGER)
842 : {
843 0 : json_object_put(poFilter);
844 0 : m_bFilterMustBeClientSideEvaluated = true;
845 0 : return nullptr;
846 : }
847 2 : json_object_array_add(
848 : poConfig,
849 2 : json_object_new_int64(poNode->papoSubExpr[i]->int_value));
850 : }
851 1 : return poFilter;
852 : }
853 : }
854 6 : else if (poNode->eNodeType == SNT_OPERATION &&
855 2 : poNode->nOperation == SWQ_EQ && poNode->nSubExprCount == 2 &&
856 1 : poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
857 1 : poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT &&
858 1 : poNode->papoSubExpr[0]->field_index ==
859 5 : m_poFeatureDefn->GetFieldIndex("permissions") &&
860 1 : poNode->papoSubExpr[1]->field_type == SWQ_STRING)
861 : {
862 1 : json_object *poFilter = json_object_new_object();
863 1 : json_object_object_add(poFilter, "type",
864 : json_object_new_string("PermissionFilter"));
865 1 : json_object *poConfig = json_object_new_array();
866 1 : json_object_object_add(poFilter, "config", poConfig);
867 1 : json_object_array_add(
868 : poConfig,
869 1 : json_object_new_string(poNode->papoSubExpr[1]->string_value));
870 1 : return poFilter;
871 : }
872 3 : else if (poNode->eNodeType == SNT_OPERATION &&
873 1 : poNode->nOperation == SWQ_IN && poNode->nSubExprCount >= 2 &&
874 3 : poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
875 1 : poNode->papoSubExpr[0]->field_index ==
876 1 : m_poFeatureDefn->GetFieldIndex("permissions"))
877 : {
878 1 : json_object *poFilter = json_object_new_object();
879 1 : json_object_object_add(poFilter, "type",
880 : json_object_new_string("PermissionFilter"));
881 1 : json_object *poConfig = json_object_new_array();
882 1 : json_object_object_add(poFilter, "config", poConfig);
883 2 : for (int i = 1; i < poNode->nSubExprCount; i++)
884 : {
885 1 : if (poNode->papoSubExpr[i]->eNodeType != SNT_CONSTANT ||
886 1 : poNode->papoSubExpr[i]->field_type != SWQ_STRING)
887 : {
888 0 : json_object_put(poFilter);
889 0 : m_bFilterMustBeClientSideEvaluated = true;
890 0 : return nullptr;
891 : }
892 1 : json_object_array_add(
893 : poConfig,
894 1 : json_object_new_string(poNode->papoSubExpr[i]->string_value));
895 : }
896 1 : return poFilter;
897 : }
898 :
899 4 : m_bFilterMustBeClientSideEvaluated = true;
900 4 : return nullptr;
901 : }
902 :
903 : /************************************************************************/
904 : /* SetAttributeFilter() */
905 : /************************************************************************/
906 :
907 9 : OGRErr OGRPLScenesDataV1Layer::SetAttributeFilter(const char *pszQuery)
908 :
909 : {
910 9 : m_poFeatures = nullptr;
911 :
912 9 : OGRErr eErr = OGRLayer::SetAttributeFilter(pszQuery);
913 :
914 9 : if (m_poAttributeFilter)
915 4 : json_object_put(m_poAttributeFilter);
916 9 : m_poAttributeFilter = nullptr;
917 9 : m_bFilterMustBeClientSideEvaluated = false;
918 9 : if (m_poAttrQuery != nullptr)
919 : {
920 8 : swq_expr_node *poNode = (swq_expr_node *)m_poAttrQuery->GetSWQExpr();
921 :
922 8 : poNode->ReplaceBetweenByGEAndLERecurse();
923 :
924 8 : m_poAttributeFilter = BuildFilter(poNode);
925 8 : if (m_poAttributeFilter == nullptr)
926 : {
927 2 : CPLDebug("PLSCENES",
928 : "Full filter will be evaluated on client side.");
929 : }
930 6 : else if (m_bFilterMustBeClientSideEvaluated)
931 : {
932 2 : CPLDebug(
933 : "PLSCENES",
934 : "Only part of the filter will be evaluated on server side.");
935 : }
936 : }
937 :
938 9 : ResetReading();
939 :
940 9 : return eErr;
941 : }
942 :
943 : /************************************************************************/
944 : /* GetNextFeature() */
945 : /************************************************************************/
946 :
947 23 : OGRFeature *OGRPLScenesDataV1Layer::GetNextFeature()
948 : {
949 : while (true)
950 : {
951 23 : OGRFeature *poFeature = GetNextRawFeature();
952 23 : if (poFeature == nullptr)
953 7 : return nullptr;
954 :
955 20 : if (m_poAttrQuery == nullptr || !m_bFilterMustBeClientSideEvaluated ||
956 4 : m_poAttrQuery->Evaluate(poFeature))
957 : {
958 16 : return poFeature;
959 : }
960 : else
961 : {
962 0 : delete poFeature;
963 : }
964 0 : }
965 : }
966 :
967 : /************************************************************************/
968 : /* GetNextRawFeature() */
969 : /************************************************************************/
970 :
971 23 : OGRFeature *OGRPLScenesDataV1Layer::GetNextRawFeature()
972 : {
973 23 : EstablishLayerDefn();
974 23 : if (m_bEOF)
975 1 : return nullptr;
976 :
977 22 : if (m_poFeatures == nullptr)
978 : {
979 16 : if (!GetNextPage())
980 3 : return nullptr;
981 : }
982 :
983 38 : if (m_nFeatureIdx ==
984 19 : static_cast<int>(json_object_array_length(m_poFeatures)))
985 : {
986 4 : m_osRequestURL = m_osNextURL;
987 4 : m_bStillInFirstPage = false;
988 4 : if (!GetNextPage())
989 2 : return nullptr;
990 : }
991 : json_object *poJSonFeature =
992 17 : json_object_array_get_idx(m_poFeatures, m_nFeatureIdx);
993 17 : m_nFeatureIdx++;
994 33 : if (poJSonFeature == nullptr ||
995 16 : json_object_get_type(poJSonFeature) != json_type_object)
996 : {
997 1 : m_bEOF = true;
998 1 : return nullptr;
999 : }
1000 :
1001 16 : OGRFeature *poFeature = new OGRFeature(m_poFeatureDefn);
1002 16 : poFeature->SetFID(m_nNextFID++);
1003 :
1004 : json_object *poJSonGeom =
1005 16 : CPL_json_object_object_get(poJSonFeature, "geometry");
1006 26 : if (poJSonGeom != nullptr &&
1007 10 : json_object_get_type(poJSonGeom) == json_type_object)
1008 : {
1009 10 : OGRGeometry *poGeom = OGRGeoJSONReadGeometry(poJSonGeom);
1010 10 : if (poGeom != nullptr)
1011 : {
1012 10 : if (poGeom->getGeometryType() == wkbPolygon)
1013 : {
1014 8 : OGRMultiPolygon *poMP = new OGRMultiPolygon();
1015 8 : poMP->addGeometryDirectly(poGeom);
1016 8 : poGeom = poMP;
1017 : }
1018 10 : poGeom->assignSpatialReference(m_poSRS);
1019 10 : poFeature->SetGeometryDirectly(poGeom);
1020 : }
1021 : }
1022 :
1023 16 : json_object *poId = CPL_json_object_object_get(poJSonFeature, "id");
1024 16 : if (poId != nullptr && json_object_get_type(poId) == json_type_string)
1025 : {
1026 : std::map<CPLString, int>::const_iterator oIter =
1027 16 : m_oMapPrefixedJSonFieldNameToFieldIdx.find("id");
1028 16 : if (oIter != m_oMapPrefixedJSonFieldNameToFieldIdx.end())
1029 : {
1030 16 : const int iField = oIter->second;
1031 16 : poFeature->SetField(iField, json_object_get_string(poId));
1032 : }
1033 : }
1034 :
1035 : json_object *poPermissions =
1036 16 : CPL_json_object_object_get(poJSonFeature, "_permissions");
1037 24 : if (poPermissions != nullptr &&
1038 8 : json_object_get_type(poPermissions) == json_type_array)
1039 : {
1040 : std::map<CPLString, int>::const_iterator oIter =
1041 8 : m_oMapPrefixedJSonFieldNameToFieldIdx.find("_permissions");
1042 8 : if (oIter != m_oMapPrefixedJSonFieldNameToFieldIdx.end())
1043 : {
1044 8 : const int iField = oIter->second;
1045 8 : const auto nStrings = json_object_array_length(poPermissions);
1046 : char **papszPermissions =
1047 8 : static_cast<char **>(CPLCalloc(nStrings + 1, sizeof(char *)));
1048 16 : for (auto i = decltype(nStrings){0}, j = decltype(nStrings){0};
1049 16 : i < nStrings; i++)
1050 : {
1051 : json_object *poPerm =
1052 8 : json_object_array_get_idx(poPermissions, i);
1053 8 : if (poPerm && json_object_get_type(poPerm) == json_type_string)
1054 : {
1055 8 : papszPermissions[j++] =
1056 8 : CPLStrdup(json_object_get_string(poPerm));
1057 : }
1058 : }
1059 8 : poFeature->SetField(iField, papszPermissions);
1060 8 : CSLDestroy(papszPermissions);
1061 : }
1062 : }
1063 :
1064 48 : for (int i = 0; i < 2; i++)
1065 : {
1066 32 : const char *pszFeaturePart = (i == 0) ? "properties" : "_links";
1067 : json_object *poProperties =
1068 32 : CPL_json_object_object_get(poJSonFeature, pszFeaturePart);
1069 52 : if (poProperties != nullptr &&
1070 20 : json_object_get_type(poProperties) == json_type_object)
1071 : {
1072 : json_object_iter it;
1073 20 : it.key = nullptr;
1074 20 : it.val = nullptr;
1075 20 : it.entry = nullptr;
1076 76 : json_object_object_foreachC(poProperties, it)
1077 : {
1078 112 : CPLString osPrefixedJSonFieldName(pszFeaturePart);
1079 56 : osPrefixedJSonFieldName += ".";
1080 56 : osPrefixedJSonFieldName += it.key;
1081 56 : if (!SetFieldFromPrefixedJSonFieldName(
1082 : poFeature, osPrefixedJSonFieldName, it.val))
1083 : {
1084 0 : if (i == 0 && m_oSetUnregisteredFields.find(
1085 0 : osPrefixedJSonFieldName) ==
1086 0 : m_oSetUnregisteredFields.end())
1087 : {
1088 0 : CPLError(CE_Warning, CPLE_AppDefined,
1089 : "Field %s found in data but not "
1090 : "in configuration",
1091 : osPrefixedJSonFieldName.c_str());
1092 : m_oSetUnregisteredFields.insert(
1093 0 : osPrefixedJSonFieldName);
1094 : }
1095 : }
1096 : }
1097 : }
1098 : }
1099 :
1100 16 : json_object *poAssets = nullptr;
1101 31 : if (m_poDS->DoesFollowLinks() &&
1102 15 : (!m_bInFeatureCountOrGetExtent || m_poAttrQuery != nullptr))
1103 : {
1104 : std::map<CPLString, int>::const_iterator oIter =
1105 14 : m_oMapPrefixedJSonFieldNameToFieldIdx.find("_links.assets");
1106 14 : if (oIter != m_oMapPrefixedJSonFieldNameToFieldIdx.end())
1107 : {
1108 14 : const int iField = oIter->second;
1109 14 : if (poFeature->IsFieldSetAndNotNull(iField))
1110 : {
1111 8 : const char *pszAssetURL = poFeature->GetFieldAsString(iField);
1112 8 : poAssets = m_poDS->RunRequest(pszAssetURL);
1113 : }
1114 : }
1115 : }
1116 16 : if (poAssets != nullptr)
1117 : {
1118 : json_object_iter itAsset;
1119 8 : itAsset.key = nullptr;
1120 8 : itAsset.val = nullptr;
1121 8 : itAsset.entry = nullptr;
1122 16 : json_object_object_foreachC(poAssets, itAsset)
1123 : {
1124 8 : if (m_oSetAssets.find(itAsset.key) == m_oSetAssets.end())
1125 : {
1126 0 : if (m_oSetUnregisteredAssets.find(itAsset.key) ==
1127 0 : m_oSetUnregisteredAssets.end())
1128 : {
1129 0 : CPLError(CE_Warning, CPLE_AppDefined,
1130 : "Asset %s found in data but "
1131 : "not in configuration",
1132 : itAsset.key);
1133 0 : m_oSetUnregisteredAssets.insert(itAsset.key);
1134 : }
1135 0 : continue;
1136 : }
1137 :
1138 8 : json_object *poAsset = itAsset.val;
1139 16 : if (poAsset != nullptr &&
1140 8 : json_object_get_type(poAsset) == json_type_object)
1141 : {
1142 : json_object_iter it;
1143 8 : it.key = nullptr;
1144 8 : it.val = nullptr;
1145 8 : it.entry = nullptr;
1146 48 : json_object_object_foreachC(poAsset, it)
1147 : {
1148 40 : if (it.val == nullptr)
1149 0 : continue;
1150 80 : CPLString osPrefixedJSonFieldName("/assets." +
1151 120 : CPLString(itAsset.key));
1152 40 : osPrefixedJSonFieldName += "." + CPLString(it.key);
1153 48 : if (strcmp(it.key, "_links") == 0 &&
1154 8 : json_object_get_type(it.val) == json_type_object)
1155 : {
1156 8 : if (CPL_json_object_object_get(it.val, "_self") !=
1157 : nullptr)
1158 : {
1159 : CPLString osPrefixedJSonFieldNameNew(
1160 16 : osPrefixedJSonFieldName + "._self");
1161 8 : SetFieldFromPrefixedJSonFieldName(
1162 : poFeature, osPrefixedJSonFieldNameNew,
1163 : CPL_json_object_object_get(it.val, "_self"));
1164 : }
1165 8 : if (CPL_json_object_object_get(it.val, "activate") !=
1166 : nullptr)
1167 : {
1168 : CPLString osPrefixedJSonFieldNameNew(
1169 16 : osPrefixedJSonFieldName + ".activate");
1170 8 : SetFieldFromPrefixedJSonFieldName(
1171 : poFeature, osPrefixedJSonFieldNameNew,
1172 : CPL_json_object_object_get(it.val, "activate"));
1173 : }
1174 : }
1175 : else
1176 : {
1177 32 : SetFieldFromPrefixedJSonFieldName(
1178 : poFeature, osPrefixedJSonFieldName, it.val);
1179 : }
1180 : }
1181 : }
1182 : }
1183 8 : json_object_put(poAssets);
1184 : }
1185 :
1186 16 : return poFeature;
1187 : }
1188 :
1189 : /************************************************************************/
1190 : /* SetFieldFromPrefixedJSonFieldName() */
1191 : /************************************************************************/
1192 :
1193 104 : bool OGRPLScenesDataV1Layer::SetFieldFromPrefixedJSonFieldName(
1194 : OGRFeature *poFeature, const CPLString &osPrefixedJSonFieldName,
1195 : json_object *poVal)
1196 : {
1197 : std::map<CPLString, int>::const_iterator oIter =
1198 104 : m_oMapPrefixedJSonFieldNameToFieldIdx.find(osPrefixedJSonFieldName);
1199 208 : if (poVal != nullptr &&
1200 208 : oIter != m_oMapPrefixedJSonFieldNameToFieldIdx.end())
1201 : {
1202 104 : const int iField = oIter->second;
1203 104 : json_type eJSonType = json_object_get_type(poVal);
1204 104 : if (eJSonType == json_type_int)
1205 : {
1206 8 : poFeature->SetField(
1207 8 : iField, static_cast<GIntBig>(json_object_get_int64(poVal)));
1208 : }
1209 96 : else if (eJSonType == json_type_double)
1210 : {
1211 9 : poFeature->SetField(iField, json_object_get_double(poVal));
1212 : }
1213 87 : else if (eJSonType == json_type_string)
1214 : {
1215 72 : poFeature->SetField(iField, json_object_get_string(poVal));
1216 : }
1217 15 : else if (eJSonType == json_type_boolean)
1218 : {
1219 7 : poFeature->SetField(iField, json_object_get_boolean(poVal));
1220 : }
1221 : else
1222 : {
1223 8 : poFeature->SetField(iField,
1224 : json_object_to_json_string_ext(poVal, 0));
1225 : }
1226 104 : return true;
1227 : }
1228 0 : return false;
1229 : }
1230 :
1231 : /************************************************************************/
1232 : /* GetFeatureCount() */
1233 : /************************************************************************/
1234 :
1235 2 : GIntBig OGRPLScenesDataV1Layer::GetFeatureCount(int bForce)
1236 : {
1237 2 : if (m_poDS->GetFilter().empty())
1238 : {
1239 2 : if (m_nTotalFeatures >= 0 && m_poFilterGeom == nullptr &&
1240 0 : m_poAttrQuery == nullptr)
1241 : {
1242 1 : return m_nTotalFeatures;
1243 : }
1244 :
1245 2 : json_object *poFilterRoot = json_object_new_object();
1246 2 : json_object *poItemTypes = json_object_new_array();
1247 2 : json_object_array_add(poItemTypes, json_object_new_string(GetName()));
1248 2 : json_object_object_add(poFilterRoot, "interval",
1249 : json_object_new_string("year"));
1250 2 : json_object_object_add(poFilterRoot, "item_types", poItemTypes);
1251 2 : json_object *poFilter = json_object_new_object();
1252 2 : json_object_object_add(poFilterRoot, "filter", poFilter);
1253 2 : json_object_object_add(poFilter, "type",
1254 : json_object_new_string("AndFilter"));
1255 2 : json_object *poConfig = json_object_new_array();
1256 2 : json_object_object_add(poFilter, "config", poConfig);
1257 :
1258 : // We need to put a dummy filter
1259 2 : if (m_poFilterGeom == nullptr && m_poAttributeFilter == nullptr)
1260 : {
1261 1 : json_object *poRangeFilter = json_object_new_object();
1262 1 : json_object_array_add(poConfig, poRangeFilter);
1263 1 : json_object_object_add(poRangeFilter, "type",
1264 : json_object_new_string("RangeFilter"));
1265 1 : json_object_object_add(poRangeFilter, "field_name",
1266 : json_object_new_string("cloud_cover"));
1267 1 : json_object *poRangeFilterConfig = json_object_new_object();
1268 1 : json_object_object_add(poRangeFilterConfig, "gte",
1269 : json_object_new_double(0.0));
1270 1 : json_object_object_add(poRangeFilter, "config",
1271 : poRangeFilterConfig);
1272 : }
1273 :
1274 2 : if (m_poFilterGeom != nullptr)
1275 : {
1276 1 : json_object *poGeomFilter = json_object_new_object();
1277 1 : json_object_array_add(poConfig, poGeomFilter);
1278 1 : json_object_object_add(poGeomFilter, "type",
1279 : json_object_new_string("GeometryFilter"));
1280 1 : json_object_object_add(poGeomFilter, "field_name",
1281 : json_object_new_string("geometry"));
1282 2 : OGRGeoJSONWriteOptions oOptions;
1283 : json_object *poGeoJSONGeom =
1284 1 : OGRGeoJSONWriteGeometry(m_poFilterGeom, oOptions);
1285 1 : json_object_object_add(poGeomFilter, "config", poGeoJSONGeom);
1286 : }
1287 2 : if (m_poAttributeFilter != nullptr)
1288 : {
1289 0 : json_object_get(m_poAttributeFilter);
1290 0 : json_object_array_add(poConfig, m_poAttributeFilter);
1291 : }
1292 :
1293 2 : CPLString osFilter = json_object_to_json_string_ext(poFilterRoot, 0);
1294 2 : json_object_put(poFilterRoot);
1295 :
1296 : json_object *poObj =
1297 2 : m_poDS->RunRequest((m_poDS->GetBaseURL() + "stats").c_str(), FALSE,
1298 : "POST", true, osFilter);
1299 2 : if (poObj != nullptr)
1300 : {
1301 : json_object *poBuckets =
1302 1 : CPL_json_object_object_get(poObj, "buckets");
1303 1 : if (poBuckets && json_object_get_type(poBuckets) == json_type_array)
1304 : {
1305 1 : GIntBig nRes = 0;
1306 1 : const auto nBuckets = json_object_array_length(poBuckets);
1307 3 : for (auto i = decltype(nBuckets){0}; i < nBuckets; i++)
1308 : {
1309 : json_object *poBucket =
1310 2 : json_object_array_get_idx(poBuckets, i);
1311 4 : if (poBucket &&
1312 2 : json_object_get_type(poBucket) == json_type_object)
1313 : {
1314 : json_object *poCount =
1315 2 : CPL_json_object_object_get(poBucket, "count");
1316 4 : if (poCount &&
1317 2 : json_object_get_type(poCount) == json_type_int)
1318 : {
1319 2 : nRes += json_object_get_int64(poCount);
1320 : }
1321 : }
1322 : }
1323 1 : if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
1324 1 : m_nTotalFeatures = nRes;
1325 :
1326 1 : json_object_put(poObj);
1327 1 : return nRes;
1328 : }
1329 0 : json_object_put(poObj);
1330 : }
1331 : }
1332 :
1333 1 : m_bInFeatureCountOrGetExtent = true;
1334 1 : GIntBig nRes = OGRLayer::GetFeatureCount(bForce);
1335 1 : m_bInFeatureCountOrGetExtent = false;
1336 1 : return nRes;
1337 : }
1338 :
1339 : /************************************************************************/
1340 : /* GetExtent() */
1341 : /************************************************************************/
1342 :
1343 1 : OGRErr OGRPLScenesDataV1Layer::GetExtent(OGREnvelope *psExtent, int bForce)
1344 : {
1345 1 : if (m_poFilterGeom != nullptr)
1346 : {
1347 0 : m_bInFeatureCountOrGetExtent = true;
1348 0 : OGRErr eErr = OGRLayer::GetExtentInternal(0, psExtent, bForce);
1349 0 : m_bInFeatureCountOrGetExtent = false;
1350 0 : return eErr;
1351 : }
1352 :
1353 1 : psExtent->MinX = -180;
1354 1 : psExtent->MinY = -90;
1355 1 : psExtent->MaxX = 180;
1356 1 : psExtent->MaxY = 90;
1357 1 : return OGRERR_NONE;
1358 : }
1359 :
1360 : /************************************************************************/
1361 : /* TestCapability() */
1362 : /************************************************************************/
1363 :
1364 11 : int OGRPLScenesDataV1Layer::TestCapability(const char *pszCap)
1365 : {
1366 11 : if (EQUAL(pszCap, OLCFastFeatureCount))
1367 1 : return !m_bFilterMustBeClientSideEvaluated;
1368 10 : if (EQUAL(pszCap, OLCStringsAsUTF8))
1369 9 : return TRUE;
1370 1 : return FALSE;
1371 : }
|