Skip to content
Permalink
Browse files

Add async model for virtual layers

  • Loading branch information
pblottiere committed Mar 2, 2018
1 parent bf7df6d commit 957e92c84707822d97c53bdd5ab54d026eda50d6
@@ -126,6 +126,7 @@
%Include qgsvectorlayerundocommand.sip
%Include qgsvectorlayerundopassthroughcommand.sip
%Include qgsvectorlayerutils.sip
%Include qgsvirtuallayertask.sip
%Include qgsvirtuallayerdefinition.sip
%Include qgsvirtuallayerdefinitionutils.sip
%Include qgsmapthemecollection.sip
@@ -50,6 +50,7 @@ of feature and attribute information from a spatial datasource.
FastTruncate,
ReadLayerMetadata,
WriteLayerMetadata,
CancelSupport,
};

typedef QFlags<QgsVectorDataProvider::Capability> Capabilities;
@@ -231,6 +232,8 @@ Providers with the FastTruncate capability will use an optimised method to trunc
.. seealso:: :py:func:`deleteFeatures`
%End

virtual bool cancel();

virtual bool addAttributes( const QList<QgsField> &attributes );
%Docstring
Adds new ``attributes`` to the provider. Returns true in case of success and false in case of failure.
@@ -150,6 +150,9 @@ Get the name of the field with unique identifiers
Set the name of the field with unique identifiers
%End

void setPostpone( bool postpone );
bool postpone() const;

QString geometryField() const;
%Docstring
Get the name of the geometry field. Empty if no geometry field
@@ -0,0 +1,46 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsvirtuallayertask.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/




class QgsVirtualLayerTask : QgsTask
{
%Docstring

Initializes a virtual layer in a separated task.

.. versionadded:: 3.0
%End

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

QgsVirtualLayerTask( const QgsVirtualLayerDefinition &definition );

QgsVectorLayer *layer();

QgsVirtualLayerDefinition definition() const;

virtual bool run();


virtual void cancel();


};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsvirtuallayertask.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
@@ -19,14 +19,14 @@
***************************************************************************/
"""

from ..data_model import TableDataModel, BaseTableModel
from ..data_model import TableDataModel, BaseTableModel, SqlResultModelAsync

from .connector import VLayerRegistry, getQueryGeometryName
from .plugin import LVectorTable
from ..plugin import DbError
from ..plugin import DbError, BaseError

from qgis.PyQt.QtCore import QTime, QTemporaryFile
from qgis.core import QgsVectorLayer, QgsWkbTypes, QgsVirtualLayerDefinition
from qgis.core import QgsVectorLayer, QgsWkbTypes, QgsVirtualLayerDefinition, QgsVirtualLayerTask, QgsTask


class LTableDataModel(TableDataModel):
@@ -63,40 +63,88 @@ def rowCount(self, index=None):
return 0


class LSqlResultModel(BaseTableModel):
# BaseTableModel
class LSqlResultModelTask(QgsTask):

def __init__(self, subtask, db):
QgsTask.__init__(self)
self.subtask = subtask
self.db = db
self.model = None

def run(self):
try:
path = self.subtask.definition().filePath()
sql = self.subtask.definition().query()
self.model = LSqlResultModel(self.db, sql, None, self.subtask.layer(), path)
except Exception as e:
self.error = BaseError(str(e))
return False
return True

def cancelQuery(self):
self.subtask.cancel()
self.cancel()


class LSqlResultModelAsync(SqlResultModelAsync):

def __init__(self, db, sql, parent=None):
# create a virtual layer with non-geometry results
t = QTime()
t.start()
SqlResultModelAsync.__init__(self, db, sql, parent)

tf = QTemporaryFile()
tf.open()
tmp = tf.fileName()
path = tf.fileName()
tf.close()

df = QgsVirtualLayerDefinition()
df.setFilePath(tmp)
df.setQuery(sql)
p = QgsVectorLayer(df.toString(), "vv", "virtual")
self._secs = t.elapsed() / 1000.0

if not p.isValid():
data = []
header = []
raise DbError(p.dataProvider().error().summary(), sql)
df.setFilePath(path)
df.setQuery(self.sql)

self.subtask = QgsVirtualLayerTask(df)
self.task = LSqlResultModelTask(self.subtask, db)
self.task.addSubTask(self.subtask, [], QgsTask.ParentDependsOnSubTask)
self.task.taskCompleted.connect(self.modelDone)
self.task.taskTerminated.connect(self.modelDone)

def modelDone(self):
self.status = self.task.status
self.model = self.task.model
self.done.emit()


class LSqlResultModel(BaseTableModel):

def __init__(self, db, sql, parent=None, layer=None, path=None):
t = QTime()
t.start()

if not layer:
tf = QTemporaryFile()
tf.open()
path = tf.fileName()
tf.close()

df = QgsVirtualLayerDefinition()
df.setFilePath(path)
df.setQuery(sql)
layer = QgsVectorLayer(df.toString(), "vv", "virtual")
self._secs = t.elapsed() / 1000.0

data = []
header = []

if not layer.isValid():
raise DbError(layer.dataProvider().error().summary(), sql)
else:
header = [f.name() for f in p.fields()]
header = [f.name() for f in layer.fields()]
has_geometry = False
if p.geometryType() != QgsWkbTypes.NullGeometry:
gn = getQueryGeometryName(tmp)
if layer.geometryType() != QgsWkbTypes.NullGeometry:
gn = getQueryGeometryName(path)
if gn:
has_geometry = True
header += [gn]

data = []
for f in p.getFeatures():
for f in layer.getFeatures():
a = f.attributes()
if has_geometry:
if f.hasGeometry():
@@ -98,6 +98,10 @@ def sqlResultModel(self, sql, parent):
from .data_model import LSqlResultModel
return LSqlResultModel(self, sql, parent)

def sqlResultModelAsync(self, sql, parent):
from .data_model import LSqlResultModelAsync
return LSqlResultModelAsync(self, sql, parent)

def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, _filter=""):
df = QgsVirtualLayerDefinition()
df.setQuery(sql)
@@ -61,6 +61,5 @@ def show(self):
super(QDialog, self).show()

def hide(self):
self.cancelStatus = False
self.mGif.stop()
super(QDialog, self).hide()
@@ -187,24 +187,25 @@ def executeSqlCanceled(self):
def executeSqlCompleted(self):
self.dlg_cancel_task.hide()

if self.modelAsync.task.status() == QgsTask.Complete:
model = self.modelAsync.model
cols = []
quotedCols = []

self.viewResult.setModel(model)
self.lblResult.setText(self.tr("{0} rows, {1:.1f} seconds").format(model.affectedRows(), model.secs()))
cols = self.viewResult.model().columnNames()
for col in cols:
quotedCols.append(self.db.connector.quoteId(col))
with OverrideCursor(Qt.WaitCursor):
if self.modelAsync.task.status() == QgsTask.Complete:
model = self.modelAsync.model
cols = []
quotedCols = []

self.viewResult.setModel(model)
self.lblResult.setText(self.tr("{0} rows, {1:.1f} seconds").format(model.affectedRows(), model.secs()))
cols = self.viewResult.model().columnNames()
for col in cols:
quotedCols.append(self.db.connector.quoteId(col))

self.setColumnCombos(cols, quotedCols)
self.update()
elif not self.dlg_cancel_task.cancelStatus:
DlgDbError.showError(self.modelAsync.error, self)
self.uniqueModel.clear()
self.geomCombo.clear()
pass
self.setColumnCombos(cols, quotedCols)
self.update()
elif not self.dlg_cancel_task.cancelStatus:
DlgDbError.showError(self.modelAsync.error, self)
self.uniqueModel.clear()
self.geomCombo.clear()
pass

def executeSql(self):

@@ -297,6 +297,7 @@ SET(QGIS_CORE_SRCS
qgsvectorfilewriter.cpp
qgsvectorfilewritertask.cpp
qgsvectorlayer.cpp
qgsvirtuallayertask.cpp
qgsvectorlayerfeaturecounter.cpp
qgsvectorlayercache.cpp
qgsvectorlayerdiagramprovider.cpp
@@ -635,6 +636,7 @@ SET(QGIS_CORE_MOC_HDRS
qgsvectorlayereditbuffer.h
qgsvectorlayereditpassthrough.h
qgsvectorlayer.h
qgsvirtuallayertask.h
qgsvectorlayerexporter.h
qgsvectorlayerfeaturecounter.h
qgsvectorlayerjoinbuffer.h
@@ -804,6 +804,11 @@ QTextCodec *QgsVectorDataProvider::textEncoding() const
return mEncoding;
}

bool QgsVectorDataProvider::cancel()
{
return false;
}

QStringList QgsVectorDataProvider::sEncodings;

QList<QgsRelation> QgsVectorDataProvider::discoverRelations( const QgsVectorLayer *, const QList<QgsVectorLayer *> & ) const
@@ -90,6 +90,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
FastTruncate = 1 << 20, //!< Supports fast truncation of the layer (removing all features). Since QGIS 3.0
ReadLayerMetadata = 1 << 21, //!< Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata()
WriteLayerMetadata = 1 << 22, //!< Provider can write layer metadata to the data store. Since QGIS 3.0. See QgsDataProvider::writeLayerMetadata()
CancelSupport = 1 << 23, //!< Supports interruption of pending queries from a separated thread. Since QGIS 3.0
};

Q_DECLARE_FLAGS( Capabilities, Capability )
@@ -248,6 +249,8 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
*/
virtual bool truncate();

virtual bool cancel();

/**
* Adds new \a attributes to the provider. Returns true in case of success and false in case of failure.
* If attributes are added using this method then QgsVectorLayer::updateFields() must be called
@@ -157,6 +157,10 @@ QgsVirtualLayerDefinition QgsVirtualLayerDefinition::fromUrl( const QUrl &url )
}
}
}
else if ( key == QLatin1String( "postpone" ) )
{
def.setPostpone( true );
}
}
def.setFields( fields );

@@ -209,6 +213,11 @@ QUrl QgsVirtualLayerDefinition::toUrl() const
url.addQueryItem( QStringLiteral( "field" ), f.name() + ":text" );
}

if ( postpone() )
{
url.addQueryItem( QStringLiteral( "postpone" ), QLatin1String( "" ) );
}

return url;
}

@@ -131,6 +131,9 @@ class CORE_EXPORT QgsVirtualLayerDefinition
//! Set the name of the field with unique identifiers
void setUid( const QString &uid ) { mUid = uid; }

void setPostpone( bool postpone ) { mPostpone = postpone; }
bool postpone() const { return mPostpone; }

//! Get the name of the geometry field. Empty if no geometry field
QString geometryField() const { return mGeometryField; }
//! Set the name of the geometry field
@@ -174,6 +177,7 @@ class CORE_EXPORT QgsVirtualLayerDefinition
QString mGeometryField;
QString mFilePath;
QgsFields mFields;
bool mPostpone = false;
QgsWkbTypes::Type mGeometryWkbType = QgsWkbTypes::Unknown;
long mGeometrySrid = 0;
};

0 comments on commit 957e92c

Please sign in to comment.
You can’t perform that action at this time.