mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-04 00:06:46 -05:00
[api] Add method for creating relationship to QgsAbstractDatabaseProviderConnection
and implement for OGR provider when built on GDAL >= 3.6
This commit is contained in:
parent
724bf9e970
commit
ff3048d19a
@ -357,6 +357,7 @@ This information is calculated from the geometry columns types.
|
||||
AddFieldDomain,
|
||||
RenameField,
|
||||
RetrieveRelationships,
|
||||
AddRelationship,
|
||||
};
|
||||
typedef QFlags<QgsAbstractDatabaseProviderConnection::Capability> Capabilities;
|
||||
|
||||
@ -796,6 +797,15 @@ forms the left (or "parent" / "referenced") side of the relationship are retriev
|
||||
:raises QgsProviderConnectionException: if any errors are encountered.
|
||||
|
||||
.. versionadded:: 3.28
|
||||
%End
|
||||
|
||||
virtual void addRelationship( const QgsWeakRelation &relationship ) const throw( QgsProviderConnectionException );
|
||||
%Docstring
|
||||
Adds a new field ``relationship`` to the database.
|
||||
|
||||
:raises QgsProviderConnectionException: if any errors are encountered.
|
||||
|
||||
.. versionadded:: 3.30
|
||||
%End
|
||||
|
||||
virtual QgsProviderSqlQueryBuilder *queryBuilder() const /Factory/;
|
||||
|
||||
@ -493,6 +493,10 @@ void QgsOgrProviderConnection::setDefaultCapabilities()
|
||||
{
|
||||
mCapabilities |= Capability::RetrieveRelationships;
|
||||
}
|
||||
if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE_RELATIONSHIP, false ) )
|
||||
{
|
||||
mCapabilities |= Capability::AddRelationship;
|
||||
}
|
||||
#endif
|
||||
|
||||
mSqlLayerDefinitionCapabilities =
|
||||
@ -936,9 +940,6 @@ QList<QgsWeakRelation> QgsOgrProviderConnection::relationships( const QString &s
|
||||
const QStringList names = QgsOgrUtils::cStringListToQStringList( relationNames );
|
||||
CSLDestroy( relationNames );
|
||||
|
||||
QgsProviderMetadata *ogrProviderMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) );
|
||||
const QVariantMap datasetUriParts = ogrProviderMetadata->decodeUri( uri() );
|
||||
|
||||
for ( const QString &name : names )
|
||||
{
|
||||
GDALRelationshipH relationship = GDALDatasetGetRelationship( hDS.get(), name.toUtf8().constData() );
|
||||
@ -949,124 +950,11 @@ QList<QgsWeakRelation> QgsOgrProviderConnection::relationships( const QString &s
|
||||
if ( !tableName.isEmpty() && leftTableName != tableName )
|
||||
continue;
|
||||
|
||||
QVariantMap leftTableUriParts = datasetUriParts;
|
||||
leftTableUriParts.insert( QStringLiteral( "layerName" ), leftTableName );
|
||||
const QString leftTableSource = ogrProviderMetadata->encodeUri( leftTableUriParts );
|
||||
|
||||
const QString rightTableName( GDALRelationshipGetRightTableName( relationship ) );
|
||||
if ( rightTableName.isEmpty() )
|
||||
continue;
|
||||
QVariantMap rightTableUriParts = datasetUriParts;
|
||||
rightTableUriParts.insert( QStringLiteral( "layerName" ), rightTableName );
|
||||
const QString rightTableSource = ogrProviderMetadata->encodeUri( rightTableUriParts );
|
||||
|
||||
const QString mappingTableName( GDALRelationshipGetMappingTableName( relationship ) );
|
||||
QString mappingTableSource;
|
||||
if ( !mappingTableName.isEmpty() )
|
||||
{
|
||||
QVariantMap mappingTableUriParts = datasetUriParts;
|
||||
mappingTableUriParts.insert( QStringLiteral( "layerName" ), mappingTableName );
|
||||
mappingTableSource = ogrProviderMetadata->encodeUri( mappingTableUriParts );
|
||||
}
|
||||
|
||||
const QString relationshipName( GDALRelationshipGetName( relationship ) );
|
||||
|
||||
char **cslLeftTableFieldNames = GDALRelationshipGetLeftTableFields( relationship );
|
||||
const QStringList leftTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslLeftTableFieldNames );
|
||||
CSLDestroy( cslLeftTableFieldNames );
|
||||
|
||||
char **cslRightTableFieldNames = GDALRelationshipGetRightTableFields( relationship );
|
||||
const QStringList rightTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslRightTableFieldNames );
|
||||
CSLDestroy( cslRightTableFieldNames );
|
||||
|
||||
char **cslLeftMappingTableFieldNames = GDALRelationshipGetLeftMappingTableFields( relationship );
|
||||
const QStringList leftMappingTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslLeftMappingTableFieldNames );
|
||||
CSLDestroy( cslLeftMappingTableFieldNames );
|
||||
|
||||
char **cslRightMappingTableFieldNames = GDALRelationshipGetRightMappingTableFields( relationship );
|
||||
const QStringList rightMappingTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslRightMappingTableFieldNames );
|
||||
CSLDestroy( cslRightMappingTableFieldNames );
|
||||
|
||||
const QString forwardPathLabel( GDALRelationshipGetForwardPathLabel( relationship ) );
|
||||
const QString backwardPathLabel( GDALRelationshipGetBackwardPathLabel( relationship ) );
|
||||
const QString relatedTableType( GDALRelationshipGetRelatedTableType( relationship ) );
|
||||
|
||||
const GDALRelationshipType relationshipType = GDALRelationshipGetType( relationship );
|
||||
Qgis::RelationshipStrength strength = Qgis::RelationshipStrength::Association;
|
||||
switch ( relationshipType )
|
||||
{
|
||||
case GRT_COMPOSITE:
|
||||
strength = Qgis::RelationshipStrength::Composition;
|
||||
break;
|
||||
|
||||
case GRT_ASSOCIATION:
|
||||
strength = Qgis::RelationshipStrength::Association;
|
||||
break;
|
||||
|
||||
case GRT_AGGREGATION:
|
||||
QgsLogger::warning( "Aggregation relationships are not supported" );
|
||||
continue;
|
||||
}
|
||||
|
||||
const GDALRelationshipCardinality eCardinality = GDALRelationshipGetCardinality( relationship );
|
||||
Qgis::RelationshipCardinality cardinality = Qgis::RelationshipCardinality::OneToOne;
|
||||
switch ( eCardinality )
|
||||
{
|
||||
case GRC_ONE_TO_ONE:
|
||||
cardinality = Qgis::RelationshipCardinality::OneToOne;
|
||||
break;
|
||||
case GRC_ONE_TO_MANY:
|
||||
cardinality = Qgis::RelationshipCardinality::OneToMany;
|
||||
break;
|
||||
case GRC_MANY_TO_ONE:
|
||||
cardinality = Qgis::RelationshipCardinality::ManyToOne;
|
||||
break;
|
||||
case GRC_MANY_TO_MANY:
|
||||
cardinality = Qgis::RelationshipCardinality::ManyToMany;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( cardinality )
|
||||
{
|
||||
case Qgis::RelationshipCardinality::OneToOne:
|
||||
case Qgis::RelationshipCardinality::OneToMany:
|
||||
case Qgis::RelationshipCardinality::ManyToOne:
|
||||
{
|
||||
QgsWeakRelation rel( relationshipName,
|
||||
relationshipName,
|
||||
strength,
|
||||
QString(), QString(), rightTableSource, QStringLiteral( "ogr" ),
|
||||
QString(), QString(), leftTableSource, QStringLiteral( "ogr" ) );
|
||||
rel.setCardinality( cardinality );
|
||||
rel.setForwardPathLabel( forwardPathLabel );
|
||||
rel.setBackwardPathLabel( backwardPathLabel );
|
||||
rel.setRelatedTableType( relatedTableType );
|
||||
rel.setReferencedLayerFields( leftTableFieldNames );
|
||||
rel.setReferencingLayerFields( rightTableFieldNames );
|
||||
output.append( rel );
|
||||
break;
|
||||
}
|
||||
|
||||
case Qgis::RelationshipCardinality::ManyToMany:
|
||||
{
|
||||
QgsWeakRelation rel( relationshipName,
|
||||
relationshipName,
|
||||
strength,
|
||||
QString(), QString(), rightTableSource, QStringLiteral( "ogr" ),
|
||||
QString(), QString(), leftTableSource, QStringLiteral( "ogr" ) );
|
||||
rel.setCardinality( cardinality );
|
||||
rel.setForwardPathLabel( forwardPathLabel );
|
||||
rel.setBackwardPathLabel( backwardPathLabel );
|
||||
rel.setRelatedTableType( relatedTableType );
|
||||
rel.setMappingTable( QgsVectorLayerRef( QString(), QString(), mappingTableSource, QStringLiteral( "ogr" ) ) );
|
||||
rel.setReferencedLayerFields( leftTableFieldNames );
|
||||
rel.setMappingReferencedLayerFields( leftMappingTableFieldNames );
|
||||
rel.setReferencingLayerFields( rightTableFieldNames );
|
||||
rel.setMappingReferencingLayerFields( rightMappingTableFieldNames );
|
||||
output.append( rel );
|
||||
break;
|
||||
}
|
||||
}
|
||||
output.append( QgsOgrUtils::convertRelationship( relationship, uri() ) );
|
||||
}
|
||||
return output;
|
||||
}
|
||||
@ -1080,4 +968,49 @@ QList<QgsWeakRelation> QgsOgrProviderConnection::relationships( const QString &s
|
||||
#endif
|
||||
}
|
||||
|
||||
void QgsOgrProviderConnection::addRelationship( const QgsWeakRelation &relationship ) const
|
||||
{
|
||||
checkCapability( Capability::AddRelationship );
|
||||
|
||||
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,6,0)
|
||||
gdal::ogr_datasource_unique_ptr hDS( GDALOpenEx( uri().toUtf8().constData(), GDAL_OF_UPDATE | GDAL_OF_VECTOR, nullptr, nullptr, nullptr ) );
|
||||
if ( hDS )
|
||||
{
|
||||
const QVariantMap leftParts = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) )->decodeUri( relationship.referencedLayerSource() );
|
||||
const QString leftTableName = leftParts.value( QStringLiteral( "layerName" ) ).toString();
|
||||
if ( leftTableName.isEmpty() )
|
||||
throw QgsProviderConnectionException( QObject::tr( "Parent table name was not set" ) );
|
||||
|
||||
const QVariantMap rightParts = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) )->decodeUri( relationship.referencingLayerSource() );
|
||||
const QString rightTableName = rightParts.value( QStringLiteral( "layerName" ) ).toString();
|
||||
if ( rightTableName.isEmpty() )
|
||||
throw QgsProviderConnectionException( QObject::tr( "Child table name was not set" ) );
|
||||
|
||||
QString error;
|
||||
gdal::relationship_unique_ptr relationH = QgsOgrUtils::convertRelationship( relationship, error );
|
||||
if ( !relationH )
|
||||
{
|
||||
throw QgsProviderConnectionException( error );
|
||||
}
|
||||
|
||||
char *failureReason = nullptr;
|
||||
if ( !GDALDatasetAddRelationship( hDS.get(), relationH.get(), &failureReason ) )
|
||||
{
|
||||
QString error( failureReason );
|
||||
CPLFree( failureReason );
|
||||
throw QgsProviderConnectionException( QObject::tr( "Could not create relationship: %1" ).arg( error ) );
|
||||
}
|
||||
|
||||
CPLFree( failureReason );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QgsProviderConnectionException( QObject::tr( "There was an error opening the dataset %1!" ).arg( uri() ) );
|
||||
}
|
||||
#else
|
||||
Q_UNUSED( tableName )
|
||||
throw QgsProviderConnectionException( QObject::tr( "Adding relationships for datasets requires GDAL 3.6 or later" ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
///@endcond
|
||||
|
||||
@ -91,6 +91,7 @@ class QgsOgrProviderConnection : public QgsAbstractDatabaseProviderConnection
|
||||
void renameField( const QString &schema, const QString &tableName, const QString &name, const QString &newName ) const override;
|
||||
SqlVectorLayerOptions sqlOptions( const QString &layerSource ) override;
|
||||
QList< QgsWeakRelation > relationships( const QString &schema = QString(), const QString &tableName = QString() ) const override;
|
||||
void addRelationship( const QgsWeakRelation &relationship ) const override;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@ -1340,6 +1340,11 @@ QList< QgsWeakRelation > QgsAbstractDatabaseProviderConnection::relationships( c
|
||||
return {};
|
||||
}
|
||||
|
||||
void QgsAbstractDatabaseProviderConnection::addRelationship( const QgsWeakRelation & ) const
|
||||
{
|
||||
checkCapability( Capability::AddRelationship );
|
||||
}
|
||||
|
||||
QString QgsAbstractDatabaseProviderConnection::TableProperty::defaultName() const
|
||||
{
|
||||
QString n = mTableName;
|
||||
|
||||
@ -509,6 +509,7 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
|
||||
AddFieldDomain = 1 << 25, //!< Can add new field domains to the database via addFieldDomain() (since QGIS 3.26)
|
||||
RenameField = 1 << 26, //!< Can rename existing fields via renameField() (since QGIS 3.28)
|
||||
RetrieveRelationships = 1 << 27, //!< Can retrieve relationships from the database (since QGIS 3.28)
|
||||
AddRelationship = 1 << 28, //!< Can add new relationships to the database via addRelationship() (since QGIS 3.30)
|
||||
};
|
||||
Q_ENUM( Capability )
|
||||
Q_DECLARE_FLAGS( Capabilities, Capability )
|
||||
@ -907,6 +908,14 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
|
||||
*/
|
||||
virtual QList< QgsWeakRelation > relationships( const QString &schema = QString(), const QString &tableName = QString() ) const SIP_THROW( QgsProviderConnectionException );
|
||||
|
||||
/**
|
||||
* Adds a new field \a relationship to the database.
|
||||
*
|
||||
* \throws QgsProviderConnectionException if any errors are encountered.
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
virtual void addRelationship( const QgsWeakRelation &relationship ) const SIP_THROW( QgsProviderConnectionException );
|
||||
|
||||
/**
|
||||
* Returns a SQL query builder for the connection, which provides an interface for provider-specific creation of SQL queries.
|
||||
*
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
#include "qgslinestring.h"
|
||||
#include "qgsmultipoint.h"
|
||||
#include "qgsmultilinestring.h"
|
||||
#include "qgsogrprovider.h"
|
||||
#include "qgslinesymbollayer.h"
|
||||
#include "qgspolygon.h"
|
||||
#include "qgsmultipolygon.h"
|
||||
@ -38,6 +37,10 @@
|
||||
#include "qgsfielddomain.h"
|
||||
#include "qgsfontmanager.h"
|
||||
#include "qgsvariantutils.h"
|
||||
#include "qgsweakrelation.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgsprovidermetadata.h"
|
||||
#include "qgsogrproviderutils.h"
|
||||
|
||||
#include <QTextCodec>
|
||||
#include <QUuid>
|
||||
@ -103,6 +106,13 @@ void gdal::GDALWarpOptionsDeleter::operator()( GDALWarpOptions *options ) const
|
||||
GDALDestroyWarpOptions( options );
|
||||
}
|
||||
|
||||
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,6,0)
|
||||
void gdal::GDALRelationshipDeleter::operator()( GDALRelationshipH relationship ) const
|
||||
{
|
||||
GDALDestroyRelationship( relationship );
|
||||
}
|
||||
#endif
|
||||
|
||||
QVariant QgsOgrUtils::OGRFieldtoVariant( const OGRField *value, OGRFieldType type )
|
||||
{
|
||||
if ( !value || OGR_RawField_IsUnset( value ) || OGR_RawField_IsNull( value ) )
|
||||
@ -2200,3 +2210,287 @@ OGRFieldDomainH QgsOgrUtils::convertFieldDomain( const QgsFieldDomain *domain )
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,6,0)
|
||||
QgsWeakRelation QgsOgrUtils::convertRelationship( GDALRelationshipH relationship, const QString &datasetUri )
|
||||
{
|
||||
QgsProviderMetadata *ogrProviderMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) );
|
||||
const QVariantMap datasetUriParts = ogrProviderMetadata->decodeUri( datasetUri );
|
||||
|
||||
const QString leftTableName( GDALRelationshipGetLeftTableName( relationship ) );
|
||||
|
||||
QVariantMap leftTableUriParts = datasetUriParts;
|
||||
leftTableUriParts.insert( QStringLiteral( "layerName" ), leftTableName );
|
||||
const QString leftTableSource = ogrProviderMetadata->encodeUri( leftTableUriParts );
|
||||
|
||||
const QString rightTableName( GDALRelationshipGetRightTableName( relationship ) );
|
||||
QVariantMap rightTableUriParts = datasetUriParts;
|
||||
rightTableUriParts.insert( QStringLiteral( "layerName" ), rightTableName );
|
||||
const QString rightTableSource = ogrProviderMetadata->encodeUri( rightTableUriParts );
|
||||
|
||||
const QString mappingTableName( GDALRelationshipGetMappingTableName( relationship ) );
|
||||
QString mappingTableSource;
|
||||
if ( !mappingTableName.isEmpty() )
|
||||
{
|
||||
QVariantMap mappingTableUriParts = datasetUriParts;
|
||||
mappingTableUriParts.insert( QStringLiteral( "layerName" ), mappingTableName );
|
||||
mappingTableSource = ogrProviderMetadata->encodeUri( mappingTableUriParts );
|
||||
}
|
||||
|
||||
const QString relationshipName( GDALRelationshipGetName( relationship ) );
|
||||
|
||||
char **cslLeftTableFieldNames = GDALRelationshipGetLeftTableFields( relationship );
|
||||
const QStringList leftTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslLeftTableFieldNames );
|
||||
CSLDestroy( cslLeftTableFieldNames );
|
||||
|
||||
char **cslRightTableFieldNames = GDALRelationshipGetRightTableFields( relationship );
|
||||
const QStringList rightTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslRightTableFieldNames );
|
||||
CSLDestroy( cslRightTableFieldNames );
|
||||
|
||||
char **cslLeftMappingTableFieldNames = GDALRelationshipGetLeftMappingTableFields( relationship );
|
||||
const QStringList leftMappingTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslLeftMappingTableFieldNames );
|
||||
CSLDestroy( cslLeftMappingTableFieldNames );
|
||||
|
||||
char **cslRightMappingTableFieldNames = GDALRelationshipGetRightMappingTableFields( relationship );
|
||||
const QStringList rightMappingTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslRightMappingTableFieldNames );
|
||||
CSLDestroy( cslRightMappingTableFieldNames );
|
||||
|
||||
const QString forwardPathLabel( GDALRelationshipGetForwardPathLabel( relationship ) );
|
||||
const QString backwardPathLabel( GDALRelationshipGetBackwardPathLabel( relationship ) );
|
||||
const QString relatedTableType( GDALRelationshipGetRelatedTableType( relationship ) );
|
||||
|
||||
const GDALRelationshipType relationshipType = GDALRelationshipGetType( relationship );
|
||||
Qgis::RelationshipStrength strength = Qgis::RelationshipStrength::Association;
|
||||
switch ( relationshipType )
|
||||
{
|
||||
case GRT_COMPOSITE:
|
||||
strength = Qgis::RelationshipStrength::Composition;
|
||||
break;
|
||||
|
||||
case GRT_ASSOCIATION:
|
||||
strength = Qgis::RelationshipStrength::Association;
|
||||
break;
|
||||
|
||||
case GRT_AGGREGATION:
|
||||
QgsLogger::warning( "Aggregation relationships are not supported, treating as association instead" );
|
||||
break;
|
||||
}
|
||||
|
||||
const GDALRelationshipCardinality eCardinality = GDALRelationshipGetCardinality( relationship );
|
||||
Qgis::RelationshipCardinality cardinality = Qgis::RelationshipCardinality::OneToOne;
|
||||
switch ( eCardinality )
|
||||
{
|
||||
case GRC_ONE_TO_ONE:
|
||||
cardinality = Qgis::RelationshipCardinality::OneToOne;
|
||||
break;
|
||||
case GRC_ONE_TO_MANY:
|
||||
cardinality = Qgis::RelationshipCardinality::OneToMany;
|
||||
break;
|
||||
case GRC_MANY_TO_ONE:
|
||||
cardinality = Qgis::RelationshipCardinality::ManyToOne;
|
||||
break;
|
||||
case GRC_MANY_TO_MANY:
|
||||
cardinality = Qgis::RelationshipCardinality::ManyToMany;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( cardinality )
|
||||
{
|
||||
case Qgis::RelationshipCardinality::OneToOne:
|
||||
case Qgis::RelationshipCardinality::OneToMany:
|
||||
case Qgis::RelationshipCardinality::ManyToOne:
|
||||
{
|
||||
QgsWeakRelation rel( relationshipName,
|
||||
relationshipName,
|
||||
strength,
|
||||
QString(), QString(), rightTableSource, QStringLiteral( "ogr" ),
|
||||
QString(), QString(), leftTableSource, QStringLiteral( "ogr" ) );
|
||||
rel.setCardinality( cardinality );
|
||||
rel.setForwardPathLabel( forwardPathLabel );
|
||||
rel.setBackwardPathLabel( backwardPathLabel );
|
||||
rel.setRelatedTableType( relatedTableType );
|
||||
rel.setReferencedLayerFields( leftTableFieldNames );
|
||||
rel.setReferencingLayerFields( rightTableFieldNames );
|
||||
return rel;
|
||||
}
|
||||
|
||||
case Qgis::RelationshipCardinality::ManyToMany:
|
||||
{
|
||||
QgsWeakRelation rel( relationshipName,
|
||||
relationshipName,
|
||||
strength,
|
||||
QString(), QString(), rightTableSource, QStringLiteral( "ogr" ),
|
||||
QString(), QString(), leftTableSource, QStringLiteral( "ogr" ) );
|
||||
rel.setCardinality( cardinality );
|
||||
rel.setForwardPathLabel( forwardPathLabel );
|
||||
rel.setBackwardPathLabel( backwardPathLabel );
|
||||
rel.setRelatedTableType( relatedTableType );
|
||||
rel.setMappingTable( QgsVectorLayerRef( QString(), QString(), mappingTableSource, QStringLiteral( "ogr" ) ) );
|
||||
rel.setReferencedLayerFields( leftTableFieldNames );
|
||||
rel.setMappingReferencedLayerFields( leftMappingTableFieldNames );
|
||||
rel.setReferencingLayerFields( rightTableFieldNames );
|
||||
rel.setMappingReferencingLayerFields( rightMappingTableFieldNames );
|
||||
return rel;
|
||||
}
|
||||
}
|
||||
return QgsWeakRelation();
|
||||
}
|
||||
|
||||
gdal::relationship_unique_ptr QgsOgrUtils::convertRelationship( const QgsWeakRelation &relationship, QString &error )
|
||||
{
|
||||
GDALRelationshipCardinality gCardinality = GDALRelationshipCardinality::GRC_ONE_TO_MANY;
|
||||
switch ( relationship.cardinality() )
|
||||
{
|
||||
case Qgis::RelationshipCardinality::OneToOne:
|
||||
gCardinality = GDALRelationshipCardinality::GRC_ONE_TO_ONE;
|
||||
break;
|
||||
case Qgis::RelationshipCardinality::OneToMany:
|
||||
gCardinality = GDALRelationshipCardinality::GRC_ONE_TO_MANY;
|
||||
break;
|
||||
case Qgis::RelationshipCardinality::ManyToOne:
|
||||
gCardinality = GDALRelationshipCardinality::GRC_MANY_TO_ONE;
|
||||
break;
|
||||
case Qgis::RelationshipCardinality::ManyToMany:
|
||||
gCardinality = GDALRelationshipCardinality::GRC_MANY_TO_MANY;
|
||||
break;
|
||||
}
|
||||
|
||||
QgsProviderMetadata *ogrProviderMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) );
|
||||
|
||||
const QVariantMap leftParts = ogrProviderMetadata->decodeUri( relationship.referencedLayerSource() );
|
||||
const QString leftTableName = leftParts.value( QStringLiteral( "layerName" ) ).toString();
|
||||
if ( leftTableName.isEmpty() )
|
||||
{
|
||||
error = QObject::tr( "Parent table name was not set" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const QVariantMap rightParts = ogrProviderMetadata->decodeUri( relationship.referencingLayerSource() );
|
||||
const QString rightTableName = rightParts.value( QStringLiteral( "layerName" ) ).toString();
|
||||
if ( rightTableName.isEmpty() )
|
||||
{
|
||||
error = QObject::tr( "Child table name was not set" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( leftParts.value( QStringLiteral( "path" ) ).toString() != rightParts.value( QStringLiteral( "path" ) ).toString() )
|
||||
{
|
||||
error = QObject::tr( "Parent and child table must be from the same dataset" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString mappingTableName;
|
||||
if ( !relationship.mappingTableSource().isEmpty() )
|
||||
{
|
||||
const QVariantMap mappingParts = ogrProviderMetadata->decodeUri( relationship.mappingTableSource() );
|
||||
mappingTableName = mappingParts.value( QStringLiteral( "layerName" ) ).toString();
|
||||
if ( leftParts.value( QStringLiteral( "path" ) ).toString() != mappingParts.value( QStringLiteral( "path" ) ).toString() )
|
||||
{
|
||||
error = QObject::tr( "Parent and mapping table must be from the same dataset" );
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gdal::relationship_unique_ptr relationH( GDALRelationshipCreate( relationship.name().toLocal8Bit().constData(),
|
||||
leftTableName.toLocal8Bit().constData(),
|
||||
rightTableName.toLocal8Bit().constData(),
|
||||
gCardinality ) );
|
||||
|
||||
// set left table fields
|
||||
const QStringList leftFieldNames = relationship.referencedLayerFields();
|
||||
int count = leftFieldNames.count();
|
||||
char **lst = new char *[count + 1];
|
||||
if ( count > 0 )
|
||||
{
|
||||
int pos = 0;
|
||||
for ( const QString &string : leftFieldNames )
|
||||
{
|
||||
lst[pos] = CPLStrdup( string.toLocal8Bit().constData() );
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
lst[count] = nullptr;
|
||||
GDALRelationshipSetLeftTableFields( relationH.get(), lst );
|
||||
CSLDestroy( lst );
|
||||
|
||||
// set right table fields
|
||||
const QStringList rightFieldNames = relationship.referencingLayerFields();
|
||||
count = rightFieldNames.count();
|
||||
lst = new char *[count + 1];
|
||||
if ( count > 0 )
|
||||
{
|
||||
int pos = 0;
|
||||
for ( const QString &string : rightFieldNames )
|
||||
{
|
||||
lst[pos] = CPLStrdup( string.toLocal8Bit().constData() );
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
lst[count] = nullptr;
|
||||
GDALRelationshipSetRightTableFields( relationH.get(), lst );
|
||||
CSLDestroy( lst );
|
||||
|
||||
if ( !mappingTableName.isEmpty() )
|
||||
{
|
||||
GDALRelationshipSetMappingTableName( relationH.get(), mappingTableName.toLocal8Bit().constData() );
|
||||
|
||||
// set left mapping table fields
|
||||
const QStringList leftFieldNames = relationship.mappingReferencedLayerFields();
|
||||
int count = leftFieldNames.count();
|
||||
char **lst = new char *[count + 1];
|
||||
if ( count > 0 )
|
||||
{
|
||||
int pos = 0;
|
||||
for ( const QString &string : leftFieldNames )
|
||||
{
|
||||
lst[pos] = CPLStrdup( string.toLocal8Bit().constData() );
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
lst[count] = nullptr;
|
||||
GDALRelationshipSetLeftMappingTableFields( relationH.get(), lst );
|
||||
CSLDestroy( lst );
|
||||
|
||||
// set right table fields
|
||||
const QStringList rightFieldNames = relationship.mappingReferencingLayerFields();
|
||||
count = rightFieldNames.count();
|
||||
lst = new char *[count + 1];
|
||||
if ( count > 0 )
|
||||
{
|
||||
int pos = 0;
|
||||
for ( const QString &string : rightFieldNames )
|
||||
{
|
||||
lst[pos] = CPLStrdup( string.toLocal8Bit().constData() );
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
lst[count] = nullptr;
|
||||
GDALRelationshipSetRightMappingTableFields( relationH.get(), lst );
|
||||
CSLDestroy( lst );
|
||||
}
|
||||
|
||||
// set type
|
||||
switch ( relationship.strength() )
|
||||
{
|
||||
case Qgis::RelationshipStrength::Association:
|
||||
GDALRelationshipSetType( relationH.get(), GDALRelationshipType::GRT_ASSOCIATION );
|
||||
break;
|
||||
|
||||
case Qgis::RelationshipStrength::Composition:
|
||||
GDALRelationshipSetType( relationH.get(), GDALRelationshipType::GRT_COMPOSITE );
|
||||
break;
|
||||
}
|
||||
|
||||
// set labels
|
||||
if ( !relationship.forwardPathLabel().isEmpty() )
|
||||
GDALRelationshipSetForwardPathLabel( relationH.get(), relationship.forwardPathLabel().toLocal8Bit().constData() );
|
||||
if ( !relationship.backwardPathLabel().isEmpty() )
|
||||
GDALRelationshipSetBackwardPathLabel( relationH.get(), relationship.backwardPathLabel().toLocal8Bit().constData() );
|
||||
|
||||
// set table type
|
||||
if ( !relationship.relatedTableType().isEmpty() )
|
||||
GDALRelationshipSetRelatedTableType( relationH.get(), relationship.relatedTableType().toLocal8Bit().constData() );
|
||||
|
||||
return relationH;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -32,6 +32,7 @@ class QgsCoordinateReferenceSystem;
|
||||
class QgsFieldDomain;
|
||||
|
||||
class QTextCodec;
|
||||
class QgsWeakRelation;
|
||||
|
||||
namespace gdal
|
||||
{
|
||||
@ -114,6 +115,22 @@ namespace gdal
|
||||
|
||||
};
|
||||
|
||||
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,6,0)
|
||||
|
||||
/**
|
||||
* Closes and cleanups GDAL relationship.
|
||||
*/
|
||||
struct GDALRelationshipDeleter
|
||||
{
|
||||
|
||||
/**
|
||||
* Destroys GDAL \a relationship, using the correct gdal calls.
|
||||
*/
|
||||
void CORE_EXPORT operator()( GDALRelationshipH relationship ) const;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Scoped OGR data source.
|
||||
*/
|
||||
@ -153,6 +170,14 @@ namespace gdal
|
||||
* Scoped GDAL warp options.
|
||||
*/
|
||||
using warp_options_unique_ptr = std::unique_ptr< GDALWarpOptions, GDALWarpOptionsDeleter >;
|
||||
|
||||
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,6,0)
|
||||
|
||||
/**
|
||||
* Scoped GDAL relationship.
|
||||
*/
|
||||
using relationship_unique_ptr = std::unique_ptr< std::remove_pointer<GDALRelationshipH>::type, GDALRelationshipDeleter >;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@ -426,6 +451,30 @@ class CORE_EXPORT QgsOgrUtils
|
||||
static OGRFieldDomainH convertFieldDomain( const QgsFieldDomain *domain );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SIP_RUN
|
||||
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,6,0)
|
||||
|
||||
/**
|
||||
* Converts an GDAL \a relationship definition to a QgsWeakRelation equivalent.
|
||||
*
|
||||
* \note Requires GDAL >= 3.6
|
||||
* \note Not available in Python bindings
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
static QgsWeakRelation convertRelationship( GDALRelationshipH relationship, const QString &datasetUri );
|
||||
|
||||
/**
|
||||
* Converts a QGIS relation to a GDAL relationship equivalent.
|
||||
*
|
||||
* \note Requires GDAL >= 3.6
|
||||
* \note Not available in Python bindings
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
static gdal::relationship_unique_ptr convertRelationship( const QgsWeakRelation &relation, QString &error );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSOGRUTILS_H
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
#include "qgsfontutils.h"
|
||||
#include "qgssymbol.h"
|
||||
#include "qgsfielddomain.h"
|
||||
#include "qgsweakrelation.h"
|
||||
|
||||
class TestQgsOgrUtils: public QObject
|
||||
{
|
||||
@ -78,6 +79,11 @@ class TestQgsOgrUtils: public QObject
|
||||
void testConvertToFieldDomain();
|
||||
#endif
|
||||
|
||||
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,6,0)
|
||||
void testConvertGdalRelationship();
|
||||
void testConvertToGdalRelationship();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
QString mTestDataDir;
|
||||
@ -1133,5 +1139,203 @@ void TestQgsOgrUtils::testConvertToFieldDomain()
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,6,0)
|
||||
void TestQgsOgrUtils::testConvertGdalRelationship()
|
||||
{
|
||||
gdal::relationship_unique_ptr relationH( GDALRelationshipCreate( "relation_name",
|
||||
"left_table",
|
||||
"right_table",
|
||||
GDALRelationshipCardinality::GRC_ONE_TO_ONE ) );
|
||||
|
||||
QgsWeakRelation rel = QgsOgrUtils::convertRelationship( relationH.get(), QStringLiteral( "/some_data.gdb" ) );
|
||||
QCOMPARE( rel.name(), QStringLiteral( "relation_name" ) );
|
||||
QCOMPARE( rel.referencedLayerSource(), QStringLiteral( "/some_data.gdb|layername=left_table" ) );
|
||||
QCOMPARE( rel.referencingLayerSource(), QStringLiteral( "/some_data.gdb|layername=right_table" ) );
|
||||
QCOMPARE( rel.cardinality(), Qgis::RelationshipCardinality::OneToOne );
|
||||
|
||||
relationH.reset( GDALRelationshipCreate( "relation_name",
|
||||
"left_table",
|
||||
"right_table",
|
||||
GDALRelationshipCardinality::GRC_ONE_TO_MANY ) );
|
||||
rel = QgsOgrUtils::convertRelationship( relationH.get(), QStringLiteral( "/some_data.gdb" ) );
|
||||
QCOMPARE( rel.cardinality(), Qgis::RelationshipCardinality::OneToMany );
|
||||
|
||||
relationH.reset( GDALRelationshipCreate( "relation_name",
|
||||
"left_table",
|
||||
"right_table",
|
||||
GDALRelationshipCardinality::GRC_MANY_TO_ONE ) );
|
||||
rel = QgsOgrUtils::convertRelationship( relationH.get(), QStringLiteral( "/some_data.gdb" ) );
|
||||
QCOMPARE( rel.cardinality(), Qgis::RelationshipCardinality::ManyToOne );
|
||||
|
||||
relationH.reset( GDALRelationshipCreate( "relation_name",
|
||||
"left_table",
|
||||
"right_table",
|
||||
GDALRelationshipCardinality::GRC_MANY_TO_MANY ) );
|
||||
rel = QgsOgrUtils::convertRelationship( relationH.get(), QStringLiteral( "/some_data.gdb" ) );
|
||||
QCOMPARE( rel.cardinality(), Qgis::RelationshipCardinality::ManyToMany );
|
||||
|
||||
const char *const fieldsLeft[] {"fielda", "fieldb", nullptr};
|
||||
GDALRelationshipSetLeftTableFields( relationH.get(), fieldsLeft );
|
||||
|
||||
const char *const fieldsRight[] {"fieldc", "fieldd", nullptr};
|
||||
GDALRelationshipSetRightTableFields( relationH.get(), fieldsRight );
|
||||
|
||||
rel = QgsOgrUtils::convertRelationship( relationH.get(), QStringLiteral( "/some_data.gdb" ) );
|
||||
QCOMPARE( rel.referencedLayerFields(), QStringList() << QStringLiteral( "fielda" ) << QStringLiteral( "fieldb" ) );
|
||||
QCOMPARE( rel.referencingLayerFields(), QStringList() << QStringLiteral( "fieldc" ) << QStringLiteral( "fieldd" ) );
|
||||
|
||||
QCOMPARE( rel.mappingTableSource(), QString() );
|
||||
|
||||
GDALRelationshipSetMappingTableName( relationH.get(), "mapping_table" );
|
||||
|
||||
const char *const mappingFieldsLeft[] {"fieldd", "fielde", nullptr};
|
||||
GDALRelationshipSetLeftMappingTableFields( relationH.get(), mappingFieldsLeft );
|
||||
|
||||
const char *const mappingFieldsRight[] {"fieldf", "fieldg", nullptr};
|
||||
GDALRelationshipSetRightMappingTableFields( relationH.get(), mappingFieldsRight );
|
||||
|
||||
rel = QgsOgrUtils::convertRelationship( relationH.get(), QStringLiteral( "/some_data.gdb" ) );
|
||||
QCOMPARE( rel.mappingTableSource(), QStringLiteral( "/some_data.gdb|layername=mapping_table" ) );
|
||||
QCOMPARE( rel.referencedLayerFields(), QStringList() << QStringLiteral( "fielda" ) << QStringLiteral( "fieldb" ) );
|
||||
QCOMPARE( rel.referencingLayerFields(), QStringList() << QStringLiteral( "fieldc" ) << QStringLiteral( "fieldd" ) );
|
||||
QCOMPARE( rel.mappingReferencedLayerFields(), QStringList() << QStringLiteral( "fieldd" ) << QStringLiteral( "fielde" ) );
|
||||
QCOMPARE( rel.mappingReferencingLayerFields(), QStringList() << QStringLiteral( "fieldf" ) << QStringLiteral( "fieldg" ) );
|
||||
|
||||
GDALRelationshipSetType( relationH.get(), GRT_COMPOSITE );
|
||||
rel = QgsOgrUtils::convertRelationship( relationH.get(), QStringLiteral( "/some_data.gdb" ) );
|
||||
QCOMPARE( rel.strength(), Qgis::RelationshipStrength::Composition );
|
||||
GDALRelationshipSetType( relationH.get(), GRT_ASSOCIATION );
|
||||
rel = QgsOgrUtils::convertRelationship( relationH.get(), QStringLiteral( "/some_data.gdb" ) );
|
||||
QCOMPARE( rel.strength(), Qgis::RelationshipStrength::Association );
|
||||
|
||||
GDALRelationshipSetForwardPathLabel( relationH.get(), "forward label" );
|
||||
GDALRelationshipSetBackwardPathLabel( relationH.get(), "backward label" );
|
||||
rel = QgsOgrUtils::convertRelationship( relationH.get(), QStringLiteral( "/some_data.gdb" ) );
|
||||
QCOMPARE( rel.forwardPathLabel(), QStringLiteral( "forward label" ) );
|
||||
QCOMPARE( rel.backwardPathLabel(), QStringLiteral( "backward label" ) );
|
||||
|
||||
GDALRelationshipSetRelatedTableType( relationH.get(), "table_type" );
|
||||
rel = QgsOgrUtils::convertRelationship( relationH.get(), QStringLiteral( "/some_data.gdb" ) );
|
||||
QCOMPARE( rel.relatedTableType(), QStringLiteral( "table_type" ) );
|
||||
}
|
||||
|
||||
void TestQgsOgrUtils::testConvertToGdalRelationship()
|
||||
{
|
||||
QgsWeakRelation rel( QStringLiteral( "id" ), QStringLiteral( "name" ),
|
||||
Qgis::RelationshipStrength::Association,
|
||||
QStringLiteral( "referencing_layer_id" ),
|
||||
QStringLiteral( "referencing_layer_name" ),
|
||||
QStringLiteral( "/some_data.gdb|layername=referencing" ),
|
||||
QStringLiteral( "ogr" ),
|
||||
QStringLiteral( "referenced_layer_id" ),
|
||||
QStringLiteral( "referenced_layer_name" ),
|
||||
QStringLiteral( "/some_data.gdb|layername=referenced" ),
|
||||
QStringLiteral( "ogr" ) );
|
||||
rel.setReferencedLayerFields( QStringList() << QStringLiteral( "fielda" ) << QStringLiteral( "fieldb" ) );
|
||||
rel.setReferencingLayerFields( QStringList() << QStringLiteral( "fieldc" ) << QStringLiteral( "fieldd" ) );
|
||||
rel.setCardinality( Qgis::RelationshipCardinality::OneToMany );
|
||||
|
||||
QString error;
|
||||
gdal::relationship_unique_ptr relationH = QgsOgrUtils::convertRelationship( rel, error );
|
||||
|
||||
QCOMPARE( QString( GDALRelationshipGetName( relationH.get() ) ), QStringLiteral( "name" ) );
|
||||
QCOMPARE( QString( GDALRelationshipGetLeftTableName( relationH.get() ) ), QStringLiteral( "referenced" ) );
|
||||
QCOMPARE( QString( GDALRelationshipGetRightTableName( relationH.get() ) ), QStringLiteral( "referencing" ) );
|
||||
|
||||
char **cslLeftTableFieldNames = GDALRelationshipGetLeftTableFields( relationH.get() );
|
||||
const QStringList leftTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslLeftTableFieldNames );
|
||||
CSLDestroy( cslLeftTableFieldNames );
|
||||
QCOMPARE( leftTableFieldNames, QStringList() << QStringLiteral( "fielda" ) << QStringLiteral( "fieldb" ) );
|
||||
|
||||
char **cslRightTableFieldNames = GDALRelationshipGetRightTableFields( relationH.get() );
|
||||
const QStringList rightTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslRightTableFieldNames );
|
||||
CSLDestroy( cslRightTableFieldNames );
|
||||
QCOMPARE( rightTableFieldNames, QStringList() << QStringLiteral( "fieldc" ) << QStringLiteral( "fieldd" ) );
|
||||
|
||||
QCOMPARE( GDALRelationshipGetCardinality( relationH.get() ), GDALRelationshipCardinality::GRC_ONE_TO_MANY );
|
||||
rel.setCardinality( Qgis::RelationshipCardinality::OneToOne );
|
||||
relationH = QgsOgrUtils::convertRelationship( rel, error );
|
||||
QCOMPARE( GDALRelationshipGetCardinality( relationH.get() ), GDALRelationshipCardinality::GRC_ONE_TO_ONE );
|
||||
rel.setCardinality( Qgis::RelationshipCardinality::ManyToOne );
|
||||
relationH = QgsOgrUtils::convertRelationship( rel, error );
|
||||
QCOMPARE( GDALRelationshipGetCardinality( relationH.get() ), GDALRelationshipCardinality::GRC_MANY_TO_ONE );
|
||||
rel.setCardinality( Qgis::RelationshipCardinality::ManyToMany );
|
||||
relationH = QgsOgrUtils::convertRelationship( rel, error );
|
||||
QCOMPARE( GDALRelationshipGetCardinality( relationH.get() ), GDALRelationshipCardinality::GRC_MANY_TO_MANY );
|
||||
|
||||
QCOMPARE( GDALRelationshipGetType( relationH.get() ), GDALRelationshipType::GRT_ASSOCIATION );
|
||||
|
||||
rel = QgsWeakRelation( QStringLiteral( "id" ), QStringLiteral( "name" ),
|
||||
Qgis::RelationshipStrength::Composition,
|
||||
QStringLiteral( "referencing_layer_id" ),
|
||||
QStringLiteral( "referencing_layer_name" ),
|
||||
QStringLiteral( "/some_data.gdb|layername=referencing" ),
|
||||
QStringLiteral( "ogr" ),
|
||||
QStringLiteral( "referenced_layer_id" ),
|
||||
QStringLiteral( "referenced_layer_name" ),
|
||||
QStringLiteral( "/some_data.gdb|layername=referenced" ),
|
||||
QStringLiteral( "ogr" ) );
|
||||
relationH = QgsOgrUtils::convertRelationship( rel, error );
|
||||
QCOMPARE( GDALRelationshipGetType( relationH.get() ), GDALRelationshipType::GRT_COMPOSITE );
|
||||
|
||||
rel.setForwardPathLabel( QStringLiteral( "forward" ) );
|
||||
rel.setBackwardPathLabel( QStringLiteral( "backward" ) );
|
||||
relationH = QgsOgrUtils::convertRelationship( rel, error );
|
||||
QCOMPARE( QString( GDALRelationshipGetForwardPathLabel( relationH.get() ) ), QStringLiteral( "forward" ) );
|
||||
QCOMPARE( QString( GDALRelationshipGetBackwardPathLabel( relationH.get() ) ), QStringLiteral( "backward" ) );
|
||||
|
||||
rel.setRelatedTableType( QStringLiteral( "table_type" ) );
|
||||
relationH = QgsOgrUtils::convertRelationship( rel, error );
|
||||
QCOMPARE( QString( GDALRelationshipGetRelatedTableType( relationH.get() ) ), QStringLiteral( "table_type" ) );
|
||||
|
||||
rel.setMappingTable( QgsVectorLayerRef( QStringLiteral( "mapping_id" ),
|
||||
QStringLiteral( "mapping_name" ),
|
||||
QStringLiteral( "/some_data.gdb|layername=mapping" ),
|
||||
QStringLiteral( "ogr" ) ) );
|
||||
rel.setMappingReferencedLayerFields( QStringList() << QStringLiteral( "fielde" ) << QStringLiteral( "fieldf" ) );
|
||||
rel.setMappingReferencingLayerFields( QStringList() << QStringLiteral( "fieldh" ) << QStringLiteral( "fieldi" ) );
|
||||
relationH = QgsOgrUtils::convertRelationship( rel, error );
|
||||
QCOMPARE( QString( GDALRelationshipGetMappingTableName( relationH.get() ) ), QStringLiteral( "mapping" ) );
|
||||
|
||||
char **cslLeftMappingTableFieldNames = GDALRelationshipGetLeftMappingTableFields( relationH.get() );
|
||||
const QStringList leftMappingTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslLeftMappingTableFieldNames );
|
||||
CSLDestroy( cslLeftMappingTableFieldNames );
|
||||
QCOMPARE( leftMappingTableFieldNames, QStringList() << QStringLiteral( "fielde" ) << QStringLiteral( "fieldf" ) );
|
||||
|
||||
char **cslRightMappingTableFieldNames = GDALRelationshipGetRightMappingTableFields( relationH.get() );
|
||||
const QStringList rightMappingTableFieldNames = QgsOgrUtils::cStringListToQStringList( cslRightMappingTableFieldNames );
|
||||
CSLDestroy( cslRightMappingTableFieldNames );
|
||||
QCOMPARE( rightMappingTableFieldNames, QStringList() << QStringLiteral( "fieldh" ) << QStringLiteral( "fieldi" ) );
|
||||
|
||||
// check that error is raised when tables from different dataset
|
||||
rel.setMappingTable( QgsVectorLayerRef( QStringLiteral( "mapping_id" ),
|
||||
QStringLiteral( "mapping_name" ),
|
||||
QStringLiteral( "/some_other_data.gdb|layername=mapping" ),
|
||||
QStringLiteral( "ogr" ) ) );
|
||||
relationH = QgsOgrUtils::convertRelationship( rel, error );
|
||||
QVERIFY( !relationH.get() );
|
||||
QCOMPARE( error, QStringLiteral( "Parent and mapping table must be from the same dataset" ) );
|
||||
error.clear();
|
||||
|
||||
rel = QgsWeakRelation( QStringLiteral( "id" ), QStringLiteral( "name" ),
|
||||
Qgis::RelationshipStrength::Composition,
|
||||
QStringLiteral( "referencing_layer_id" ),
|
||||
QStringLiteral( "referencing_layer_name" ),
|
||||
QStringLiteral( "/some_data.gdb|layername=referencing" ),
|
||||
QStringLiteral( "ogr" ),
|
||||
QStringLiteral( "referenced_layer_id" ),
|
||||
QStringLiteral( "referenced_layer_name" ),
|
||||
QStringLiteral( "/some_other_data.gdb|layername=referenced" ),
|
||||
QStringLiteral( "ogr" ) );
|
||||
relationH = QgsOgrUtils::convertRelationship( rel, error );
|
||||
QVERIFY( !relationH.get() );
|
||||
QCOMPARE( error, QStringLiteral( "Parent and child table must be from the same dataset" ) );
|
||||
error.clear();
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
QGSTEST_MAIN( TestQgsOgrUtils )
|
||||
#include "testqgsogrutils.moc"
|
||||
|
||||
@ -23,6 +23,7 @@ from qgis.PyQt.QtXml import QDomDocument
|
||||
|
||||
from qgis.core import (
|
||||
NULL,
|
||||
QgsCoordinateReferenceSystem,
|
||||
QgsAuthMethodConfig,
|
||||
QgsApplication,
|
||||
QgsCoordinateTransformContext,
|
||||
@ -54,7 +55,8 @@ from qgis.core import (
|
||||
QgsProviderMetadata,
|
||||
QgsRelation,
|
||||
QgsUnsetAttributeValue,
|
||||
QgsFieldConstraints
|
||||
QgsFieldConstraints,
|
||||
QgsWeakRelation
|
||||
)
|
||||
|
||||
from qgis.gui import (
|
||||
@ -2892,6 +2894,63 @@ class PyQgsOGRProvider(unittest.TestCase):
|
||||
relationships = conn.relationships('', 'table2')
|
||||
self.assertFalse(relationships)
|
||||
|
||||
@unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required")
|
||||
def test_provider_connection_create_relationship(self):
|
||||
"""
|
||||
Test creating relationship via the connections API
|
||||
"""
|
||||
metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
tmpfile = os.path.join(temp_dir, 'test_gdb.gdb')
|
||||
|
||||
ok, err = metadata.createDatabase(tmpfile)
|
||||
self.assertTrue(ok)
|
||||
self.assertFalse(err)
|
||||
|
||||
conn = metadata.createConnection(tmpfile, {})
|
||||
self.assertTrue(conn)
|
||||
|
||||
conn.createVectorTable('', 'child', QgsFields(), QgsWkbTypes.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {})
|
||||
layer = QgsVectorLayer(tmpfile + '|layername=child')
|
||||
self.assertTrue(layer.isValid())
|
||||
|
||||
conn.createVectorTable('', 'parent', QgsFields(), QgsWkbTypes.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {})
|
||||
layer = QgsVectorLayer(tmpfile + '|layername=parent')
|
||||
self.assertTrue(layer.isValid())
|
||||
del layer
|
||||
|
||||
self.assertTrue(
|
||||
conn.capabilities() & QgsAbstractDatabaseProviderConnection.AddRelationship)
|
||||
|
||||
relationships = conn.relationships()
|
||||
self.assertFalse(relationships)
|
||||
|
||||
rel = QgsWeakRelation('id',
|
||||
'rel_name',
|
||||
Qgis.RelationshipStrength.Association,
|
||||
'referencing_id',
|
||||
'referencing_name',
|
||||
tmpfile + '|layername=child',
|
||||
'ogr',
|
||||
'referenced_id',
|
||||
'referenced_name',
|
||||
tmpfile + '|layername=parent',
|
||||
'ogr'
|
||||
)
|
||||
rel.setReferencedLayerFields(['fielda'])
|
||||
rel.setReferencingLayerFields(['fieldb'])
|
||||
|
||||
conn.addRelationship(rel)
|
||||
relationships = conn.relationships()
|
||||
self.assertEqual(len(relationships), 1)
|
||||
|
||||
result = relationships[0]
|
||||
self.assertEqual(result.name(), 'rel_name')
|
||||
self.assertEqual(result.referencingLayerSource(), tmpfile + '|layername=child')
|
||||
self.assertEqual(result.referencedLayerSource(), tmpfile + '|layername=parent')
|
||||
self.assertEqual(result.referencingLayerFields(), ['fieldb'])
|
||||
self.assertEqual(result.referencedLayerFields(), ['fielda'])
|
||||
|
||||
def testUniqueGeometryType(self):
|
||||
"""
|
||||
Test accessing a layer of type wkbUnknown that contains a single geometry type but also null geometries
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user