From 414bb5e3e482e114b490fa50185464b075ece6d4 Mon Sep 17 00:00:00 2001 From: wuxiaoqing Date: Thu, 14 Sep 2017 19:38:23 +0800 Subject: [PATCH 1/5] add return_null support --- architect/databases/bases.py | 1 + architect/databases/postgresql/partition.py | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/architect/databases/bases.py b/architect/databases/bases.py index e0efab7..5ad6729 100644 --- a/architect/databases/bases.py +++ b/architect/databases/bases.py @@ -19,6 +19,7 @@ def __init__(self, model, **meta): self.column_value = meta['column_value'] self.column_name = meta['column'] self.pks = meta['pk'] if isinstance(meta['pk'], list) else [meta['pk']] + self.return_null = meta.get('return_null', False) def prepare(self): """ diff --git a/architect/databases/postgresql/partition.py b/architect/databases/postgresql/partition.py index 70b7dfe..49f6b06 100644 --- a/architect/databases/postgresql/partition.py +++ b/architect/databases/postgresql/partition.py @@ -28,7 +28,7 @@ def prepare(self): definitions[definition] = '\n'.join(definitions[definition]).format(**formatters) - return self.database.execute(""" + execute_sql = """ -- We need to create a before insert function CREATE OR REPLACE FUNCTION {{parent_table}}_insert_child() RETURNS TRIGGER AS $$ @@ -55,7 +55,7 @@ def prepare(self): END; EXECUTE 'INSERT INTO ' || tablename || ' VALUES (($1).*);' USING NEW; - RETURN NEW; + RETURN {{return_val}}; END; $$ LANGUAGE plpgsql; @@ -73,7 +73,9 @@ def prepare(self): FOR EACH ROW EXECUTE PROCEDURE {{parent_table}}_insert_child(); END IF; END $$; - + """ + if not self.return_null: + execute_sql += """ -- Then we create a function to delete duplicate row from the master table after insert CREATE OR REPLACE FUNCTION {{parent_table}}_delete_master() RETURNS TRIGGER AS $$ @@ -97,10 +99,13 @@ def prepare(self): FOR EACH ROW EXECUTE PROCEDURE {{parent_table}}_delete_master(); END IF; END $$; - """.format(**definitions).format( + """ + + return self.database.execute(execute_sql.format(**definitions).format( pk=' AND '.join('{pk} = NEW.{pk}'.format(pk=pk) for pk in self.pks), parent_table=self.table, - column='"{0}"'.format(self.column_name) + column='"{0}"'.format(self.column_name), + return_val='NULL' if self.return_null else 'NEW' )) def exists(self): From 73de9374c9f31527fd4ac7797f57e61f162e5431 Mon Sep 17 00:00:00 2001 From: wuxiaoqing Date: Fri, 15 Sep 2017 13:49:13 +0800 Subject: [PATCH 2/5] add tests for django --- tests/models/django.py | 61 ++++++++++++++++++++++-------------------- tests/test_django.py | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 29 deletions(-) diff --git a/tests/models/django.py b/tests/models/django.py index 54f23b9..b3e775e 100644 --- a/tests/models/django.py +++ b/tests/models/django.py @@ -51,55 +51,58 @@ # Generation of entities for date range partitioning for item in ('day', 'week', 'month', 'year'): - class Meta(object): - app_label = 'test' - db_table = 'test_rangedate{0}'.format(item) - - name = '{0}RangeDate{1}'.format(dbname, item.capitalize()) - partition = install('partition', type='range', subtype='date', constraint=item, column='created') - - locals()[name] = partition(type(name, (models.Model,), { - '__module__': 'test.models', - 'name': models.CharField(max_length=255), - 'created': models.DateTimeField(null=True), - 'Meta': Meta, - 'db': database, - })) - - if database == 'pgsql': - # Generation of entities for integer range partitioning - for item in ('2', '5'): + for return_null in (True, False): class Meta(object): app_label = 'test' - db_table = 'test_rangeinteger{0}'.format(item) + db_table = 'test_rangedate{0}{1}'.format(item, '_return_null' if return_null else '') - name = '{0}RangeInteger{1}'.format(dbname, item) - partition = install('partition', type='range', subtype='integer', constraint=item, column='num') + name = '{0}RangeDate{1}{2}'.format(dbname, item.capitalize(), 'ReturnNULL' if return_null else '') + partition = install('partition', type='range', subtype='date', constraint=item, column='created', return_null=return_null) locals()[name] = partition(type(name, (models.Model,), { '__module__': 'test.models', 'name': models.CharField(max_length=255), - 'num': models.IntegerField(null=True), + 'created': models.DateTimeField(null=True), 'Meta': Meta, 'db': database, })) - # Generation of entities for string range partitioning - for subtype in ('string_firstchars', 'string_lastchars'): - for item in ('2', '5'): + if database == 'pgsql': + # Generation of entities for integer range partitioning + for item in ('2', '5'): + for return_null in (True, False): class Meta(object): app_label = 'test' - db_table = 'test_range{0}{1}'.format(subtype, item) + db_table = 'test_rangeinteger{0}{1}'.format(item, '_return_null' if return_null else '') - name = '{0}Range{1}{2}'.format(dbname, ''.join(s.capitalize() for s in subtype.split('_')), item) - partition = install('partition', type='range', subtype=subtype, constraint=item, column='title') + name = '{0}RangeInteger{1}{2}'.format(dbname, item, 'ReturnNULL' if return_null else '') + partition = install('partition', type='range', subtype='integer', constraint=item, column='num', return_null=return_null) locals()[name] = partition(type(name, (models.Model,), { '__module__': 'test.models', 'name': models.CharField(max_length=255), - 'title': models.CharField(max_length=255, null=True), + 'num': models.IntegerField(null=True), 'Meta': Meta, 'db': database, })) + # Generation of entities for string range partitioning + for subtype in ('string_firstchars', 'string_lastchars'): + for item in ('2', '5'): + for return_null in (True, False): + class Meta(object): + app_label = 'test' + db_table = 'test_range{0}{1}{2}'.format(subtype, item, '_return_null' if return_null else '') + + name = '{0}Range{1}{2}{3}'.format(dbname, ''.join(s.capitalize() for s in subtype.split('_')), item, 'ReturnNULL' if return_null else '') + partition = install('partition', type='range', subtype=subtype, constraint=item, column='title', return_null=return_null) + + locals()[name] = partition(type(name, (models.Model,), { + '__module__': 'test.models', + 'name': models.CharField(max_length=255), + 'title': models.CharField(max_length=255, null=True), + 'Meta': Meta, + 'db': database, + })) + management.call_command(command, database=database, run_syncdb=True, verbosity=0, interactive=False) diff --git a/tests/test_django.py b/tests/test_django.py index 9cbaf7a..cb1264b 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -80,6 +80,13 @@ def test_range_date_day_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_day_return_null(self): + object1 = PgsqlRangeDateDayReturnNULL.objects.create(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + object2 = PgsqlRangeDateDayReturnNULL.objects.raw( + 'SELECT * FROM test_rangedateday_return_null_y2014d105 WHERE id = %s', [object1.id])[0] + + self.assertTrue(object1.name, object2.name) + def test_range_date_week(self): object1 = PgsqlRangeDateWeek.objects.create(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) object2 = PgsqlRangeDateWeek.objects.raw( @@ -94,6 +101,13 @@ def test_range_date_week_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_week_return_null(self): + object1 = PgsqlRangeDateWeekReturnNULL.objects.create(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + object2 = PgsqlRangeDateWeekReturnNULL.objects.raw( + 'SELECT * FROM test_rangedateweek_return_null_y2014w16 WHERE id = %s', [object1.id])[0] + + self.assertTrue(object1.name, object2.name) + def test_range_date_month(self): object1 = PgsqlRangeDateMonth.objects.create(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) object2 = PgsqlRangeDateMonth.objects.raw( @@ -108,6 +122,13 @@ def test_range_date_month_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_month_return_null(self): + object1 = PgsqlRangeDateMonthReturnNULL.objects.create(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + object2 = PgsqlRangeDateMonthReturnNULL.objects.raw( + 'SELECT * FROM test_rangedatemonth_return_null_y2014m04 WHERE id = %s', [object1.id])[0] + + self.assertTrue(object1.name, object2.name) + def test_range_date_year(self): object1 = PgsqlRangeDateYear.objects.create(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) object2 = PgsqlRangeDateYear.objects.raw( @@ -122,6 +143,13 @@ def test_range_date_year_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_year_return_null(self): + object1 = PgsqlRangeDateYearReturnNULL.objects.create(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + object2 = PgsqlRangeDateYearReturnNULL.objects.raw( + 'SELECT * FROM test_rangedateyear_return_null_y2014 WHERE id = %s', [object1.id])[0] + + self.assertTrue(object1.name, object2.name) + def test_range_integer_positive(self): object1 = PgsqlRangeInteger2.objects.create(name='foo', num=3) object2 = PgsqlRangeInteger2.objects.raw('SELECT * FROM test_rangeinteger2_3_4 WHERE id = %s', [object1.id])[0] @@ -160,6 +188,15 @@ def test_range_integer_null(self): self.assertTrue(object1.name, object2.name) self.assertTrue(object3.name, object4.name) + def test_range_integer_positive_return_null(self): + object1 = PgsqlRangeInteger2ReturnNULL.objects.create(id=1, name='foo', num=3) + object2 = PgsqlRangeInteger2ReturnNULL.objects.raw('SELECT * FROM test_rangeinteger2_return_null_3_4 WHERE id = %s', [object1.id])[0] + object3 = PgsqlRangeInteger5ReturnNULL.objects.create(id=1, name='foo', num=3) + object4 = PgsqlRangeInteger5ReturnNULL.objects.raw('SELECT * FROM test_rangeinteger5_return_null_1_5 WHERE id = %s', [object3.id])[0] + + self.assertTrue(object1.name, object2.name) + self.assertTrue(object3.name, object4.name) + def test_range_string_firstchars(self): object1 = PgsqlRangeStringFirstchars2.objects.create(name='foo', title='abcdef') object2 = PgsqlRangeStringFirstchars2.objects.raw( @@ -193,6 +230,17 @@ def test_range_string_firstchars_null(self): self.assertTrue(object1.name, object2.name) self.assertTrue(object3.name, object4.name) + def test_range_string_firstchars_return_null(self): + object1 = PgsqlRangeStringFirstchars2ReturnNULL.objects.create(id=1, name='foo', title='abcdef') + object2 = PgsqlRangeStringFirstchars2ReturnNULL.objects.raw( + 'SELECT * FROM test_rangestring_firstchars2_return_null_ab WHERE id = %s', [object1.id])[0] + object3 = PgsqlRangeStringFirstchars5ReturnNULL.objects.create(id=1, name='foo', title='abcdef') + object4 = PgsqlRangeStringFirstchars5ReturnNULL.objects.raw( + 'SELECT * FROM test_rangestring_firstchars5_return_null_abcde WHERE id = %s', [object3.id])[0] + + self.assertTrue(object1.name, object2.name) + self.assertTrue(object3.name, object4.name) + def test_range_string_lastchars(self): object1 = PgsqlRangeStringLastchars2.objects.create(name='foo', title='abcdef') object2 = PgsqlRangeStringLastchars2.objects.raw( @@ -226,6 +274,17 @@ def test_range_string_lastchars_null(self): self.assertTrue(object1.name, object2.name) self.assertTrue(object3.name, object4.name) + def test_range_string_lastchars_return_null(self): + object1 = PgsqlRangeStringLastchars2ReturnNULL.objects.create(id=1, name='foo', title='abcdef') + object2 = PgsqlRangeStringLastchars2ReturnNULL.objects.raw( + 'SELECT * FROM test_rangestring_lastchars2_return_null_ef WHERE id = %s', [object1.id])[0] + object3 = PgsqlRangeStringLastchars5ReturnNULL.objects.create(id=1, name='foo', title='abcdef') + object4 = PgsqlRangeStringLastchars5ReturnNULL.objects.raw( + 'SELECT * FROM test_rangestring_lastchars5_return_null_bcdef WHERE id = %s', [object3.id])[0] + + self.assertTrue(object1.name, object2.name) + self.assertTrue(object3.name, object4.name) + @unittest.skipUnless(os.environ['DB'] in ('mysql', 'all'), 'Not a MySQL build') class MysqlDjangoPartitionTestCase(unittest.TestCase): From 1c71da46a4fd71589e61805daed3f2300394d21a Mon Sep 17 00:00:00 2001 From: wuxiaoqing Date: Fri, 15 Sep 2017 14:58:51 +0800 Subject: [PATCH 3/5] add tests for pony --- tests/models/pony.py | 47 +++++++++++++++-------------- tests/test_pony.py | 70 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 22 deletions(-) diff --git a/tests/models/pony.py b/tests/models/pony.py index 6c3ea43..a614393 100644 --- a/tests/models/pony.py +++ b/tests/models/pony.py @@ -20,37 +20,40 @@ # Generation of entities for date range partitioning for item in ('day', 'week', 'month', 'year'): - name = '{0}RangeDate{1}'.format(dbname, item.capitalize()) - partition = install('partition', type='range', subtype='date', constraint=item, column='created') + for return_null in (True, False): + name = '{0}RangeDate{1}{2}'.format(dbname, item.capitalize(), 'ReturnNULL' if return_null else '') + partition = install('partition', type='range', subtype='date', constraint=item, column='created', return_null=return_null) - locals()[name] = partition(type(name, (db.Entity,), { - '_table_': 'test_rangedate{0}'.format(item), - 'name': Required(unicode), - 'created': Optional(datetime.datetime, nullable=True), - })) + locals()[name] = partition(type(name, (db.Entity,), { + '_table_': 'test_rangedate{0}{1}'.format(item, '_return_null' if return_null else ''), + 'name': Required(unicode), + 'created': Optional(datetime.datetime, nullable=True), + })) if database == 'pgsql': # Generation of entities for integer range partitioning for item in ('2', '5'): - name = '{0}RangeInteger{1}'.format(dbname, item) - partition = install('partition', type='range', subtype='integer', constraint=item, column='num') + for return_null in (True, False): + name = '{0}RangeInteger{1}{2}'.format(dbname, item, 'ReturnNULL' if return_null else '') + partition = install('partition', type='range', subtype='integer', constraint=item, column='num', return_null=return_null) - locals()[name] = partition(type(name, (db.Entity,), { - '_table_': 'test_rangeinteger{0}'.format(item), - 'name': Required(unicode), - 'num': Optional(int, nullable=True) - })) + locals()[name] = partition(type(name, (db.Entity,), { + '_table_': 'test_rangeinteger{0}{1}'.format(item, '_return_null' if return_null else ''), + 'name': Required(unicode), + 'num': Optional(int, nullable=True) + })) # Generation of entities for string range partitioning for subtype in ('string_firstchars', 'string_lastchars'): for item in ('2', '5'): - name = '{0}Range{1}{2}'.format(dbname, ''.join(s.capitalize() for s in subtype.split('_')), item) - partition = install('partition', type='range', subtype=subtype, constraint=item, column='title') - - locals()[name] = partition(type(name, (db.Entity,), { - '_table_': 'test_range{0}{1}'.format(subtype, item), - 'name': Required(unicode), - 'title': Optional(unicode, nullable=True), - })) + for return_null in (True, False): + name = '{0}Range{1}{2}{3}'.format(dbname, ''.join(s.capitalize() for s in subtype.split('_')), item, 'ReturnNULL' if return_null else '') + partition = install('partition', type='range', subtype=subtype, constraint=item, column='title', return_null=return_null) + + locals()[name] = partition(type(name, (db.Entity,), { + '_table_': 'test_range{0}{1}{2}'.format(subtype, item, '_return_null' if return_null else ''), + 'name': Required(unicode), + 'title': Optional(unicode, nullable=True), + })) db.generate_mapping(create_tables=True) diff --git a/tests/test_pony.py b/tests/test_pony.py index 7652fe0..bff9dfe 100644 --- a/tests/test_pony.py +++ b/tests/test_pony.py @@ -58,6 +58,14 @@ def test_range_date_day_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_day_return_null(self): + with db_session: + object1 = PgsqlRangeDateDayReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + commit() + object2 = PgsqlRangeDateDayReturnNULL.get_by_sql('SELECT * FROM test_rangedateday_return_null_y2014d105 WHERE id = $object1.id') + + self.assertTrue(object1.name, object2.name) + def test_range_date_week(self): with db_session: object1 = PgsqlRangeDateWeek(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) @@ -74,6 +82,14 @@ def test_range_date_week_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_week_return_null(self): + with db_session: + object1 = PgsqlRangeDateWeekReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + commit() + object2 = PgsqlRangeDateWeekReturnNULL.get_by_sql('SELECT * FROM test_rangedateweek_return_null_y2014w16 WHERE id = $object1.id') + + self.assertTrue(object1.name, object2.name) + def test_range_date_month(self): with db_session: object1 = PgsqlRangeDateMonth(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) @@ -91,6 +107,15 @@ def test_range_date_month_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_month_return_null(self): + with db_session: + object1 = PgsqlRangeDateMonthReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + commit() + object2 = PgsqlRangeDateMonthReturnNULL.get_by_sql( + 'SELECT * FROM test_rangedatemonth_return_null_y2014m04 WHERE id = $object1.id') + + self.assertTrue(object1.name, object2.name) + def test_range_date_year(self): with db_session: object1 = PgsqlRangeDateYear(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) @@ -107,6 +132,14 @@ def test_range_date_year_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_year_return_null(self): + with db_session: + object1 = PgsqlRangeDateYearReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + commit() + object2 = PgsqlRangeDateYearReturnNULL.get_by_sql('SELECT * FROM test_rangedateyear_return_null_y2014 WHERE id = $object1.id') + + self.assertTrue(object1.name, object2.name) + def test_range_integer_positive(self): with db_session: object1 = PgsqlRangeInteger2(name='foo', num=3) @@ -151,6 +184,17 @@ def test_range_integer_null(self): self.assertTrue(object1.name, object2.name) self.assertTrue(object3.name, object4.name) + def test_range_integer_positive_return_null(self): + with db_session: + object1 = PgsqlRangeInteger2ReturnNULL(id=1, name='foo', num=3) + object3 = PgsqlRangeInteger5ReturnNULL(id=1, name='foo', num=3) + commit() + object2 = PgsqlRangeInteger2ReturnNULL.get_by_sql('SELECT * FROM test_rangeinteger2_return_null_3_4 WHERE id = $object1.id') + object4 = PgsqlRangeInteger5ReturnNULL.get_by_sql('SELECT * FROM test_rangeinteger5_return_null_1_5 WHERE id = $object3.id') + + self.assertTrue(object1.name, object2.name) + self.assertTrue(object3.name, object4.name) + def test_range_string_firstchars(self): with db_session: object1 = PgsqlRangeStringFirstchars2(name='foo', title='abcdef') @@ -190,6 +234,19 @@ def test_range_string_firstchars_null(self): self.assertTrue(object1.name, object2.name) self.assertTrue(object3.name, object4.name) + def test_range_string_firstchars_return_null(self): + with db_session: + object1 = PgsqlRangeStringFirstchars2ReturnNULL(id=1, name='foo', title='abcdef') + object3 = PgsqlRangeStringFirstchars5ReturnNULL(id=1, name='foo', title='abcdef') + commit() + object2 = PgsqlRangeStringFirstchars2ReturnNULL.get_by_sql( + 'SELECT * FROM test_rangestring_firstchars2_return_null_ab WHERE id = $object1.id') + object4 = PgsqlRangeStringFirstchars5ReturnNULL.get_by_sql( + 'SELECT * FROM test_rangestring_firstchars5_return_null_abcde WHERE id = $object3.id') + + self.assertTrue(object1.name, object2.name) + self.assertTrue(object3.name, object4.name) + def test_range_string_lastchars(self): with db_session: object1 = PgsqlRangeStringLastchars2(name='foo', title='abcdef') @@ -229,6 +286,19 @@ def test_range_string_lastchars_null(self): self.assertTrue(object1.name, object2.name) self.assertTrue(object3.name, object4.name) + def test_range_string_lastchars_return_null(self): + with db_session: + object1 = PgsqlRangeStringLastchars2ReturnNULL(id=1, name='foo', title='abcdef') + object3 = PgsqlRangeStringLastchars5ReturnNULL(id=1, name='foo', title='abcdef') + commit() + object2 = PgsqlRangeStringLastchars2ReturnNULL.get_by_sql( + 'SELECT * FROM test_rangestring_lastchars2_return_null_ef WHERE id = $object1.id') + object4 = PgsqlRangeStringLastchars5ReturnNULL.get_by_sql( + 'SELECT * FROM test_rangestring_lastchars5_return_null_bcdef WHERE id = $object3.id') + + self.assertTrue(object1.name, object2.name) + self.assertTrue(object3.name, object4.name) + @unittest.skipUnless(os.environ['DB'] in ('mysql', 'all'), 'Not a MySQL build') class MysqlPonyPartitionTestCase(unittest.TestCase): From dc9ae0ff64ad785bbf76d1836779eab3d51c9f64 Mon Sep 17 00:00:00 2001 From: wuxiaoqing Date: Fri, 15 Sep 2017 15:17:25 +0800 Subject: [PATCH 4/5] add tests for sqlalchemy --- tests/models/sqlalchemy.py | 52 ++++++++++----------- tests/test_sqlalchemy.py | 92 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 25 deletions(-) diff --git a/tests/models/sqlalchemy.py b/tests/models/sqlalchemy.py index 3d01fba..805a54b 100644 --- a/tests/models/sqlalchemy.py +++ b/tests/models/sqlalchemy.py @@ -22,43 +22,45 @@ # Generation of entities for date range partitioning for item in ('day', 'week', 'month', 'year'): - name = '{0}RangeDate{1}'.format(dbname, item.capitalize()) - partition = install( - 'partition', type='range', subtype='date', constraint=item, column='created', db=engine.url) - - locals()[name] = partition(type(name, (Base,), { - '__tablename__': 'test_rangedate{0}'.format(item), - 'id': Column(Integer, primary_key=True), - 'name': Column(String(length=255)), - 'created': Column(DateTime, nullable=True) - })) - - if database == 'pgsql': - # Generation of entities for integer range partitioning - for item in ('2', '5'): - name = '{0}RangeInteger{1}'.format(dbname, item) + for return_null in (True, False): + name = '{0}RangeDate{1}{2}'.format(dbname, item.capitalize(), 'ReturnNULL' if return_null else '') partition = install( - 'partition', type='range', subtype='integer', constraint=item, column='num', db=engine.url) + 'partition', type='range', subtype='date', constraint=item, column='created', db=engine.url, return_null=return_null) locals()[name] = partition(type(name, (Base,), { - '__tablename__': 'test_rangeinteger{0}'.format(item), + '__tablename__': 'test_rangedate{0}{1}'.format(item, '_return_null' if return_null else ''), 'id': Column(Integer, primary_key=True), 'name': Column(String(length=255)), - 'num': Column(Integer, nullable=True) + 'created': Column(DateTime, nullable=True) })) - # Generation of entities for string range partitioning - for subtype in ('string_firstchars', 'string_lastchars'): - for item in ('2', '5'): - name = '{0}Range{1}{2}'.format(dbname, ''.join(s.capitalize() for s in subtype.split('_')), item) + if database == 'pgsql': + # Generation of entities for integer range partitioning + for item in ('2', '5'): + for return_null in (True, False): + name = '{0}RangeInteger{1}{2}'.format(dbname, item, 'ReturnNULL' if return_null else '') partition = install( - 'partition', type='range', subtype=subtype, constraint=item, column='title', db=engine.url) + 'partition', type='range', subtype='integer', constraint=item, column='num', db=engine.url, return_null=return_null) locals()[name] = partition(type(name, (Base,), { - '__tablename__': 'test_range{0}{1}'.format(subtype, item), + '__tablename__': 'test_rangeinteger{0}{1}'.format(item, '_return_null' if return_null else ''), 'id': Column(Integer, primary_key=True), 'name': Column(String(length=255)), - 'title': Column(String(length=255), nullable=True) + 'num': Column(Integer, nullable=True) })) + # Generation of entities for string range partitioning + for subtype in ('string_firstchars', 'string_lastchars'): + for item in ('2', '5'): + for return_null in (True, False): + name = '{0}Range{1}{2}{3}'.format(dbname, ''.join(s.capitalize() for s in subtype.split('_')), item, 'ReturnNULL' if return_null else '') + partition = install('partition', type='range', subtype=subtype, constraint=item, column='title', db=engine.url, return_null=return_null) + + locals()[name] = partition(type(name, (Base,), { + '__tablename__': 'test_range{0}{1}{2}'.format(subtype, item, '_return_null' if return_null else ''), + 'id': Column(Integer, primary_key=True), + 'name': Column(String(length=255)), + 'title': Column(String(length=255), nullable=True) + })) + Base.metadata.create_all(engine) diff --git a/tests/test_sqlalchemy.py b/tests/test_sqlalchemy.py index b91831a..1775432 100644 --- a/tests/test_sqlalchemy.py +++ b/tests/test_sqlalchemy.py @@ -137,6 +137,17 @@ def test_range_date_day_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_day_return_null(self): + object1 = PgsqlRangeDateDayReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + self.session.add(object1) + self.session.commit() + + object2 = self.session.query(PgsqlRangeDateDayReturnNULL).from_statement( + text('SELECT * FROM test_rangedateday_return_null_y2014d105 WHERE id = :id') + ).params(id=object1.id).first() + + self.assertTrue(object1.name, object2.name) + def test_range_date_week(self): object1 = PgsqlRangeDateWeek(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) self.session.add(object1) @@ -159,6 +170,17 @@ def test_range_date_week_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_week_return_null(self): + object1 = PgsqlRangeDateWeekReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + self.session.add(object1) + self.session.commit() + + object2 = self.session.query(PgsqlRangeDateWeekReturnNULL).from_statement( + text('SELECT * FROM test_rangedateweek_return_null_y2014w16 WHERE id = :id') + ).params(id=object1.id).first() + + self.assertTrue(object1.name, object2.name) + def test_range_date_month(self): object1 = PgsqlRangeDateMonth(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) self.session.add(object1) @@ -181,6 +203,17 @@ def test_range_date_month_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_month_return_null(self): + object1 = PgsqlRangeDateMonthReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + self.session.add(object1) + self.session.commit() + + object2 = self.session.query(PgsqlRangeDateMonthReturnNULL).from_statement( + text('SELECT * FROM test_rangedatemonth_return_null_y2014m04 WHERE id = :id') + ).params(id=object1.id).first() + + self.assertTrue(object1.name, object2.name) + def test_range_date_year(self): object1 = PgsqlRangeDateYear(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) self.session.add(object1) @@ -203,6 +236,17 @@ def test_range_date_year_null(self): self.assertTrue(object1.name, object2.name) + def test_range_date_year_return_null(self): + object1 = PgsqlRangeDateYearReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + self.session.add(object1) + self.session.commit() + + object2 = self.session.query(PgsqlRangeDateYearReturnNULL).from_statement( + text('SELECT * FROM test_rangedateyear_return_null_y2014 WHERE id = :id') + ).params(id=object1.id).first() + + self.assertTrue(object1.name, object2.name) + def test_range_integer_positive(self): object1 = PgsqlRangeInteger2(name='foo', num=3) object3 = PgsqlRangeInteger5(name='foo', num=3) @@ -267,6 +311,22 @@ def test_range_integer_null(self): self.assertTrue(object1.name, object2.name) self.assertTrue(object3.name, object4.name) + def test_range_integer_positive_return_null(self): + object1 = PgsqlRangeInteger2ReturnNULL(id=1, name='foo', num=3) + object3 = PgsqlRangeInteger5ReturnNULL(id=1, name='foo', num=3) + self.session.add_all([object1, object3]) + self.session.commit() + + object2 = self.session.query(PgsqlRangeInteger2ReturnNULL).from_statement( + text('SELECT * FROM test_rangeinteger2_return_null_3_4 WHERE id = :id') + ).params(id=object1.id).first() + object4 = self.session.query(PgsqlRangeInteger5ReturnNULL).from_statement( + text('SELECT * FROM test_rangeinteger5_return_null_1_5 WHERE id = :id') + ).params(id=object3.id).first() + + self.assertTrue(object1.name, object2.name) + self.assertTrue(object3.name, object4.name) + def test_range_string_firstchars(self): object1 = PgsqlRangeStringFirstchars2(name='foo', title='abcdef') object3 = PgsqlRangeStringFirstchars5(name='foo', title='abcdef') @@ -315,6 +375,22 @@ def test_range_string_firstchars_null(self): self.assertTrue(object1.name, object2.name) self.assertTrue(object3.name, object4.name) + def test_range_string_firstchars_return_null(self): + object1 = PgsqlRangeStringFirstchars2ReturnNULL(id=1, name='foo', title='abcdef') + object3 = PgsqlRangeStringFirstchars5ReturnNULL(id=1, name='foo', title='abcdef') + self.session.add_all([object1, object3]) + self.session.commit() + + object2 = self.session.query(PgsqlRangeStringFirstchars2ReturnNULL).from_statement( + text('SELECT * FROM test_rangestring_firstchars2_return_null_ab WHERE id = :id') + ).params(id=object1.id).first() + object4 = self.session.query(PgsqlRangeStringFirstchars5ReturnNULL).from_statement( + text('SELECT * FROM test_rangestring_firstchars5_return_null_abcde WHERE id = :id') + ).params(id=object3.id).first() + + self.assertTrue(object1.name, object2.name) + self.assertTrue(object3.name, object4.name) + def test_range_string_lastchars(self): object1 = PgsqlRangeStringLastchars2(name='foo', title='abcdef') object3 = PgsqlRangeStringLastchars5(name='foo', title='abcdef') @@ -363,6 +439,22 @@ def test_range_string_lastchars_null(self): self.assertTrue(object1.name, object2.name) self.assertTrue(object3.name, object4.name) + def test_range_string_lastchars_return_null(self): + object1 = PgsqlRangeStringLastchars2ReturnNULL(id=1, name='foo', title='abcdef') + object3 = PgsqlRangeStringLastchars5ReturnNULL(id=1, name='foo', title='abcdef') + self.session.add_all([object1, object3]) + self.session.commit() + + object2 = self.session.query(PgsqlRangeStringLastchars2ReturnNULL).from_statement( + text('SELECT * FROM test_rangestring_lastchars2_return_null_ef WHERE id = :id') + ).params(id=object1.id).first() + object4 = self.session.query(PgsqlRangeStringLastchars5ReturnNULL).from_statement( + text('SELECT * FROM test_rangestring_lastchars5_return_null_bcdef WHERE id = :id') + ).params(id=object3.id).first() + + self.assertTrue(object1.name, object2.name) + self.assertTrue(object3.name, object4.name) + @unittest.skipUnless(os.environ['DB'] in ('mysql', 'all'), 'Not a MySQL build') class MysqlSqlAlchemyPartitionTestCase(unittest.TestCase): From 0e8246d657e66ff1af8af460d9ace1b990eba408 Mon Sep 17 00:00:00 2001 From: wuxiaoqing Date: Fri, 15 Sep 2017 15:31:45 +0800 Subject: [PATCH 5/5] add tests for sqlobject --- tests/models/sqlobject.py | 62 +++++++++++++++++++++------------------ tests/test_sqlobject.py | 61 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 29 deletions(-) diff --git a/tests/models/sqlobject.py b/tests/models/sqlobject.py index 0dad852..693a953 100644 --- a/tests/models/sqlobject.py +++ b/tests/models/sqlobject.py @@ -22,53 +22,57 @@ # Generation of entities for date range partitioning for item in ('day', 'week', 'month', 'year'): - class sqlmeta(object): - table = 'test_rangedate{0}'.format(item) - - name = '{0}RangeDate{1}'.format(dbname, item.capitalize()) - partition = install('partition', type='range', subtype='date', constraint=item, column='created') - - locals()[name] = partition(type(name, (SQLObject,), { - 'name': StringCol(), - 'created': DateTimeCol(default=None), - 'sqlmeta': sqlmeta, - '_connection': connection - })) - - locals()[name].createTable(True) - - if database == 'pgsql': - # Generation of entities for integer range partitioning - for item in ('2', '5'): + for return_null in (True, False): class sqlmeta(object): - table = 'test_rangeinteger{0}'.format(item) + table = 'test_rangedate{0}{1}'.format(item, '_return_null' if return_null else '') + - name = '{0}RangeInteger{1}'.format(dbname, item) - partition = install('partition', type='range', subtype='integer', constraint=item, column='num') + name = '{0}RangeDate{1}{2}'.format(dbname, item.capitalize(), 'ReturnNULL' if return_null else '') + partition = install('partition', type='range', subtype='date', constraint=item, column='created', return_null=return_null) locals()[name] = partition(type(name, (SQLObject,), { 'name': StringCol(), - 'num': IntCol(default=None), + 'created': DateTimeCol(default=None), 'sqlmeta': sqlmeta, '_connection': connection })) locals()[name].createTable(True) - # Generation of entities for string range partitioning - for subtype in ('string_firstchars', 'string_lastchars'): - for item in ('2', '5'): + if database == 'pgsql': + # Generation of entities for integer range partitioning + for item in ('2', '5'): + for return_null in (True, False): class sqlmeta(object): - table = 'test_range{0}{1}'.format(subtype, item) + table = 'test_rangeinteger{0}{1}'.format(item, '_return_null' if return_null else '') - name = '{0}Range{1}{2}'.format(dbname, ''.join(s.capitalize() for s in subtype.split('_')), item) - partition = install('partition', type='range', subtype=subtype, constraint=item, column='title') + name = '{0}RangeInteger{1}{2}'.format(dbname, item, 'ReturnNULL' if return_null else '') + partition = install('partition', type='range', subtype='integer', constraint=item, column='num', return_null=return_null) locals()[name] = partition(type(name, (SQLObject,), { 'name': StringCol(), - 'title': StringCol(default=None), + 'num': IntCol(default=None), 'sqlmeta': sqlmeta, '_connection': connection })) locals()[name].createTable(True) + + # Generation of entities for string range partitioning + for subtype in ('string_firstchars', 'string_lastchars'): + for item in ('2', '5'): + for return_null in (True, False): + class sqlmeta(object): + table = 'test_range{0}{1}{2}'.format(subtype, item, '_return_null' if return_null else '') + + name = '{0}Range{1}{2}{3}'.format(dbname, ''.join(s.capitalize() for s in subtype.split('_')), item, 'ReturnNULL' if return_null else '') + partition = install('partition', type='range', subtype=subtype, constraint=item, column='title', return_null=return_null) + + locals()[name] = partition(type(name, (SQLObject,), { + 'name': StringCol(), + 'title': StringCol(default=None), + 'sqlmeta': sqlmeta, + '_connection': connection + })) + + locals()[name].createTable(True) diff --git a/tests/test_sqlobject.py b/tests/test_sqlobject.py index 06fdf59..292df42 100644 --- a/tests/test_sqlobject.py +++ b/tests/test_sqlobject.py @@ -46,6 +46,13 @@ def test_range_date_day_null(self): self.assertTrue(object1.name, object2[1]) + def test_range_date_day_return_null(self): + object1 = PgsqlRangeDateDayReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + object2 = PgsqlRangeDateDayReturnNULL._connection.queryOne( + 'SELECT * FROM test_rangedateday_return_null_y2014d105 WHERE id = %s' % object1.id) + + self.assertTrue(object1.name, object2[1]) + def test_range_date_week(self): object1 = PgsqlRangeDateWeek(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) object2 = PgsqlRangeDateWeek._connection.queryOne( @@ -60,6 +67,13 @@ def test_range_date_week_null(self): self.assertTrue(object1.name, object2[1]) + def test_range_date_week_return_null(self): + object1 = PgsqlRangeDateWeekReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + object2 = PgsqlRangeDateWeekReturnNULL._connection.queryOne( + 'SELECT * FROM test_rangedateweek_return_null_y2014w16 WHERE id = %s' % object1.id) + + self.assertTrue(object1.name, object2[1]) + def test_range_date_month(self): object1 = PgsqlRangeDateMonth(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) object2 = PgsqlRangeDateMonth._connection.queryOne( @@ -74,6 +88,13 @@ def test_range_date_month_null(self): self.assertTrue(object1.name, object2[1]) + def test_range_date_month_return_null(self): + object1 = PgsqlRangeDateMonthReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + object2 = PgsqlRangeDateMonthReturnNULL._connection.queryOne( + 'SELECT * FROM test_rangedatemonth_return_null_y2014m04 WHERE id = %s' % object1.id) + + self.assertTrue(object1.name, object2[1]) + def test_range_date_year(self): object1 = PgsqlRangeDateYear(name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) object2 = PgsqlRangeDateYear._connection.queryOne( @@ -88,6 +109,13 @@ def test_range_date_year_null(self): self.assertTrue(object1.name, object2[1]) + def test_range_date_year_return_null(self): + object1 = PgsqlRangeDateYearReturnNULL(id=1, name='foo', created=datetime.datetime(2014, 4, 15, 18, 44, 23)) + object2 = PgsqlRangeDateYearReturnNULL._connection.queryOne( + 'SELECT * FROM test_rangedateyear_return_null_y2014 WHERE id = %s' % object1.id) + + self.assertTrue(object1.name, object2[1]) + def test_range_integer_positive(self): object1 = PgsqlRangeInteger2(name='foo', num=3) object3 = PgsqlRangeInteger5(name='foo', num=3) @@ -132,6 +160,17 @@ def test_range_integer_null(self): self.assertTrue(object1.name, object2[1]) self.assertTrue(object3.name, object4[1]) + def test_range_integer_positive_return_null(self): + object1 = PgsqlRangeInteger2ReturnNULL(id=1, name='foo', num=3) + object3 = PgsqlRangeInteger5ReturnNULL(id=1, name='foo', num=3) + object2 = PgsqlRangeInteger2ReturnNULL._connection.queryOne( + 'SELECT * FROM test_rangeinteger2_return_null_3_4 WHERE id = %s' % object1.id) + object4 = PgsqlRangeInteger5ReturnNULL._connection.queryOne( + 'SELECT * FROM test_rangeinteger5_return_null_1_5 WHERE id = %s' % object3.id) + + self.assertTrue(object1.name, object2[1]) + self.assertTrue(object3.name, object4[1]) + def test_range_string_firstchars(self): object1 = PgsqlRangeStringFirstchars2(name='foo', title='abcdef') object3 = PgsqlRangeStringFirstchars5(name='foo', title='abcdef') @@ -165,6 +204,17 @@ def test_range_string_firstchars_null(self): self.assertTrue(object1.name, object2[1]) self.assertTrue(object3.name, object4[1]) + def test_range_string_firstchars_return_null(self): + object1 = PgsqlRangeStringFirstchars2ReturnNULL(id=1, name='foo', title='abcdef') + object3 = PgsqlRangeStringFirstchars5ReturnNULL(id=1, name='foo', title='abcdef') + object2 = PgsqlRangeStringFirstchars2ReturnNULL._connection.queryOne( + 'SELECT * FROM test_rangestring_firstchars2_return_null_ab WHERE id = %s' % object1.id) + object4 = PgsqlRangeStringFirstchars5ReturnNULL._connection.queryOne( + 'SELECT * FROM test_rangestring_firstchars5_return_null_abcde WHERE id = %s' % object3.id) + + self.assertTrue(object1.name, object2[1]) + self.assertTrue(object3.name, object4[1]) + def test_range_string_lastchars(self): object1 = PgsqlRangeStringLastchars2(name='foo', title='abcdef') object3 = PgsqlRangeStringLastchars5(name='foo', title='abcdef') @@ -198,6 +248,17 @@ def test_range_string_lastchars_null(self): self.assertTrue(object1.name, object2[1]) self.assertTrue(object3.name, object4[1]) + def test_range_string_lastchars_return_null(self): + object1 = PgsqlRangeStringLastchars2ReturnNULL(id=1, name='foo', title='abcdef') + object3 = PgsqlRangeStringLastchars5ReturnNULL(id=1, name='foo', title='abcdef') + object2 = PgsqlRangeStringLastchars2ReturnNULL._connection.queryOne( + 'SELECT * FROM test_rangestring_lastchars2_return_null_ef WHERE id = %s' % object1.id) + object4 = PgsqlRangeStringLastchars5ReturnNULL._connection.queryOne( + 'SELECT * FROM test_rangestring_lastchars5_return_null_bcdef WHERE id = %s' % object3.id) + + self.assertTrue(object1.name, object2[1]) + self.assertTrue(object3.name, object4[1]) + @unittest.skipUnless(os.environ['DB'] in ('mysql', 'all'), 'Not a MySQL build') class MysqlSqlObjectPartitionTestCase(unittest.TestCase):