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 : #ifndef OGR_SCHEMA_OVERRIDE_H_INCLUDED 13 : #define OGR_SCHEMA_OVERRIDE_H_INCLUDED 14 : 15 : //! @cond Doxygen_Suppress 16 : 17 : #include <functional> 18 : #include <string> 19 : #include <map> 20 : #include <optional> 21 : #include <ogr_api.h> 22 : #include <ogr_feature.h> 23 : #include <cpl_vsi.h> 24 : #include <cpl_json.h> 25 : 26 : /** Class that holds the schema override options for a single field */ 27 : class CPL_DLL OGRFieldDefnOverride 28 : { 29 : public: 30 169 : OGRFieldDefnOverride() = default; 31 : 32 9 : void SetFieldName(const std::string &osName) 33 : { 34 9 : m_osName = osName; 35 9 : } 36 : 37 2 : void SetSrcFieldType(OGRFieldType eType) 38 : { 39 2 : m_eSrcType = eType; 40 2 : } 41 : 42 1 : void SetSrcFieldSubType(OGRFieldSubType eSubType) 43 : { 44 1 : m_eSrcSubType = eSubType; 45 1 : } 46 : 47 59 : void SetFieldType(OGRFieldType eType) 48 : { 49 59 : m_eType = eType; 50 59 : } 51 : 52 23 : void SetFieldSubType(OGRFieldSubType eSubType) 53 : { 54 23 : m_eSubType = eSubType; 55 23 : } 56 : 57 5 : void SetFieldWidth(int nWidth) 58 : { 59 5 : m_nWidth = nWidth; 60 5 : } 61 : 62 5 : void SetFieldPrecision(int nPrecision) 63 : { 64 5 : m_nPrecision = nPrecision; 65 5 : } 66 : 67 13 : void SetNullable(bool bNullable) 68 : { 69 13 : m_bNullable = bNullable; 70 13 : } 71 : 72 13 : void SetUnique(bool bUnique) 73 : { 74 13 : m_bUnique = bUnique; 75 13 : } 76 : 77 0 : void SetComment(const std::string &osComment) 78 : { 79 0 : m_osComment = osComment; 80 0 : } 81 : 82 0 : void SetAlias(const std::string &osAlias) 83 : { 84 0 : m_osAlias = osAlias; 85 0 : } 86 : 87 2 : void SetTimezone(const std::string &osTimezone) 88 : { 89 2 : m_osTimezone = osTimezone; 90 2 : } 91 : 92 0 : void SetDomainName(const std::string &osDomainName) 93 : { 94 0 : m_osDomainName = osDomainName; 95 0 : } 96 : 97 0 : void SetDefaultValue(const std::string &osDefaultValue) 98 : { 99 0 : m_osDefaultValue = osDefaultValue; 100 0 : } 101 : 102 61 : std::optional<std::string> GetFieldName() const 103 : { 104 61 : return m_osName; 105 : } 106 : 107 22 : std::optional<OGRFieldType> GetSrcFieldType() const 108 : { 109 22 : return m_eSrcType; 110 : } 111 : 112 7 : std::optional<OGRFieldSubType> GetSrcFieldSubType() const 113 : { 114 7 : return m_eSrcSubType; 115 : } 116 : 117 84 : std::optional<OGRFieldType> GetFieldType() const 118 : { 119 84 : return m_eType; 120 : } 121 : 122 89 : std::optional<OGRFieldSubType> GetFieldSubType() const 123 : { 124 89 : return m_eSubType; 125 : } 126 : 127 59 : std::optional<int> GetFieldWidth() const 128 : { 129 59 : return m_nWidth; 130 : } 131 : 132 59 : std::optional<int> GetFieldPrecision() const 133 : { 134 59 : return m_nPrecision; 135 : } 136 : 137 : std::optional<int> GetNullable() const 138 : { 139 : return m_bNullable; 140 : } 141 : 142 : std::optional<int> GetUnique() const 143 : { 144 : return m_bUnique; 145 : } 146 : 147 : std::optional<std::string> GetComment() const 148 : { 149 : return m_osComment; 150 : } 151 : 152 : std::optional<std::string> GetAlias() const 153 : { 154 : return m_osAlias; 155 : } 156 : 157 : std::optional<std::string> GetTimezone() const 158 : { 159 : return m_osTimezone; 160 : } 161 : 162 : std::optional<std::string> GetDomainName() const 163 : { 164 : return m_osDomainName; 165 : } 166 : 167 : // Considered valid if it carries any change information, otherwise it's considered a no-op 168 : bool IsValid() const; 169 : 170 : /** 171 : * Build an OGRFieldDefn based on the override information. 172 : * \a osDefaultName is used as field name if the override doesn't specify one. 173 : */ 174 : OGRFieldDefn ToFieldDefn(const std::string &osDefaultName) const; 175 : 176 : private: 177 : std::optional<std::string> m_osName{}; 178 : std::optional<OGRFieldType> m_eSrcType{}; 179 : std::optional<OGRFieldSubType> m_eSrcSubType{}; 180 : std::optional<OGRFieldType> m_eType{}; 181 : std::optional<OGRFieldSubType> m_eSubType{}; 182 : std::optional<int> m_nWidth{}; 183 : std::optional<int> m_nPrecision{}; 184 : std::optional<bool> m_bUnique{}; 185 : std::optional<bool> m_bNullable{}; 186 : std::optional<std::string> m_osComment{}; 187 : std::optional<std::string> m_osAlias{}; 188 : std::optional<std::string> m_osTimezone{}; 189 : std::optional<std::string> m_osDomainName{}; 190 : std::optional<std::string> m_osDefaultValue{}; 191 : }; 192 : 193 : /** 194 : * Class that holds the schema override options for a single geometry field 195 : */ 196 : class CPL_DLL OGRGeomFieldDefnOverride 197 : { 198 : public: 199 16 : OGRGeomFieldDefnOverride() = default; 200 : 201 16 : void SetFieldName(const std::string &osName) 202 : { 203 16 : m_osName = osName; 204 16 : } 205 : 206 16 : void SetGeometryType(OGRwkbGeometryType eType) 207 : { 208 16 : m_eType = eType; 209 16 : } 210 : 211 15 : void SetSRS(const OGRSpatialReference &oSRS) 212 : { 213 15 : m_oSRS = oSRS; 214 15 : } 215 : 216 : void SetNullable(bool bNullable) 217 : { 218 : m_bNullable = bNullable; 219 : } 220 : 221 : std::optional<std::string> GetFieldName() const 222 : { 223 : return m_osName; 224 : } 225 : 226 : std::optional<OGRwkbGeometryType> GetGeometryType() const 227 : { 228 : return m_eType; 229 : } 230 : 231 : std::optional<OGRSpatialReference> GetSRS() const 232 : { 233 : return m_oSRS; 234 : } 235 : 236 : std::optional<bool> GetNullable() const 237 : { 238 : return m_bNullable; 239 : } 240 : 241 : /** 242 : * Build an OGRGeometryFieldDefn based on the override information. 243 : * \a osDefaultName is used as field name if the override doesn't specify one. 244 : * If the override doesn't specify a type, wkbUnknown is used as default type. 245 : */ 246 : OGRGeomFieldDefn 247 : ToGeometryFieldDefn(const std::string &osDefaultName) const; 248 : 249 : private: 250 : std::optional<bool> m_bNullable{}; 251 : std::optional<std::string> m_osName{}; 252 : std::optional<OGRwkbGeometryType> m_eType{}; 253 : std::optional<OGRSpatialReference> m_oSRS{}; 254 : }; 255 : 256 : /** Class that holds the schema override options for a single layer */ 257 : class CPL_DLL OGRLayerSchemaOverride 258 : { 259 : public: 260 77 : OGRLayerSchemaOverride() = default; 261 : 262 : void SetLayerName(const std::string &osLayerName); 263 : 264 : void SetFIDColumnName(const std::string &osFIDColumnName); 265 : 266 : void AddNamedFieldOverride(const std::string &osFieldName, 267 : const OGRFieldDefnOverride &oFieldOverride); 268 : 269 : void AddUnnamedFieldOverride(const OGRFieldDefnOverride &oFieldOverride); 270 : 271 : const std::string &GetLayerName() const; 272 : 273 : const std::string &GetFIDColumnName() const; 274 : 275 : const std::map<std::string, OGRFieldDefnOverride> & 276 : GetNamedFieldOverrides() const; 277 : 278 : const std::vector<OGRFieldDefnOverride> &GetUnnamedFieldOverrides() const; 279 : 280 : void AddGeometryFieldOverride( 281 : const OGRGeomFieldDefnOverride &oGeomFieldOverride); 282 : 283 : const std::vector<OGRGeomFieldDefnOverride> & 284 : GetGeometryFieldOverrides() const; 285 : 286 : std::vector<OGRFieldDefn> GetFieldDefinitions() const; 287 : 288 : std::vector<OGRGeomFieldDefn> GetGeomFieldDefinitions() const; 289 : 290 : bool IsFullOverride() const; 291 : 292 : void SetFullOverride(bool bIsFullOverride); 293 : 294 : bool IsValid() const; 295 : 296 : bool empty() const; 297 : 298 : private: 299 : std::string m_osLayerName{}; 300 : std::string m_osFIDColumnName{}; 301 : std::map<std::string, OGRFieldDefnOverride> m_oNamedFieldOverrides{}; 302 : std::vector<OGRFieldDefnOverride> m_aoUnnamedFieldOverrides{}; 303 : std::vector<OGRGeomFieldDefnOverride> m_aoGeomFieldOverrides{}; 304 : bool m_bIsFullOverride = false; 305 : }; 306 : 307 : class GDALDataset; 308 : 309 : /** Class that holds the schema override options for a datasource */ 310 : class CPL_DLL OGRSchemaOverride 311 : { 312 : public: 313 92 : OGRSchemaOverride() = default; 314 : 315 : void AddLayerOverride(const OGRLayerSchemaOverride &oLayerOverride); 316 : 317 : /** 318 : * Load an override schema from JSON string that follows OGR_SCHEMA specification. 319 : * @param osJSON JSON string 320 : * @param bAllowGeometryFields Whether to allow a geometry fields in the JSON (normally not overridable but allowed if the schema is applied to a dataset that doesn't have any geometry field, so that it can be used to create a geometry field in that case) 321 : * @return TRUE if the JSON was successfully parsed and the schema override is valid, FALSE otherwise 322 : */ 323 : bool LoadFromJSON(const std::string &osJSON, 324 : bool bAllowGeometryFields = false); 325 : 326 : const std::vector<OGRLayerSchemaOverride> &GetLayerOverrides() const; 327 : 328 : bool IsValid() const; 329 : 330 : /** 331 : * Default implementation to apply the overrides to a dataset 332 : * \note geometry fields are ignored (not overridable) 333 : */ 334 : bool DefaultApply( 335 : GDALDataset *poDS, const char *pszDebugKey, 336 : std::function<void(OGRLayer *, int)> callbackWhenRemovingField = 337 12 : [](OGRLayer *, int) {}) const; 338 : 339 : const OGRLayerSchemaOverride & 340 : GetLayerOverride(const std::string &osLayerName) const; 341 : 342 : private: 343 : std::vector<OGRLayerSchemaOverride> m_aoLayerOverrides{}; 344 : }; 345 : 346 : //! @endcond 347 : 348 : #endif /* ndef OGR_FEATURE_H_INCLUDED */