Skip to content

Commit 31fc2b0

Browse files
author
Hugo Mercier
authored
Merge pull request #3278 from mhugo/master
Fix virtual layer construction from joined layer
2 parents 564c02e + 2257d71 commit 31fc2b0

File tree

2 files changed

+69
-6
lines changed

2 files changed

+69
-6
lines changed

src/core/qgsvirtuallayerdefinitionutils.cpp

+13-5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ email : hugo dot mercier at oslandia dot com
1717
#include "qgsvirtuallayerdefinitionutils.h"
1818
#include "qgsvectorlayer.h"
1919
#include "qgsvectordataprovider.h"
20+
#include "qgsmaplayerregistry.h"
2021

2122
QgsVirtualLayerDefinition QgsVirtualLayerDefinitionUtils::fromJoinedLayer( QgsVectorLayer* layer )
2223
{
@@ -25,8 +26,6 @@ QgsVirtualLayerDefinition QgsVirtualLayerDefinitionUtils::fromJoinedLayer( QgsVe
2526
QStringList leftJoins;
2627
QStringList columns;
2728

28-
columns << "t.*"; // columns from the main layer
29-
3029
// look for the uid
3130
const QgsFields& fields = layer->dataProvider()->fields();
3231
{
@@ -47,14 +46,21 @@ QgsVirtualLayerDefinition QgsVirtualLayerDefinitionUtils::fromJoinedLayer( QgsVe
4746
def.setUid( uid );
4847
}
4948
}
49+
Q_FOREACH ( const QgsField& f, layer->dataProvider()->fields() )
50+
{
51+
columns << "t." + f.name();
52+
}
5053

5154
int joinIdx = 0;
5255
Q_FOREACH ( const QgsVectorJoinInfo& join, layer->vectorJoins() )
5356
{
5457
QString joinName = QString( "j%1" ).arg( ++joinIdx );
55-
QString prefix = join.prefix.isEmpty() ? layer->name() + "_" : join.prefix;
58+
QgsVectorLayer* joinedLayer = static_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join.joinLayerId ) );
59+
if ( !joinedLayer )
60+
continue;
61+
QString prefix = join.prefix.isEmpty() ? joinedLayer->name() + "_" : join.prefix;
5662

57-
leftJoins << QString( "LEFT JOIN %1 AS %2 ON t.\"%3\"=%2.\"%5\"" ).arg( join.joinLayerId, joinName, join.joinFieldName, join.targetFieldName );
63+
leftJoins << QString( "LEFT JOIN %1 AS %2 ON t.\"%5\"=%2.\"%3\"" ).arg( join.joinLayerId, joinName, join.joinFieldName, join.targetFieldName );
5864
if ( join.joinFieldNamesSubset() )
5965
{
6066
Q_FOREACH ( const QString& f, *join.joinFieldNamesSubset() )
@@ -64,8 +70,10 @@ QgsVirtualLayerDefinition QgsVirtualLayerDefinitionUtils::fromJoinedLayer( QgsVe
6470
}
6571
else
6672
{
67-
Q_FOREACH ( const QgsField& f, layer->dataProvider()->fields() )
73+
Q_FOREACH ( const QgsField& f, joinedLayer->fields() )
6874
{
75+
if ( f.name() == join.joinFieldName )
76+
continue;
6977
columns << joinName + "." + f.name() + " AS " + prefix + f.name();
7078
}
7179
}

tests/src/python/test_provider_virtual.py

+56-1
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
QgsMapLayerRegistry,
2323
QgsRectangle,
2424
QgsVirtualLayerDefinition,
25+
QgsVirtualLayerDefinitionUtils,
2526
QgsWKBTypes,
26-
QgsProject
27+
QgsProject,
28+
QgsVectorJoinInfo
2729
)
2830

2931
from qgis.testing import start_app, unittest
@@ -731,6 +733,59 @@ def test_query_with_accents(self):
731733
ids = [f.id() for f in vl2.getFeatures()]
732734
self.assertEqual(ids, [])
733735

736+
def test_joined_layers_conversion(self):
737+
v1 = QgsVectorLayer("Point?field=id:integer&field=b_id:integer&field=c_id:integer&field=name:string", "A", "memory")
738+
self.assertEqual(v1.isValid(), True)
739+
v2 = QgsVectorLayer("Point?field=id:integer&field=bname:string&field=bfield:integer", "B", "memory")
740+
self.assertEqual(v2.isValid(), True)
741+
v3 = QgsVectorLayer("Point?field=id:integer&field=cname:string", "C", "memory")
742+
self.assertEqual(v3.isValid(), True)
743+
QgsMapLayerRegistry.instance().addMapLayers([v1, v2, v3])
744+
joinInfo = QgsVectorJoinInfo()
745+
joinInfo.targetFieldName = "b_id"
746+
joinInfo.joinLayerId = v2.id()
747+
joinInfo.joinFieldName = "id"
748+
#joinInfo.prefix = "B_";
749+
v1.addJoin(joinInfo)
750+
self.assertEqual(len(v1.fields()), 6)
751+
752+
df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1)
753+
self.assertEqual(df.query(), 'SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS B_bname, j1.bfield AS B_bfield FROM {} AS t LEFT JOIN {} AS j1 ON t."b_id"=j1."id"'.format(v1.id(), v2.id()))
754+
755+
# with a field subset
756+
v1.removeJoin(v2.id())
757+
joinInfo.setJoinFieldNamesSubset(["bname"])
758+
v1.addJoin(joinInfo)
759+
self.assertEqual(len(v1.fields()), 5)
760+
df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1)
761+
self.assertEqual(df.query(), 'SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS B_bname FROM {} AS t LEFT JOIN {} AS j1 ON t."b_id"=j1."id"'.format(v1.id(), v2.id()))
762+
joinInfo.setJoinFieldNamesSubset(None)
763+
764+
# add a table prefix to the join
765+
v1.removeJoin(v2.id())
766+
joinInfo.prefix = "BB_"
767+
v1.addJoin(joinInfo)
768+
self.assertEqual(len(v1.fields()), 6)
769+
df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1)
770+
self.assertEqual(df.query(), 'SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS BB_bname, j1.bfield AS BB_bfield FROM {} AS t LEFT JOIN {} AS j1 ON t."b_id"=j1."id"'.format(v1.id(), v2.id()))
771+
joinInfo.prefix = ""
772+
v1.removeJoin(v2.id())
773+
v1.addJoin(joinInfo)
774+
775+
# add another join
776+
joinInfo2 = QgsVectorJoinInfo()
777+
joinInfo2.targetFieldName = "c_id"
778+
joinInfo2.joinLayerId = v3.id()
779+
joinInfo2.joinFieldName = "id"
780+
v1.addJoin(joinInfo2)
781+
self.assertEqual(len(v1.fields()), 7)
782+
df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1)
783+
self.assertEqual(df.query(), ('SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS B_bname, j1.bfield AS B_bfield, j2.cname AS C_cname FROM {} AS t ' +
784+
'LEFT JOIN {} AS j1 ON t."b_id"=j1."id" ' +
785+
'LEFT JOIN {} AS j2 ON t."c_id"=j2."id"').format(v1.id(), v2.id(), v3.id()))
786+
787+
QgsMapLayerRegistry.instance().removeMapLayers([v1, v2, v3])
788+
734789

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

0 commit comments

Comments
 (0)