def testVectorLayerUtilsCreateFeatureWithProviderDefaultLiteral(self):
        vl = QgsVectorLayer(
            "dbname=%s table='test_defaults' key='id'" % self.dbname,
            "test_defaults", "spatialite")
        self.assertEqual(vl.dataProvider().defaultValue(2), 5)

        f = QgsVectorLayerUtils.createFeature(vl)
        self.assertEqual(f.attributes(), [None, "qgis 'is good", 5, 5.7, None])

        # check that provider default literals take precedence over passed attribute values
        f = QgsVectorLayerUtils.createFeature(vl,
                                              attributes={
                                                  1: 'qgis is great',
                                                  0: 3
                                              })
        self.assertEqual(f.attributes(), [3, "qgis 'is good", 5, 5.7, None])

        # test that vector layer default value expression overrides provider default literal
        vl.setDefaultValueDefinition(3, QgsDefaultValue("4*3"))
        f = QgsVectorLayerUtils.createFeature(vl,
                                              attributes={
                                                  1: 'qgis is great',
                                                  0: 3
                                              })
        self.assertEqual(f.attributes(), [3, "qgis 'is good", 5, 12, None])
Example #2
0
    def testVectorLayerUtilsCreateFeatureWithProviderDefault(self):
        vl = QgsVectorLayer('%s table="qgis_test"."someData" sql=' % (self.dbconn), "someData", "postgres")
        default_clause = 'nextval(\'qgis_test."someData_pk_seq"\'::regclass)'
        self.assertEqual(vl.dataProvider().defaultValueClause(0), default_clause)

        # check that provider default clause takes precedence over passed attribute values
        # this also checks that the inbuilt unique constraint handling is bypassed in the case of a provider default clause
        f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: 'map'})
        self.assertEqual(f.attributes(), [default_clause, 5, "'qgis'::text", "'qgis'::text", None, None])

        # test take vector layer default value expression overrides postgres provider default clause
        vl.setDefaultValueDefinition(3, QgsDefaultValue("'mappy'"))
        f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: 'map'})
        self.assertEqual(f.attributes(), [default_clause, 5, "'qgis'::text", 'mappy', None, None])
Example #3
0
    def testVectorLayerUtilsCreateFeatureWithProviderDefault(self):
        vl = QgsVectorLayer('%s table="qgis_test"."someData" sql=' % (self.dbconn), "someData", "postgres")
        default_clause = 'nextval(\'qgis_test."someData_pk_seq"\'::regclass)'
        self.assertEqual(vl.dataProvider().defaultValueClause(0), default_clause)

        # check that provider default clause takes precedence over passed attribute values
        # this also checks that the inbuilt unique constraint handling is bypassed in the case of a provider default clause
        f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: 'map'})
        self.assertEqual(f.attributes(), [default_clause, 5, "'qgis'::text", "'qgis'::text", None, None])

        # test take vector layer default value expression overrides postgres provider default clause
        vl.setDefaultValueDefinition(3, QgsDefaultValue("'mappy'"))
        f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: 'map'})
        self.assertEqual(f.attributes(), [default_clause, 5, "'qgis'::text", 'mappy', None, None])
    def testVectorLayerUtilsCreateFeatureWithProviderDefaultLiteral(self):
        vl = QgsVectorLayer("dbname=%s table='test_defaults' key='id'" % self.dbname, "test_defaults", "spatialite")
        self.assertEqual(vl.dataProvider().defaultValue(2), 5)

        f = QgsVectorLayerUtils.createFeature(vl)
        self.assertEqual(f.attributes(), [None, "qgis 'is good", 5, 5.7, None])

        # check that provider default literals take precedence over passed attribute values
        f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 'qgis is great', 0: 3})
        self.assertEqual(f.attributes(), [3, "qgis 'is good", 5, 5.7, None])

        # test that vector layer default value expression overrides provider default literal
        vl.setDefaultValueDefinition(3, QgsDefaultValue("4*3"))
        f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 'qgis is great', 0: 3})
        self.assertEqual(f.attributes(), [3, "qgis 'is good", 5, 12, None])
    def testCreateFeature(self):
        """ test creating a feature respecting unique values of postgres provider """
        layer = QgsVectorLayer(
            "Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double",
            "addfeat", "memory")

        # init connection string
        dbconn = 'service=qgis_test'
        if 'QGIS_PGTEST_DB' in os.environ:
            dbconn = os.environ['QGIS_PGTEST_DB']

        # create a vector layer
        pg_layer = QgsVectorLayer(
            '{} table="qgis_test"."authors" sql='.format(dbconn), "authors",
            "postgres")
        self.assertTrue(pg_layer.isValid())
        # check the default clause
        default_clause = 'nextval(\'qgis_test.authors_pk_seq\'::regclass)'
        self.assertEqual(pg_layer.dataProvider().defaultValueClause(0),
                         default_clause)

        # though default_clause is after the first create not unique (until save), it should fill up all the features with it
        pg_layer.startEditing()
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [default_clause, NULL])
        self.assertTrue(pg_layer.addFeatures([f]))
        self.assertTrue(
            QgsVectorLayerUtils.valueExists(pg_layer, 0, default_clause))
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [default_clause, NULL])
        self.assertTrue(pg_layer.addFeatures([f]))
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [default_clause, NULL])
        self.assertTrue(pg_layer.addFeatures([f]))
        # if a unique value is passed, use it
        f = QgsVectorLayerUtils.createFeature(pg_layer,
                                              attributes={
                                                  0: 40,
                                                  1: NULL
                                              })
        self.assertEqual(f.attributes(), [40, NULL])
        # and if a default value is configured use it as well
        pg_layer.setDefaultValueDefinition(0, QgsDefaultValue('11*4'))
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [44, NULL])
        pg_layer.rollBack()
Example #6
0
    def testCreateFeature(self):
        """ test creating a feature respecting defaults and constraints """
        layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double",
                               "addfeat", "memory")
        # add a bunch of features
        f = QgsFeature()
        f.setAttributes(["test", 123, 1.0])
        f1 = QgsFeature(2)
        f1.setAttributes(["test_1", 124, 1.1])
        f2 = QgsFeature(3)
        f2.setAttributes(["test_2", 125, 2.4])
        f3 = QgsFeature(4)
        f3.setAttributes(["test_3", 126, 1.7])
        f4 = QgsFeature(5)
        f4.setAttributes(["superpig", 127, 0.8])
        self.assertTrue(layer.dataProvider().addFeatures([f, f1, f2, f3, f4]))

        # no layer
        self.assertFalse(QgsVectorLayerUtils.createFeature(None).isValid())

        # basic tests
        f = QgsVectorLayerUtils.createFeature(layer)
        self.assertTrue(f.isValid())
        self.assertEqual(f.fields(), layer.fields())
        self.assertFalse(f.hasGeometry())
        self.assertEqual(f.attributes(), [NULL, NULL, NULL])

        # set geometry
        g = QgsGeometry.fromPointXY(QgsPointXY(100, 200))
        f = QgsVectorLayerUtils.createFeature(layer, g)
        self.assertTrue(f.hasGeometry())
        self.assertEqual(f.geometry().asWkt(), g.asWkt())

        # using attribute map
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0})
        self.assertEqual(f.attributes(), ['a', NULL, 6.0])

        # layer with default value expression
        layer.setDefaultValueDefinition(2, QgsDefaultValue('3*4'))
        f = QgsVectorLayerUtils.createFeature(layer)
        self.assertEqual(f.attributes(), [NULL, NULL, 12])
        # we do not expect the default value expression to take precedence over the attribute map
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0})
        self.assertEqual(f.attributes(), ['a', NULL, 6.0])
        # layer with default value expression based on geometry
        layer.setDefaultValueDefinition(2, QgsDefaultValue('3*$x'))
        f = QgsVectorLayerUtils.createFeature(layer, g)
        #adjusted so that input value and output feature are the same
        self.assertEqual(f.attributes(), [NULL, NULL, 300.0])
        layer.setDefaultValueDefinition(2, QgsDefaultValue(None))

        # test with violated unique constraints
        layer.setFieldConstraint(1, QgsFieldConstraints.ConstraintUnique)
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        # since field 1 has Unique Constraint, it ignores value 123 that already has been set and sets to 128
        self.assertEqual(f.attributes(), ['test_1', 128, NULL])
        layer.setFieldConstraint(0, QgsFieldConstraints.ConstraintUnique)
        # since field 0 and 1 already have values test_1 and 123, the output must be a new unique value
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        self.assertEqual(f.attributes(), ['test_4', 128, NULL])
Example #7
0
    def test_on_update(self):
        """Test live update"""

        layer = QgsVectorLayer("Point?field=age:int", "vl", "memory")
        # set default value for numbers to [1, {age}], it will depend on the field age and should update
        field = QgsField('numbers', QVariant.List, 'array')
        field.setEditorWidgetSetup(QgsEditorWidgetSetup('List', {}))
        layer.dataProvider().addAttributes([field])
        layer.updateFields()
        layer.setDefaultValueDefinition(1,
                                        QgsDefaultValue('array(1, age)', True))
        layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup('List', {}))
        layer.startEditing()
        form = QgsAttributeForm(layer)
        feature = QgsFeature(layer.fields())
        form.setFeature(feature)
        form.setMode(QgsAttributeEditorContext.AddFeatureMode)
        form.changeAttribute('numbers', [12])
        form.changeAttribute('age', 1)
        self.assertEqual(form.currentFormFeature()['numbers'], [1, 1])
        form.changeAttribute('age', 7)
        self.assertEqual(form.currentFormFeature()['numbers'], [1, 7])
    def testCreateFeature(self):
        """ test creating a feature respecting defaults and constraints """
        layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double",
                               "addfeat", "memory")
        # add a bunch of features
        f = QgsFeature()
        f.setAttributes(["test", 123, 1.0])
        f1 = QgsFeature(2)
        f1.setAttributes(["test_1", 124, 1.1])
        f2 = QgsFeature(3)
        f2.setAttributes(["test_2", 125, 2.4])
        f3 = QgsFeature(4)
        f3.setAttributes(["test_3", 126, 1.7])
        f4 = QgsFeature(5)
        f4.setAttributes(["superpig", 127, 0.8])
        self.assertTrue(layer.dataProvider().addFeatures([f, f1, f2, f3, f4]))

        # no layer
        self.assertFalse(QgsVectorLayerUtils.createFeature(None).isValid())

        # basic tests
        f = QgsVectorLayerUtils.createFeature(layer)
        self.assertTrue(f.isValid())
        self.assertEqual(f.fields(), layer.fields())
        self.assertFalse(f.hasGeometry())
        self.assertEqual(f.attributes(), [NULL, NULL, NULL])

        # set geometry
        g = QgsGeometry.fromPointXY(QgsPointXY(100, 200))
        f = QgsVectorLayerUtils.createFeature(layer, g)
        self.assertTrue(f.hasGeometry())
        self.assertEqual(f.geometry().asWkt(), g.asWkt())

        # using attribute map
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0})
        self.assertEqual(f.attributes(), ['a', NULL, 6.0])

        # layer with default value expression
        layer.setDefaultValueDefinition(2, QgsDefaultValue('3*4'))
        f = QgsVectorLayerUtils.createFeature(layer)
        self.assertEqual(f.attributes(), [NULL, NULL, 12.0])
        # we expect the default value expression to take precedence over the attribute map
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0})
        self.assertEqual(f.attributes(), ['a', NULL, 12.0])
        # layer with default value expression based on geometry
        layer.setDefaultValueDefinition(2, QgsDefaultValue('3*$x'))
        f = QgsVectorLayerUtils.createFeature(layer, g)
        self.assertEqual(f.attributes(), [NULL, NULL, 300.0])
        layer.setDefaultValueDefinition(2, QgsDefaultValue(None))

        # test with violated unique constraints
        layer.setFieldConstraint(1, QgsFieldConstraints.ConstraintUnique)
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        self.assertEqual(f.attributes(), ['test_1', 128, NULL])
        layer.setFieldConstraint(0, QgsFieldConstraints.ConstraintUnique)
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        self.assertEqual(f.attributes(), ['test_4', 128, NULL])
Example #9
0
    def testDuplicateFeature(self):
        """ test duplicating a feature """

        project = QgsProject().instance()

        # LAYERS
        # - add first layer (parent)
        layer1 = QgsVectorLayer("Point?field=fldtxt:string&field=pkid:integer",
                                "parentlayer", "memory")
        # > check first layer (parent)
        self.assertTrue(layer1.isValid())
        # -  set the value for the copy
        layer1.setDefaultValueDefinition(1, QgsDefaultValue("rand(1000,2000)"))
        # > check first layer (parent)
        self.assertTrue(layer1.isValid())
        # - add second layer (child)
        layer2 = QgsVectorLayer(
            "Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer",
            "childlayer", "memory")
        # > check second layer (child)
        self.assertTrue(layer2.isValid())
        # - add layers
        project.addMapLayers([layer1, layer2])

        # FEATURES
        # - add 2 features on layer1 (parent)
        l1f1orig = QgsFeature()
        l1f1orig.setFields(layer1.fields())
        l1f1orig.setAttributes(["F_l1f1", 100])
        l1f2orig = QgsFeature()
        l1f2orig.setFields(layer1.fields())
        l1f2orig.setAttributes(["F_l1f2", 101])
        # > check by adding features
        self.assertTrue(layer1.dataProvider().addFeatures([l1f1orig,
                                                           l1f2orig]))
        # add 4 features on layer2 (child)
        l2f1orig = QgsFeature()
        l2f1orig.setFields(layer2.fields())
        l2f1orig.setAttributes(["F_l2f1", 201, 100])
        l2f2orig = QgsFeature()
        l2f2orig.setFields(layer2.fields())
        l2f2orig.setAttributes(["F_l2f2", 202, 100])
        l2f3orig = QgsFeature()
        l2f3orig.setFields(layer2.fields())
        l2f3orig.setAttributes(["F_l2f3", 203, 100])
        l2f4orig = QgsFeature()
        l2f4orig.setFields(layer2.fields())
        l2f4orig.setAttributes(["F_l2f4", 204, 101])
        # > check by adding features
        self.assertTrue(layer2.dataProvider().addFeatures(
            [l2f1orig, l2f2orig, l2f3orig, l2f4orig]))

        # RELATION
        # - create the relationmanager
        relMgr = project.relationManager()
        # - create the relation
        rel = QgsRelation()
        rel.setId('rel1')
        rel.setName('childrel')
        rel.setReferencingLayer(layer2.id())
        rel.setReferencedLayer(layer1.id())
        rel.addFieldPair('foreign_key', 'pkid')
        rel.setStrength(QgsRelation.Composition)
        # > check relation
        self.assertTrue(rel.isValid())
        # - add relation
        relMgr.addRelation(rel)
        # > check if referencedLayer is layer1
        self.assertEqual(rel.referencedLayer(), layer1)
        # > check if referencingLayer is layer2
        self.assertEqual(rel.referencingLayer(), layer2)
        # > check if the layers are correct in relation when loading from relationManager
        relations = project.relationManager().relations()
        relation = relations[list(relations.keys())[0]]
        # > check if referencedLayer is layer1
        self.assertEqual(relation.referencedLayer(), layer1)
        # > check if referencingLayer is layer2
        self.assertEqual(relation.referencingLayer(), layer2)
        # > check the relatedfeatures
        '''
        # testoutput 1
        print( "\nAll Features and relations")
        featit=layer1.getFeatures()
        f=QgsFeature()
        while featit.nextFeature(f):
            print( f.attributes())
            childFeature = QgsFeature()
            relfeatit=rel.getRelatedFeatures(f)
            while relfeatit.nextFeature(childFeature):
                 print( childFeature.attributes() )
        print( "\n--------------------------")

        print( "\nFeatures on layer1")
        for f in layer1.getFeatures():
            print( f.attributes() )

        print( "\nFeatures on layer2")
        for f in layer2.getFeatures():
            print( f.attributes() )
        '''

        # DUPLICATION
        # - duplicate feature l1f1orig with children
        layer1.startEditing()
        results = QgsVectorLayerUtils.duplicateFeature(layer1, l1f1orig,
                                                       project, 0)

        # > check if name is name of duplicated (pk is different)
        result_feature = results[0]
        self.assertEqual(result_feature.attribute('fldtxt'),
                         l1f1orig.attribute('fldtxt'))
        # > check duplicated child layer
        result_layer = results[1].layers()[0]
        self.assertEqual(result_layer, layer2)
        #  > check duplicated child features
        self.assertTrue(results[1].duplicatedFeatures(result_layer))
        '''
        # testoutput 2
        print( "\nFeatures on layer1 (after duplication)")
        for f in layer1.getFeatures():
            print( f.attributes() )

        print( "\nFeatures on layer2 (after duplication)")
        for f in layer2.getFeatures():
            print( f.attributes() )

        print( "\nAll Features and relations")
        featit=layer1.getFeatures()
        f=QgsFeature()
        while featit.nextFeature(f):
            print( f.attributes())
            childFeature = QgsFeature()
            relfeatit=rel.getRelatedFeatures(f)
            while relfeatit.nextFeature(childFeature):
                 print( childFeature.attributes() )
        '''

        # > compare text of parent feature
        self.assertEqual(result_feature.attribute('fldtxt'),
                         l1f1orig.attribute('fldtxt'))

        # - create copyValueList
        childFeature = QgsFeature()
        relfeatit = rel.getRelatedFeatures(result_feature)
        copyValueList = []
        while relfeatit.nextFeature(childFeature):
            copyValueList.append(childFeature.attribute('fldtxt'))
        # - create origValueList
        childFeature = QgsFeature()
        relfeatit = rel.getRelatedFeatures(l1f1orig)
        origValueList = []
        while relfeatit.nextFeature(childFeature):
            origValueList.append(childFeature.attribute('fldtxt'))

        # - check if the ids are still the same
        self.assertEqual(copyValueList, origValueList)
Example #10
0
    def testCreateFeature(self):
        """ test creating a feature respecting defaults and constraints """
        layer = QgsVectorLayer(
            "Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double",
            "addfeat", "memory")
        # add a bunch of features
        f = QgsFeature()
        f.setAttributes(["test", 123, 1.0])
        f1 = QgsFeature(2)
        f1.setAttributes(["test_1", 124, 1.1])
        f2 = QgsFeature(3)
        f2.setAttributes(["test_2", 125, 2.4])
        f3 = QgsFeature(4)
        f3.setAttributes(["test_3", 126, 1.7])
        f4 = QgsFeature(5)
        f4.setAttributes(["superpig", 127, 0.8])
        self.assertTrue(layer.dataProvider().addFeatures([f, f1, f2, f3, f4]))

        # no layer
        self.assertFalse(QgsVectorLayerUtils.createFeature(None).isValid())

        # basic tests
        f = QgsVectorLayerUtils.createFeature(layer)
        self.assertTrue(f.isValid())
        self.assertEqual(f.fields(), layer.fields())
        self.assertFalse(f.hasGeometry())
        self.assertEqual(f.attributes(), [NULL, NULL, NULL])

        # set geometry
        g = QgsGeometry.fromPointXY(QgsPointXY(100, 200))
        f = QgsVectorLayerUtils.createFeature(layer, g)
        self.assertTrue(f.hasGeometry())
        self.assertEqual(f.geometry().asWkt(), g.asWkt())

        # using attribute map
        f = QgsVectorLayerUtils.createFeature(layer,
                                              attributes={
                                                  0: 'a',
                                                  2: 6.0
                                              })
        self.assertEqual(f.attributes(), ['a', NULL, 6.0])

        # layer with default value expression
        layer.setDefaultValueDefinition(2, QgsDefaultValue('3*4'))
        f = QgsVectorLayerUtils.createFeature(layer)
        self.assertEqual(f.attributes(), [NULL, NULL, 12])
        # we do not expect the default value expression to take precedence over the attribute map
        f = QgsVectorLayerUtils.createFeature(layer,
                                              attributes={
                                                  0: 'a',
                                                  2: 6.0
                                              })
        self.assertEqual(f.attributes(), ['a', NULL, 6.0])
        # layer with default value expression based on geometry
        layer.setDefaultValueDefinition(2, QgsDefaultValue('3*$x'))
        f = QgsVectorLayerUtils.createFeature(layer, g)
        #adjusted so that input value and output feature are the same
        self.assertEqual(f.attributes(), [NULL, NULL, 300.0])
        layer.setDefaultValueDefinition(2, QgsDefaultValue(None))

        # test with violated unique constraints
        layer.setFieldConstraint(1, QgsFieldConstraints.ConstraintUnique)
        f = QgsVectorLayerUtils.createFeature(layer,
                                              attributes={
                                                  0: 'test_1',
                                                  1: 123
                                              })
        # since field 1 has Unique Constraint, it ignores value 123 that already has been set and sets to 128
        self.assertEqual(f.attributes(), ['test_1', 128, NULL])
        layer.setFieldConstraint(0, QgsFieldConstraints.ConstraintUnique)
        # since field 0 and 1 already have values test_1 and 123, the output must be a new unique value
        f = QgsVectorLayerUtils.createFeature(layer,
                                              attributes={
                                                  0: 'test_1',
                                                  1: 123
                                              })
        self.assertEqual(f.attributes(), ['test_4', 128, NULL])

        # test with violated unique constraints and default value expression providing unique value
        layer.setDefaultValueDefinition(1, QgsDefaultValue('130'))
        f = QgsVectorLayerUtils.createFeature(layer,
                                              attributes={
                                                  0: 'test_1',
                                                  1: 123
                                              })
        # since field 1 has Unique Constraint, it ignores value 123 that already has been set and adds the default value
        self.assertEqual(f.attributes(), ['test_4', 130, NULL])
        # fallback: test with violated unique constraints and default value expression providing already existing value
        # add the feature with the default value:
        self.assertTrue(layer.dataProvider().addFeatures([f]))
        f = QgsVectorLayerUtils.createFeature(layer,
                                              attributes={
                                                  0: 'test_1',
                                                  1: 123
                                              })
        # since field 1 has Unique Constraint, it ignores value 123 that already has been set and adds the default value
        # and since the default value providing an already existing value (130) it generates a unique value (next int: 131)
        self.assertEqual(f.attributes(), ['test_5', 131, NULL])
        layer.setDefaultValueDefinition(1, QgsDefaultValue(None))

        # test with manually correct unique constraint
        f = QgsVectorLayerUtils.createFeature(layer,
                                              attributes={
                                                  0: 'test_1',
                                                  1: 132
                                              })
        self.assertEqual(f.attributes(), ['test_5', 132, NULL])
        """ test creating a feature respecting unique values of postgres provider """
        layer = QgsVectorLayer(
            "Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double",
            "addfeat", "memory")

        # init connection string
        dbconn = 'dbname=\'qgis_test\''
        if 'QGIS_PGTEST_DB' in os.environ:
            dbconn = os.environ['QGIS_PGTEST_DB']

        # create a vector layer
        pg_layer = QgsVectorLayer(
            '{} table="qgis_test"."authors" sql='.format(dbconn), "authors",
            "postgres")
        self.assertTrue(pg_layer.isValid())
        # check the default clause
        default_clause = 'nextval(\'qgis_test.authors_pk_seq\'::regclass)'
        self.assertEqual(pg_layer.dataProvider().defaultValueClause(0),
                         default_clause)

        # though default_clause is after the first create not unique (until save), it should fill up all the features with it
        pg_layer.startEditing()
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [default_clause, NULL])
        self.assertTrue(pg_layer.addFeatures([f]))
        self.assertTrue(
            QgsVectorLayerUtils.valueExists(pg_layer, 0, default_clause))
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [default_clause, NULL])
        self.assertTrue(pg_layer.addFeatures([f]))
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [default_clause, NULL])
        self.assertTrue(pg_layer.addFeatures([f]))
        # if a unique value is passed, use it
        f = QgsVectorLayerUtils.createFeature(pg_layer,
                                              attributes={
                                                  0: 40,
                                                  1: NULL
                                              })
        self.assertEqual(f.attributes(), [40, NULL])
        # and if a default value is configured use it as well
        pg_layer.setDefaultValueDefinition(0, QgsDefaultValue('11*4'))
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [44, NULL])
        pg_layer.rollBack()
Example #11
0
    def testDuplicateFeature(self):
        """ test duplicating a feature """

        project = QgsProject().instance()

        # LAYERS
        # - add first layer (parent)
        layer1 = QgsVectorLayer("Point?field=fldtxt:string&field=pkid:integer",
                                "parentlayer", "memory")
        # > check first layer (parent)
        self.assertTrue(layer1.isValid())
        # -  set the value for the copy
        layer1.setDefaultValueDefinition(1, QgsDefaultValue("rand(1000,2000)"))
        # > check first layer (parent)
        self.assertTrue(layer1.isValid())
        # - add second layer (child)
        layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer",
                                "childlayer", "memory")
        # > check second layer (child)
        self.assertTrue(layer2.isValid())
        # - add layers
        project.addMapLayers([layer1, layer2])

        # FEATURES
        # - add 2 features on layer1 (parent)
        l1f1orig = QgsFeature()
        l1f1orig.setFields(layer1.fields())
        l1f1orig.setAttributes(["F_l1f1", 100])
        l1f2orig = QgsFeature()
        l1f2orig.setFields(layer1.fields())
        l1f2orig.setAttributes(["F_l1f2", 101])
        # > check by adding features
        self.assertTrue(layer1.dataProvider().addFeatures([l1f1orig, l1f2orig]))
        # add 4 features on layer2 (child)
        l2f1orig = QgsFeature()
        l2f1orig.setFields(layer2.fields())
        l2f1orig.setAttributes(["F_l2f1", 201, 100])
        l2f2orig = QgsFeature()
        l2f2orig.setFields(layer2.fields())
        l2f2orig.setAttributes(["F_l2f2", 202, 100])
        l2f3orig = QgsFeature()
        l2f3orig.setFields(layer2.fields())
        l2f3orig.setAttributes(["F_l2f3", 203, 100])
        l2f4orig = QgsFeature()
        l2f4orig.setFields(layer2.fields())
        l2f4orig.setAttributes(["F_l2f4", 204, 101])
        # > check by adding features
        self.assertTrue(layer2.dataProvider().addFeatures([l2f1orig, l2f2orig, l2f3orig, l2f4orig]))

        # RELATION
        # - create the relationmanager
        relMgr = project.relationManager()
        # - create the relation
        rel = QgsRelation()
        rel.setId('rel1')
        rel.setName('childrel')
        rel.setReferencingLayer(layer2.id())
        rel.setReferencedLayer(layer1.id())
        rel.addFieldPair('foreign_key', 'pkid')
        rel.setStrength(QgsRelation.Composition)
        # > check relation
        self.assertTrue(rel.isValid())
        # - add relation
        relMgr.addRelation(rel)
        # > check if referencedLayer is layer1
        self.assertEqual(rel.referencedLayer(), layer1)
        # > check if referencingLayer is layer2
        self.assertEqual(rel.referencingLayer(), layer2)
        # > check if the layers are correct in relation when loading from relationManager
        relations = project.relationManager().relations()
        relation = relations[list(relations.keys())[0]]
        # > check if referencedLayer is layer1
        self.assertEqual(relation.referencedLayer(), layer1)
        # > check if referencingLayer is layer2
        self.assertEqual(relation.referencingLayer(), layer2)
        # > check the relatedfeatures

        '''
        # testoutput 1
        print( "\nAll Features and relations")
        featit=layer1.getFeatures()
        f=QgsFeature()
        while featit.nextFeature(f):
            print( f.attributes())
            childFeature = QgsFeature()
            relfeatit=rel.getRelatedFeatures(f)
            while relfeatit.nextFeature(childFeature):
                 print( childFeature.attributes() )
        print( "\n--------------------------")

        print( "\nFeatures on layer1")
        for f in layer1.getFeatures():
            print( f.attributes() )

        print( "\nFeatures on layer2")
        for f in layer2.getFeatures():
            print( f.attributes() )
        '''

        # DUPLICATION
        # - duplicate feature l1f1orig with children
        layer1.startEditing()
        results = QgsVectorLayerUtils.duplicateFeature(layer1, l1f1orig, project, 0)

        # > check if name is name of duplicated (pk is different)
        result_feature = results[0]
        self.assertEqual(result_feature.attribute('fldtxt'), l1f1orig.attribute('fldtxt'))
        # > check duplicated child layer
        result_layer = results[1].layers()[0]
        self.assertEqual(result_layer, layer2)
        #  > check duplicated child features
        self.assertTrue(results[1].duplicatedFeatures(result_layer))

        '''
        # testoutput 2
        print( "\nFeatures on layer1 (after duplication)")
        for f in layer1.getFeatures():
            print( f.attributes() )

        print( "\nFeatures on layer2 (after duplication)")
        for f in layer2.getFeatures():
            print( f.attributes() )
            
        print( "\nAll Features and relations")
        featit=layer1.getFeatures()
        f=QgsFeature()
        while featit.nextFeature(f):
            print( f.attributes())
            childFeature = QgsFeature()
            relfeatit=rel.getRelatedFeatures(f)
            while relfeatit.nextFeature(childFeature):
                 print( childFeature.attributes() )
        '''

        # > compare text of parent feature
        self.assertEqual(result_feature.attribute('fldtxt'), l1f1orig.attribute('fldtxt'))

        # - create copyValueList
        childFeature = QgsFeature()
        relfeatit = rel.getRelatedFeatures(result_feature)
        copyValueList = []
        while relfeatit.nextFeature(childFeature):
            copyValueList.append(childFeature.attribute('fldtxt'))
        # - create origValueList
        childFeature = QgsFeature()
        relfeatit = rel.getRelatedFeatures(l1f1orig)
        origValueList = []
        while relfeatit.nextFeature(childFeature):
            origValueList.append(childFeature.attribute('fldtxt'))

        # - check if the ids are still the same
        self.assertEqual(copyValueList, origValueList)
    def testCreateFeature(self):
        """ test creating a feature respecting defaults and constraints """
        layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double",
                               "addfeat", "memory")
        # add a bunch of features
        f = QgsFeature()
        f.setAttributes(["test", 123, 1.0])
        f1 = QgsFeature(2)
        f1.setAttributes(["test_1", 124, 1.1])
        f2 = QgsFeature(3)
        f2.setAttributes(["test_2", 125, 2.4])
        f3 = QgsFeature(4)
        f3.setAttributes(["test_3", 126, 1.7])
        f4 = QgsFeature(5)
        f4.setAttributes(["superpig", 127, 0.8])
        self.assertTrue(layer.dataProvider().addFeatures([f, f1, f2, f3, f4]))

        # no layer
        self.assertFalse(QgsVectorLayerUtils.createFeature(None).isValid())

        # basic tests
        f = QgsVectorLayerUtils.createFeature(layer)
        self.assertTrue(f.isValid())
        self.assertEqual(f.fields(), layer.fields())
        self.assertFalse(f.hasGeometry())
        self.assertEqual(f.attributes(), [NULL, NULL, NULL])

        # set geometry
        g = QgsGeometry.fromPointXY(QgsPointXY(100, 200))
        f = QgsVectorLayerUtils.createFeature(layer, g)
        self.assertTrue(f.hasGeometry())
        self.assertEqual(f.geometry().asWkt(), g.asWkt())

        # using attribute map
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0})
        self.assertEqual(f.attributes(), ['a', NULL, 6.0])

        # layer with default value expression
        layer.setDefaultValueDefinition(2, QgsDefaultValue('3*4'))
        f = QgsVectorLayerUtils.createFeature(layer)
        self.assertEqual(f.attributes(), [NULL, NULL, 12])
        # we do not expect the default value expression to take precedence over the attribute map
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0})
        self.assertEqual(f.attributes(), ['a', NULL, 6.0])
        # layer with default value expression based on geometry
        layer.setDefaultValueDefinition(2, QgsDefaultValue('3*$x'))
        f = QgsVectorLayerUtils.createFeature(layer, g)
        #adjusted so that input value and output feature are the same
        self.assertEqual(f.attributes(), [NULL, NULL, 300.0])
        layer.setDefaultValueDefinition(2, QgsDefaultValue(None))

        # test with violated unique constraints
        layer.setFieldConstraint(1, QgsFieldConstraints.ConstraintUnique)
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        # since field 1 has Unique Constraint, it ignores value 123 that already has been set and sets to 128
        self.assertEqual(f.attributes(), ['test_1', 128, NULL])
        layer.setFieldConstraint(0, QgsFieldConstraints.ConstraintUnique)
        # since field 0 and 1 already have values test_1 and 123, the output must be a new unique value
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        self.assertEqual(f.attributes(), ['test_4', 128, NULL])

        # test with violated unique constraints and default value expression providing unique value
        layer.setDefaultValueDefinition(1, QgsDefaultValue('130'))
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        # since field 1 has Unique Constraint, it ignores value 123 that already has been set and adds the default value
        self.assertEqual(f.attributes(), ['test_4', 130, NULL])
        # fallback: test with violated unique constraints and default value expression providing already existing value
        # add the feature with the default value:
        self.assertTrue(layer.dataProvider().addFeatures([f]))
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        # since field 1 has Unique Constraint, it ignores value 123 that already has been set and adds the default value
        # and since the default value providing an already existing value (130) it generates a unique value (next int: 131)
        self.assertEqual(f.attributes(), ['test_5', 131, NULL])
        layer.setDefaultValueDefinition(1, QgsDefaultValue(None))

        # test with manually correct unique constraint
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 132})
        self.assertEqual(f.attributes(), ['test_5', 132, NULL])

        """ test creating a feature respecting unique values of postgres provider """
        layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double",
                               "addfeat", "memory")

        # init connection string
        dbconn = 'dbname=\'qgis_test\''
        if 'QGIS_PGTEST_DB' in os.environ:
            dbconn = os.environ['QGIS_PGTEST_DB']

        # create a vector layer
        pg_layer = QgsVectorLayer('{} table="qgis_test"."authors" sql='.format(dbconn), "authors", "postgres")
        self.assertTrue(pg_layer.isValid())
        # check the default clause
        default_clause = 'nextval(\'qgis_test.authors_pk_seq\'::regclass)'
        self.assertEqual(pg_layer.dataProvider().defaultValueClause(0), default_clause)

        # though default_clause is after the first create not unique (until save), it should fill up all the features with it
        pg_layer.startEditing()
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [default_clause, NULL])
        self.assertTrue(pg_layer.addFeatures([f]))
        self.assertTrue(QgsVectorLayerUtils.valueExists(pg_layer, 0, default_clause))
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [default_clause, NULL])
        self.assertTrue(pg_layer.addFeatures([f]))
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [default_clause, NULL])
        self.assertTrue(pg_layer.addFeatures([f]))
        # if a unique value is passed, use it
        f = QgsVectorLayerUtils.createFeature(pg_layer, attributes={0: 40, 1: NULL})
        self.assertEqual(f.attributes(), [40, NULL])
        # and if a default value is configured use it as well
        pg_layer.setDefaultValueDefinition(0, QgsDefaultValue('11*4'))
        f = QgsVectorLayerUtils.createFeature(pg_layer)
        self.assertEqual(f.attributes(), [44, NULL])
        pg_layer.rollBack()
    def testCreateFeature(self):
        """ test creating a feature respecting defaults and constraints """
        layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double",
                               "addfeat", "memory")
        # add a bunch of features
        f = QgsFeature()
        f.setAttributes(["test", 123, 1.0])
        f1 = QgsFeature(2)
        f1.setAttributes(["test_1", 124, 1.1])
        f2 = QgsFeature(3)
        f2.setAttributes(["test_2", 125, 2.4])
        f3 = QgsFeature(4)
        f3.setAttributes(["test_3", 126, 1.7])
        f4 = QgsFeature(5)
        f4.setAttributes(["superpig", 127, 0.8])
        self.assertTrue(layer.dataProvider().addFeatures([f, f1, f2, f3, f4]))

        # no layer
        self.assertFalse(QgsVectorLayerUtils.createFeature(None).isValid())

        # basic tests
        f = QgsVectorLayerUtils.createFeature(layer)
        self.assertTrue(f.isValid())
        self.assertEqual(f.fields(), layer.fields())
        self.assertFalse(f.hasGeometry())
        self.assertEqual(f.attributes(), [NULL, NULL, NULL])

        # set geometry
        g = QgsGeometry.fromPointXY(QgsPointXY(100, 200))
        f = QgsVectorLayerUtils.createFeature(layer, g)
        self.assertTrue(f.hasGeometry())
        self.assertEqual(f.geometry().asWkt(), g.asWkt())

        # using attribute map
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0})
        self.assertEqual(f.attributes(), ['a', NULL, 6.0])

        # layer with default value expression
        layer.setDefaultValueDefinition(2, QgsDefaultValue('3*4'))
        f = QgsVectorLayerUtils.createFeature(layer)
        self.assertEqual(f.attributes(), [NULL, NULL, 12])
        # we do not expect the default value expression to take precedence over the attribute map
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0})
        self.assertEqual(f.attributes(), ['a', NULL, 6.0])
        # layer with default value expression based on geometry
        layer.setDefaultValueDefinition(2, QgsDefaultValue('3*$x'))
        f = QgsVectorLayerUtils.createFeature(layer, g)
        #adjusted so that input value and output feature are the same
        self.assertEqual(f.attributes(), [NULL, NULL, 300.0])
        layer.setDefaultValueDefinition(2, QgsDefaultValue(None))

        # test with violated unique constraints
        layer.setFieldConstraint(1, QgsFieldConstraints.ConstraintUnique)
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        # since field 1 has Unique Constraint, it ignores value 123 that already has been set and sets to 128
        self.assertEqual(f.attributes(), ['test_1', 128, NULL])
        layer.setFieldConstraint(0, QgsFieldConstraints.ConstraintUnique)
        # since field 0 and 1 already have values test_1 and 123, the output must be a new unique value
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        self.assertEqual(f.attributes(), ['test_4', 128, NULL])

        # test with violated unique constraints and default value expression providing unique value
        layer.setDefaultValueDefinition(1, QgsDefaultValue('130'))
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        # since field 1 has Unique Constraint, it ignores value 123 that already has been set and adds the default value
        self.assertEqual(f.attributes(), ['test_4', 130, NULL])
        # fallback: test with violated unique constraints and default value expression providing already existing value
        # add the feature with the default value:
        self.assertTrue(layer.dataProvider().addFeatures([f]))
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123})
        # since field 1 has Unique Constraint, it ignores value 123 that already has been set and adds the default value
        # and since the default value providing an already existing value (130) it generates a unique value (next int: 131)
        self.assertEqual(f.attributes(), ['test_5', 131, NULL])
        layer.setDefaultValueDefinition(1, QgsDefaultValue(None))

        # test with manually correct unique constraint
        f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 132})
        self.assertEqual(f.attributes(), ['test_5', 132, NULL])