schemas filtering for QgsMssqlProviderConnection

This commit is contained in:
vcloarec 2021-01-08 20:52:51 -04:00 committed by Martin Dobias
parent e6a2e1f6f3
commit f81737c960
9 changed files with 193 additions and 113 deletions

View File

@ -429,6 +429,10 @@ QgsDataSourceUri QgsMssqlConnection::connUri( const QString &connName )
}
}
QStringList excludedSchemas = QgsMssqlConnection::excludedSchemasList( connName );
if ( !excludedSchemas.isEmpty() )
uri.setParam( QStringLiteral( "excludedSchemas" ), excludedSchemas.join( ',' ) );
return uri;
}
@ -469,59 +473,80 @@ QList<QgsVectorDataProvider::NativeType> QgsMssqlConnection::nativeTypes()
;
}
QString QgsMssqlConnection::buildQueryForSchemas( const QString &connName, bool allowTablesWithNoGeometry )
QStringList QgsMssqlConnection::excludedSchemasList( const QString &connName )
{
QgsSettings settings;
QString selectedSchemas;
QString databaseName = settings.value( QStringLiteral( "/MSSQL/connections/" ) + connName + "/database" ).toString();
return excludedSchemasList( connName, databaseName );
}
QStringList QgsMssqlConnection::excludedSchemasList( const QString &connName, const QString &database )
{
QgsSettings settings;
bool schemaFilteringEnabled = settings.value( QStringLiteral( "/MSSQL/connections/" ) + connName + "/schemasFiltering" ).toBool();
if ( schemaFilteringEnabled )
{
QVariant schemaSettingsVariant = settings.value( QStringLiteral( "/MSSQL/connections/" ) + connName + "/schemasFiltered" );
QVariant schemaSettingsVariant = settings.value( QStringLiteral( "/MSSQL/connections/" ) + connName + "/excludedSchemas" );
if ( schemaSettingsVariant.type() == QVariant::Map )
{
QVariantMap schemaSettings = schemaSettingsVariant.toMap();
QVariantMap schemaSettingsForDatabase = schemaSettings.value( databaseName ).toMap();
//schema filter
QStringList schemaNames;
for ( const QString &schemaName : schemaSettingsForDatabase.keys() )
{
if ( schemaSettingsForDatabase.value( schemaName ).toBool() )
{
schemaNames.append( QgsMssqlProvider::quotedValue( schemaName ) );
}
}
if ( !schemaNames.empty() )
selectedSchemas = schemaNames.join( ',' );
selectedSchemas.prepend( QStringLiteral( "( " ) );
selectedSchemas.append( QStringLiteral( " )" ) );
const QVariantMap schemaSettings = schemaSettingsVariant.toMap();
if ( schemaSettings.contains( database ) && schemaSettings.value( database ).type() == QVariant::StringList )
return schemaSettings.value( database ).toStringList();
}
}
// build sql statement
return QStringList();
}
void QgsMssqlConnection::setExcludedSchemasList( const QString &connName, const QStringList &excludedSchemas )
{
QgsSettings settings;
QString currentDatabaseName = settings.value( QStringLiteral( "/MSSQL/connections/" ) + connName + "/database" ).toString();
setExcludedSchemasList( connName, currentDatabaseName, excludedSchemas );
}
void QgsMssqlConnection::setExcludedSchemasList( const QString &connName, const QString &database, const QStringList &excludedSchemas )
{
QgsSettings settings;
settings.setValue( QStringLiteral( "/MSSQL/connections/" ) + connName + "/schemasFiltering", excludedSchemas.isEmpty() ? 0 : 1 );
QVariant schemaSettingsVariant = settings.value( QStringLiteral( "/MSSQL/connections/" ) + connName + "/excludedSchemas" );
QVariantMap schemaSettings = schemaSettingsVariant.toMap();
schemaSettings.insert( database, excludedSchemas );
settings.setValue( QStringLiteral( "/MSSQL/connections/" ) + connName + "/excludedSchemas", schemaSettings );
}
QString QgsMssqlConnection::buildQueryForTables( bool allowTablesWithNoGeometry, bool geometryColumnOnly, const QStringList &excludedSchemaList )
{
QString notSelectedSchemas;
if ( !excludedSchemaList.isEmpty() )
{
QStringList quotedSchemas;
for ( const QString &sch : excludedSchemaList )
quotedSchemas.append( QgsMssqlProvider::quotedValue( sch ) );
notSelectedSchemas = quotedSchemas.join( ',' );
notSelectedSchemas.prepend( QStringLiteral( "( " ) );
notSelectedSchemas.append( QStringLiteral( " )" ) );
}
QString query( QStringLiteral( "SELECT " ) );
if ( geometryColumnsOnly( connName ) )
if ( geometryColumnOnly )
{
query += QStringLiteral( "f_table_schema, f_table_name, f_geometry_column, srid, geometry_type, 0 FROM geometry_columns" );
if ( !selectedSchemas.isEmpty() )
query += QStringLiteral( " WHERE f_table_schema IN %1" ).arg( selectedSchemas );
if ( !notSelectedSchemas.isEmpty() )
query += QStringLiteral( " WHERE f_table_schema NOT IN %1" ).arg( notSelectedSchemas );
}
else
{
query += QStringLiteral( "sys.schemas.name, sys.objects.name, sys.columns.name, null, 'GEOMETRY', CASE when sys.objects.type = 'V' THEN 1 ELSE 0 END \n"
"FROM sys.columns JOIN sys.types ON sys.columns.system_type_id = sys.types.system_type_id AND sys.columns.user_type_id = sys.types.user_type_id JOIN sys.objects ON sys.objects.object_id = sys.columns.object_id JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id \n"
"WHERE (sys.types.name = 'geometry' OR sys.types.name = 'geography') AND (sys.objects.type = 'U' OR sys.objects.type = 'V')" );
if ( !selectedSchemas.isEmpty() )
query += QStringLiteral( " AND (sys.schemas.name IN %1)" ).arg( selectedSchemas );
if ( !notSelectedSchemas.isEmpty() )
query += QStringLiteral( " AND (sys.schemas.name NOT IN %1)" ).arg( notSelectedSchemas );
}
if ( allowTablesWithNoGeometry )
@ -530,16 +555,21 @@ QString QgsMssqlConnection::buildQueryForSchemas( const QString &connName, bool
"SELECT sys.schemas.name, sys.objects.name, null, null, 'NONE', case when sys.objects.type = 'V' THEN 1 ELSE 0 END \n"
"FROM sys.objects JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id "
"WHERE NOT EXISTS (SELECT * FROM sys.columns sc1 JOIN sys.types ON sc1.system_type_id = sys.types.system_type_id WHERE (sys.types.name = 'geometry' OR sys.types.name = 'geography') AND sys.objects.object_id = sc1.object_id) AND (sys.objects.type = 'U' or sys.objects.type = 'V')" );
if ( !selectedSchemas.isEmpty() )
query += QStringLiteral( " AND sys.schemas.name IN %1" ).arg( selectedSchemas );
if ( !notSelectedSchemas.isEmpty() )
query += QStringLiteral( " AND sys.schemas.name NOT IN %1" ).arg( notSelectedSchemas );
}
return query;
}
QString QgsMssqlConnection::buildQueryForSchemas( const QString &connName )
QString QgsMssqlConnection::buildQueryForTables( const QString &connName, bool allowTablesWithNoGeometry )
{
return buildQueryForSchemas( connName, allowGeometrylessTables( connName ) );
return buildQueryForTables( allowTablesWithNoGeometry, geometryColumnsOnly( connName ), excludedSchemasList( connName ) );
}
QString QgsMssqlConnection::buildQueryForTables( const QString &connName )
{
return buildQueryForTables( allowGeometrylessTables( connName ), geometryColumnsOnly( connName ), excludedSchemasList( connName ) );
}
QString QgsMssqlConnection::dbConnectionName( const QString &name )

View File

@ -45,7 +45,6 @@ class QgsMssqlConnection
*/
static QSqlDatabase getDatabase( const QString &service, const QString &host, const QString &database, const QString &username, const QString &password );
static bool openDatabase( QSqlDatabase &db );
/**
@ -151,6 +150,7 @@ class QgsMssqlConnection
/**
* Returns a list of all schemas on the \a dataBase.
* \since QGIS 3.18
*/
static QStringList schemas( QSqlDatabase &dataBase, QString *errorMessage );
@ -176,16 +176,47 @@ class QgsMssqlConnection
static QList<QgsVectorDataProvider::NativeType> nativeTypes();
/**
* Builds and returns a sql query string to obtain schemas list depending on settings and \a allowTablesWithNoGeometry
* Returns a list of excluded schemas for connection \a connName depending on settings, returns empty list if nothing is set for this connection
* \since QGIS 3.18
*/
static QString buildQueryForSchemas( const QString &connName, bool allowTablesWithNoGeometry );
static QStringList excludedSchemasList( const QString &connName );
/**
* Returns a list of excluded schemas for connection \a connName for a specific \a database depending on settings, returns empty list if nothing is set for this connection
* \since QGIS 3.18
*/
static QStringList excludedSchemasList( const QString &connName, const QString &database );
/**
* Sets a list of excluded schemas for connection \a connName depending on settings, returns empty list if nothing is set for this connection
* \since QGIS 3.18
*/
static void setExcludedSchemasList( const QString &connName, const QStringList &excludedSchemas );
/**
* Sets a list of excluded schemas for connection \a connName for a specific \a database depending on settings, returns empty list if nothing is set for this connection
* \since QGIS 3.18
*/
static void setExcludedSchemasList( const QString &connName, const QString &database, const QStringList &excludedSchemas );
/**
* Builds and returns a sql query string to obtain tables list depending on \a allowTablesWithNoGeometry, \a geometryColumnOnly and on \a notSelectedSchemasList
* \since QGIS 3.18
*/
static QString buildQueryForTables( bool allowTablesWithNoGeometry, bool geometryColumnOnly, const QStringList &excludedSchemaList = QStringList() );
/**
* Builds and returns a sql query string to obtain tables list depending on settings and \a allowTablesWithNoGeometry
* \since QGIS 3.18
*/
static QString buildQueryForTables( const QString &connName, bool allowTablesWithNoGeometry );
/**
* Builds and returns a sql query string to obtain schemas list depending only on settings
* \since QGIS 3.18
*/
static QString buildQueryForSchemas( const QString &connName );
static QString buildQueryForTables( const QString &connName );
private:

View File

@ -74,9 +74,10 @@ void QgsMssqlConnectionItem::readConnectionSettings()
mSchemaSettings.clear();
mSchemasFilteringEnabled = settings.value( key + "/schemasFiltering" ).toBool();
if ( mSchemasFilteringEnabled )
{
QVariant schemasSettingsVariant = settings.value( key + "/schemasFiltered" );
QVariant schemasSettingsVariant = settings.value( key + "/excludedSchemas" );
if ( schemasSettingsVariant.isValid() && schemasSettingsVariant.type() == QVariant::Map )
mSchemaSettings = schemasSettingsVariant.toMap();
}
@ -144,7 +145,7 @@ QVector<QgsDataItem *> QgsMssqlConnectionItem::createChildren()
}
// build sql statement
QString query = QgsMssqlConnection::buildQueryForSchemas( mName );
QString query = QgsMssqlConnection::buildQueryForTables( mName );
const bool disableInvalidGeometryHandling = QgsMssqlConnection::isInvalidGeometryHandlingDisabled( mName );
@ -252,14 +253,13 @@ QVector<QgsDataItem *> QgsMssqlConnectionItem::createChildren()
}
}
// add missing schemas (i.e., empty schemas)
const QString uri = connInfo();
const QStringList allSchemas = QgsMssqlConnection::schemas( uri, nullptr );
QVariantMap schemaSettings = mSchemaSettings.value( mDatabase ).toMap();
QStringList excludedSchema = QgsMssqlConnection::excludedSchemasList( mName );
for ( const QString &schema : allSchemas )
{
if ( mSchemasFilteringEnabled && !schemaSettings.value( schema ).toBool() )
if ( mSchemasFilteringEnabled && excludedSchema.contains( schema ) )
continue; // user does not want it to be shown
if ( addedSchemas.contains( schema ) )
@ -274,8 +274,6 @@ QVector<QgsDataItem *> QgsMssqlConnectionItem::createChildren()
children.append( schemaItem );
}
// spawn threads (new layers will be added later on)
if ( mColumnTypeThread )
{

View File

@ -61,7 +61,7 @@ QgsMssqlNewConnection::QgsMssqlNewConnection( QWidget *parent, const QString &co
txtHost->setText( settings.value( key + "/host" ).toString() );
listDatabase->addItem( settings.value( key + "/database" ).toString() );
groupBoxSchemasFilter->setChecked( settings.value( key + "/schemasFiltering" ).toBool() );
QVariant schemasVariant = settings.value( key + "/schemasFiltered" );
QVariant schemasVariant = settings.value( key + "/excludedSchemas" );
if ( schemasVariant.isValid() && schemasVariant.type() == QVariant::Map )
mSchemaSettings = schemasVariant.toMap();
@ -90,14 +90,8 @@ QgsMssqlNewConnection::QgsMssqlNewConnection( QWidget *parent, const QString &co
cb_trustedConnection_clicked();
schemaView->setModel( &mSchemaModel );
if ( listDatabase->currentItem() )
{
QString dataBaseName = listDatabase->currentItem()->text();
mSchemaModel.setDataBaseName( dataBaseName );
mSchemaModel.setSchemasSetting( mSchemaSettings.value( dataBaseName ).toMap() );
}
onCurrentDataBaseChange();
groupBoxSchemasFilter->setCollapsed( !groupBoxSchemasFilter->isChecked() );
}
@ -147,8 +141,8 @@ void QgsMssqlNewConnection::accept()
if ( groupBoxSchemasFilter->isChecked() )
{
if ( !mSchemaModel.dataBaseName().isEmpty() )
mSchemaSettings.insert( mSchemaModel.dataBaseName(), mSchemaModel.schemasSettings() );
settings.setValue( baseKey + "/schemasFiltered", mSchemaSettings );
mSchemaSettings.insert( mSchemaModel.dataBaseName(), mSchemaModel.uncheckedSchemas() );
settings.setValue( baseKey + "/excludedSchemas", mSchemaSettings );
}
settings.setValue( baseKey + "/schemasFiltering", groupBoxSchemasFilter->isChecked() );
@ -303,9 +297,8 @@ void QgsMssqlNewConnection::updateOkButtonState()
void QgsMssqlNewConnection::onCurrentDataBaseChange()
{
//First store the schema settings for the previous dataBase
QVariantMap vm = mSchemaModel.schemasSettings();
if ( !mSchemaModel.dataBaseName().isEmpty() )
mSchemaSettings.insert( mSchemaModel.dataBaseName(), mSchemaModel.schemasSettings() );
mSchemaSettings.insert( mSchemaModel.dataBaseName(), mSchemaModel.uncheckedSchemas() );
QString databaseName;
if ( listDatabase->currentItem() )
@ -318,23 +311,16 @@ void QgsMssqlNewConnection::onCurrentDataBaseChange()
txtPassword->text().trimmed() );
QStringList schemasList = QgsMssqlConnection::schemas( db, nullptr );
QVariantMap newSchemaSettings = mSchemaSettings.value( databaseName ).toMap();
for ( const QString &sch : newSchemaSettings.keys() )
int i = 0;
while ( i < schemasList.count() )
{
if ( !schemasList.contains( sch ) )
newSchemaSettings.remove( sch );
if ( QgsMssqlConnection::isSystemSchema( schemasList.at( i ) ) )
schemasList.removeAt( i );
else
++i;
}
for ( const QString &sch : schemasList )
{
if ( !newSchemaSettings.contains( sch ) && !QgsMssqlConnection::isSystemSchema( sch ) )
newSchemaSettings.insert( sch, true );
}
mSchemaModel.setDataBaseName( databaseName );
mSchemaModel.setSchemasSetting( newSchemaSettings );
mSchemaModel.setSettings( databaseName, schemasList, QgsMssqlConnection::excludedSchemasList( txtName->text(), databaseName ) );
}
QgsMssqlNewConnection::SchemaModel::SchemaModel( QObject *parent ): QAbstractListModel( parent )
@ -351,18 +337,17 @@ QVariant QgsMssqlNewConnection::SchemaModel::data( const QModelIndex &index, int
if ( !index.isValid() || index.row() >= mSchemas.count() )
return QVariant();
QList<QString> schemasName = mSchemas.keys();
switch ( role )
{
case Qt::CheckStateRole:
if ( mSchemas.value( schemasName.at( index.row() ) ).toBool() )
return Qt::CheckState::Checked;
else
if ( mExcludedSchemas.contains( mSchemas.at( index.row() ) ) )
return Qt::CheckState::Unchecked;
else
return Qt::CheckState::Checked;
break;
case Qt::DisplayRole:
return schemasName.at( index.row() );
return mSchemas.at( index.row() );
break;
default:
return QVariant();
@ -376,11 +361,13 @@ bool QgsMssqlNewConnection::SchemaModel::setData( const QModelIndex &index, cons
if ( !index.isValid() || index.row() >= mSchemas.count() )
return false;
QList<QString> schemasName = mSchemas.keys();
switch ( role )
{
case Qt::CheckStateRole:
mSchemas[schemasName.at( index.row() )] = value;
if ( value == Qt::Checked && mExcludedSchemas.contains( mSchemas.at( index.row() ) ) )
mExcludedSchemas.removeOne( mSchemas.at( index.row() ) );
else if ( value == Qt::Unchecked && !mExcludedSchemas.contains( mSchemas.at( index.row() ) ) )
mExcludedSchemas.append( mSchemas.at( index.row() ) );
return true;
break;
default:
@ -395,17 +382,11 @@ Qt::ItemFlags QgsMssqlNewConnection::SchemaModel::flags( const QModelIndex &inde
return QAbstractListModel::flags( index ) | Qt::ItemFlag::ItemIsUserCheckable;
}
void QgsMssqlNewConnection::SchemaModel::setSchemasSetting( const QVariantMap &schemas )
QStringList QgsMssqlNewConnection::SchemaModel::uncheckedSchemas() const
{
beginResetModel();
mSchemas = schemas;
endResetModel();
return mExcludedSchemas;
}
QVariantMap QgsMssqlNewConnection::SchemaModel::schemasSettings() const
{
return mSchemas;
}
QString QgsMssqlNewConnection::SchemaModel::dataBaseName() const
{
@ -416,3 +397,12 @@ void QgsMssqlNewConnection::SchemaModel::setDataBaseName( const QString &dataBas
{
mDataBaseName = dataBaseName;
}
void QgsMssqlNewConnection::SchemaModel::setSettings( const QString &database, const QStringList &schemas, const QStringList &excludedSchemas )
{
beginResetModel();
mDataBaseName = database;
mSchemas = schemas;
mExcludedSchemas = excludedSchemas;
endResetModel();
}

View File

@ -62,11 +62,8 @@ class QgsMssqlNewConnection : public QDialog, private Ui::QgsMssqlNewConnectionB
bool setData( const QModelIndex &index, const QVariant &value, int role ) override;
Qt::ItemFlags flags( const QModelIndex &index ) const override;
//! Sets the schema settings (keyd : schema names, value : bool that represents whether the schema is checked)
void setSchemasSetting( const QVariantMap &schemas );
//! Returns the schema settings (keyd : schema names, value : bool that represents whether the schema is checked)
QVariantMap schemasSettings() const;
//! Returns the unchecked schemas
QStringList uncheckedSchemas() const;
//! Returns the database nale represented by the model
QString dataBaseName() const;
@ -74,9 +71,13 @@ class QgsMssqlNewConnection : public QDialog, private Ui::QgsMssqlNewConnectionB
//! Sets the database nale represented by the model
void setDataBaseName( const QString &dataBaseName );
//! Sets the settings for \a database
void setSettings( const QString &database, const QStringList &schemas, const QStringList &excludedSchemas );
private:
QVariantMap mSchemas;
QString mDataBaseName;
QStringList mSchemas;
QStringList mExcludedSchemas;
};

View File

@ -66,6 +66,9 @@ QgsMssqlProviderConnection::QgsMssqlProviderConnection( const QString &uri, cons
}
}
if ( inputUri.hasParam( QStringLiteral( "excludedSchemas" ) ) )
currentUri.setParam( QStringLiteral( "excludedSchemas" ), inputUri.param( QStringLiteral( "excludedSchemas" ) ) );
setUri( currentUri.uri() );
setDefaultCapabilities();
}
@ -456,9 +459,14 @@ QStringList QgsMssqlProviderConnection::schemas( ) const
{
checkCapability( Capability::Schemas );
QStringList schemas;
QgsDataSourceUri connUri( uri() );
const QgsDataSourceUri dsUri { uri() };
const QString sql { QStringLiteral(
R"raw(
const QString sql
{
QStringLiteral(
R"raw(
SELECT s.name AS schema_name,
s.schema_id,
u.name AS schema_owner
@ -467,12 +475,22 @@ QStringList QgsMssqlProviderConnection::schemas( ) const
ON u.uid = s.principal_id
WHERE u.issqluser = 1
AND u.name NOT IN ('sys', 'guest', 'INFORMATION_SCHEMA')
)raw" )};
)raw" )
};
const QList<QVariantList> result { executeSqlPrivate( sql, false ).rows() };
QStringList excludedSchemaList;
if ( connUri.hasParam( QStringLiteral( "excludedSchemas" ) ) )
excludedSchemaList = QgsDataSourceUri( uri() ).param( QStringLiteral( "excludedSchemas" ) ).split( ',' );
for ( const auto &row : result )
{
if ( row.size() > 0 )
schemas.push_back( row.at( 0 ).toString() );
{
QString schema = row.at( 0 ).toString();
if ( !excludedSchemaList.contains( schema ) )
schemas.push_back( schema );
}
}
return schemas;
}
@ -498,13 +516,14 @@ void QgsMssqlProviderConnection::store( const QString &name ) const
settings.setValue( "password", dsUri.password() );
settings.setValue( "estimatedMetadata", dsUri.useEstimatedMetadata() );
QgsMssqlConnection::setExcludedSchemasList( name, dsUri.database(), dsUri.param( QStringLiteral( "excludedSchemas" ) ).split( ',' ) );
for ( const auto &param : EXTRA_CONNECTION_PARAMETERS )
{
if ( dsUri.hasParam( param ) )
{
settings.setValue( param, dsUri.param( param ) == QStringLiteral( "true" )
|| dsUri.param( param ) == '1' );
}
}

View File

@ -540,7 +540,7 @@ void QgsMssqlSourceSelect::btnConnect_clicked()
// Read supported layers from database
QApplication::setOverrideCursor( Qt::WaitCursor );
QString query = QgsMssqlConnection::buildQueryForSchemas( cmbConnections->currentText(), allowGeometrylessTables );
QString query = QgsMssqlConnection::buildQueryForTables( cmbConnections->currentText(), allowGeometrylessTables );
// issue the sql query
q = QSqlQuery( db );

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>772</width>
<height>691</height>
<height>687</height>
</rect>
</property>
<property name="sizePolicy">
@ -272,19 +272,6 @@ Untick save if you don't wish to be the case.</string>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="Line" name="line">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBoxSchemasFilter">
<property name="title">
<string>Use Only a Subset of Schemas</string>
@ -317,7 +304,7 @@ Untick save if you don't wish to be the case.</string>
</layout>
</widget>
</item>
<item row="9" column="0" colspan="2">
<item row="8" column="0" colspan="2">
<widget class="QPushButton" name="btnConnect">
<property name="text">
<string>Test Connection</string>

View File

@ -102,6 +102,30 @@ class TestPyQgsProviderConnectionMssql(unittest.TestCase, TestPyQgsProviderConne
fields = conn.fields('qgis_test', 'someData')
self.assertEqual(fields.names(), ['pk', 'cnt', 'name', 'name2', 'num_char', 'dt', 'date', 'time'])
def test_schemas_filtering(self):
"""Test schemas filtering"""
md = QgsProviderRegistry.instance().providerMetadata('mssql')
conn = md.createConnection(self.uri, {})
schemas = conn.schemas()
self.assertEqual(len(schemas), 2)
self.assertEqual(schemas, ['dbo', 'qgis_test'])
filterUri = QgsDataSourceUri(self.uri)
filterUri.setParam('excludedSchemas', 'dbo')
conn = md.createConnection(filterUri.uri(), {})
schemas = conn.schemas()
self.assertEqual(len(schemas), 1)
self.assertEqual(schemas, ['qgis_test'])
# Store the connection
conn.store('filteredConnection')
otherConn = md.createConnection('filteredConnection')
schemas = otherConn.schemas()
self.assertEqual(len(schemas), 1)
self.assertEqual(schemas, ['qgis_test'])
if __name__ == '__main__':
unittest.main()