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