Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add QgsRelation::getReferencedFeature to access parent feature
  • Loading branch information
m-kuhn committed Jul 24, 2015
1 parent 740e3ab commit d01424a
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 75 deletions.
14 changes: 11 additions & 3 deletions python/core/qgsrelation.sip
Expand Up @@ -118,13 +118,22 @@ class QgsRelation
*/
QgsFeatureRequest getRelatedFeaturesRequest( const QgsFeature& feature ) const;

const QString name() const;
QgsFeatureRequest getReferencedFeatureRequest( const QgsFeature& feature ) const;

QgsFeature getReferencedFeature( const QgsFeature& child ) const;

/**
* The id
* @return
*/
const QString& id() const;
QString name() const;

/**
* A (project-wide) unique id for this relation
*
* @return The id
*/
QString id() const;

/**
* Access the referencing (child) layer's id
Expand Down Expand Up @@ -182,5 +191,4 @@ class QgsRelation

protected:
void updateRelationStatus();
void runChecks();
};
77 changes: 58 additions & 19 deletions src/core/qgsrelation.cpp
Expand Up @@ -97,7 +97,7 @@ void QgsRelation::writeXML( QDomNode &node, QDomDocument &doc ) const
elem.setAttribute( "referencingLayer", mReferencingLayerId );
elem.setAttribute( "referencedLayer", mReferencedLayerId );

foreach ( FieldPair fields, mFieldPairs )
Q_FOREACH ( FieldPair fields, mFieldPairs )
{
QDomElement referenceElem = doc.createElement( "fieldRef" );
referenceElem.setAttribute( "referencingField", fields.first );
Expand Down Expand Up @@ -153,22 +153,20 @@ QgsFeatureRequest QgsRelation::getRelatedFeaturesRequest( const QgsFeature& feat
{
QStringList conditions;

foreach ( const QgsRelation::FieldPair& fieldPair, mFieldPairs )
Q_FOREACH ( const QgsRelation::FieldPair& fieldPair, mFieldPairs )
{
int referencingIdx = referencingLayer()->pendingFields().indexFromName( fieldPair.referencingField() );
QgsField referencingField = referencingLayer()->pendingFields().at( referencingIdx );

switch ( referencingField.type() )
if ( referencingField.type() == QVariant::String )
{
case QVariant::String:
// Use quotes
conditions << QString( "\"%1\" = '%2'" ).arg( fieldPair.referencingField(), feature.attribute( fieldPair.referencedField() ).toString() );
break;

default:
// No quotes
conditions << QString( "\"%1\" = %2" ).arg( fieldPair.referencingField(), feature.attribute( fieldPair.referencedField() ).toString() );
break;
// Use quotes
conditions << QString( "\"%1\" = '%2'" ).arg( fieldPair.referencingField(), feature.attribute( fieldPair.referencedField() ).toString() );
}
else
{
// No quotes
conditions << QString( "\"%1\" = %2" ).arg( fieldPair.referencingField(), feature.attribute( fieldPair.referencedField() ).toString() );
}
}

Expand All @@ -181,12 +179,58 @@ QgsFeatureRequest QgsRelation::getRelatedFeaturesRequest( const QgsFeature& feat
return myRequest;
}

const QString QgsRelation::name() const
QgsFeatureRequest QgsRelation::getReferencedFeatureRequest( const QgsAttributes& attributes ) const
{
QStringList conditions;

Q_FOREACH ( const QgsRelation::FieldPair& fieldPair, mFieldPairs )
{
int referencedIdx = referencedLayer()->pendingFields().indexFromName( fieldPair.referencedField() );
int referencingIdx = referencingLayer()->pendingFields().indexFromName( fieldPair.referencingField() );

QgsField referencedField = referencedLayer()->pendingFields().at( referencedIdx );

if ( referencedField.type() == QVariant::String )
{
// Use quotes
conditions << QString( "\"%1\" = '%2'" ).arg( fieldPair.referencedField(), attributes[referencingIdx].toString() );
}
else
{
// No quotes
conditions << QString( "\"%1\" = %2" ).arg( fieldPair.referencedField(), attributes[referencingIdx].toString() );
}
}

QgsFeatureRequest myRequest;

QgsDebugMsg( QString( "Filter conditions: '%1'" ).arg( conditions.join( " AND " ) ) );

myRequest.setFilterExpression( conditions.join( " AND " ) );

return myRequest;
}

QgsFeatureRequest QgsRelation::getReferencedFeatureRequest( const QgsFeature& feature ) const
{
return getReferencedFeatureRequest( feature.attributes() );
}

QgsFeature QgsRelation::getReferencedFeature( const QgsFeature& child ) const
{
QgsFeatureRequest request = getReferencedFeatureRequest( child );

QgsFeature f;
mReferencedLayer->getFeatures( request ).nextFeature( f );
return f;
}

QString QgsRelation::name() const
{
return mRelationName;
}

const QString& QgsRelation::id() const
QString QgsRelation::id() const
{
return mRelationId;
}
Expand Down Expand Up @@ -251,8 +295,3 @@ void QgsRelation::updateRelationStatus()
}
}
}

void QgsRelation::runChecks()
{

}
49 changes: 43 additions & 6 deletions src/core/qgsrelation.h
Expand Up @@ -138,17 +138,55 @@ class CORE_EXPORT QgsRelation
*
* @param feature A feature from the referenced (parent) layer
*
* @return An request for all the referenced features
* @return A request for all the referencing features
*/
QgsFeatureRequest getRelatedFeaturesRequest( const QgsFeature& feature ) const;

const QString name() const;
/**
* Creates a request to return the feature on the referenced (parent) layer
* which is referenced by the provided feature.
*
* @param attributes An attribute vector containing the foreign key
*
* @return A request the referenced feature
*/
QgsFeatureRequest getReferencedFeatureRequest( const QgsAttributes& attributes ) const;

/**
* Creates a request to return the feature on the referenced (parent) layer
* which is referenced by the provided feature.
*
* @param feature A feature from the referencing (child) layer
*
* @return A request the referenced feature
*/
QgsFeatureRequest getReferencedFeatureRequest( const QgsFeature& feature ) const;

/**
* Creates a request to return the feature on the referenced (parent) layer
* which is referenced by the provided feature.
*
* @param feature A feature from the referencing (child) layer
*
* @return A request the referenced feature
*/
QgsFeature getReferencedFeature( const QgsFeature& child ) const;

/**
* Returns a human readable name for this relation. Mostly used as title for the children.
*
* @see id()
*
* @return A name
*/
QString name() const;

/**
* The id
* @return
* A (project-wide) unique id for this relation
*
* @return The id
*/
const QString& id() const;
QString id() const;

/**
* Access the referencing (child) layer's id
Expand Down Expand Up @@ -198,7 +236,6 @@ class CORE_EXPORT QgsRelation

protected:
void updateRelationStatus();
void runChecks();

private:
/** Unique Id */
Expand Down
106 changes: 59 additions & 47 deletions tests/src/python/test_qgsrelation.py
Expand Up @@ -25,110 +25,122 @@
TestCase,
unittest
)

QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp()


def createReferencingLayer():
layer = QgsVectorLayer("Point?field=fldtxt:string&field=foreignkey:integer",
"referencinglayer", "memory")
pr = layer.dataProvider()
f1 = QgsFeature()
f1.setFields( layer.pendingFields() )
f1.setFields(layer.pendingFields())
f1.setAttributes(["test1", 123])
f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(100,200)))
f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(100, 200)))
f2 = QgsFeature()
f2.setFields( layer.pendingFields() )
f2.setFields(layer.pendingFields())
f2.setAttributes(["test2", 123])
f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(101,201)))
assert pr.addFeatures([f1,f2])
f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(101, 201)))
assert pr.addFeatures([f1, f2])
return layer


def createReferencedLayer():
layer = QgsVectorLayer(
"Point?field=x:string&field=y:integer&field=z:integer",
"referencedlayer", "memory")
pr = layer.dataProvider()
f1 = QgsFeature()
f1.setFields( layer.pendingFields() )
f1.setFields(layer.pendingFields())
f1.setAttributes(["foo", 123, 321])
f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(1,1)))
f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(1, 1)))
f2 = QgsFeature()
f2.setFields( layer.pendingFields() )
f2.setFields(layer.pendingFields())
f2.setAttributes(["bar", 456, 654])
f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(2,2)))
f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(2, 2)))
f3 = QgsFeature()
f3.setFields( layer.pendingFields() )
f3.setFields(layer.pendingFields())
f3.setAttributes(["foobar", 789, 554])
f3.setGeometry(QgsGeometry.fromPoint(QgsPoint(2,3)))
f3.setGeometry(QgsGeometry.fromPoint(QgsPoint(2, 3)))
assert pr.addFeatures([f1, f2, f3])
return layer


def formatAttributes(attrs):
return repr([ unicode(a) for a in attrs ])
return repr([unicode(a) for a in attrs])


class TestQgsRelation( TestCase ):
class TestQgsRelation(TestCase):
def setUp(self):
self.referencedLayer = createReferencedLayer()
self.referencingLayer = createReferencingLayer()
QgsMapLayerRegistry.instance().addMapLayers([self.referencedLayer, self.referencingLayer])

def tearDown(self):
QgsMapLayerRegistry.instance().removeAllMapLayers()

def test_isValid(self):
referencedLayer = createReferencedLayer()
referencingLayer = createReferencingLayer()
QgsMapLayerRegistry.instance().addMapLayers([referencedLayer,referencingLayer])

rel = QgsRelation()
assert not rel.isValid()

rel.setRelationId( 'rel1' )
rel.setRelationId('rel1')
assert not rel.isValid()

rel.setRelationName( 'Relation Number One' )
rel.setRelationName('Relation Number One')
assert not rel.isValid()

rel.setReferencingLayer( referencingLayer.id() )
rel.setReferencingLayer(self.referencingLayer.id())
assert not rel.isValid()

rel.setReferencedLayer( referencedLayer.id() )
rel.setReferencedLayer(self.referencedLayer.id())
assert not rel.isValid()

rel.addFieldPair( 'foreignkey', 'y' )
rel.addFieldPair('foreignkey', 'y')
assert rel.isValid()

QgsMapLayerRegistry.instance().removeAllMapLayers()

def test_getRelatedFeatures(self):
referencedLayer = createReferencedLayer()
referencingLayer = createReferencingLayer()
QgsMapLayerRegistry.instance().addMapLayers([referencedLayer,referencingLayer])

rel = QgsRelation()

rel.setRelationId( 'rel1' )
rel.setRelationName( 'Relation Number One' )
rel.setReferencingLayer( referencingLayer.id() )
rel.setReferencedLayer( referencedLayer.id() )
rel.addFieldPair( 'foreignkey', 'y' )
rel.setRelationId('rel1')
rel.setRelationName('Relation Number One')
rel.setReferencingLayer(self.referencingLayer.id())
rel.setReferencedLayer(self.referencedLayer.id())
rel.addFieldPair('foreignkey', 'y')

feat = referencedLayer.getFeatures().next()
feat = self.referencedLayer.getFeatures().next()

it = rel.getRelatedFeatures( feat )
it = rel.getRelatedFeatures(feat)

[ a.attributes() for a in it ] == [[u'test1', 123], [u'test2', 123]]
assert [a.attributes() for a in it] == [[u'test1', 123], [u'test2', 123]]

QgsMapLayerRegistry.instance().removeAllMapLayers()
def test_getReferencedFeature(self):
rel = QgsRelation()
rel.setRelationId('rel1')
rel.setRelationName('Relation Number One')
rel.setReferencingLayer(self.referencingLayer.id())
rel.setReferencedLayer(self.referencedLayer.id())
rel.addFieldPair('foreignkey', 'y')

def test_fieldPairs(self):
referencedLayer = createReferencedLayer()
referencingLayer = createReferencingLayer()
QgsMapLayerRegistry.instance().addMapLayers([referencedLayer,referencingLayer])
feat = self.referencingLayer.getFeatures().next()

rel = QgsRelation()
f = rel.getReferencedFeature(feat)

rel.setRelationId( 'rel1' )
rel.setRelationName( 'Relation Number One' )
rel.setReferencingLayer( referencingLayer.id() )
rel.setReferencedLayer( referencedLayer.id() )
rel.addFieldPair( 'foreignkey', 'y' )
assert f.isValid()
assert f[0] == 'foo'

assert( rel.fieldPairs() == { 'foreignkey': 'y'} )

QgsMapLayerRegistry.instance().removeAllMapLayers()
def test_fieldPairs(self):
rel = QgsRelation()

rel.setRelationId('rel1')
rel.setRelationName('Relation Number One')
rel.setReferencingLayer(self.referencingLayer.id())
rel.setReferencedLayer(self.referencedLayer.id())
rel.addFieldPair('foreignkey', 'y')

assert (rel.fieldPairs() == {'foreignkey': 'y'})


if __name__ == '__main__':
Expand Down

0 comments on commit d01424a

Please sign in to comment.