Skip to content

Commit

Permalink
QgsQueryResultModel
Browse files Browse the repository at this point in the history
A model for QgsAbstractDatabaseProviderConnection::QueryResult
  • Loading branch information
elpaso committed Jan 13, 2021
1 parent 8a85cae commit ea72ab9
Show file tree
Hide file tree
Showing 7 changed files with 258 additions and 0 deletions.
48 changes: 48 additions & 0 deletions python/core/auto_generated/qgsqueryresultmodel.sip.in
@@ -0,0 +1,48 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsqueryresultmodel.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/




class QgsQueryResultModel : QAbstractListModel
{
%Docstring
The QgsQueryResultModel class is a model for QgsAbstractDatabaseProviderConnection.QueryResult

.. versionadded:: 3.18
%End

%TypeHeaderCode
#include "qgsqueryresultmodel.h"
%End
public:

QgsQueryResultModel( const QgsAbstractDatabaseProviderConnection::QueryResult &queryResult, QObject *parent = 0 );

public:

virtual int rowCount( const QModelIndex &parent ) const;

virtual int columnCount( const QModelIndex &parent ) const;

virtual QVariant data( const QModelIndex &index, int role ) const;

virtual void fetchMore( const QModelIndex &parent );

virtual bool canFetchMore( const QModelIndex &parent ) const;


};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsqueryresultmodel.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/core/core_auto.sip
Expand Up @@ -156,6 +156,7 @@
%Include auto_generated/qgsproxyfeaturesink.sip
%Include auto_generated/qgsproxyprogresstask.sip
%Include auto_generated/qgspythonrunner.sip
%Include auto_generated/qgsqueryresultmodel.sip
%Include auto_generated/qgsrange.sip
%Include auto_generated/qgsreadwritecontext.sip
%Include auto_generated/qgsreadwritelocker.sip
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -397,6 +397,7 @@ set(QGIS_CORE_SRCS
qgspointxy.cpp
qgspointlocator.cpp
qgspointlocatorinittask.cpp
qgsqueryresultmodel.cpp
qgssnappingconfig.cpp
qgsprojutils.cpp
qgsproperty.cpp
Expand Down Expand Up @@ -1002,6 +1003,7 @@ set(QGIS_CORE_HDRS
qgsproxyfeaturesink.h
qgsproxyprogresstask.h
qgspythonrunner.h
qgsqueryresultmodel.h
qgsrange.h
qgsreadwritecontext.h
qgsreadwritelocker.h
Expand Down
83 changes: 83 additions & 0 deletions src/core/qgsqueryresultmodel.cpp
@@ -0,0 +1,83 @@
/***************************************************************************
qgsqueryresultmodel.cpp - QgsQueryResultModel
---------------------
begin : 24.12.2020
copyright : (C) 2020 by Alessandro Pasotti
email : elpaso@itopen.it
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsqueryresultmodel.h"

const int QgsQueryResultModel::ROWS_TO_FETCH = 200;

QgsQueryResultModel::QgsQueryResultModel( const QgsAbstractDatabaseProviderConnection::QueryResult &queryResult, QObject *parent )
: QAbstractListModel( parent )
, mQueryResult( queryResult )
{
}

int QgsQueryResultModel::rowCount( const QModelIndex &parent ) const
{
if ( parent.isValid() )
return 0;
return mRowCount;
}

int QgsQueryResultModel::columnCount( const QModelIndex &parent ) const
{
if ( parent.isValid() )
return 0;
return mQueryResult.columns().count();
}

QVariant QgsQueryResultModel::data( const QModelIndex &index, int role ) const
{
if ( !index.isValid() )
return QVariant();

Q_ASSERT( mQueryResult.rows().count( ) == mRowCount );

if ( index.row() >= mRowCount || index.row() < 0 )
return QVariant();

if ( role == Qt::DisplayRole )
{
return mQueryResult.rows().at( index.row() );
}
return QVariant();
}

void QgsQueryResultModel::fetchMore( const QModelIndex &parent )
{
if ( parent.isValid() )
return;

QVariantList newRows;
for ( int i = 0; i < ROWS_TO_FETCH && mQueryResult.hasNextRow(); ++i )
{
newRows.push_back( mQueryResult.nextRow() );
}

if ( !newRows.isEmpty() )
{
const qlonglong newRowsCount { newRows.count() };
beginInsertRows( QModelIndex(), newRowsCount, newRowsCount + newRows.count() - 1 );
mRowCount += newRowsCount;
endInsertRows();
}
}

bool QgsQueryResultModel::canFetchMore( const QModelIndex &parent ) const
{
if ( parent.isValid() )
return false;

return mQueryResult.hasNextRow();
}
56 changes: 56 additions & 0 deletions src/core/qgsqueryresultmodel.h
@@ -0,0 +1,56 @@
/***************************************************************************
qgsqueryresultmodel.h - QgsQueryResultModel
---------------------
begin : 24.12.2020
copyright : (C) 2020 by Alessandro Pasotti
email : elpaso@itopen.it
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QgsQueryResultModel_H
#define QgsQueryResultModel_H

#include <QAbstractListModel>

#include "qgis_core.h"
#include "qgis_sip.h"

#include "qgsabstractdatabaseproviderconnection.h"

/**
* The QgsQueryResultModel class is a model for QgsAbstractDatabaseProviderConnection::QueryResult
*
* \ingroup core
* \since QGIS 3.18
*/
class CORE_EXPORT QgsQueryResultModel : public QAbstractListModel
{
Q_OBJECT
public:

QgsQueryResultModel( const QgsAbstractDatabaseProviderConnection::QueryResult &queryResult, QObject *parent = nullptr );

// QAbstractItemModel interface
public:

int rowCount( const QModelIndex &parent ) const override;
int columnCount( const QModelIndex &parent ) const override;
QVariant data( const QModelIndex &index, int role ) const override;
void fetchMore( const QModelIndex &parent ) override;
bool canFetchMore( const QModelIndex &parent ) const override;

private:

QgsAbstractDatabaseProviderConnection::QueryResult mQueryResult;
qlonglong mRowCount = 0;
// Batch of rows to fetch
static const int ROWS_TO_FETCH;
};

#endif // qgsqueryresultmodel.h
1 change: 1 addition & 0 deletions tests/src/python/CMakeLists.txt
Expand Up @@ -241,6 +241,7 @@ ADD_PYTHON_TEST(PyQgsProviderConnectionSpatialite test_qgsproviderconnection_spa
ADD_PYTHON_TEST(PyQgsProviderRegistry test_qgsproviderregistry.py)
ADD_PYTHON_TEST(PyQgsProviderSourceWidgetProviderRegistry test_qgssourcewidgetproviderregistry.py)
ADD_PYTHON_TEST(TestQgsRandomMarkerSymbolLayer test_qgsrandommarkersymbollayer.py)
ADD_PYTHON_TEST(PyQgsQueryResultModel test_qgsqueryresultmodel.py)
ADD_PYTHON_TEST(PyQgsRange test_qgsrange.py)
ADD_PYTHON_TEST(PyQgsRangeSlider test_qgsrangeslider.py)
ADD_PYTHON_TEST(PyQgsRangeWidgets test_qgsrangewidgets.py)
Expand Down
67 changes: 67 additions & 0 deletions tests/src/python/test_qgsqueryresultmodel.py
@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for Postgres QgsQueryResultModel.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Alessandro Pasotti'
__date__ = '24/12/2020'
__copyright__ = 'Copyright 2020, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import os
from qgis.core import (
QgsProviderRegistry,
QgsQueryResultModel,
QgsAbstractDatabaseProviderConnection,
)
from qgis.testing import unittest, start_app
from qgis.PyQt.QtCore import QCoreApplication


class TestPyQgsQgsQueryResultModel(unittest.TestCase):

@classmethod
def setUpClass(cls):
"""Run before all tests"""

QCoreApplication.setOrganizationName("QGIS_Test")
QCoreApplication.setOrganizationDomain(cls.__name__)
QCoreApplication.setApplicationName(cls.__name__)
start_app()
cls.postgres_conn = "service='qgis_test'"
if 'QGIS_PGTEST_DB' in os.environ:
cls.postgres_conn = os.environ['QGIS_PGTEST_DB']
cls.uri = cls.postgres_conn + ' sslmode=disable'

def test_model(self):
"""Test the model"""

md = QgsProviderRegistry.instance().providerMetadata('postgres')
conn = md.createConnection(self.uri, {})
res = conn.execSql('SELECT generate_series(1, 1000)')
model = QgsQueryResultModel(res)
self.assertEqual(model.columnCount(model.index(-1)), 1)
self.assertEqual(model.rowCount(model.index(-1)), 0)
self.assertTrue(model.canFetchMore(model.index(-1)))

model.fetchMore(model.index(-1))
self.assertEqual(model.rowCount(model.index(-1)), 200)
self.assertTrue(res.hasNextRow())

# Fetch the rest
for batch in range(2, 6):
model.fetchMore(model.index(-1))
self.assertEqual(model.rowCount(model.index(-1)), 200 * batch)

self.assertEqual(model.rowCount(model.index(-1)), 1000)
self.assertFalse(res.hasNextRow())
self.assertFalse(model.canFetchMore(model.index(-1)))


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

0 comments on commit ea72ab9

Please sign in to comment.