Skip to content

Commit

Permalink
Merge pull request #37628 from elpaso/connections-api-fields
Browse files Browse the repository at this point in the history
DB Connections API: add fields method -> column info
  • Loading branch information
elpaso committed Jul 7, 2020
2 parents ed000d4 + 8ded0f1 commit 961e6e8
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 0 deletions.
Expand Up @@ -234,6 +234,8 @@ This information is calculated from the geometry columns types.
CreateSpatialIndex,
SpatialIndexExists,
DeleteSpatialIndex,
DeleteField,
CreateField,
};

typedef QFlags<QgsAbstractDatabaseProviderConnection::Capability> Capabilities;
Expand Down Expand Up @@ -461,6 +463,28 @@ Returns information about the existing schemas.
Raises a QgsProviderConnectionException if any errors are encountered.

:raises :: py:class:`QgsProviderConnectionException`
%End

virtual QgsFields fields( const QString &schema, const QString &table ) const throw( QgsProviderConnectionException );
%Docstring
Returns the fields of a ``table`` and ``schema``.
Raises a QgsProviderConnectionException if any errors are encountered.

.. note::

the default implementation creates a temporary vector layer, providers may
choose to override this method for a greater efficiency.

.. versionadded:: 3.16

:raises :: py:class:`QgsProviderConnectionException`
%End

QString providerKey() const;
%Docstring
Returns the provider key

.. versionadded:: 3.16
%End

protected:
Expand Down
2 changes: 2 additions & 0 deletions src/core/providers/ogr/qgsgeopackageproviderconnection.cpp
Expand Up @@ -24,6 +24,7 @@
QgsGeoPackageProviderConnection::QgsGeoPackageProviderConnection( const QString &name )
: QgsAbstractDatabaseProviderConnection( name )
{
mProviderKey = QStringLiteral( "ogr" );
setDefaultCapabilities();
QgsSettings settings;
settings.beginGroup( QStringLiteral( "ogr" ), QgsSettings::Section::Providers );
Expand All @@ -36,6 +37,7 @@ QgsGeoPackageProviderConnection::QgsGeoPackageProviderConnection( const QString
QgsGeoPackageProviderConnection::QgsGeoPackageProviderConnection( const QString &uri, const QVariantMap &configuration ):
QgsAbstractDatabaseProviderConnection( uri, configuration )
{
mProviderKey = QStringLiteral( "ogr" );
// Cleanup the URI in case it contains other information other than the file path
if ( uri.contains( '|' ) )
{
Expand Down
20 changes: 20 additions & 0 deletions src/core/qgsabstractdatabaseproviderconnection.cpp
Expand Up @@ -14,6 +14,7 @@
* *
***************************************************************************/
#include "qgsabstractdatabaseproviderconnection.h"
#include "qgsvectorlayer.h"
#include "qgsexception.h"
#include <QVariant>
#include <QObject>
Expand Down Expand Up @@ -51,6 +52,11 @@ void QgsAbstractDatabaseProviderConnection::checkCapability( QgsAbstractDatabase
throw QgsProviderConnectionException( QObject::tr( "Operation '%1' is not supported for this connection" ).arg( capName ) );
}
}

QString QgsAbstractDatabaseProviderConnection::providerKey() const
{
return mProviderKey;
}
///@endcond

void QgsAbstractDatabaseProviderConnection::createVectorTable( const QString &schema,
Expand Down Expand Up @@ -212,6 +218,20 @@ QList<QgsAbstractDatabaseProviderConnection::TableProperty::GeometryColumnType>
return mGeometryColumnTypes;
}

QgsFields QgsAbstractDatabaseProviderConnection::fields( const QString &schema, const QString &tableName ) const
{
QgsVectorLayer::LayerOptions options { true, true };
options.skipCrsValidation = true;
QgsVectorLayer vl { tableUri( schema, tableName ), QStringLiteral( "temp_layer" ), mProviderKey, options };
if ( vl.isValid() )
{
return vl.fields();
}
else
{
throw QgsProviderConnectionException( QObject::tr( "Error retrieving fields information for uri: %1" ).arg( vl.publicSource() ) );
}
}

QString QgsAbstractDatabaseProviderConnection::TableProperty::defaultName() const
{
Expand Down
19 changes: 19 additions & 0 deletions src/core/qgsabstractdatabaseproviderconnection.h
Expand Up @@ -293,6 +293,8 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
CreateSpatialIndex = 1 << 16, //!< The connection can create spatial indices
SpatialIndexExists = 1 << 17, //!< The connection can determine if a spatial index exists
DeleteSpatialIndex = 1 << 18, //!< The connection can delete spatial indices for tables
DeleteField = 1 << 19, //!< Can delete an existing field
CreateField = 1 << 20, //!< Can add a new field
};

Q_ENUM( Capability )
Expand Down Expand Up @@ -494,6 +496,22 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
*/
virtual QStringList schemas() const SIP_THROW( QgsProviderConnectionException );

/**
* Returns the fields of a \a table and \a schema.
* Raises a QgsProviderConnectionException if any errors are encountered.
* \note the default implementation creates a temporary vector layer, providers may
* choose to override this method for a greater efficiency.
* \since QGIS 3.16
* \throws QgsProviderConnectionException
*/
virtual QgsFields fields( const QString &schema, const QString &table ) const SIP_THROW( QgsProviderConnectionException );

/**
* Returns the provider key
* \since QGIS 3.16
*/
QString providerKey() const;

protected:

///@cond PRIVATE
Expand All @@ -506,6 +524,7 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
///@endcond

Capabilities mCapabilities = nullptr SIP_SKIP;
QString mProviderKey;

};

Expand Down
2 changes: 2 additions & 0 deletions src/providers/mssql/qgsmssqlproviderconnection.cpp
Expand Up @@ -37,6 +37,7 @@ const QStringList QgsMssqlProviderConnection::EXTRA_CONNECTION_PARAMETERS
QgsMssqlProviderConnection::QgsMssqlProviderConnection( const QString &name )
: QgsAbstractDatabaseProviderConnection( name )
{
mProviderKey = QStringLiteral( "mssql" );
// Remove the sql and table empty parts
setUri( QgsMssqlConnection::connUri( name ).uri() );
setDefaultCapabilities();
Expand All @@ -45,6 +46,7 @@ QgsMssqlProviderConnection::QgsMssqlProviderConnection( const QString &name )
QgsMssqlProviderConnection::QgsMssqlProviderConnection( const QString &uri, const QVariantMap &configuration ):
QgsAbstractDatabaseProviderConnection( QString(), configuration )
{
mProviderKey = QStringLiteral( "mssql" );
// Additional connection information
const QgsDataSourceUri inputUri( uri );
QgsDataSourceUri currentUri { QgsDataSourceUri( uri ).connectionInfo( false ) };
Expand Down
2 changes: 2 additions & 0 deletions src/providers/postgres/qgspostgresproviderconnection.cpp
Expand Up @@ -29,6 +29,7 @@ extern "C"
QgsPostgresProviderConnection::QgsPostgresProviderConnection( const QString &name )
: QgsAbstractDatabaseProviderConnection( name )
{
mProviderKey = QStringLiteral( "postgres" );
// Remove the sql and table empty parts
const QRegularExpression removePartsRe { R"raw(\s*sql=\s*|\s*table=""\s*)raw" };
setUri( QgsPostgresConn::connUri( name ).uri().replace( removePartsRe, QString() ) );
Expand All @@ -38,6 +39,7 @@ QgsPostgresProviderConnection::QgsPostgresProviderConnection( const QString &nam
QgsPostgresProviderConnection::QgsPostgresProviderConnection( const QString &uri, const QVariantMap &configuration ):
QgsAbstractDatabaseProviderConnection( QgsDataSourceUri( uri ).connectionInfo( false ), configuration )
{
mProviderKey = QStringLiteral( "postgres" );
setDefaultCapabilities();
}

Expand Down
2 changes: 2 additions & 0 deletions src/providers/spatialite/qgsspatialiteproviderconnection.cpp
Expand Up @@ -25,6 +25,7 @@
QgsSpatiaLiteProviderConnection::QgsSpatiaLiteProviderConnection( const QString &name )
: QgsAbstractDatabaseProviderConnection( name )
{
mProviderKey = QStringLiteral( "spatialite" );
setDefaultCapabilities();
// TODO: QGIS 4: move into QgsSettings::Section::Providers group
QgsSettings settings;
Expand All @@ -39,6 +40,7 @@ QgsSpatiaLiteProviderConnection::QgsSpatiaLiteProviderConnection( const QString
QgsSpatiaLiteProviderConnection::QgsSpatiaLiteProviderConnection( const QString &uri, const QVariantMap &configuration ):
QgsAbstractDatabaseProviderConnection( uri, configuration )
{
mProviderKey = QStringLiteral( "spatialite" );
const QRegularExpression removePartsRe { R"raw(\s*sql=\s*|\s*table=""\s*|\([^\)]+\))raw" };
// Cleanup the URI in case it contains other information other than the file path
setUri( QString( uri ).replace( removePartsRe, QString() ) );
Expand Down
8 changes: 8 additions & 0 deletions tests/src/python/test_qgsproviderconnection_mssql.py
Expand Up @@ -101,6 +101,14 @@ def test_table_uri(self):
vl = QgsVectorLayer(conn.tableUri('qgis_test', 'someData'), 'my', 'mssql')
self.assertTrue(vl.isValid())

def test_gpkg_fields(self):
"""Test fields"""

md = QgsProviderRegistry.instance().providerMetadata('mssql')
conn = md.createConnection(self.uri, {})
fields = conn.fields('qgis_test', 'someData')
self.assertEqual(fields.names(), ['pk', 'cnt', 'name', 'name2', 'num_char'])


if __name__ == '__main__':
unittest.main()
8 changes: 8 additions & 0 deletions tests/src/python/test_qgsproviderconnection_ogr_gpkg.py
Expand Up @@ -118,6 +118,14 @@ def test_gpkg_connections(self):
self.assertFalse('myNewTable' in table_names)
self.assertTrue('myNewAspatialTable' in table_names)

def test_gpkg_fields(self):
"""Test fields"""

md = QgsProviderRegistry.instance().providerMetadata('ogr')
conn = md.createConnection(self.uri, {})
fields = conn.fields('', 'cdb_lines')
self.assertEqual(fields.names(), ['fid', 'id', 'typ', 'name', 'ortsrat', 'id_long'])


if __name__ == '__main__':
unittest.main()
8 changes: 8 additions & 0 deletions tests/src/python/test_qgsproviderconnection_postgres.py
Expand Up @@ -317,6 +317,14 @@ def test_foreign_table_server(self):
conn.executeSql(foreign_table_definition)
self.assertEquals(conn.tables('foreign_schema', QgsAbstractDatabaseProviderConnection.Foreign)[0].tableName(), 'someData')

def test_fields(self):
"""Test fields"""

md = QgsProviderRegistry.instance().providerMetadata('postgres')
conn = md.createConnection(self.uri, {})
fields = conn.fields('qgis_test', 'someData')
self.assertEqual(fields.names(), ['pk', 'cnt', 'name', 'name2', 'num_char', 'dt', 'date', 'time', 'geom'])


if __name__ == '__main__':
unittest.main()
8 changes: 8 additions & 0 deletions tests/src/python/test_qgsproviderconnection_spatialite.py
Expand Up @@ -110,6 +110,14 @@ def test_spatialite_connections(self):
self.assertFalse('myNewTable' in table_names)
self.assertTrue('myNewAspatialTable' in table_names)

def test_gpkg_fields(self):
"""Test fields"""

md = QgsProviderRegistry.instance().providerMetadata('spatialite')
conn = md.createConnection(self.uri, {})
fields = conn.fields('', 'cdb_lines')
self.assertEqual(fields.names(), ['pk', 'geom', 'fid', 'id', 'typ', 'name', 'ortsrat', 'id_long'])


if __name__ == '__main__':
unittest.main()

0 comments on commit 961e6e8

Please sign in to comment.