diff --git a/py_dbcn/connectors/core/clauses.py b/py_dbcn/connectors/core/clauses.py new file mode 100644 index 0000000000000000000000000000000000000000..81cc7fe3d8884ed5aa85de4c021167bfbce961d6 --- /dev/null +++ b/py_dbcn/connectors/core/clauses.py @@ -0,0 +1,450 @@ +""" +Helper classes to build and store clause logic for queries. +""" + +# System Imports. +import re +from io import StringIO +from tokenize import ( + generate_tokens, + ENDMARKER, + NAME, + NEWLINE, + NUMBER, + OP, + STRING, +) + + +class BaseClauseBuilder(object): + """""" + def __init__(self, validation_class, clause, clause_type, *args, **kwargs): + # Call parent logic. + super().__init__(*args, **kwargs) + + # Validate clause type. + self._clause_type = str(clause_type).lower().strip() + valid_clause_types = { + 'select': None, + 'where': None, + 'columns': None, + 'values': None, + 'order_by': None, + } + try: + valid_clause_types[self._clause_type] + except KeyError: + raise ValueError('Invalid clause type of "{0}".'.format(clause_type)) + + # Initialize values. + self._parent = validation_class + self._base = validation_class._base + self._clause_array = [] + self._sanitized_clause = None + self._print_parens = True + self.array = clause + + def __str__(self): + if len(self.array) > 0: + # Non-empty clause. Format for str output. + to_str = ', '.join('{}' for x in range(len(self.array))) + to_str = to_str.format(*self.array) + if self._print_parens: + to_str = '{0}({1})'.format(self._print_prefix, to_str) + else: + to_str = '{0}{1}'.format(self._print_prefix, to_str) + return to_str + else: + # Empty clause. + return '' + + def __repr__(self): + return str(tuple(self._clause_array)) + + def __len__(self): + return len(self.__str__()) + + def __iter__(self): + return iter(self.__str__()) + + def split(self, *args, **kwargs): + return self.__str__().split(*args, **kwargs) + + @property + def array(self): + return self._clause_array + + @array.setter + def array(self, value): + self._to_array(value) + + def _to_array(self, value): + """Converts clause to array format for initial parsing.""" + + if self._clause_prefix is None: + raise NotImplementedError('Query type {0} missing clause_prefix value.'.format(self.__class__)) + if self._print_prefix is None: + raise NotImplementedError('Query type {0} missing print_prefix value.'.format(self.__class__)) + if self._quote_format is None: + raise NotImplementedError('Query type {0} missing quote_format value.'.format(self.__class__)) + + if isinstance(value, list): + # Already list format. + clause = value + elif isinstance(value, tuple): + # Close to list format. Simply convert. + clause = list(value) + else: + # Attempt to parse as str for all other formats. + if value is None: + # None type defaults to empty. + clause = [] + else: + clause = str(value).strip() + + # Trim prefix, if present. + if len(self._clause_prefix) > 0: + # Check if starts with prefix, brackets, and space. + if ( + clause.upper().startswith('{0} ('.format(self._clause_prefix)) and clause.endswith(')') + or clause.upper().startswith('{0} ['.format(self._clause_prefix)) and clause.endswith(']') + ): + clause = clause[(len(self._clause_prefix) + 2):-1] + + # Check if starts with prefix, brackets, and no space. + elif ( + clause.upper().startswith('{0}('.format(self._clause_prefix)) and clause.endswith(')') + or clause.upper().startswith('{0}['.format(self._clause_prefix)) and clause.endswith(']') + ): + clause = clause[(len(self._clause_prefix) + 1):-1] + + # Check if starts with prefix and no brackets. + elif clause.upper().startswith('{0} '.format(self._clause_prefix)): + clause = clause[(len(self._clause_prefix) + 1):] + + # Convert to list. + clause = clause.split(',') + for index in range(len(clause)): + clause[index] = str(clause[index]).strip() + + # Remove potential trailing deadspace. + if len(clause) > 1 and clause[-1] == '': + clause = clause[:-1] + + # Validate each item in clause, now that it's an array. + if len(clause) == 1 and clause[0] == '*': + # Save wildcard clause. + self._clause_array = ['*'] + + elif len(clause) > 0: + # Handle any other clause that is non-empty. + new_clause = [] + for item in clause: + item = str(item).strip() + + # Strip out function values. + # First check against regex matches. + func_call_regex = (r'\(*|'.join(self._parent._reserved_function_names)) + matches = re.match(func_call_regex, item, flags=re.IGNORECASE) + + # Proceed if at least one match is found. + stripped_left = '' + stripped_right = '' + if matches: + index = 0 + while index < len(self._parent._reserved_function_names): + func_call = self._parent._reserved_function_names[index] + if ( + re.match(r'^{0}\('.format(func_call), item, flags=re.IGNORECASE) + and item[-1] == ')' + ): + # Found a match. Update identifier and check for further matches. + length = len(func_call) + 1 + stripped_left += item[:length] + stripped_right += ')' + item = item[length:-1].strip() + index += 1 + + # Ignore potential type casting syntax. + cast_identifier = '' + if self._base._config.db_type == 'PostgreSQL': + # Handle for PostgreSQL casting. + cast_split = item.split('::') + if len(cast_split) > 2: + raise ValueError('Invalid casting identifier "{0}"'.format(item)) + elif len(cast_split) > 1: + cast_identifier = cast_split[1] + if not re.match(r'[A-Za-z0-9]+', cast_identifier): + raise ValueError('Invalid casting identifier "{0}"'.format(cast_identifier)) + cast_identifier = '::{0}'.format(cast_identifier) + item = cast_split[0] + + # Validate individual identifier. + order_by_descriptor = '' + if item != '*': + # To check identifier, trim possible ASC/DESC values. + if item.lower().endswith(' asc'): + # Handle for ASC syntax. + item = item[:-4].rstrip() + order_by_descriptor = ' ASC' + if item.lower().endswith(' desc'): + # Handle for DESC syntax. + 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 self.is_quoted(item): + item = item[1:-1].strip() + + # Skip items that are empty. Otherwise append. + if len(item) > 0: + if item != '*': + # Readd quotes in proper format. + # Account for statements that may have multiple parts (denoted by spaces). + item_split = item.split(' ') + item = '{1}{0}{1}'.format(item_split.pop(0), self._quote_format) + while len(item_split) > 0: + item_split_part = item_split.pop(0).strip() + if len(item_split_part) > 0: + item = '{0} {1}'.format(item, item_split_part) + + # Readd identifiers in proper format. + item = '{0}{1}{2}'.format(item, cast_identifier, order_by_descriptor) + + # Readd function calls if present. + item = '{1}{0}{2}'.format(item, stripped_left.upper(), stripped_right) + + # Save item to clause. + new_clause.append(item) + + # Save validated clause. + self._clause_array = new_clause + else: + # Save empty clause. + self._clause_array = [] + + @staticmethod + def is_quoted(value): + """Checks if provided value is quoted. + + Aka, these are three "quoted" values: "id", `first_name`, 'last_name' + These are not "quoted" values: + id, first_name, last_name + "id' + 'id" + `id' + etc... + """ + is_quoted = False + if isinstance(value, str): + # Only attempt to check if str type. + value = value.strip() + + # Must have matching outer quotes, plus at least one inner character. + if len(value) > 2 and value[0] == value[-1] and value[0] in ['`', '"', "'"]: + is_quoted = True + + return is_quoted + + +class SelectClauseBuilder(BaseClauseBuilder): + """""" + def __init__(self, *args, clause_type='SELECT', **kwargs): + # Pre-parent-call initialize values. + self._clause_prefix = '' + self._print_prefix = '' + self._quote_format = '"' + + # Call parent logic. + super().__init__(*args, clause_type=clause_type, **kwargs) + + def __str__(self): + # Handle for all-star return. + if len(self.array) == 1 and self.array[0] == '*': + return '*' + + # Handle for all other values. + return super().__str__() + + def _to_array(self, value): + # If none, set to all-star. + if value is None: + value = ['*'] + + # Call parent logic. + super()._to_array(value) + + # If validation returned empty set, set to all-star. + if len(self.array) == 0: + self.array = ['*'] + + # Error if wildcard star used with any other values. + elif len(self.array) > 1 and '*' in self.array: + raise ValueError('SELECT clause provided * with other params. * is only valid alone.') + + +class WhereClauseBuilder(BaseClauseBuilder): + """""" + def __init__(self, *args, clause_type='WHERE', **kwargs): + # Pre-parent-call initialize values. + self._clause_prefix = 'WHERE' + self._print_prefix = 'WHERE ' + self._quote_format = '"' + + # Call parent logic. + super().__init__(*args, clause_type=clause_type, **kwargs) + + def __str__(self): + if len(self.array) > 0: + # Non-empty clause. Format for str output. + to_str = ' AND '.join('({})' for x in range(len(self.array))) + to_str = to_str.format(*self.array) + to_str = '\n{0}{1}'.format(self._print_prefix, to_str) + return to_str + else: + # Empty clause. + return '' + + def _to_array(self, value): + """Converts clause to array format for initial parsing.""" + if self._clause_prefix is None: + raise NotImplementedError('Query type {0} missing clause_prefix value.'.format(self.__class__)) + if self._quote_format is None: + raise NotImplementedError('Query type {0} missing quote_format value.'.format(self.__class__)) + + if isinstance(value, list): + # Already list format. + clause = value + elif isinstance(value, tuple): + # Close to list format. Simply convert. + clause = list(value) + else: + # Attempt to parse as str for all other formats. + if value is None: + # None type defaults to empty. + clause = [] + else: + clause = str(value).strip() + + # Trim prefix, if present. + if len(self._clause_prefix) > 0: + # Check if starts with prefix, brackets, and space. + if ( + clause.upper().startswith('{0} ('.format(self._clause_prefix)) and clause.endswith(')') + or clause.upper().startswith('{0} ['.format(self._clause_prefix)) and clause.endswith(']') + ): + clause = clause[(len(self._clause_prefix) + 2):-1] + + # Check if starts with prefix, brackets, and no space. + elif ( + clause.upper().startswith('{0}('.format(self._clause_prefix)) and clause.endswith(')') + or clause.upper().startswith('{0}['.format(self._clause_prefix)) and clause.endswith(']') + ): + clause = clause[(len(self._clause_prefix) + 1):-1] + + # Check if starts with prefix and no brackets. + elif clause.upper().startswith('{0} '.format(self._clause_prefix)): + clause = clause[(len(self._clause_prefix) + 1):] + + # Split into subsections, based on AND + OR delimiters. + full_split = [] + # First separate by AND delimiters. + and_split = clause.split(' AND ') + for and_clause in and_split: + # For each inner section, also separate by OR delimiters. + or_split = and_clause.split(' OR ') + for or_clause in or_split: + # For each of these, strip spaces and add if non-empty. + or_clause = or_clause.strip() + if len(or_clause) > 0: + full_split.append(or_clause) + + # Use final result. + clause = full_split + + # Validate each item in clause, now that it's an array. + if len(clause) > 0: + + # Loop through each clause item. Correct quotes. + # TODO: For now, we assume that the first item (separated by spaces) will always be a column. + # Fix this logic later. + for index in range(len(clause)): + clause_item = clause[index] + + # 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): + first_item = first_item[1:-1] + first_item = '{1}{0}{1}'.format(first_item, self._quote_format) + + # Recombine into single string. + clause_split[0] = first_item + clause[index] = ' '.join(clause_split) + + # Save validated clause. + self._clause_array = clause + else: + # Save empty clause. + self._clause_array = [] + + +class ColumnsClauseBuilder(BaseClauseBuilder): + """""" + def __init__(self, *args, clause_type='COLUMNS', **kwargs): + # Pre-parent-call initialize values. + self._clause_prefix = 'COLUMNS' + self._print_prefix = '' + self._quote_format = '"' + + # Call parent logic. + super().__init__(*args, clause_type=clause_type, **kwargs) + + def _to_array(self, value): + # Call parent logic. + super()._to_array(value) + + # Verify that wildcard star is not present. + if '*' in self._clause_array: + raise ValueError('The * identifier can only be used in a SELECT clause.') + + +class ValuesClauseBuilder(BaseClauseBuilder): + """""" + def __init__(self, *args, clause_type='VALUES', **kwargs): + # Pre-parent-call initialize values. + self._clause_prefix = 'VALUES' + self._print_prefix = 'VALUES ' + + # Call parent logic. + super().__init__(*args, clause_type=clause_type, **kwargs) + + +class OrderByClauseBuilder(BaseClauseBuilder): + """""" + def __init__(self, *args, clause_type='ORDER_BY', **kwargs): + # Pre-parent-call initialize values. + self._clause_prefix = 'ORDER BY' + self._print_prefix = 'ORDER BY ' + self._quote_format = '"' + + # Call parent logic. + super().__init__(*args, clause_type=clause_type, **kwargs) + + # Post-parent-call initialize values. + self._print_parens = False + + def __str__(self): + if len(self.array) > 0: + # Call parent logic. + str_value = super().__str__() + return '\n{0}'.format(str_value) + else: + return '' + + def _to_array(self, value): + # Call parent logic. + super()._to_array(value) + + if '*' in self._clause_array: + raise ValueError('The * identifier can only be used in a SELECT clause.') diff --git a/py_dbcn/connectors/core/display.py b/py_dbcn/connectors/core/display.py index 160edf442461abe3597a2cc61577fec6c20998f9..273f1a52649490b9788d92db8afa3f899befaeae 100644 --- a/py_dbcn/connectors/core/display.py +++ b/py_dbcn/connectors/core/display.py @@ -294,13 +294,6 @@ class RecordDisplay: raise ValueError('Column quote format is not defined.') if results: - # Check select clause, which directly affects desired output columns. - # First we initialize to a default str. - if select_clause is None: - select_clause = '*' - else: - select_clause = str(select_clause).strip() - if self._base._config.db_type == 'MySQL': col_name_index = 0 elif self._base._config.db_type == 'PostgreSQL': @@ -310,26 +303,27 @@ class RecordDisplay: # Handle based on star or specific cols. # TODO: Probably need to tokenize this, to properly compare. - if select_clause == '*' or '(*)' in select_clause: + if len(select_clause.array) == 1 and select_clause.array[0] == '*': # Calculate column header values, using all columns. table_cols = [ x[col_name_index] for x in self._base.tables.describe(table_name, display_query=False, display_results=False) ] else: - select_clause = select_clause.split(',') + # Calculate column header values, using only provided columns. table_cols = [] table_describe = self._base.tables.describe(table_name, display_query=False, display_results=False) - for index in range(len(select_clause)): + select_clause_arr = select_clause.array + for index in range(len(select_clause_arr)): # Sanitize select clause values. - clause = select_clause[index].strip() - if len(clause) > 1 and clause[0] == clause[-1] and clause[0] in ['`', '"', "'"]: - clause = clause[1:-1] - select_clause[index] = clause - - # Calculate column header values, filtered by select clause. - table_cols = copy.deepcopy(select_clause) + if select_clause.is_quoted(select_clause_arr[index]): + clause = select_clause_arr[index][1:-1] + else: + clause = select_clause_arr[index] + # if clause in table_describe: + table_cols.append(clause) + # Calculate column header values with determined columns. col_len_array = [] total_col_len = 0 for table_col in table_cols: diff --git a/py_dbcn/connectors/core/records.py b/py_dbcn/connectors/core/records.py index 3f992bd12d55fc8b6b017e7638fface73281b0d0..698a9e34c3575294a69eb66e31a35764bdfdc57a 100644 --- a/py_dbcn/connectors/core/records.py +++ b/py_dbcn/connectors/core/records.py @@ -73,6 +73,7 @@ class BaseRecords: order_by_clause, limit_clause, ) + results = self._base.query.execute(query, display_query=display_query) if display_results: self._base.display.records.select(results, logger, table_name, select_clause) @@ -94,8 +95,6 @@ class BaseRecords: # Check that provided COLUMNS clause is valid format. columns_clause = self._base.validate.sanitize_columns_clause(columns_clause) - if len(columns_clause) > 0: - columns_clause = ' ({0})'.format(columns_clause) # Check that provided VALUES clause is valid format. values_clause = self._base.validate.sanitize_values_clause(values_clause) @@ -113,6 +112,10 @@ class BaseRecords: # Is a date object. Convert to string. item = item.strftime('%Y-%m-%d') + # # Handle if quote in item. + # if isinstance(item, str) and "'" in item: + # item = """E'{0}'""".format(item) + # Add item to updated clause. updated_values_clause += (item,) @@ -140,8 +143,6 @@ class BaseRecords: # Check that provided COLUMNS clause is valid format. columns_clause = self._base.validate.sanitize_columns_clause(columns_clause) - if columns_clause != '': - columns_clause = ' ({0})'.format(columns_clause) # Check that provided VALUES clause is valid format. # Must be array format. diff --git a/py_dbcn/connectors/core/validate.py b/py_dbcn/connectors/core/validate.py index 51a363a55955ff19be08a57032eb982052d96bad..6792a97569e10412172aba95989bb76e3b949e0a 100644 --- a/py_dbcn/connectors/core/validate.py +++ b/py_dbcn/connectors/core/validate.py @@ -7,18 +7,9 @@ Should be inherited by language-specific connectors. # System Imports. import copy, re -from io import StringIO -from tokenize import ( - generate_tokens, - ENDMARKER, - NAME, - NEWLINE, - NUMBER, - OP, - STRING, -) # Internal Imports. +from . import clauses from py_dbcn.logging import init_logging @@ -41,6 +32,7 @@ class BaseValidate: # Define provided direct parent object. self._parent = parent + self.clauses = clauses # Define inheritance variables. self._reserved_function_names = None @@ -334,30 +326,14 @@ class BaseValidate: # region Sanitization Functions - def sanitize_select_identifier_clause(self, clause, as_str=True): + def sanitize_select_identifier_clause(self, clause): """ Validates that provided clause follows acceptable format. :param clause: SELECT clause to validate. :param as_str: Bool indicating if return value should be formatted as a str. Otherwise is list. :return: Properly formatted clause if possible, otherwise error. """ - if not self._reserved_function_names: - raise ValueError('Reserved keyword list is not defined.') - - # Sanitize overall clause. - clause = self._inner_sanitize_columns(clause, allow_wildcard=True) - - # Check that each inner clause item is valid. - for item in clause: - self.validate_select_clause(item) - - # All items in clause were valid. Return validated and sanitized SELECT clause. - if as_str: - # Re-concatenate into single expected str format. - return ', '.join(clause) - else: - # Return as list. - return clause + return clauses.SelectClauseBuilder(self, clause) def sanitize_where_clause(self, clause): """ @@ -365,52 +341,16 @@ class BaseValidate: :param clause: WHERE clause to validate. :return: Properly formatted clause if possible, otherwise error. """ - # TODO: Implement proper sanitization. + return clauses.WhereClauseBuilder(self, clause) - # Handle if none. - if clause is None: - clause = '' - - # Convert to str. - clause = str(clause).strip() - - # Remove prefix, if present. - if clause.lower().startswith('where'): - clause = clause[5:] - - # Strip now that prefix is gone. - clause = clause.strip() - - # Put into expected format. - if len(clause) > 1: - clause = '\nWHERE {0}'.format(clause) - - return clause - - def sanitize_columns_clause(self, clause, as_str=True): + def sanitize_columns_clause(self, clause): """ Validates that provided clause follows acceptable format. :param clause: COLUMNS clause to validate. :param as_str: Bool indicating if return value should be formatted as a str. Otherwise is list. :return: Properly formatted clause if possible, otherwise error. """ - if not self._reserved_function_names: - raise ValueError('Reserved keyword list is not defined.') - - # Sanitize overall clause. - clause = self._inner_sanitize_columns(clause, allow_wildcard=False) - - # Check that each inner clause item is valid. - for item in clause: - self.validate_columns_clause(item) - - # All items in clause were valid. Return validated and sanitized SELECT clause. - if as_str: - # Re-concatenate into single expected str format. - return ', '.join(clause) - else: - # Return as list. - return clause + return clauses.ColumnsClauseBuilder(self, clause) def sanitize_values_clause(self, clause): """ @@ -517,47 +457,14 @@ class BaseValidate: # # Return formatted clause. # return ' VALUES ({0})'.format(', '.join(clause)) - def sanitize_order_by_clause(self, clause, as_str=True): + def sanitize_order_by_clause(self, clause): """ Validates that provided clause follows acceptable format. :param clause: ORDER_BY clause to validate. :param as_str: Bool indicating if return value should be formatted as a str. Otherwise is list. :return: Properly formatted clause if possible, otherwise error. """ - if not self._reserved_function_names: - raise ValueError('Reserved keyword list is not defined.') - - # Quickly sanitize if string format. - if isinstance(clause, str): - clause = clause.strip() - - # Remove clause starting value. - if clause.lower().startswith('order by'): - clause = clause[8:].strip() - - # Ensure not empty when prefix was provided. - if len(clause) < 1: - raise ValueError('Invalid ORDER BY clause.') - - # Validate. - clause = self._inner_sanitize_columns(clause, allow_wildcard=False, order_by=True) - - # Handle empty clause. - if clause == '': - return '' - - # Check that each inner clause item is valid. - for item in clause: - self.validate_order_by_clause(item) - - # All items in clause were valid. Return validated and sanitized SELECT clause. - if as_str: - # Re-concatenate into single expected str format. - clause = ', '.join(clause) - return '\nORDER BY {0}'.format(clause) - else: - # Return as list. - return clause + return clauses.OrderByClauseBuilder(self, clause) def sanitize_limit_clause(self, clause): """ diff --git a/py_dbcn/connectors/postgresql/records.py b/py_dbcn/connectors/postgresql/records.py index 556e052ba832abdcc405ac69b850b6885f2275f4..72692f099ef3f9cf67c5f7f8ade61a32e536f875 100644 --- a/py_dbcn/connectors/postgresql/records.py +++ b/py_dbcn/connectors/postgresql/records.py @@ -80,12 +80,10 @@ class PostgresqlRecords(BaseRecords): # Check that provided WHERE clause is valid format. columns_clause = self._base.validate.sanitize_columns_clause(columns_clause) where_columns_clause = self._base.validate.sanitize_columns_clause(where_columns_clause) - columns_clause = columns_clause.split(', ') - where_columns_clause = where_columns_clause.split(', ') # Verify each "where column" is present in the base columns clause. - for column in where_columns_clause: - if column not in columns_clause: + for column in where_columns_clause.array: + if column not in columns_clause.array: raise ValueError( 'All columns specified in WHERE_COLUMNS must also be present in COLUMNS.' 'Failed to find "{0}" in {1}'.format( @@ -96,44 +94,43 @@ class PostgresqlRecords(BaseRecords): # Check for values that might need formatting. # For example, if we find date/datetime objects, we automatically convert to a str value that won't error. - if isinstance(values_clause, list) or isinstance(values_clause, tuple): - updated_values_clause = () - for value_set in values_clause: - updated_values_set = () - for item in value_set: + updated_values_clause = () + for value_set in values_clause: + updated_values_set = () + for item in value_set: - if isinstance(item, datetime.datetime): - # Is a datetime object. Convert to string. - item = item.strftime('%Y-%m-%d %H:%M:%S') - elif isinstance(item, datetime.date): - # Is a date object. Convert to string. - item = item.strftime('%Y-%m-%d') + if isinstance(item, datetime.datetime): + # Is a datetime object. Convert to string. + item = item.strftime('%Y-%m-%d %H:%M:%S') + elif isinstance(item, datetime.date): + # Is a date object. Convert to string. + item = item.strftime('%Y-%m-%d') - # Add item to updated inner set. - updated_values_set += (item,) + # Add item to updated inner set. + updated_values_set += (item,) - # Add item to updated clause. - updated_values_clause += (updated_values_set,) + # Add item to updated clause. + updated_values_clause += (updated_values_set,) - # Replace original clause. - values_clause = updated_values_clause + # Replace original clause. + values_clause = updated_values_clause # Now format our clauses for query. if column_types_clause is not None: # Provide type hinting for columns. set_clause = '' - for index in range(len(columns_clause)): + for index in range(len(columns_clause.array)): if set_clause != '': set_clause += ',\n' set_clause += ' "{0}" = pydbcn_temp."{0}"::{1}'.format( - columns_clause[index].strip(self._base.validate._quote_column_format), + columns_clause.array[index].strip(self._base.validate._quote_column_format), column_types_clause[index], ) else: # No type hinting. Provide columns as-is. set_clause = ',\n'.join([ ' "{0}" = pydbcn_temp."{0}"'.format(x.strip(self._base.validate._quote_column_format)) - for x in columns_clause + for x in columns_clause.array ]) values_clause = ',\n'.join([ ' {0}'.format(x) @@ -141,11 +138,11 @@ class PostgresqlRecords(BaseRecords): ]) columns_clause = ', '.join([ '"{0}"'.format(x.strip(self._base.validate._quote_column_format)) - for x in columns_clause + for x in columns_clause.array ]) where_columns_clause = ' AND\n'.join([ ' pydbcn_update_table."{0}" = pydbcn_temp."{0}"'.format(x.strip(self._base.validate._quote_column_format)) - for x in where_columns_clause + for x in where_columns_clause.array ]) # Update records. diff --git a/tests/connectors/core/test_clauses.py b/tests/connectors/core/test_clauses.py new file mode 100644 index 0000000000000000000000000000000000000000..e359f6c72047f36a5842b775c0e613795135ff30 --- /dev/null +++ b/tests/connectors/core/test_clauses.py @@ -0,0 +1,363 @@ +""" +Initialization of "clause" logic of "Core" DB Connector class. + +Note that the tests for the "Core" DB Connector class don't do anything in themselves. +They're meant to define a majority of overall database logic, which is then inherited/tweaked by the +various specific database test classes. This ensures that all databases types run similar/equal tests. +""" + +# System Imports. + +# Internal Imports. + + +class CoreClauseTestMixin: + """ + Tests "Core" DB Connector class database logic. + """ + @classmethod + def set_up_class(cls): + """ + Acts as the equivalent of the UnitTesting "setUpClass()" function. + + However, since this is not inheriting from a given TestCase, + calling the literal function here would override instead. + """ + cls.test_db_name_start = cls.test_db_name_start.format(cls.db_type) + + def test__clause__select(self): + """Test logic for parsing a SELECT clause.""" + validation_class = self.connector.validate + + with self.subTest('SELECT clause as Empty'): + # With passing none. + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, None) + self.assertEqual(['*'], clause_object.array) + self.assertText('*', str(clause_object)) + + # With empty single-quote string. + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, '') + self.assertEqual(['*'], clause_object.array) + self.assertText('*', str(clause_object)) + + # With empty double-quote string. + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, "") + self.assertEqual(['*'], clause_object.array) + self.assertText('*', str(clause_object)) + + # With emtpy triple double-quote string. + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, """""") + self.assertEqual(['*'], clause_object.array) + self.assertText('*', str(clause_object)) + + with self.subTest('Basic SELECT clause - As str'): + # With no quotes. + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, 'id') + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + # With single quotes. + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, "'id'") + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + # With double quotes. + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, '"id"') + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + # With backtick quotes. + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, '`id`') + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, 'id, code, name') + self.assertEqual(['"id"', '"code"', '"name"'], clause_object.array) + self.assertText("""("id", "code", "name")""", str(clause_object)) + + with self.subTest('Basic SELECT clause - As list'): + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, ['id']) + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + clause_object = self.connector.validate.clauses.SelectClauseBuilder( + validation_class, + ['id', 'code', 'name'], + ) + self.assertEqual(['"id"', '"code"', '"name"'], clause_object.array) + self.assertText("""("id", "code", "name")""", str(clause_object)) + + with self.subTest('Basic SELECT clause - As tuple'): + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, ('id',)) + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + clause_object = self.connector.validate.clauses.SelectClauseBuilder( + validation_class, + ('id', 'code', 'name'), + ) + self.assertEqual(['"id"', '"code"', '"name"'], clause_object.array) + self.assertText("""("id", "code", "name")""", str(clause_object)) + + with self.subTest('Values with function calls'): + # Uppercase. + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, 'COUNT(*)') + self.assertEqual(['COUNT(*)'], clause_object.array) + self.assertText("""(COUNT(*))""", str(clause_object)) + + # Lowercase. + clause_object = self.connector.validate.clauses.SelectClauseBuilder(validation_class, 'count(*)') + self.assertEqual(['COUNT(*)'], clause_object.array) + self.assertText("""(COUNT(*))""", str(clause_object)) + + def test__clause__where(self): + """Test logic for parsing a WHERE clause.""" + validation_class = self.connector.validate + + with self.subTest('WHERE clause as Empty'): + # With passing none. + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, None) + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + # With empty single-quote string. + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, '') + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + # With empty double-quote string. + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, "") + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + # With emtpy triple double-quote string. + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, """""") + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + with self.subTest('Basic WHERE clause - As str'): + # With no quotes. + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, """id = 'test'""") + self.assertEqual([""""id" = 'test'"""], clause_object.array) + self.assertText("""WHERE ("id" = 'test')""", str(clause_object)) + + # With single quotes. + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, """'id' = 'test'""") + self.assertEqual([""""id" = 'test'"""], clause_object.array) + self.assertText("""WHERE ("id" = 'test')""", str(clause_object)) + + # With double quotes. + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, """"id" = 'test'""") + self.assertEqual([""""id" = 'test'"""], clause_object.array) + self.assertText("""WHERE ("id" = 'test')""", str(clause_object)) + + # With backtick quotes. + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, """`id` = 'test'""") + self.assertEqual([""""id" = 'test'"""], clause_object.array) + self.assertText("""WHERE ("id" = 'test')""", str(clause_object)) + + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, """id = 'test' AND code = 1234 AND name = 'Test User'""") + self.assertEqual([""""id" = 'test'""", """"code" = 1234""", """"name" = 'Test User'"""], clause_object.array) + self.assertText("""WHERE ("id" = 'test') AND ("code" = 1234) AND ("name" = 'Test User')""", str(clause_object)) + + with self.subTest('Basic WHERE clause - As list'): + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, ["""id = 'test'"""]) + self.assertEqual([""""id" = 'test'"""], clause_object.array) + self.assertText("""WHERE ("id" = 'test')""", str(clause_object)) + + clause_object = self.connector.validate.clauses.WhereClauseBuilder( + validation_class, + ["""id = 'test'""", """code = 1234""", """name = 'Test User'"""], + ) + self.assertEqual([""""id" = 'test'""", """"code" = 1234""", """"name" = 'Test User'"""], clause_object.array) + self.assertText("""WHERE ("id" = 'test') AND ("code" = 1234) AND ("name" = 'Test User')""", str(clause_object)) + + with self.subTest('Basic WHERE clause - As tuple'): + clause_object = self.connector.validate.clauses.WhereClauseBuilder(validation_class, ("""id = 'test'""",)) + self.assertEqual([""""id" = 'test'"""], clause_object.array) + self.assertText("""WHERE ("id" = 'test')""", str(clause_object)) + + clause_object = self.connector.validate.clauses.WhereClauseBuilder( + validation_class, + ("""id = 'test'""", """code = 1234""", """name = 'Test User'"""), + ) + self.assertEqual([""""id" = 'test'""", """"code" = 1234""", """"name" = 'Test User'"""], clause_object.array) + self.assertText("""WHERE ("id" = 'test') AND ("code" = 1234) AND ("name" = 'Test User')""", str(clause_object)) + + def test__clause__columns(self): + """Test logic for parsing a COLUMNS clause.""" + validation_class = self.connector.validate + + with self.subTest('COLUMNS clause as Empty'): + # With passing none. + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, None) + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + # With empty single-quote string. + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, '') + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + # With empty double-quote string. + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, "") + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + # With emtpy triple double-quote string. + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, """""") + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + with self.subTest('Basic COLUMNS clause - As str'): + # With no quotes. + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, 'id') + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + # With single quotes. + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, "'id'") + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + # With double quotes. + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, '"id"') + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + # With backtick quotes. + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, '`id`') + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, 'id, code, name') + self.assertEqual(['"id"', '"code"', '"name"'], clause_object.array) + self.assertText("""("id", "code", "name")""", str(clause_object)) + + with self.subTest('Basic COLUMNS clause - As list'): + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, ['id']) + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder( + validation_class, + ['id', 'code', 'name'], + ) + self.assertEqual(['"id"', '"code"', '"name"'], clause_object.array) + self.assertText("""("id", "code", "name")""", str(clause_object)) + + with self.subTest('Basic COLUMNS clause - As tuple'): + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder(validation_class, ('id',)) + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""("id")""", str(clause_object)) + + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder( + validation_class, + ('id', 'code', 'name'), + ) + self.assertEqual(['"id"', '"code"', '"name"'], clause_object.array) + self.assertText("""("id", "code", "name")""", str(clause_object)) + + with self.subTest('Standard COLUMNS clause - As str'): + clause_object = self.connector.validate.clauses.ColumnsClauseBuilder( + validation_class, + ( + 'id INT NOT NULL AUTO_INCREMENT, ' + 'title VARCHAR(100) NOT NULL, ' + 'description VARCHAR(255) NOT NULL' + ), + ) + self.assertEqual( + [ + '"id" INT NOT NULL AUTO_INCREMENT', + '"title" VARCHAR(100) NOT NULL', + '"description" VARCHAR(255) NOT NULL', + ], + clause_object.array, + ) + self.assertText( + """("id" INT NOT NULL AUTO_INCREMENT, "title" VARCHAR(100) NOT NULL, "description" VARCHAR(255) NOT NULL)""", + str(clause_object), + ) + + def test__clause__values(self): + """Test logic for paring a VALUES clause.""" + validation_class = self.connector.validate + + def test__clause__order_by(self): + """Test logic for parsing an ORDER BY clause.""" + validation_class = self.connector.validate + + with self.subTest('ORDER BY clause as Empty'): + # With passing none. + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, None) + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + # With empty single-quote string. + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, '') + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + # With empty double-quote string. + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, "") + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + # With emtpy triple double-quote string. + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, """""") + self.assertEqual([], clause_object.array) + self.assertText('', str(clause_object)) + + with self.subTest('Basic ORDER BY clause - As str'): + # With no quotes. + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, 'id') + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""ORDER BY "id\"""", str(clause_object)) + + # With single quotes. + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, "'id'") + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""ORDER BY "id\"""", str(clause_object)) + + # With double quotes. + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, '"id"') + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""ORDER BY "id\"""", str(clause_object)) + + # With backtick quotes. + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, '`id`') + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""ORDER BY "id\"""", str(clause_object)) + + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, 'id, code, name') + self.assertEqual(['"id"', '"code"', '"name"'], clause_object.array) + self.assertText("""ORDER BY "id", "code", "name\"""", str(clause_object)) + + with self.subTest('Basic ORDER BY clause - As list'): + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, ['id']) + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""ORDER BY "id\"""", str(clause_object)) + + clause_object = self.connector.validate.clauses.OrderByClauseBuilder( + validation_class, + ['id', 'code', 'name'], + ) + self.assertEqual(['"id"', '"code"', '"name"'], clause_object.array) + self.assertText("""ORDER BY "id", "code", "name\"""", str(clause_object)) + + with self.subTest('Basic ORDER BY clause - As tuple'): + clause_object = self.connector.validate.clauses.OrderByClauseBuilder(validation_class, ('id',)) + self.assertEqual(['"id"'], clause_object.array) + self.assertText("""ORDER BY "id\"""", str(clause_object)) + + clause_object = self.connector.validate.clauses.OrderByClauseBuilder( + validation_class, + ('id', 'code', 'name'), + ) + self.assertEqual(['"id"', '"code"', '"name"'], clause_object.array) + self.assertText("""ORDER BY "id", "code", "name\"""", str(clause_object)) + + def test__clause__limit(self): + """Test logic for paring a LIMIT clause.""" + validation_class = self.connector.validate diff --git a/tests/connectors/core/test_display.py b/tests/connectors/core/test_display.py index aeac8f70636fe6eb6b8e0307ee94398ed0322146..7f43894f7b87218974ad8c439a97a1188a9b87b1 100644 --- a/tests/connectors/core/test_display.py +++ b/tests/connectors/core/test_display.py @@ -675,7 +675,7 @@ class CoreDisplayRecordsMixin: # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category2') - self.assertText(self.get_logging_output(ilog, 0), select_from_query.format('*')) + self.assertText(select_from_query.format('*'), self.get_logging_output(ilog, 0)) self.assertText( self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( @@ -689,105 +689,105 @@ class CoreDisplayRecordsMixin: # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category2', 'name, description') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_name, quoted_desc)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_name, quoted_desc)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__BASIC__OMIT_ID, OUTPUT_RESET ), + self.get_logging_output(ilog, 1), ) with self.subTest('With basic column types - Exclude name'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category2', 'id, description') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_id, quoted_desc)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_id, quoted_desc)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__BASIC__OMIT_NAME, OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) with self.subTest('With basic column types - Exclude description'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category2', 'id, name') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_id, quoted_name)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_id, quoted_name)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__BASIC__OMIT_DESC, OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) with self.subTest('With basic column types - Pull all reversed'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category2', 'description, name, id') - curr_select_clause = select_from_query.format('{0}, {1}, {2}'.format(quoted_desc, quoted_name, quoted_id)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1}, {2})'.format(quoted_desc, quoted_name, quoted_id)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__BASIC__REVERSED_ALL, OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) with self.subTest('With basic column types - Exclude id reversed'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category2', 'description, name') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_desc, quoted_name)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_desc, quoted_name)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__BASIC__REVERSED_OMIT_ID, OUTPUT_RESET ), + self.get_logging_output(ilog, 1), ) with self.subTest('With basic column types - Exclude name reversed'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category2', 'description, id') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_desc, quoted_id)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_desc, quoted_id)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__BASIC__REVERSED_OMIT_NAME, OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) with self.subTest('With basic column types - Exclude description reversed'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category2', 'name, id') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_name, quoted_id)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_name, quoted_id)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__BASIC__REVERSED_OMIT_DESC, OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) datetime_now = datetime.now() @@ -805,9 +805,8 @@ class CoreDisplayRecordsMixin: # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category3') - self.assertText(self.get_logging_output(ilog, 0), select_from_query.format('*')) + self.assertText(select_from_query.format('*'), self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__DATETIME__ALL.format( @@ -816,16 +815,16 @@ class CoreDisplayRecordsMixin: ), OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) with self.subTest('With datetime column types - Exclude id'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category3', 'test_datetime, test_date') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_datetime, quoted_date)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_datetime, quoted_date)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__DATETIME__OMIT_ID.format( @@ -834,16 +833,16 @@ class CoreDisplayRecordsMixin: ), OUTPUT_RESET ), + self.get_logging_output(ilog, 1), ) with self.subTest('With datetime column types - Exclude datetime'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category3', 'id, test_date') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_id, quoted_date)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_id, quoted_date)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__DATETIME__OMIT_DATETIME.format( @@ -851,16 +850,16 @@ class CoreDisplayRecordsMixin: ), OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) with self.subTest('With datetime column types - Exclude date'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category3', 'id, test_datetime') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_id, quoted_datetime)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_id, quoted_datetime)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__DATETIME__OMIT_DATE.format( @@ -868,6 +867,7 @@ class CoreDisplayRecordsMixin: ), OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) with self.subTest('With datetime column types - Pull all reversed'): @@ -875,11 +875,10 @@ class CoreDisplayRecordsMixin: with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category3', 'test_date, test_datetime, id') curr_select_clause = select_from_query.format( - '{0}, {1}, {2}'.format(quoted_date, quoted_datetime, quoted_id), + '({0}, {1}, {2})'.format(quoted_date, quoted_datetime, quoted_id), ) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__DATETIME__REVERSED_ALL.format( @@ -888,16 +887,16 @@ class CoreDisplayRecordsMixin: ), OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) with self.subTest('With datetime column types - Exclude id reversed'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category3', 'test_date, test_datetime') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_date, quoted_datetime)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_date, quoted_datetime)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__DATETIME__REVERSED_OMIT_ID.format( @@ -906,16 +905,16 @@ class CoreDisplayRecordsMixin: ), OUTPUT_RESET ), + self.get_logging_output(ilog, 1), ) with self.subTest('With datetime column types - Exclude datetime reversed'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category3', 'test_date, id') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_date, quoted_id)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_date, quoted_id)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__DATETIME__REVERSED_OMIT_DATETIME.format( @@ -923,16 +922,16 @@ class CoreDisplayRecordsMixin: ), OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) with self.subTest('With datetime column types - Exclude date reversed'): # Capture logging output. with self.assertLogs(None, 'INFO') as ilog: self.connector.records.select('category3', 'test_datetime, id') - curr_select_clause = select_from_query.format('{0}, {1}'.format(quoted_datetime, quoted_id)) - self.assertText(self.get_logging_output(ilog, 0), curr_select_clause) + curr_select_clause = select_from_query.format('({0}, {1})'.format(quoted_datetime, quoted_id)) + self.assertText(curr_select_clause, self.get_logging_output(ilog, 0)) self.assertText( - self.get_logging_output(ilog, 1), '{0}{1}{2}'.format( OUTPUT_RESULTS, self.expected_output.records.LIMITED_SELECT__DATETIME__REVERSED_OMIT_DATE.format( @@ -940,4 +939,5 @@ class CoreDisplayRecordsMixin: ), OUTPUT_RESET, ), + self.get_logging_output(ilog, 1), ) diff --git a/tests/connectors/core/test_records.py b/tests/connectors/core/test_records.py index 252d8d816906a88cdf530821200df1ef07fe2f80..e0b99f7bef4bfba06dcfe1d649bd2eca87ef7f6d 100644 --- a/tests/connectors/core/test_records.py +++ b/tests/connectors/core/test_records.py @@ -875,6 +875,11 @@ class CoreRecordsTestMixin: # Test with columns defined. row = (3, 'test_name_3', 'test_desc_3') self.connector.records.insert(table_name, row, columns_clause='id, name, description') + results = self.connector.query.execute('SELECT * FROM {0};'.format(table_name)) + + # Verify two records returned. + self.assertEqual(len(results), 3) + self.assertIn(row, results) def test__insert__datetime__success(self): """ diff --git a/tests/connectors/core/test_validate.py b/tests/connectors/core/test_validate.py index 65b86b70d55554075e4059837b6b8abe55b24937..b32a1b8b1a84fcb12895907b220f68756ac06470 100644 --- a/tests/connectors/core/test_validate.py +++ b/tests/connectors/core/test_validate.py @@ -42,8 +42,6 @@ class CoreValidateTestMixin: # with self.assertRaises(): # self.connector.validate.validate_select_clause('DROP DATABASE {0}'.format(self.test_db_name_start)) - - def test__column_quote_format(self): raise NotImplementedError('Check for column quote formatting not implemented.') @@ -924,455 +922,456 @@ class CoreValidateTestMixin: # None provided. Defaults back to "*". result = self.connector.validate.sanitize_select_identifier_clause(None) - self.assertText(result, '*') + self.assertText('*', result) # All flag provided. result = self.connector.validate.sanitize_select_identifier_clause('*') - self.assertText(result, '*') + self.assertText('*', result) with self.subTest('Values as str - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause('id') - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause(' id ') - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause('id, name') self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name') ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause(' id , name ') self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause('id, name, code') self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause(' id , name , code ') self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as triple str - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause("""id""") - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause(""" id """) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause("""id, name""") self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause(""" id , name """) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause("""id, name, code""") self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause(""" id , name , code """) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as list - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause(['id']) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause([' id ']) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause(['id', 'name']) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause([' id ', ' name ']) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause(['id', 'name', 'code']) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause([' id ', ' name ', ' code ']) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as tuple - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause(('id',)) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause((' id ',)) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause(('id', 'name')) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause((' id ', ' name ')) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause(('id', 'name', 'code')) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_select_identifier_clause((' id ', ' name ', ' code ')) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as str - With single quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause("'id'") - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause("'id', 'name'") self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause("'id', 'name', 'code'") self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code') ), + result, ) with self.subTest('Values as list - With single quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause(["'id'"]) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause(["'id'", "'name'"]) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause(["'id'", "'name'", "'code'"]) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as tuple - With single quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause(("'id'",)) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause(("'id'", "'name'")) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause(("'id'", "'name'", "'code'")) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as str - With double quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause('"id"') - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause('"id", "name"') self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause('"id", "name", code') self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as list - With double quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause(['"id"']) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause(['"id"', '"name"']) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause(['"id"', '"name"', '"code"']) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as tuple - With double quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause(('"id"',)) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause(('"id"', '"name"')) self.assertText( - result, '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause(('"id"', '"name"', '"code"')) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as str - With backtick quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause('`id`') - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause('`id`, `name`') self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause('`id`, `name`, `code`') self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as list - With backtick quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause(['`id`']) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause(['`id`', '`name`']) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause(['`id`', '`name`', '`code`']) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as tuple - With backtick quotes'): # Single val provided. result = self.connector.validate.sanitize_select_identifier_clause(('`id`',)) - self.assertText(result, self._quote_select_identifier_format.format('id')) + self.assertText('({0})'.format(self._quote_select_identifier_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_select_identifier_clause(('`id`', '`name`')) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_select_identifier_clause(('`id`', '`name`', '`code`')) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_select_identifier_format.format('id'), self._quote_select_identifier_format.format('name'), self._quote_select_identifier_format.format('code'), ), + result, ) with self.subTest('Values as non-standard types'): result = self.connector.validate.sanitize_select_identifier_clause((1, True)) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_select_identifier_format.format(1), self._quote_select_identifier_format.format(True), ), + result, ) with self.subTest('Values with function calls'): # Uppercase. result = self.connector.validate.sanitize_select_identifier_clause('COUNT(*)') - self.assertText(result, 'COUNT(*)') + self.assertText('(COUNT(*))', result) # Lowercase. result = self.connector.validate.sanitize_select_identifier_clause('count(*)') - self.assertText(result, 'COUNT(*)') + self.assertText('(COUNT(*))', result) def test__sanitize_select_identifier_clause__failure(self): """ @@ -1383,59 +1382,61 @@ class CoreValidateTestMixin: self.connector.validate.sanitize_select_identifier_clause('* , id') self.assertText('SELECT clause provided * with other params. * is only valid alone.', str(err.exception)) - # Mistmatching quotes - double then single. - identifier = """\"id'""" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_select_identifier_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier "id\'', - str(err.exception), - ) - - # Mistmatching quotes - single then double. - identifier = """'id\"""" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_select_identifier_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier \'id"', - str(err.exception), - ) - - # Mistmatching quotes - backtick then single. - identifier = "`id'" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_select_identifier_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier `id\'', - str(err.exception), - ) - - # Mistmatching quotes - single then backtick. - identifier = "'id`" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_select_identifier_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier \'id`', - str(err.exception), - ) - - # Mistmatching quotes - double then backtick. - identifier = '"id`' - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_select_identifier_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier "id`', - str(err.exception), - ) - - # Mistmatching quotes - backtick then double. - identifier = '`id"' - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_select_identifier_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier `id"', - str(err.exception), - ) + # # For now, we are no longer testing this. + # # While uncommon, there might be legitimate cases where a string starts/ends with one quote. + # # Mistmatching quotes - double then single. + # identifier = """\"id'""" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_select_identifier_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier "id\'', + # str(err.exception), + # ) + # + # # Mistmatching quotes - single then double. + # identifier = """'id\"""" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_select_identifier_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier \'id"', + # str(err.exception), + # ) + # + # # Mistmatching quotes - backtick then single. + # identifier = "`id'" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_select_identifier_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier `id\'', + # str(err.exception), + # ) + # + # # Mistmatching quotes - single then backtick. + # identifier = "'id`" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_select_identifier_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier \'id`', + # str(err.exception), + # ) + # + # # Mistmatching quotes - double then backtick. + # identifier = '"id`' + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_select_identifier_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier "id`', + # str(err.exception), + # ) + # + # # Mistmatching quotes - backtick then double. + # identifier = '`id"' + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_select_identifier_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier `id"', + # str(err.exception), + # ) def test__sanitize_columns_clause__success(self): """ @@ -1450,450 +1451,451 @@ class CoreValidateTestMixin: # None provided. Defaults back to empty string. result = self.connector.validate.sanitize_columns_clause(None) - self.assertText(result, '') + self.assertText('', result) # Empty string provided (single-quote str). result = self.connector.validate.sanitize_columns_clause('') - self.assertText(result, '') + self.assertText('', result) # Empty string provided (double-quote str). result = self.connector.validate.sanitize_columns_clause("") - self.assertText(result, '') + self.assertText('', result) # Empty string provided (triple double-quote str). result = self.connector.validate.sanitize_columns_clause("""""") - self.assertText(result, '') + self.assertText('', result) with self.subTest('Values as str - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause('id') - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause(' id ') - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Single val provided and COLUMNS. result = self.connector.validate.sanitize_columns_clause('COLUMNS (id)') - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause(' COLUMNS ( id ) ') - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause('id, name') self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name') ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause(' id , name ') self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause('id, name, code') self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause(' id , name , code ') self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as triple str - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause("""id""") - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause(""" id """) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause("""id, name""") self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause(""" id , name """) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause("""id, name, code""") self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause(""" id , name , code """) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as list - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause(['id']) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause([' id ']) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause(['id', 'name']) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause([' id ', ' name ']) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause(['id', 'name', 'code']) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause([' id ', ' name ', ' code ']) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as tuple - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause(('id',)) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause((' id ',)) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause(('id', 'name')) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause((' id ', ' name ')) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause(('id', 'name', 'code')) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_columns_clause((' id ', ' name ', ' code ')) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as str - With single quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause("'id'") - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause("'id', 'name'") self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause("'id', 'name', 'code'") self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code') ), + result, ) with self.subTest('Values as list - With single quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause(["'id'"]) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause(["'id'", "'name'"]) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause(["'id'", "'name'", "'code'"]) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as tuple - With single quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause(("'id'",)) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause(("'id'", "'name'")) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause(("'id'", "'name'", "'code'")) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as str - With double quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause('"id"') - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause('"id", "name"') self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause('"id", "name", code') self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as list - With double quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause(['"id"']) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause(['"id"', '"name"']) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause(['"id"', '"name"', '"code"']) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as tuple - With double quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause(('"id"',)) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause(('"id"', '"name"')) self.assertText( - result, '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause(('"id"', '"name"', '"code"')) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as str - With backtick quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause('`id`') - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause('`id`, `name`') self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause('`id`, `name`, `code`') self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as list - With backtick quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause(['`id`']) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause(['`id`', '`name`']) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause(['`id`', '`name`', '`code`']) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as tuple - With backtick quotes'): # Single val provided. result = self.connector.validate.sanitize_columns_clause(('`id`',)) - self.assertText(result, self._quote_columns_format.format('id')) + self.assertText('({0})'.format(self._quote_columns_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_columns_clause(('`id`', '`name`')) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_columns_clause(('`id`', '`name`', '`code`')) self.assertText( - result, - '{0}, {1}, {2}'.format( + '({0}, {1}, {2})'.format( self._quote_columns_format.format('id'), self._quote_columns_format.format('name'), self._quote_columns_format.format('code'), ), + result, ) with self.subTest('Values as non-standard types'): @@ -1901,11 +1903,11 @@ class CoreValidateTestMixin: # I think only literal column names should work. result = self.connector.validate.sanitize_columns_clause((1, True)) self.assertText( - result, - '{0}, {1}'.format( + '({0}, {1})'.format( self._quote_columns_format.format(1), self._quote_columns_format.format(True), ), + result, ) def test__sanitize_columns_clause__failure(self): @@ -1922,59 +1924,61 @@ class CoreValidateTestMixin: self.connector.validate.sanitize_columns_clause('* , id') self.assertText('The * identifier can only be used in a SELECT clause.', str(err.exception)) - # Mistmatching quotes - double then single. - identifier = """\"id'""" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_columns_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier "id\'', - str(err.exception), - ) - - # Mistmatching quotes - single then double. - identifier = """'id\"""" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_columns_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier \'id"', - str(err.exception), - ) - - # Mistmatching quotes - backtick then single. - identifier = "`id'" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_columns_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier `id\'', - str(err.exception), - ) - - # Mistmatching quotes - single then backtick. - identifier = "'id`" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_columns_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier \'id`', - str(err.exception), - ) - - # Mistmatching quotes - double then backtick. - identifier = '"id`' - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_columns_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier "id`', - str(err.exception), - ) - - # Mistmatching quotes - backtick then double. - identifier = '`id"' - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_columns_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier `id"', - str(err.exception), - ) + # # For now, we are no longer testing this. + # # While uncommon, there might be legitimate cases where a string starts/ends with one quote. + # # Mistmatching quotes - double then single. + # identifier = """\"id'""" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_columns_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier "id\'', + # str(err.exception), + # ) + # + # # Mistmatching quotes - single then double. + # identifier = """'id\"""" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_columns_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier \'id"', + # str(err.exception), + # ) + # + # # Mistmatching quotes - backtick then single. + # identifier = "`id'" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_columns_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier `id\'', + # str(err.exception), + # ) + # + # # Mistmatching quotes - single then backtick. + # identifier = "'id`" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_columns_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier \'id`', + # str(err.exception), + # ) + # + # # Mistmatching quotes - double then backtick. + # identifier = '"id`' + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_columns_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier "id`', + # str(err.exception), + # ) + # + # # Mistmatching quotes - backtick then double. + # identifier = '`id"' + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_columns_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier `id"', + # str(err.exception), + # ) # def test__sanitize_values_clause__success(self): # """ @@ -1992,154 +1996,154 @@ class CoreValidateTestMixin: # with self.subTest('Single val provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause('id') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(' id ') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause('VALUES id') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause('values id') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause('VALUES (id)') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause('values (id)') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # with self.subTest('Two vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause('id, name') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(' id , name ') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause('VALUES id, name') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause('values id, name') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause('VALUES (id, name)') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause('values (id, name)') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # with self.subTest('Three vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause('id, name, code') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(' id , name , code ') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause('VALUES id, name, code') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause('values id, name, code') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause('VALUES (id, name, code)') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause('values (id, name, code)') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # with self.subTest('Values as triple str - Without quotes'): @@ -2147,154 +2151,154 @@ class CoreValidateTestMixin: # with self.subTest('Single val provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause("""id""") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(""" id """) - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause("""VALUES id""") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause("""values id""") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause("""VALUES (id)""") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause("""values (id)""") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # with self.subTest('Two vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause("""id, name""") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(""" id , name """) # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause("""VALUES id, name""") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause("""values id, name""") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause("""VALUES (id, name)""") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause("""values (id, name)""") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # with self.subTest('Three vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause("""id, name, code""") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(""" id , name , code """) # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause("""VALUES id, name, code""") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause("""values id, name, code""") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause("""VALUES (id, name, code)""") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause("""values (id, name, code)""") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # with self.subTest('Values as list - Without quotes'): @@ -2302,54 +2306,54 @@ class CoreValidateTestMixin: # with self.subTest('Single val provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause(['id']) - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause([' id ']) - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format(' id '))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format(' id ')), result) # # with self.subTest('Two vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause(['id', 'name']) # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause([' id ', ' name ']) # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format(' id '), # self._quote_str_literal_format.format(' name '), # ), + # result, # ) # # with self.subTest('Three vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause(['id', 'name', 'code']) # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause([' id ', ' name ', ' code ']) # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format(' id '), # self._quote_str_literal_format.format(' name '), # self._quote_str_literal_format.format(' code '), # ), + # result, # ) # # with self.subTest('Values as tuple - Without quotes'): @@ -2357,54 +2361,54 @@ class CoreValidateTestMixin: # with self.subTest('Single val provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause(('id',)) - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause((' id ',)) - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format(' id '))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format(' id ')), result) # # with self.subTest('Two vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause(('id', 'name')) # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause((' id ', ' name ')) # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format(' id '), # self._quote_str_literal_format.format(' name '), # ), + # result, # ) # # with self.subTest('Three vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause(('id', 'name', 'code')) # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause((' id ', ' name ', ' code ')) # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format(' id '), # self._quote_str_literal_format.format(' name '), # self._quote_str_literal_format.format(' code '), # ), + # result, # ) # # with self.subTest('Values as str - With single quotes'): @@ -2412,154 +2416,154 @@ class CoreValidateTestMixin: # with self.subTest('Single val provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause("'id'") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(" ' id ' ") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format(' id '))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format(' id ')), result) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause("VALUES 'id'") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause("values 'id'") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause("VALUES ('id')") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause("values ('id')") - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # with self.subTest('Two vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause("'id', 'name'") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(" ' id ' , ' name ' ") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format(' id '), # self._quote_str_literal_format.format(' name '), # ), + # result, # ) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause("VALUES 'id', 'name',") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause("values 'id', 'name'") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause("VALUES ('id', 'name')") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause("values ('id', 'name')") # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # with self.subTest('Three vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause("'id', 'name', 'code'") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(" ' id ' , ' name ' , ' code ' ") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format(' id '), # self._quote_str_literal_format.format(' name '), # self._quote_str_literal_format.format(' code '), # ), + # result, # ) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause("VALUES 'id', 'name', 'code'") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause("values 'id', 'name', 'code'") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause("VALUES ('id', 'name', 'code')") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause("values ('id', 'name', 'code')") # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # with self.subTest('Values as list - With single quotes'): @@ -2573,11 +2577,11 @@ class CoreValidateTestMixin: # # result = self.connector.validate.sanitize_values_clause("id") # # result = self.connector.validate.sanitize_values_clause("'id'") # # result = self.connector.validate.sanitize_values_clause(["'id'"]) - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format("'id'"))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format("'id'"))) # # # # # With extra whitespace. # # result = self.connector.validate.sanitize_values_clause([" ' id ' "]) - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format(" ' id ' "))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format(" ' id ' "))) # # # # with self.subTest('Two vals provided'): # # # Base value. @@ -2628,11 +2632,11 @@ class CoreValidateTestMixin: # # with self.subTest('Single val provided'): # # # Base value. # # result = self.connector.validate.sanitize_values_clause(("'id'",)) - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format("'id'"))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format("'id'"))) # # # # # With extra whitespace. # # result = self.connector.validate.sanitize_values_clause((" ' id ' ",)) - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format(" ' id ' "))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format(" ' id ' "))) # # # # with self.subTest('Two vals provided'): # # # Base value. @@ -2683,208 +2687,208 @@ class CoreValidateTestMixin: # with self.subTest('Single val provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause('"id"') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(' " id " ') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format(' id '))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format(' id ')), result) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause('VALUES "id"') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause('values "id"') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause('VALUES ("id")') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause('values ("id")') - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('id'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('id')), result) # # with self.subTest('Two vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause('"id", "name"') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(' " id " , " name " ') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format(' id '), # self._quote_str_literal_format.format(' name '), # ), + # result, # ) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause('VALUES "id", "name"') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause('values "id", "name"') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause('VALUES ("id", "name")') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause('values ("id", "name")') # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # ), + # result, # ) # # with self.subTest('Three vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause('"id", "name", "code"') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause(' " id " , " name " , " code " ') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format(' id '), # self._quote_str_literal_format.format(' name '), # self._quote_str_literal_format.format(' code '), # ), + # result, # ) # # # With full statement - upper, no parens. # result = self.connector.validate.sanitize_values_clause('VALUES "id", "name", "code"') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - lower, no parens. # result = self.connector.validate.sanitize_values_clause('values "id", "name", "code"') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - upper, with parens. # result = self.connector.validate.sanitize_values_clause('VALUES ("id", "name", "code")') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # # With full statement - lower, with parens. # result = self.connector.validate.sanitize_values_clause('values ("id", "name", "code")') # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('id'), # self._quote_str_literal_format.format('name'), # self._quote_str_literal_format.format('code'), # ), + # result, # ) # # with self.subTest('Values as list - With double quotes'): # with self.subTest('Single val provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause(['"id"']) - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('"id"'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('"id"')), result) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause([' " id " ']) - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format(' " id " '))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format(' " id " ')), result) # # with self.subTest('Two vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause(['"id"', '"name"']) # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('"id"'), # self._quote_str_literal_format.format('"name"'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause([' " id " ', ' " name " ']) # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format(' " id " '), # self._quote_str_literal_format.format(' " name " '), # ), + # result, # ) # # with self.subTest('Three vals provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause(['"id"', '"name"', '"code"']) # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('"id"'), # self._quote_str_literal_format.format('"name"'), # self._quote_str_literal_format.format('"code"'), # ), + # result, # ) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause([' " id " ', ' " name " ', ' " code " ']) # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format(' " id " '), # self._quote_str_literal_format.format(' " name " '), # self._quote_str_literal_format.format(' " code " '), # ), + # result, # ) # # with self.subTest('Values as tuple - With double quotes'): @@ -2892,52 +2896,52 @@ class CoreValidateTestMixin: # with self.subTest('Single val provided'): # # Base value. # result = self.connector.validate.sanitize_values_clause(('"id"',)) - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('"id"'))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('"id"')), result) # # # With extra whitespace. # result = self.connector.validate.sanitize_values_clause((' " id " ',)) - # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format(' " id " '))) + # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format(' " id " ')), result) # # with self.subTest('Two vals provided'): # # Base value. - # result = self.connector.validate.sanitize_values_clause(('"id"', '"name"')) - # self.assertText( - # result, '\nVALUES ({0}, {1})'.format( + # result = self.connector.validate.sanitize_values_clause(('"id"', '"name"'), result) + # self.assertText( '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format('"id"'), # self._quote_str_literal_format.format('"name"'), # ), + # result, # ) # # # With extra whitespace. - # result = self.connector.validate.sanitize_values_clause((' " id " ', ' " name " ')) - # self.assertText( - # result, '\nVALUES ({0}, {1})'.format( + # result = self.connector.validate.sanitize_values_clause((' " id " ', ' " name " '), result) + # self.assertText( '\nVALUES ({0}, {1})'.format( # self._quote_str_literal_format.format(' " id " '), # self._quote_str_literal_format.format(' " name " '), # ), + # result, # ) # # with self.subTest('Three vals provided'): # # Base value. - # result = self.connector.validate.sanitize_values_clause(('"id"', '"name"', '"code"')) + # result = self.connector.validate.sanitize_values_clause(('"id"', '"name"', '"code"'), result) # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format('"id"'), # self._quote_str_literal_format.format('"name"'), # self._quote_str_literal_format.format('"code"'), # ), + # result, # ) # # # With extra whitespace. - # result = self.connector.validate.sanitize_values_clause((' " id " ', ' " name " ', ' " code " ')) + # result = self.connector.validate.sanitize_values_clause((' " id " ', ' " name " ', ' " code " '), result) # self.assertText( - # result, # '\nVALUES ({0}, {1}, {2})'.format( # self._quote_str_literal_format.format(' " id " '), # self._quote_str_literal_format.format(' " name " '), # self._quote_str_literal_format.format(' " code " '), # ), + # result, # ) # # # with self.subTest('Values as str - With backtick quotes'): @@ -2945,27 +2949,27 @@ class CoreValidateTestMixin: # # with self.subTest('Single val provided'): # # # Base value. # # result = self.connector.validate.sanitize_values_clause('`id`') - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) # # # # # With extra whitespace. # # result = self.connector.validate.sanitize_values_clause(' ` id ` ') - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('` id `'))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('` id `'))) # # # # # With full statement - upper, no parens. # # result = self.connector.validate.sanitize_values_clause('VALUES `id`') - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) # # # # # With full statement - lower, no parens. # # result = self.connector.validate.sanitize_values_clause('values `id`') - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) # # # # # With full statement - upper, no parens. # # result = self.connector.validate.sanitize_values_clause('VALUES `id`') - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) # # # # # With full statement - lower, no parens. # # result = self.connector.validate.sanitize_values_clause('values `id`') - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) # # # # with self.subTest('Two vals provided'): # # # Base value. @@ -3100,11 +3104,11 @@ class CoreValidateTestMixin: # # with self.subTest('Single val provided'): # # # Base value. # # result = self.connector.validate.sanitize_values_clause(['`id`']) - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) # # # # # With extra whitespace. # # result = self.connector.validate.sanitize_values_clause([' ` id ` ']) - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('` id `'))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('` id `'))) # # # # with self.subTest('Two vals provided'): # # # Base value. @@ -3155,11 +3159,11 @@ class CoreValidateTestMixin: # # with self.subTest('Single val provided'): # # # Base value. # # result = self.connector.validate.sanitize_values_clause(('`id`',)) - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format('`id`'))) # # # # # With extra whitespace. # # result = self.connector.validate.sanitize_values_clause((' ` id ` ',)) - # # self.assertText(result, '\nVALUES ({0})'.format(self._quote_str_literal_format.format(' ` id ` '))) + # # self.assertText('\nVALUES ({0})'.format(self._quote_str_literal_format.format(' ` id ` '))) # # # # with self.subTest('Two vals provided'): # # # Base value. @@ -3208,11 +3212,11 @@ class CoreValidateTestMixin: # with self.subTest('Values as non-standard types'): # result = self.connector.validate.sanitize_values_clause((1, True)) # self.assertText( - # result, # '\nVALUES ({0}, {1})'.format( # 1, # True, # ), + # result, # ) # # # # Mistmatching quotes - double then single. @@ -3318,370 +3322,370 @@ class CoreValidateTestMixin: # None provided. Defaults back to empty string. result = self.connector.validate.sanitize_order_by_clause(None) - self.assertText(result, '') + self.assertText('', result) # Empty string provided (single-quote str). result = self.connector.validate.sanitize_order_by_clause('') - self.assertText(result, '') + self.assertText('', result) # Empty string provided (double-quote str). result = self.connector.validate.sanitize_order_by_clause("") - self.assertText(result, '') + self.assertText('', result) # Empty string provided (triple double-quote str). result = self.connector.validate.sanitize_order_by_clause("""""") - self.assertText(result, '') + self.assertText('', result) with self.subTest('Values as str - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause('id') - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause(' id ') - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With full statement - upper. result = self.connector.validate.sanitize_order_by_clause('ORDER BY id') - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With full statement - lower. result = self.connector.validate.sanitize_order_by_clause('order by id') - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause('id, name') self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name') ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause(' id , name ') self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause('id, name, code') self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause(' id , name , code ') self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as triple str - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause("""id""") - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause(""" id """) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With full statement - upper. result = self.connector.validate.sanitize_order_by_clause("""ORDER BY id""") - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With full statement - lower. result = self.connector.validate.sanitize_order_by_clause("""order by id""") - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause("""id, name""") self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause(""" id , name """) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause("""id, name, code""") self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause(""" id , name , code """) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as list - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause(['id']) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause([' id ']) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause(['id', 'name']) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause([' id ', ' name ']) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause(['id', 'name', 'code']) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause([' id ', ' name ', ' code ']) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as tuple - Without quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause(('id',)) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause((' id ',)) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause(('id', 'name')) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause((' id ', ' name ')) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause(('id', 'name', 'code')) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) # With extra whitespace. result = self.connector.validate.sanitize_order_by_clause((' id ', ' name ', ' code ')) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as str - With single quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause("'id'") - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With full statement - upper. result = self.connector.validate.sanitize_order_by_clause("ORDER BY 'id'") - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With full statement - lower. result = self.connector.validate.sanitize_order_by_clause("order by 'id'") - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause("'id', 'name'") self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause("'id', 'name', 'code'") self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code') ), + result, ) with self.subTest('Values as list - With single quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause(["'id'"]) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause(["'id'", "'name'"]) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause(["'id'", "'name'", "'code'"]) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as tuple - With single quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause(("'id'",)) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause(("'id'", "'name'")) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause(("'id'", "'name'", "'code'")) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as str - With double quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause('"id"') - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With full statement - upper. result = self.connector.validate.sanitize_order_by_clause('ORDER BY "id"') - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With full statement - lower. result = self.connector.validate.sanitize_order_by_clause('order by "id"') - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause('"id", "name"') self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause('"id", "name", code') self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as list - With double quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause(['"id"']) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause(['"id"', '"name"']) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause(['"id"', '"name"', '"code"']) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as tuple - With double quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause(('"id"',)) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause(('"id"', '"name"')) @@ -3690,101 +3694,102 @@ class CoreValidateTestMixin: self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause(('"id"', '"name"', '"code"')) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as str - With backtick quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause('`id`') - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With full statement - upper. result = self.connector.validate.sanitize_order_by_clause('ORDER BY `id`') - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # With full statement - lower. result = self.connector.validate.sanitize_order_by_clause('order by `id`') - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause('`id`, `name`') self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause('`id`, `name`, `code`') self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as list - With backtick quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause(['`id`']) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause(['`id`', '`name`']) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause(['`id`', '`name`', '`code`']) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as tuple - With backtick quotes'): # Single val provided. result = self.connector.validate.sanitize_order_by_clause(('`id`',)) - self.assertText(result, '\nORDER BY {0}'.format(self._quote_order_by_format.format('id'))) + self.assertText('\nORDER BY {0}'.format(self._quote_order_by_format.format('id')), result) # Two vals provided. result = self.connector.validate.sanitize_order_by_clause(('`id`', '`name`')) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), ), + result, ) # Three vals provided. result = self.connector.validate.sanitize_order_by_clause(('`id`', '`name`', '`code`')) self.assertText( - result, '\nORDER BY {0}, {1}, {2}'.format( self._quote_order_by_format.format('id'), self._quote_order_by_format.format('name'), self._quote_order_by_format.format('code'), ), + result, ) with self.subTest('Values as non-standard types'): @@ -3792,25 +3797,17 @@ class CoreValidateTestMixin: # I think only literal column names should work. result = self.connector.validate.sanitize_order_by_clause((1, True)) self.assertText( - result, '\nORDER BY {0}, {1}'.format( self._quote_order_by_format.format(1), self._quote_order_by_format.format(True), ), + result, ) def test__sanitize_order_by_clause__failure(self): """ Test sanitizing an ORDER BY clause, in cases when it should fail. """ - # "ORDER BY" provided without any additional values. - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_order_by_clause('ORDER BY') - self.assertText('Invalid ORDER BY clause.', str(err.exception)) - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_order_by_clause(' ORDER BY ') - self.assertText('Invalid ORDER BY clause.', str(err.exception)) - # Param "*" provided. with self.assertRaises(ValueError) as err: self.connector.validate.sanitize_order_by_clause('*') @@ -3821,59 +3818,61 @@ class CoreValidateTestMixin: self.connector.validate.sanitize_order_by_clause('* , id') self.assertText('The * identifier can only be used in a SELECT clause.', str(err.exception)) - # Mistmatching quotes - double then single. - identifier = """\"id'""" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_order_by_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier "id\'', - str(err.exception), - ) - - # Mistmatching quotes - single then double. - identifier = """'id\"""" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_order_by_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier \'id"', - str(err.exception), - ) - - # Mistmatching quotes - backtick then single. - identifier = "`id'" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_order_by_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier `id\'', - str(err.exception), - ) - - # Mistmatching quotes - single then backtick. - identifier = "'id`" - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_order_by_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier \'id`', - str(err.exception), - ) - - # Mistmatching quotes - double then backtick. - identifier = '"id`' - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_order_by_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier "id`', - str(err.exception), - ) - - # Mistmatching quotes - backtick then double. - identifier = '`id"' - with self.assertRaises(ValueError) as err: - self.connector.validate.sanitize_order_by_clause(identifier) - self.assertText( - 'Found mismatching quotes for identifier `id"', - str(err.exception), - ) + # # For now, we are no longer testing this. + # # While uncommon, there might be legitimate cases where a string starts/ends with one quote. + # # Mistmatching quotes - double then single. + # identifier = """\"id'""" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_order_by_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier "id\'', + # str(err.exception), + # ) + # + # # Mistmatching quotes - single then double. + # identifier = """'id\"""" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_order_by_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier \'id"', + # str(err.exception), + # ) + # + # # Mistmatching quotes - backtick then single. + # identifier = "`id'" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_order_by_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier `id\'', + # str(err.exception), + # ) + # + # # Mistmatching quotes - single then backtick. + # identifier = "'id`" + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_order_by_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier \'id`', + # str(err.exception), + # ) + # + # # Mistmatching quotes - double then backtick. + # identifier = '"id`' + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_order_by_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier "id`', + # str(err.exception), + # ) + # + # # Mistmatching quotes - backtick then double. + # identifier = '`id"' + # with self.assertRaises(ValueError) as err: + # self.connector.validate.sanitize_order_by_clause(identifier) + # self.assertText( + # 'Found mismatching quotes for identifier `id"', + # str(err.exception), + # ) def test__sanitize_limit_clause__success(self): """ @@ -3881,70 +3880,70 @@ class CoreValidateTestMixin: """ # None provided. Defaults back to empty string. result = self.connector.validate.sanitize_limit_clause(None) - self.assertText(result, '') + self.assertText('', result) # Empty string provided (single-quote str). result = self.connector.validate.sanitize_limit_clause('') - self.assertText(result, '') + self.assertText('', result) # Empty string provided (double-quote str). result = self.connector.validate.sanitize_limit_clause("") - self.assertText(result, '') + self.assertText('', result) # Empty string provided (triple double-quote str). result = self.connector.validate.sanitize_limit_clause("""""") - self.assertText(result, '') + self.assertText('', result) with self.subTest('Limit of 1 (lowest acceptable limit)'): # As int. result = self.connector.validate.sanitize_limit_clause(1) - self.assertText(result, ' LIMIT 1') + self.assertText(' LIMIT 1', result) # As str. result = self.connector.validate.sanitize_limit_clause('1') - self.assertText(result, ' LIMIT 1') + self.assertText(' LIMIT 1', result) # As full str (upper). result = self.connector.validate.sanitize_limit_clause('LIMIT 1') - self.assertText(result, ' LIMIT 1') + self.assertText(' LIMIT 1', result) # As full str (lower). result = self.connector.validate.sanitize_limit_clause('limit 1') - self.assertText(result, ' LIMIT 1') + self.assertText(' LIMIT 1', result) with self.subTest('Limit of 2'): # As int. result = self.connector.validate.sanitize_limit_clause(2) - self.assertText(result, ' LIMIT 2') + self.assertText(' LIMIT 2', result) # As str. result = self.connector.validate.sanitize_limit_clause('2') - self.assertText(result, ' LIMIT 2') + self.assertText(' LIMIT 2', result) # As full str (upper). result = self.connector.validate.sanitize_limit_clause('LIMIT 2') - self.assertText(result, ' LIMIT 2') + self.assertText(' LIMIT 2', result) # As full str (lower). result = self.connector.validate.sanitize_limit_clause('limit 2') - self.assertText(result, ' LIMIT 2') + self.assertText(' LIMIT 2', result) with self.subTest('Limit of 100'): # As int. result = self.connector.validate.sanitize_limit_clause(100) - self.assertText(result, ' LIMIT 100') + self.assertText(' LIMIT 100', result) # As str. result = self.connector.validate.sanitize_limit_clause('100') - self.assertText(result, ' LIMIT 100') + self.assertText(' LIMIT 100', result) # As full str (upper). result = self.connector.validate.sanitize_limit_clause('LIMIT 100') - self.assertText(result, ' LIMIT 100') + self.assertText(' LIMIT 100', result) # As full str (lower). result = self.connector.validate.sanitize_limit_clause('limit 100') - self.assertText(result, ' LIMIT 100') + self.assertText(' LIMIT 100', result) def test__sanitize_limit_clause__failure(self): """ diff --git a/tests/connectors/mysql/test_clauses.py b/tests/connectors/mysql/test_clauses.py new file mode 100644 index 0000000000000000000000000000000000000000..2ede9e139bbf52022d54724996a79a8992e7164a --- /dev/null +++ b/tests/connectors/mysql/test_clauses.py @@ -0,0 +1,25 @@ +""" +Tests for "clauses" logic of "MySQL" DB Connector class. +""" + +# System Imports. + +# Internal Imports. +from .test_core import TestMysqlDatabaseParent +from tests.connectors.core.test_clauses import CoreClauseTestMixin + + +class TestMysqlDatabase(TestMysqlDatabaseParent, CoreClauseTestMixin): + """ + Tests "MySQL" DB Connector class clause logic. + """ + @classmethod + def setUpClass(cls): + # Run parent setup logic. + super().setUpClass() + + # Also call CoreTestMixin setup logic. + cls.set_up_class() + + # Define database name to use in tests. + cls.test_db_name = '{0}test_database'.format(cls.test_db_name_start) diff --git a/tests/connectors/postgresql/test_clauses.py b/tests/connectors/postgresql/test_clauses.py new file mode 100644 index 0000000000000000000000000000000000000000..c0ad10c50cedbd7e7387fadb85b561df96f145e5 --- /dev/null +++ b/tests/connectors/postgresql/test_clauses.py @@ -0,0 +1,25 @@ +""" +Tests for "clause validation" logic of "PostgreSQL" DB Connector class. +""" + +# System Imports. + +# Internal Imports. +from .test_core import TestPostgresqlDatabaseParent +from tests.connectors.core.test_clauses import CoreClauseTestMixin + + +class TestPostgresqlDatabase(TestPostgresqlDatabaseParent, CoreClauseTestMixin): + """ + Tests "PostgreSQL" DB Connector class clause validation logic. + """ + @classmethod + def setUpClass(cls): + # Run parent setup logic. + super().setUpClass() + + # Also call CoreTestMixin setup logic. + cls.set_up_class() + + # Define database name to use in tests. + cls.test_db_name = '{0}test_database'.format(cls.test_db_name_start)