data_model.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. """
  2. /***************************************************************************
  3. Name : Virtual layers plugin for DB Manager
  4. Date : December 2015
  5. copyright : (C) 2015 by Hugo Mercier
  6. email : hugo dot mercier at oslandia dot com
  7. ***************************************************************************/
  8. /***************************************************************************
  9. * *
  10. * This program is free software; you can redistribute it and/or modify *
  11. * it under the terms of the GNU General Public License as published by *
  12. * the Free Software Foundation; either version 2 of the License, or *
  13. * (at your option) any later version. *
  14. * *
  15. ***************************************************************************/
  16. """
  17. from ..data_model import (TableDataModel,
  18. BaseTableModel,
  19. SqlResultModelAsync,
  20. SqlResultModelTask)
  21. from .connector import VLayerRegistry, getQueryGeometryName
  22. from .plugin import LVectorTable
  23. from ..plugin import DbError, BaseError
  24. from qgis.PyQt.QtCore import QTime, QTemporaryFile
  25. from qgis.core import (QgsVectorLayer,
  26. QgsWkbTypes,
  27. QgsVirtualLayerDefinition,
  28. QgsVirtualLayerTask,
  29. QgsTask)
  30. class LTableDataModel(TableDataModel):
  31. def __init__(self, table, parent=None):
  32. TableDataModel.__init__(self, table, parent)
  33. self.layer = None
  34. if isinstance(table, LVectorTable):
  35. self.layer = VLayerRegistry.instance().getLayer(table.name)
  36. else:
  37. self.layer = VLayerRegistry.instance().getLayer(table)
  38. if not self.layer:
  39. return
  40. # populate self.resdata
  41. self.resdata = []
  42. for f in self.layer.getFeatures():
  43. a = f.attributes()
  44. # add the geometry type
  45. if f.hasGeometry():
  46. a.append(QgsWkbTypes.displayString(f.geometry().wkbType()))
  47. else:
  48. a.append('None')
  49. self.resdata.append(a)
  50. self.fetchedFrom = 0
  51. self.fetchedCount = len(self.resdata)
  52. def rowCount(self, index=None):
  53. if self.layer:
  54. return self.layer.featureCount()
  55. return 0
  56. class LSqlResultModelTask(SqlResultModelTask):
  57. def __init__(self, db, sql, parent):
  58. super().__init__(db, sql, parent)
  59. tf = QTemporaryFile()
  60. tf.open()
  61. path = tf.fileName()
  62. tf.close()
  63. df = QgsVirtualLayerDefinition()
  64. df.setFilePath(path)
  65. df.setQuery(sql)
  66. self.subtask = QgsVirtualLayerTask(df)
  67. self.addSubTask(self.subtask, [], QgsTask.ParentDependsOnSubTask)
  68. def run(self):
  69. try:
  70. path = self.subtask.definition().filePath()
  71. sql = self.subtask.definition().query()
  72. self.model = LSqlResultModel(self.db, sql, None, self.subtask.layer(), path)
  73. except Exception as e:
  74. self.error = BaseError(str(e))
  75. return False
  76. return True
  77. def cancel(self):
  78. SqlResultModelTask.cancel(self)
  79. class LSqlResultModelAsync(SqlResultModelAsync):
  80. def __init__(self, db, sql, parent=None):
  81. super().__init__()
  82. self.task = LSqlResultModelTask(db, sql, parent)
  83. self.task.taskCompleted.connect(self.modelDone)
  84. self.task.taskTerminated.connect(self.modelDone)
  85. def modelDone(self):
  86. self.status = self.task.status
  87. self.model = self.task.model
  88. if self.task.subtask.exceptionText():
  89. self.error = BaseError(self.task.subtask.exceptionText())
  90. self.done.emit()
  91. class LSqlResultModel(BaseTableModel):
  92. def __init__(self, db, sql, parent=None, layer=None, path=None):
  93. t = QTime()
  94. t.start()
  95. if not layer:
  96. tf = QTemporaryFile()
  97. tf.open()
  98. path = tf.fileName()
  99. tf.close()
  100. df = QgsVirtualLayerDefinition()
  101. df.setFilePath(path)
  102. df.setQuery(sql)
  103. layer = QgsVectorLayer(df.toString(), "vv", "virtual")
  104. self._secs = t.elapsed() / 1000.0
  105. data = []
  106. header = []
  107. if not layer.isValid():
  108. raise DbError(layer.dataProvider().error().summary(), sql)
  109. else:
  110. header = [f.name() for f in layer.fields()]
  111. has_geometry = False
  112. if layer.geometryType() != QgsWkbTypes.NullGeometry:
  113. gn = getQueryGeometryName(path)
  114. if gn:
  115. has_geometry = True
  116. header += [gn]
  117. for f in layer.getFeatures():
  118. a = f.attributes()
  119. if has_geometry:
  120. if f.hasGeometry():
  121. a += [f.geometry().asWkt()]
  122. else:
  123. a += [None]
  124. data += [a]
  125. self._secs = 0
  126. self._affectedRows = len(data)
  127. BaseTableModel.__init__(self, header, data, parent)
  128. def secs(self):
  129. return self._secs
  130. def affectedRows(self):
  131. return self._affectedRows