LCOV - code coverage report
Current view: top level - ogr - ogr_schema_override.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 73 87 83.9 %
Date: 2025-01-18 12:42:00 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Project:  OGR_SCHEMA open options handling
       3             :  * Purpose:  Class for representing a layer schema override.
       4             :  * Author:   Alessandro Pasotti, elpaso@itopen.it
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2024, Alessandro Pasotti <elpaso at itopen dot it>
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : 
      12             : //! @cond Doxygen_Suppress
      13             : 
      14             : #include "ogr_schema_override.h"
      15             : 
      16          51 : bool OGRSchemaOverride::LoadFromJSON(const std::string &osJSON)
      17             : {
      18         102 :     std::string osFieldsSchemaOverride;
      19          51 :     bool bFieldsSchemaOverrideIsFilePath{false};
      20             : 
      21             :     // Try to load the content of the file
      22          51 :     GByte *pabyRet = nullptr;
      23          51 :     if (VSIIngestFile(nullptr, osJSON.c_str(), &pabyRet, nullptr, -1) == TRUE)
      24             :     {
      25          13 :         bFieldsSchemaOverrideIsFilePath = true;
      26          13 :         osFieldsSchemaOverride = std::string(reinterpret_cast<char *>(pabyRet));
      27          13 :         VSIFree(pabyRet);
      28             :     }
      29             : 
      30          51 :     if (!bFieldsSchemaOverrideIsFilePath)
      31             :     {
      32          38 :         osFieldsSchemaOverride = osJSON;
      33             :     }
      34             : 
      35         102 :     CPLJSONDocument oSchemaDoc;
      36          51 :     if (oSchemaDoc.LoadMemory(osFieldsSchemaOverride))
      37             :     {
      38         102 :         const CPLJSONObject oRoot = oSchemaDoc.GetRoot();
      39          51 :         if (oRoot.IsValid())
      40             :         {
      41         153 :             const auto aoLayers = oRoot.GetArray("layers");
      42             :             // Loop through layer names and get the field details for each field.
      43          99 :             for (const auto &oLayer : aoLayers)
      44             :             {
      45          53 :                 if (oLayer.IsValid())
      46             :                 {
      47         106 :                     const auto oLayerFields = oLayer.GetArray("fields");
      48             :                     // Parse fields
      49         106 :                     const auto osLayerName = oLayer.GetString("name");
      50         106 :                     const auto osSchemaType = oLayer.GetString("schemaType");
      51             :                     // Default schemaType is "Patch"
      52             :                     const auto bSchemaFullOverride =
      53          53 :                         CPLString(osSchemaType).tolower() == "full";
      54          53 :                     OGRLayerSchemaOverride oLayerOverride;
      55          53 :                     oLayerOverride.SetLayerName(osLayerName);
      56          53 :                     oLayerOverride.SetFullOverride(bSchemaFullOverride);
      57             : 
      58          53 :                     if (oLayerFields.Size() > 0 && !osLayerName.empty())
      59             :                     {
      60         113 :                         for (const auto &oField : oLayerFields)
      61             :                         {
      62         130 :                             const auto osFieldName = oField.GetString("name");
      63          65 :                             if (osFieldName.empty())
      64             :                             {
      65           0 :                                 CPLError(CE_Warning, CPLE_AppDefined,
      66             :                                          "Field name is missing");
      67           0 :                                 return false;
      68             :                             }
      69          65 :                             OGRFieldDefnOverride oFieldOverride;
      70             : 
      71             :                             const CPLString oType(
      72         130 :                                 CPLString(oField.GetString("type")).tolower());
      73             :                             const CPLString oSubType(
      74         130 :                                 CPLString(oField.GetString("subType"))
      75          65 :                                     .tolower());
      76             :                             const CPLString osNewName(
      77         130 :                                 CPLString(oField.GetString("newName"))
      78          65 :                                     .tolower());
      79          65 :                             const auto nWidth = oField.GetInteger("width", 0);
      80             :                             const auto nPrecision =
      81          65 :                                 oField.GetInteger("precision", 0);
      82             : 
      83          65 :                             if (!osNewName.empty())
      84             :                             {
      85           4 :                                 oFieldOverride.SetFieldName(osNewName);
      86             :                             }
      87             : 
      88          65 :                             if (!oType.empty())
      89             :                             {
      90             :                                 const OGRFieldType eType =
      91          41 :                                     OGRFieldDefn::GetFieldTypeByName(
      92             :                                         oType.c_str());
      93             :                                 // Check if the field type is valid
      94          41 :                                 if (eType == OFTString && oType != "string")
      95             :                                 {
      96           5 :                                     CPLError(CE_Failure, CPLE_AppDefined,
      97             :                                              "Unsupported field type: %s "
      98             :                                              "for field %s",
      99             :                                              oType.c_str(),
     100             :                                              osFieldName.c_str());
     101           5 :                                     return false;
     102             :                                 }
     103          36 :                                 oFieldOverride.SetFieldType(eType);
     104             :                             }
     105             : 
     106          60 :                             if (!oSubType.empty())
     107             :                             {
     108             :                                 const OGRFieldSubType eSubType =
     109          19 :                                     OGRFieldDefn::GetFieldSubTypeByName(
     110             :                                         oSubType.c_str());
     111             :                                 // Check if the field subType is valid
     112          19 :                                 if (eSubType == OFSTNone && oSubType != "none")
     113             :                                 {
     114           0 :                                     CPLError(CE_Failure, CPLE_AppDefined,
     115             :                                              "Unsupported field subType: "
     116             :                                              "%s for field %s",
     117             :                                              oSubType.c_str(),
     118             :                                              osFieldName.c_str());
     119           0 :                                     return false;
     120             :                                 }
     121          19 :                                 oFieldOverride.SetFieldSubType(eSubType);
     122             :                             }
     123             : 
     124          60 :                             if (nWidth != 0)
     125             :                             {
     126           5 :                                 oFieldOverride.SetFieldWidth(nWidth);
     127             :                             }
     128             : 
     129          60 :                             if (nPrecision != 0)
     130             :                             {
     131           5 :                                 oFieldOverride.SetFieldPrecision(nPrecision);
     132             :                             }
     133             : 
     134          60 :                             if (bSchemaFullOverride || oFieldOverride.IsValid())
     135             :                             {
     136          60 :                                 oLayerOverride.AddFieldOverride(osFieldName,
     137             :                                                                 oFieldOverride);
     138             :                             }
     139             :                             else
     140             :                             {
     141           0 :                                 CPLError(CE_Failure, CPLE_AppDefined,
     142             :                                          "Field %s has no valid overrides "
     143             :                                          "and schemaType is not \"Full\"",
     144             :                                          osFieldName.c_str());
     145           0 :                                 return false;
     146             :                             }
     147             :                         }
     148             :                     }
     149             : 
     150          48 :                     if (oLayerOverride.IsValid())
     151             :                     {
     152          48 :                         AddLayerOverride(osLayerName, oLayerOverride);
     153             :                     }
     154             :                     else
     155             :                     {
     156           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     157             :                                  "Layer %s has no valid overrides",
     158             :                                  osLayerName.c_str());
     159           0 :                         return false;
     160             :                     }
     161             :                 }
     162             :                 else
     163             :                 {
     164           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     165             :                              "SCHEMA info is invalid JSON");
     166           0 :                     return false;
     167             :                 }
     168             :             }
     169          46 :             return true;
     170             :         }
     171             :         else
     172             :         {
     173           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     174             :                      "SCHEMA info is invalid JSON");
     175           0 :             return false;
     176             :         }
     177             :     }
     178             :     else
     179             :     {
     180           0 :         CPLError(CE_Failure, CPLE_AppDefined, "SCHEMA info is invalid JSON");
     181           0 :         return false;
     182             :     }
     183             : }
     184             : 
     185          46 : bool OGRSchemaOverride::IsValid() const
     186             : {
     187          46 :     bool isValid = !m_moLayerOverrides.empty();
     188          94 :     for (const auto &oLayerOverride : m_moLayerOverrides)
     189             :     {
     190          48 :         isValid &= oLayerOverride.second.IsValid();
     191             :     }
     192          46 :     return isValid;
     193             : }
     194             : 
     195          96 : bool OGRLayerSchemaOverride::IsValid() const
     196             : {
     197          96 :     bool isValid = !m_osLayerName.empty() && !m_moFieldOverrides.empty();
     198         216 :     for (const auto &oFieldOverride : m_moFieldOverrides)
     199             :     {
     200         120 :         isValid &= !oFieldOverride.first.empty();
     201             :         // When schemaType is "full" override we don't need to check if the field
     202             :         // overrides are valid: a list of fields to keep is enough.
     203         120 :         if (!m_bIsFullOverride)
     204             :         {
     205          96 :             isValid &= oFieldOverride.second.IsValid();
     206             :         }
     207             :     }
     208          96 :     return isValid;
     209             : }
     210             : 
     211         144 : bool OGRFieldDefnOverride::IsValid() const
     212             : {
     213         318 :     return m_osName.has_value() || m_eType.has_value() ||
     214         318 :            m_eSubType.has_value() || m_nWidth.has_value() ||
     215         144 :            m_nPrecision.has_value();
     216             : }
     217             : 
     218             : //! @endcond

Generated by: LCOV version 1.14