Add more fine-grained control of what to include when converting

features to JSON
This commit is contained in:
Nyall Dawson 2022-07-18 13:28:46 +10:00
parent 78277e2b0e
commit fe7407b29c
6 changed files with 92 additions and 9 deletions

View File

@ -38,6 +38,20 @@ Sets the time ``zone`` for datetime values.
Returns the time zone for datetime values.
.. seealso:: :py:func:`setTimeZone`
%End
void setObjectIdFieldName( const QString &name );
%Docstring
Sets the name of the objectId field.
.. seealso:: :py:func:`objectIdFieldName`
%End
QString objectIdFieldName() const;
%Docstring
Returns the name of the objectId field.
.. seealso:: :py:func:`setObjectIdFieldName`
%End
};
@ -55,6 +69,9 @@ Utility functions for working with ArcGIS REST services.
%TypeHeaderCode
#include "qgsarcgisrestutils.h"
%End
public:
static const QMetaObject staticMetaObject;
public:
static QVariant::Type convertFieldType( const QString &type );
@ -151,10 +168,19 @@ Returns an empty map if the ``crs`` is not valid.
.. versionadded:: 3.28
%End
enum class FeatureToJsonFlag
{
IncludeGeometry,
IncludeNonObjectIdAttributes,
};
typedef QFlags<QgsArcGisRestUtils::FeatureToJsonFlag> FeatureToJsonFlags;
static QVariantMap featureToJson( const QgsFeature &feature,
const QgsArcGisRestContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem(),
bool includeGeometry = true );
QgsArcGisRestUtils::FeatureToJsonFlags flags = QgsArcGisRestUtils::FeatureToJsonFlags( static_cast< int >( QgsArcGisRestUtils::FeatureToJsonFlag::IncludeGeometry ) | static_cast< int >( QgsArcGisRestUtils::FeatureToJsonFlag::IncludeNonObjectIdAttributes ) ) );
%Docstring
Converts a ``feature`` to an ArcGIS REST JSON representation.
@ -170,6 +196,9 @@ Converts a variant to a REST attribute value.
};
QFlags<QgsArcGisRestUtils::FeatureToJsonFlag> operator|(QgsArcGisRestUtils::FeatureToJsonFlag f1, QFlags<QgsArcGisRestUtils::FeatureToJsonFlag> f2);
/************************************************************************
* This file has been generated automatically from *
* *

View File

@ -1451,10 +1451,10 @@ QVariantMap QgsArcGisRestUtils::crsToJson( const QgsCoordinateReferenceSystem &c
return res;
}
QVariantMap QgsArcGisRestUtils::featureToJson( const QgsFeature &feature, const QgsArcGisRestContext &context, const QgsCoordinateReferenceSystem &crs, bool includeGeometry )
QVariantMap QgsArcGisRestUtils::featureToJson( const QgsFeature &feature, const QgsArcGisRestContext &context, const QgsCoordinateReferenceSystem &crs, QgsArcGisRestUtils::FeatureToJsonFlags flags )
{
QVariantMap res;
if ( includeGeometry && feature.hasGeometry() )
if ( ( flags & FeatureToJsonFlag::IncludeGeometry ) && feature.hasGeometry() )
{
res.insert( QStringLiteral( "geometry" ), geometryToJson( feature.geometry(), context, crs ) );
}
@ -1463,7 +1463,8 @@ QVariantMap QgsArcGisRestUtils::featureToJson( const QgsFeature &feature, const
const QgsFields fields = feature.fields();
for ( const QgsField &field : fields )
{
attributes.insert( field.name(), variantToAttributeValue( feature.attribute( field.name() ), field.type(), context ) );
if ( ( flags & FeatureToJsonFlag::IncludeNonObjectIdAttributes ) || field.name() == context.objectIdFieldName() )
attributes.insert( field.name(), variantToAttributeValue( feature.attribute( field.name() ), field.type(), context ) );
}
if ( !attributes.isEmpty() )
{

View File

@ -79,10 +79,26 @@ class CORE_EXPORT QgsArcGisRestContext
*/
QTimeZone timeZone() const { return mTimeZone; }
/**
* Sets the name of the objectId field.
*
* \see objectIdFieldName()
*/
void setObjectIdFieldName( const QString &name ) { mObjectIdFieldName = name; }
/**
* Returns the name of the objectId field.
*
* \see setObjectIdFieldName()
*/
QString objectIdFieldName() const { return mObjectIdFieldName; }
private:
QTimeZone mTimeZone;
QString mObjectIdFieldName;
};
/**
@ -95,6 +111,8 @@ class CORE_EXPORT QgsArcGisRestContext
*/
class CORE_EXPORT QgsArcGisRestUtils
{
Q_GADGET
public:
/**
@ -191,6 +209,26 @@ class CORE_EXPORT QgsArcGisRestUtils
*/
static QVariantMap crsToJson( const QgsCoordinateReferenceSystem &crs );
/**
* Flags which control the behavior of converting features to JSON.
*
* \since QGIS 3.28
*/
enum class FeatureToJsonFlag : int
{
IncludeGeometry = 1 << 0, //!< Whether to include the geometry definition
IncludeNonObjectIdAttributes = 1 << 1, //!< Whether to include any non-objectId attributes
};
Q_ENUM( FeatureToJsonFlag );
/**
* Flags which control the behavior of converting features to JSON.
*
* \since QGIS 3.28
*/
Q_DECLARE_FLAGS( FeatureToJsonFlags, FeatureToJsonFlag )
Q_FLAG( FeatureToJsonFlags )
/**
* Converts a \a feature to an ArcGIS REST JSON representation.
*
@ -199,7 +237,7 @@ class CORE_EXPORT QgsArcGisRestUtils
static QVariantMap featureToJson( const QgsFeature &feature,
const QgsArcGisRestContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem(),
bool includeGeometry = true );
QgsArcGisRestUtils::FeatureToJsonFlags flags = QgsArcGisRestUtils::FeatureToJsonFlags( static_cast< int >( QgsArcGisRestUtils::FeatureToJsonFlag::IncludeGeometry ) | static_cast< int >( QgsArcGisRestUtils::FeatureToJsonFlag::IncludeNonObjectIdAttributes ) ) );
/**
* Converts a variant to a REST attribute value.
@ -278,4 +316,6 @@ class CORE_EXPORT QgsArcGisRestUtils
friend class TestQgsArcGisRestUtils;
};
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsArcGisRestUtils::FeatureToJsonFlags )
#endif // QGSARCGISRESTUTILS_H

View File

@ -322,18 +322,25 @@ bool QgsAfsSharedData::addFeatures( QgsFeatureList &features, QString &errorMess
return true;
}
bool QgsAfsSharedData::updateFeatures( const QgsFeatureList &features, bool includeGeometries, QString &error, QgsFeedback *feedback )
bool QgsAfsSharedData::updateFeatures( const QgsFeatureList &features, bool includeGeometries, bool includeAttributes, QString &error, QgsFeedback *feedback )
{
error.clear();
QUrl queryUrl( mDataSource.param( QStringLiteral( "url" ) ) + "/updateFeatures" );
QgsArcGisRestContext context;
context.setObjectIdFieldName( mObjectIdFieldName );
QgsArcGisRestUtils::FeatureToJsonFlags flags;
if ( includeGeometries )
flags |= QgsArcGisRestUtils::FeatureToJsonFlag::IncludeGeometry;
if ( includeAttributes )
flags |= QgsArcGisRestUtils::FeatureToJsonFlag::IncludeNonObjectIdAttributes;
QVariantList featuresJson;
featuresJson.reserve( features.size() );
for ( const QgsFeature &feature : features )
{
featuresJson.append( QgsArcGisRestUtils::featureToJson( feature, context, QgsCoordinateReferenceSystem(), includeGeometries ) );
featuresJson.append( QgsArcGisRestUtils::featureToJson( feature, context, QgsCoordinateReferenceSystem(), flags ) );
}
const QString json = QString::fromStdString( QgsJsonUtils::jsonFromVariant( featuresJson ).dump( 2 ) );

View File

@ -48,7 +48,7 @@ class QgsAfsSharedData : public QObject
bool deleteFeatures( const QgsFeatureIds &id, QString &error, QgsFeedback *feedback );
bool addFeatures( QgsFeatureList &features, QString &error, QgsFeedback *feedback );
bool updateFeatures( const QgsFeatureList &features, bool includeGeometries, QString &error, QgsFeedback *feedback );
bool updateFeatures( const QgsFeatureList &features, bool includeGeometries, bool includeAttributes, QString &error, QgsFeedback *feedback );
bool hasCachedAllFeatures() const;

View File

@ -309,7 +309,7 @@ class TestQgsArcGisRestUtils(unittest.TestCase):
'a_null_value': None},
'geometry': {'x': 1.0, 'y': 2.0}})
# without geometry
res = QgsArcGisRestUtils.featureToJson(test_feature, context, includeGeometry=False)
res = QgsArcGisRestUtils.featureToJson(test_feature, context, flags=QgsArcGisRestUtils.FeatureToJsonFlags(QgsArcGisRestUtils.FeatureToJsonFlag.IncludeNonObjectIdAttributes))
self.assertEqual(res, {'attributes': {'a_boolean_field': True,
'a_datetime_field': 1646395994000,
'a_date_field': 1646352000000,
@ -317,6 +317,12 @@ class TestQgsArcGisRestUtils(unittest.TestCase):
'a_int_field': 5,
'a_string_field': 'my string value',
'a_null_value': None}})
# without attributes
context.setObjectIdFieldName('a_int_field')
res = QgsArcGisRestUtils.featureToJson(test_feature, context, flags=QgsArcGisRestUtils.FeatureToJsonFlags(QgsArcGisRestUtils.FeatureToJsonFlag.IncludeGeometry))
self.assertEqual(res, {'attributes': {
'a_int_field': 5},
'geometry': {'x': 1.0, 'y': 2.0}})
if __name__ == '__main__':