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