Skip to content
Permalink
Browse files

Provider default values: more tests and homogenize

Fixes #33383

Homogenization is not complete but at least
there are test cases for the future.
  • Loading branch information
elpaso committed Jan 24, 2020
1 parent f259345 commit ebf7d247d8efa3d387447a68b9dd4a494d887b57
@@ -1385,7 +1385,7 @@ QVariant QgsOgrProvider::defaultValue( int fieldId ) const

QString defaultVal = mDefaultValues.value( fieldId, QString() );
if ( defaultVal.isEmpty() )
return QVariant();
return defaultVal;

QVariant resultVar = defaultVal;
if ( defaultVal == QStringLiteral( "CURRENT_TIMESTAMP" ) )
@@ -982,7 +982,7 @@ void QgsSpatiaLiteProvider::insertDefaultValue( int fieldIndex, QString defaultV
}
}

if ( ! ok ) // Must be a SQL clause
if ( ! ok ) // Must be a SQL clause and not a literal
{
mDefaultValueClause.insert( fieldIndex, defaultVal );
}
@@ -992,6 +992,36 @@ void QgsSpatiaLiteProvider::insertDefaultValue( int fieldIndex, QString defaultV
}
}


QVariant QgsSpatiaLiteProvider::defaultValue( int fieldId ) const
{
// TODO: backend-side evaluation
if ( fieldId < 0 || fieldId >= mAttributeFields.count() )
return QVariant();

QString defaultVal = mDefaultValues.value( fieldId, QString() );
if ( defaultVal.isEmpty() )
return QVariant();

QVariant resultVar = defaultVal;
if ( defaultVal == QStringLiteral( "CURRENT_TIMESTAMP" ) )
resultVar = QDateTime::currentDateTime();
else if ( defaultVal == QStringLiteral( "CURRENT_DATE" ) )
resultVar = QDate::currentDate();
else if ( defaultVal == QStringLiteral( "CURRENT_TIME" ) )
resultVar = QTime::currentTime();
else if ( defaultVal.startsWith( '\'' ) )
{
defaultVal = defaultVal.remove( 0, 1 );
defaultVal.chop( 1 );
defaultVal.replace( QLatin1String( "''" ), QLatin1String( "'" ) );
resultVar = defaultVal;
}

( void )mAttributeFields.at( fieldId ).convertCompatible( resultVar );
return resultVar;
}

QString QgsSpatiaLiteProvider::defaultValueClause( int fieldIndex ) const
{
return mDefaultValueClause.value( fieldIndex, QString() );
@@ -4559,34 +4589,6 @@ QgsVectorDataProvider::Capabilities QgsSpatiaLiteProvider::capabilities() const
return mEnabledCapabilities;
}

QVariant QgsSpatiaLiteProvider::defaultValue( int fieldId ) const
{
if ( fieldId < 0 || fieldId >= mAttributeFields.count() )
return QVariant();

QString defaultVal = mDefaultValues.value( fieldId, QString() );
if ( defaultVal.isEmpty() )
return QVariant();

QVariant resultVar = defaultVal;
if ( defaultVal == QStringLiteral( "CURRENT_TIMESTAMP" ) )
resultVar = QDateTime::currentDateTime();
else if ( defaultVal == QStringLiteral( "CURRENT_DATE" ) )
resultVar = QDate::currentDate();
else if ( defaultVal == QStringLiteral( "CURRENT_TIME" ) )
resultVar = QTime::currentTime();
else if ( defaultVal.startsWith( '\'' ) )
{
defaultVal = defaultVal.remove( 0, 1 );
defaultVal.chop( 1 );
defaultVal.replace( QLatin1String( "''" ), QLatin1String( "'" ) );
resultVar = defaultVal;
}

( void )mAttributeFields.at( fieldId ).convertCompatible( resultVar );
return resultVar;
}

bool QgsSpatiaLiteProvider::skipConstraintCheck( int fieldIndex, QgsFieldConstraints::Constraint constraint, const QVariant &value ) const
{
Q_UNUSED( constraint )
@@ -628,7 +628,7 @@ def testSpatialiteDefaultValues(self):

# simple table with primary key
sql = """
CREATE TABLE test_table (
CREATE TABLE test_table_default_values (
id integer primary key autoincrement,
comment TEXT,
created_at_01 text DEFAULT (datetime('now','localtime')),
@@ -641,24 +641,44 @@ def testSpatialiteDefaultValues(self):
cur.execute("COMMIT")
con.close()

vl = QgsVectorLayer(dbname + '|layername=test_table', 'test_table', 'ogr')
vl = QgsVectorLayer(dbname + '|layername=test_table_default_values', 'test_table_default_values', 'ogr')
self.assertTrue(vl.isValid())

# Save it for the test
now = datetime.now()

# Test default values
dp = vl.dataProvider()
#FIXME: should it be None?
self.assertTrue(dp.defaultValue(0).isNull())
self.assertTrue(dp.defaultValue(1).isNull())
#FIXME: This fails because there is no backend-side evaluation in this provider
#self.assertTrue(dp.defaultValue(2).startswith(now.strftime('%Y-%m-%d')))
self.assertTrue(dp.defaultValue(3).startswith(now.strftime('%Y-%m-%d')))
self.assertEqual(dp.defaultValue(4), 123)
self.assertEqual(dp.defaultValue(5), 'My default')

self.assertEqual(dp.defaultValueClause(0), 'Autogenerate')
self.assertEqual(dp.defaultValueClause(1), '')
self.assertEqual(dp.defaultValueClause(2), "datetime('now','localtime')")
self.assertEqual(dp.defaultValueClause(3), "CURRENT_TIMESTAMP")
#FIXME: ogr provider simply returns values when asked for clauses
#self.assertEqual(dp.defaultValueClause(4), '')
#self.assertEqual(dp.defaultValueClause(5), '')

feature = QgsFeature(vl.fields())
for idx in range(vl.fields().count()):
default = vl.dataProvider().defaultValue(idx)
if default is not None:
feature.setAttribute(idx, default)
else:
if not default:
feature.setAttribute(idx, 'A comment')

# Save it for the test
now = datetime.now()
else:
feature.setAttribute(idx, default)

self.assertTrue(vl.dataProvider().addFeature(feature))
del(vl)

# Verify
vl2 = QgsVectorLayer(dbname + '|layername=test_table', 'test_table', 'ogr')
vl2 = QgsVectorLayer(dbname + '|layername=test_table_default_values', 'test_table_default_values', 'ogr')
self.assertTrue(vl2.isValid())
feature = next(vl2.getFeatures())
self.assertEqual(feature.attribute(1), 'A comment')
@@ -24,6 +24,7 @@

import os
import time
from datetime import datetime

from qgis.core import (
QgsVectorLayer,
@@ -1438,6 +1439,61 @@ def testIdentityPk(self):
self.assertTrue(vl.isValid())
feature = next(vl.getFeatures())
self.assertIsNotNone(feature.id())

def testDefaultValuesAndClauses(self):
"""Test wether default values like CURRENT_TIMESTAMP or
now() they are respected. See GH #33383"""

# Create the test table

vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="public"."test_table_default_values" sql=', 'test', 'postgres')
self.assertTrue(vl.isValid())

# Save it for the test
now = datetime.now()

# Test default values
dp = vl.dataProvider()
dp.setProviderProperty(QgsDataProvider.EvaluateDefaultValues, 1)
self.assertIsNotNone(dp.defaultValue(0))
self.assertIsNone(dp.defaultValue(1))
self.assertTrue(dp.defaultValue(2).startswith(now.strftime('%Y-%m-%d')))
self.assertTrue(dp.defaultValue(3).startswith(now.strftime('%Y-%m-%d')))
self.assertEqual(dp.defaultValue(4), 123)
self.assertEqual(dp.defaultValue(5), 'My default')

#FIXME: the provider should return the clause definition
# regardless of the EvaluateDefaultValues setting
dp.setProviderProperty(QgsDataProvider.EvaluateDefaultValues, 0)
self.assertEqual(dp.defaultValueClause(0), "nextval('test_table_default_values_id_seq'::regclass)")
self.assertEqual(dp.defaultValueClause(1), '')
self.assertEqual(dp.defaultValueClause(2), "now()")
self.assertEqual(dp.defaultValueClause(3), "CURRENT_TIMESTAMP")
self.assertEqual(dp.defaultValueClause(4), '123')
self.assertEqual(dp.defaultValueClause(5), "'My default'::text")
#FIXME: the test fails if the value is not reset to 1
dp.setProviderProperty(QgsDataProvider.EvaluateDefaultValues, 1)

feature = QgsFeature(vl.fields())
for idx in range(vl.fields().count()):
default = vl.dataProvider().defaultValue(idx)
if default is not None:
feature.setAttribute(idx, default)
else:
feature.setAttribute(idx, 'A comment')

self.assertTrue(vl.dataProvider().addFeature(feature))
del(vl)

# Verify
vl2 = QgsVectorLayer(self.dbconn + ' sslmode=disable table="public"."test_table_default_values" sql=', 'test', 'postgres')
self.assertTrue(vl2.isValid())
feature = next(vl2.getFeatures())
self.assertEqual(feature.attribute(1), 'A comment')
self.assertTrue(feature.attribute(2).startswith(now.strftime('%Y-%m-%d')))
self.assertTrue(feature.attribute(3).startswith(now.strftime('%Y-%m-%d')))
self.assertEqual(feature.attribute(4), 123)
self.assertEqual(feature.attribute(5), 'My default')


class TestPyQgsPostgresProviderCompoundKey(unittest.TestCase, ProviderTestCase):
@@ -1177,7 +1177,7 @@ def testSpatialiteDefaultValues(self):

# simple table with primary key
sql = """
CREATE TABLE test_table (
CREATE TABLE test_table_default_values (
id integer primary key autoincrement,
comment text,
created_at_01 text DEFAULT (datetime('now','localtime')),
@@ -1190,24 +1190,43 @@ def testSpatialiteDefaultValues(self):
cur.execute("COMMIT")
con.close()

vl = QgsVectorLayer("dbname='%s' table='test_table'" % dbname, 'test_table', 'spatialite')
vl = QgsVectorLayer("dbname='%s' table='test_table_default_values'" % dbname, 'test_table_default_values', 'spatialite')
self.assertTrue(vl.isValid())

# Save it for the test
now = datetime.now()

# Test default values
dp = vl.dataProvider()
# FIXME: should it be None?
self.assertTrue(dp.defaultValue(0).isNull())
self.assertIsNone(dp.defaultValue(1))
# FIXME: This fails because there is no backend-side evaluation in this provider
#self.assertTrue(dp.defaultValue(2).startswith(now.strftime('%Y-%m-%d')))
self.assertTrue(dp.defaultValue(3).startswith(now.strftime('%Y-%m-%d')))
self.assertEqual(dp.defaultValue(4), 123)
self.assertEqual(dp.defaultValue(5), 'My default')

self.assertEqual(dp.defaultValueClause(0), '')
self.assertEqual(dp.defaultValueClause(1), '')
self.assertEqual(dp.defaultValueClause(2), "datetime('now','localtime')")
self.assertEqual(dp.defaultValueClause(3), "CURRENT_TIMESTAMP")
self.assertEqual(dp.defaultValueClause(4), '')
self.assertEqual(dp.defaultValueClause(5), '')

feature = QgsFeature(vl.fields())
for idx in range(vl.fields().count()):
default = vl.dataProvider().defaultValue(idx)
if default is not None:
feature.setAttribute(idx, default)
else:
if not default:
feature.setAttribute(idx, 'A comment')

# Save it for the test
now = datetime.now()
else:
feature.setAttribute(idx, default)

self.assertTrue(vl.dataProvider().addFeature(feature))
del(vl)

# Verify
vl2 = QgsVectorLayer("dbname='%s' table='test_table'" % dbname, 'test_table', 'spatialite')
vl2 = QgsVectorLayer("dbname='%s' table='test_table_default_values'" % dbname, 'test_table_default_values', 'spatialite')
self.assertTrue(vl2.isValid())
feature = next(vl2.getFeatures())
self.assertEqual(feature.attribute(1), 'A comment')
@@ -686,3 +686,18 @@ CREATE TABLE qgis_test.b29560 (
INSERT INTO qgis_test.b29560 (geom)
VALUES ('POLYGON EMPTY'::geometry);


---------------------------------------------
--
-- Aspatial table with default values
--

CREATE TABLE test_table_default_values (
id SERIAL primary key,
comment TEXT,
created_at_01 text DEFAULT now(),
created_at_02 text DEFAULT CURRENT_TIMESTAMP,
anumber INTEGER DEFAULT 123,
atext TEXT default 'My default'
)

0 comments on commit ebf7d24

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