diff --git a/py_dbcn/connectors/core/clauses.py b/py_dbcn/connectors/core/clauses.py index f2c9e2f0352ed4d4bbfba44050a04362754b81bc..e613c2a69c7305759f98c3494aba144d15d1c925 100644 --- a/py_dbcn/connectors/core/clauses.py +++ b/py_dbcn/connectors/core/clauses.py @@ -44,6 +44,7 @@ class BaseClauseBuilder(object): self._print_parens = True self._always_quote = True self._allow_spaces = False + self._skip_empty_clause_values = True def __str__(self): if len(self.array) > 0: @@ -161,7 +162,7 @@ class BaseClauseBuilder(object): elif len(clause) > 0: # Handle any other clause that is non-empty. - clause = self._validate_clause(clause) + clause = self._validate_clause(clause, value) # Save validated clause. self._clause_array = clause @@ -169,8 +170,13 @@ class BaseClauseBuilder(object): # Save empty clause. self._clause_array = [] - def _validate_clause(self, original_clause): + def _validate_clause(self, original_clause, original_value=None): """Used to validate/sanitize an array of clause values.""" + + # Special case for clause of an empty str. + if original_value == '': + return [] + new_clause = [] for item in original_clause: @@ -244,16 +250,16 @@ class BaseClauseBuilder(object): item = item[:-5].rstrip() order_by_descriptor = ' DESC' - # If we made it this far, item is valid. Escape with proper quote format and readd. + # If we made it this far, item is valid. Escape with proper quote format and re-add. is_quoted = False - if self.is_quoted(item): + if self._base.validate._is_quoted(item): item = item[1:-1].strip() is_quoted = True - # Skip items that are empty. Otherwise append. - if len(item) > 0: + # Situationally skip items that are empty. Otherwise append. + if (not self._skip_empty_clause_values) or len(item) > 0: if item != '*': - # Readd quotes in proper format. + # Re-add quotes in proper format. # Account for statements that may have multiple parts (denoted by spaces). if not self._allow_spaces: item_split = item.split(' ') @@ -290,6 +296,9 @@ class BaseClauseBuilder(object): `id' etc... """ + # TODO: Why is there two instances of this method? + # One here, and one in validate.py. + # One in validate.py seems to be thoroughly tested and more reliable. is_quoted = False if isinstance(value, str): # Only attempt to check if str type. @@ -448,7 +457,7 @@ class WhereClauseBuilder(BaseClauseBuilder): # Split based on spaces. For now, we assume only the first item needs quotes. clause_split = clause_item.split(' ') first_item = clause_split[0] - if self.is_quoted(first_item): + if self._base.validate._is_quoted(first_item): first_item = first_item[1:-1] first_item = '{1}{0}{1}'.format(first_item, self._quote_format) @@ -906,6 +915,7 @@ class ValuesClauseBuilder(BaseClauseBuilder): self._quote_format = self._parent._quote_str_literal_format self._always_quote = False self._allow_spaces = True + self._skip_empty_clause_values = False # Process and save provided clause. self.array = clause @@ -913,7 +923,7 @@ class ValuesClauseBuilder(BaseClauseBuilder): class ValuesManyClauseBuilder(ValuesClauseBuilder): """""" - def _validate_clause(self, original_clause): + def _validate_clause(self, original_clause, original_value=None): """Used to validate/sanitize an array of clause values.""" # Handle the same as original logic, except there is one extra layer. @@ -922,7 +932,7 @@ class ValuesManyClauseBuilder(ValuesClauseBuilder): if len(original_clause) > 0: for index in range(len(original_clause)): inner_clause = original_clause[index] - original_clause[index] = super()._validate_clause(inner_clause) + original_clause[index] = super()._validate_clause(inner_clause, original_value=original_value) # Return validated clause. return original_clause diff --git a/py_dbcn/connectors/core/validate.py b/py_dbcn/connectors/core/validate.py index 0208cc79017e15d382fc34db9c463af10d0ea8f8..59a9e703b9c1c85c82b2da30f02bc820416a810b 100644 --- a/py_dbcn/connectors/core/validate.py +++ b/py_dbcn/connectors/core/validate.py @@ -469,7 +469,8 @@ class BaseValidate: # Only attempt to check if str type. value = value.strip() - # Must have matching outer quotes, plus at least one inner character. + # Must have matching outer quotes. + # Generally expects at least one inner character, but also allows 0 inner characters for empty strings. if len(value) > 1 and value[0] == value[-1] and value[0] in ['`', '"', "'"]: is_quoted = True diff --git a/tests/connectors/core/test_clauses.py b/tests/connectors/core/test_clauses.py index b6d5aee215db8ef03b84e2e314dc4951e6c47884..84804e2ae333a145cfc3eec5b2b000b5bdef719f 100644 --- a/tests/connectors/core/test_clauses.py +++ b/tests/connectors/core/test_clauses.py @@ -1271,13 +1271,28 @@ class CoreClauseTestMixin: self.assertEqual(["""test"""], clause_object.array) self.assertText("""VALUES (test)""", str(clause_object)) + # Empty str with single quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, """''""") + self.assertEqual(["""{0}{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}{0})""".format(self.str_literal_format), str(clause_object)) + + # Empty str with double quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, """\"\"""") + self.assertEqual(["""{0}{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}{0})""".format(self.str_literal_format), str(clause_object)) + + # Empty str with backtick quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, """``""") + self.assertEqual(["""{0}{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}{0})""".format(self.str_literal_format), str(clause_object)) + # With single quotes. clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, """'test'""") self.assertEqual(["""{0}test{0}""".format(self.str_literal_format)], clause_object.array) self.assertText("""VALUES ({0}test{0})""".format(self.str_literal_format), str(clause_object)) # With double quotes. - clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, """"test\"""") + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, """\"test\"""") self.assertEqual(["""{0}test{0}""".format(self.str_literal_format)], clause_object.array) self.assertText("""VALUES ({0}test{0})""".format(self.str_literal_format), str(clause_object)) @@ -1286,7 +1301,11 @@ class CoreClauseTestMixin: self.assertEqual(["""{0}test{0}""".format(self.str_literal_format)], clause_object.array) self.assertText("""VALUES ({0}test{0})""".format(self.str_literal_format), str(clause_object)) - clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, """'test', 1234, 'Test User'""") + # Multi-value clause. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder( + validation_class, + """'test', 1234, 'Test User'""", + ) self.assertEqual([ """{0}test{0}""".format(self.str_literal_format), """1234""", @@ -1297,50 +1316,275 @@ class CoreClauseTestMixin: str(clause_object), ) + # Mixed empty and non-empty strings, with single quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder( + validation_class, + """'', 'test 1', '', 'test 2', ''""", + ) + self.assertEqual( + [ + """{0}{0}""".format(self.str_literal_format), + """{0}test 1{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 2{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + ], + clause_object.array, + ) + self.assertText( + """VALUES ({0}{0}, {0}test 1{0}, {0}{0}, {0}test 2{0}, {0}{0})""".format(self.str_literal_format), + str(clause_object), + ) + + # Mixed empty and non-empty strings, with double quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder( + validation_class, + """"", "test 1", "", "test 2", "\"""", + ) + self.assertEqual( + [ + """{0}{0}""".format(self.str_literal_format), + """{0}test 1{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 2{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + ], + clause_object.array, + ) + self.assertText( + """VALUES ({0}{0}, {0}test 1{0}, {0}{0}, {0}test 2{0}, {0}{0})""".format(self.str_literal_format), + str(clause_object), + ) + + # Mixed empty and non-empty strings, with backtick quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder( + validation_class, + """``, `test 1`, ``, `test 2`, ``""", + ) + self.assertEqual( + [ + """{0}{0}""".format(self.str_literal_format), + """{0}test 1{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 2{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + ], + clause_object.array, + ) + self.assertText( + """VALUES ({0}{0}, {0}test 1{0}, {0}{0}, {0}test 2{0}, {0}{0})""".format(self.str_literal_format), + str(clause_object), + ) + with self.subTest('Basic VALUES clause - As list'): + # Empty str with single quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, ["""''"""]) + self.assertEqual(["""{0}{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}{0})""".format(self.str_literal_format), str(clause_object)) + + # Empty str with double quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, ["""\"\""""]) + self.assertEqual(["""{0}{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}{0})""".format(self.str_literal_format), str(clause_object)) + + # Empty str with backtick quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, ["""``"""]) + self.assertEqual(["""{0}{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}{0})""".format(self.str_literal_format), str(clause_object)) + + # With single quotes. clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, ["""'test'"""]) self.assertEqual(["""{0}test{0}""".format(self.str_literal_format)], clause_object.array) self.assertText("""VALUES ({0}test{0})""".format(self.str_literal_format), str(clause_object)) + # With double quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, [""""test\""""]) + self.assertEqual(["""{0}test{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}test{0})""".format(self.str_literal_format), str(clause_object)) + + # With backtick quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, ["""`test`"""]) + self.assertEqual(["""{0}test{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}test{0})""".format(self.str_literal_format), str(clause_object)) + + # Multi-value clause. clause_object = self.connector.validate.clauses.ValuesClauseBuilder( validation_class, ["""'test'""", """1234""", """'Test User'"""], ) + self.assertEqual([ + """{0}test{0}""".format(self.str_literal_format), + """1234""", + """{0}Test User{0}""".format(self.str_literal_format), + ], clause_object.array) + self.assertText( + """VALUES ({0}test{0}, 1234, {0}Test User{0})""".format(self.str_literal_format), + str(clause_object), + ) + + # Mixed empty and non-empty strings, with single quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder( + validation_class, + ["""''""", """'test 1'""", """''""", """'test 2'""", """''"""], + ) self.assertEqual( [ - """{0}test{0}""".format(self.str_literal_format), - """1234""", - """{0}Test User{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 1{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 2{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), ], clause_object.array, ) self.assertText( - """VALUES ({0}test{0}, 1234, {0}Test User{0})""".format(self.str_literal_format), + """VALUES ({0}{0}, {0}test 1{0}, {0}{0}, {0}test 2{0}, {0}{0})""".format(self.str_literal_format), + str(clause_object), + ) + + # Mixed empty and non-empty strings, with double quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder( + validation_class, + ["""\"\"""", """\"test 1\"""", """\"\"""", """\"test 2\"""", """\"\""""], + ) + self.assertEqual( + [ + """{0}{0}""".format(self.str_literal_format), + """{0}test 1{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 2{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + ], + clause_object.array, + ) + self.assertText( + """VALUES ({0}{0}, {0}test 1{0}, {0}{0}, {0}test 2{0}, {0}{0})""".format(self.str_literal_format), + str(clause_object), + ) + + # Mixed empty and non-empty strings, with backtick quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder( + validation_class, + ["""``""", """`test 1`""", """``""", """`test 2`""", """``"""], + ) + self.assertEqual( + [ + """{0}{0}""".format(self.str_literal_format), + """{0}test 1{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 2{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + ], + clause_object.array, + ) + self.assertText( + """VALUES ({0}{0}, {0}test 1{0}, {0}{0}, {0}test 2{0}, {0}{0})""".format(self.str_literal_format), str(clause_object), ) with self.subTest('Basic VALUES clause - As tuple'): + # Empty str with single quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, ("""''""",)) + self.assertEqual(["""{0}{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}{0})""".format(self.str_literal_format), str(clause_object)) + + # Empty str with double quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, ("""\"\"""",)) + self.assertEqual(["""{0}{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}{0})""".format(self.str_literal_format), str(clause_object)) + + # Empty str with backtick quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, ("""``""",)) + self.assertEqual(["""{0}{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}{0})""".format(self.str_literal_format), str(clause_object)) + + # With single quotes. clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, ("""'test'""",)) self.assertEqual(["""{0}test{0}""".format(self.str_literal_format)], clause_object.array) self.assertText("""VALUES ({0}test{0})""".format(self.str_literal_format), str(clause_object)) + # With double quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, (""""test\"""",)) + self.assertEqual(["""{0}test{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}test{0})""".format(self.str_literal_format), str(clause_object)) + + # With backtick quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder(validation_class, ("""`test`""",)) + self.assertEqual(["""{0}test{0}""".format(self.str_literal_format)], clause_object.array) + self.assertText("""VALUES ({0}test{0})""".format(self.str_literal_format), str(clause_object)) + + # Multi-value clause. clause_object = self.connector.validate.clauses.ValuesClauseBuilder( validation_class, - ( - """{0}test{0}""".format(self.str_literal_format), - """1234""", - """{0}Test User{0}""".format(self.str_literal_format)), + ("""'test'""", """1234""", """'Test User'"""), + ) + self.assertEqual([ + """{0}test{0}""".format(self.str_literal_format), + """1234""", + """{0}Test User{0}""".format(self.str_literal_format), + ], clause_object.array) + self.assertText( + """VALUES ({0}test{0}, 1234, {0}Test User{0})""".format(self.str_literal_format), + str(clause_object), + ) + + # Mixed empty and non-empty strings, with single quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder( + validation_class, + ("""''""", """'test 1'""", """''""", """'test 2'""", """''"""), ) self.assertEqual( [ - """{0}test{0}""".format(self.str_literal_format), - """1234""", - """{0}Test User{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 1{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 2{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), ], clause_object.array, ) self.assertText( - """VALUES ({0}test{0}, 1234, {0}Test User{0})""".format(self.str_literal_format), + """VALUES ({0}{0}, {0}test 1{0}, {0}{0}, {0}test 2{0}, {0}{0})""".format(self.str_literal_format), + str(clause_object), + ) + + # Mixed empty and non-empty strings, with double quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder( + validation_class, + ("""\"\"""", """\"test 1\"""", """\"\"""", """\"test 2\"""", """\"\""""), + ) + self.assertEqual( + [ + """{0}{0}""".format(self.str_literal_format), + """{0}test 1{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 2{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + ], + clause_object.array, + ) + self.assertText( + """VALUES ({0}{0}, {0}test 1{0}, {0}{0}, {0}test 2{0}, {0}{0})""".format(self.str_literal_format), + str(clause_object), + ) + + # Mixed empty and non-empty strings, with backtick quotes. + clause_object = self.connector.validate.clauses.ValuesClauseBuilder( + validation_class, + ("""``""", """`test 1`""", """``""", """`test 2`""", """``"""), + ) + self.assertEqual( + [ + """{0}{0}""".format(self.str_literal_format), + """{0}test 1{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + """{0}test 2{0}""".format(self.str_literal_format), + """{0}{0}""".format(self.str_literal_format), + ], + clause_object.array, + ) + self.assertText( + """VALUES ({0}{0}, {0}test 1{0}, {0}{0}, {0}test 2{0}, {0}{0})""".format(self.str_literal_format), str(clause_object), ) diff --git a/tests/connectors/core/test_records.py b/tests/connectors/core/test_records.py index 1ddf7570e63da641706c3f456f4947bbc98017d0..b4aba579ba09a2baf917f706565a7a3e6b2716bd 100644 --- a/tests/connectors/core/test_records.py +++ b/tests/connectors/core/test_records.py @@ -30,6 +30,7 @@ class CoreRecordsTestMixin: cls._columns_clause__basic = None cls._columns_clause__datetime = None cls._columns_clause__aggregates = None + cls._columns_clause__insert_bug__number_of_values = None def test_error_catch_types(self): """Tests to ensure database ERROR types are properly caught. @@ -976,6 +977,67 @@ class CoreRecordsTestMixin: self.assertEqual(len(results), 2) self.assertIn(row, results) + def test__insert__extra_cases(self): + """Various cases that were bugs at one point or another.""" + + with self.subTest('Blank strings are not translated to properly validated data columns'): + # Verify table exists. + try: + self.connector.query.execute('CREATE TABLE {0}{1};'.format( + 'test__insert_bug__blank_strings_not_translated', + self._columns_clause__insert_bug__number_of_values, + )) + except self.connector.errors.table_already_exists: + # Table already exists, as we want. + pass + + # Insert record. + self.connector.records.insert( + 'test__insert_bug__blank_strings_not_translated', + [ + '', + 'test_first', + 'test_last', + '', + '123 Test St', + 'Room 456', + 'Test City', + 'Michigan', + '12345', + '', + '(123) 456-7890', + '(098) 765-4321', + 'test@test.com', + '', + datetime.datetime.now(), + datetime.datetime.now(), + False, + datetime.datetime.now(), + '', + ], + columns_clause=[ + 'test_blank_1', + 'first_name', + 'last_name', + 'test_blank_2', + 'address1', + 'address2', + 'city', + 'state', + 'zipcode', + 'test_blank_3', + 'phone', + 'fax', + 'email', + 'test_blank_4', + 'date_created', + 'date_modified', + 'is_active', + 'last_activity', + 'test_blank_5', + ], + ) + def test__insert_many__basic__success(self): """ Test execute_many `INSERT` query. diff --git a/tests/connectors/core/test_validate.py b/tests/connectors/core/test_validate.py index 470a5c2f675d7f27b8af772dbf17b41928baab27..a3fe25b09aef3a8565c16e223aab9ad88f468080 100644 --- a/tests/connectors/core/test_validate.py +++ b/tests/connectors/core/test_validate.py @@ -3970,6 +3970,12 @@ class CoreValidateTestMixin: self.assertTrue(self.connector.validate._is_quoted("'True, False'")) self.assertTrue(self.connector.validate._is_quoted('`True, False`')) + # Empty strings. + self.assertTrue(self.connector.validate._is_quoted("""''""")) + self.assertTrue(self.connector.validate._is_quoted("""\"\"""")) + self.assertTrue(self.connector.validate._is_quoted("""``""")) + + def test__is_quoted__false(self): """ Tests is_quoted() function, when return val should be False. diff --git a/tests/connectors/mysql/constants.py b/tests/connectors/mysql/constants.py index ef69418088fae3fffd03bd65273169cb086d75e9..6314a33a2925e12471105e367deac32211bcba37 100644 --- a/tests/connectors/mysql/constants.py +++ b/tests/connectors/mysql/constants.py @@ -50,3 +50,28 @@ COLUMNS_CLAUSE__AGGREGATES = """ PRIMARY KEY ( id ) ) """.strip() + + +COLUMNS_CLAUSE__INSERT_BUG__NUMBER_OF_VALUES = """ + id INT NOT NULL AUTO_INCREMENT, + test_blank_1 VARCHAR(255), + first_name VARCHAR(255), + last_name VARCHAR(255), + test_blank_2 VARCHAR(255), + address1 VARCHAR(255), + address2 VARCHAR(255), + city VARCHAR(255), + state VARCHAR(255), + zipcode VARCHAR(255), + test_blank_3 VARCHAR(255), + phone VARCHAR(255), + fax VARCHAR(255), + email VARCHAR(255), + test_blank_4 VARCHAR(255), + date_created DATETIME, + date_modified DATETIME, + is_active TINYINT, + last_activity TIMESTAMP, + test_blank_5 VARCHAR(255) + PRIMARY KEY ( id ) +""" diff --git a/tests/connectors/mysql/test_records.py b/tests/connectors/mysql/test_records.py index 5c682864067d0d131faf9fea01f347b772cb120c..471e7a6e7b315a4aa19b7a7de84734c681fdbdda 100644 --- a/tests/connectors/mysql/test_records.py +++ b/tests/connectors/mysql/test_records.py @@ -6,7 +6,12 @@ Tests for "records" logic of "MySQL" DB Connector class. from decimal import Decimal # Internal Imports. -from .constants import COLUMNS_CLAUSE__BASIC, COLUMNS_CLAUSE__DATETIME, COLUMNS_CLAUSE__AGGREGATES +from .constants import ( + COLUMNS_CLAUSE__BASIC, + COLUMNS_CLAUSE__DATETIME, + COLUMNS_CLAUSE__AGGREGATES, + COLUMNS_CLAUSE__INSERT_BUG__NUMBER_OF_VALUES, +) from .test_core import TestMysqlDatabaseParent from tests.connectors.core.test_records import CoreRecordsTestMixin @@ -50,6 +55,7 @@ class TestMysqlRecords(TestMysqlDatabaseParent, CoreRecordsTestMixin): cls._columns_clause__basic = COLUMNS_CLAUSE__BASIC cls._columns_clause__datetime = COLUMNS_CLAUSE__DATETIME cls._columns_clause__aggregates = COLUMNS_CLAUSE__AGGREGATES + cls._columns_clause__insert_bug__number_of_values = COLUMNS_CLAUSE__INSERT_BUG__NUMBER_OF_VALUES def test_error_catch_types(self): """Tests to ensure database ERROR types are properly caught. diff --git a/tests/connectors/postgresql/constants.py b/tests/connectors/postgresql/constants.py index 046dea67dd82f1bcf74075abd1fa50ab099b2119..5f1e9edc890f87c89cc73891b03d9d415684d276 100644 --- a/tests/connectors/postgresql/constants.py +++ b/tests/connectors/postgresql/constants.py @@ -48,3 +48,29 @@ COLUMNS_CLAUSE__AGGREGATES = """ test_bool BOOLEAN ) """.strip() + + +COLUMNS_CLAUSE__INSERT_BUG__NUMBER_OF_VALUES = """ +( + id serial PRIMARY KEY, + test_blank_1 VARCHAR(255), + first_name VARCHAR(255), + last_name VARCHAR(255), + test_blank_2 VARCHAR(255), + address1 VARCHAR(255), + address2 VARCHAR(255), + city VARCHAR(255), + state VARCHAR(255), + zipcode VARCHAR(255), + test_blank_3 VARCHAR(255), + phone VARCHAR(255), + fax VARCHAR(255), + email VARCHAR(255), + test_blank_4 VARCHAR(255), + date_created TIMESTAMP, + date_modified TIMESTAMP, + is_active BOOLEAN, + last_activity TIMESTAMP, + test_blank_5 VARCHAR(255) +) +""".strip() diff --git a/tests/connectors/postgresql/test_records.py b/tests/connectors/postgresql/test_records.py index 4acf2436bc7184d15c423097b3a1fd6729da0ab0..bdb3e97dff4e890c7d7193644b84a0b16893ee05 100644 --- a/tests/connectors/postgresql/test_records.py +++ b/tests/connectors/postgresql/test_records.py @@ -6,7 +6,12 @@ Tests for "records" logic of "PostgreSQL" DB Connector class. from decimal import Decimal # Internal Imports. -from .constants import COLUMNS_CLAUSE__BASIC, COLUMNS_CLAUSE__DATETIME, COLUMNS_CLAUSE__AGGREGATES +from .constants import ( + COLUMNS_CLAUSE__BASIC, + COLUMNS_CLAUSE__DATETIME, + COLUMNS_CLAUSE__AGGREGATES, + COLUMNS_CLAUSE__INSERT_BUG__NUMBER_OF_VALUES, +) from .test_core import TestPostgresqlDatabaseParent from tests.connectors.core.test_records import CoreRecordsTestMixin @@ -50,6 +55,7 @@ class TestPostgresqlRecords(TestPostgresqlDatabaseParent, CoreRecordsTestMixin): cls._columns_clause__basic = COLUMNS_CLAUSE__BASIC cls._columns_clause__datetime = COLUMNS_CLAUSE__DATETIME cls._columns_clause__aggregates = COLUMNS_CLAUSE__AGGREGATES + cls._columns_clause__insert_bug__number_of_values = COLUMNS_CLAUSE__INSERT_BUG__NUMBER_OF_VALUES def test_error_catch_types(self): """Tests to ensure database ERROR types are properly caught.