diff --git a/tap_mysql/discover_utils.py b/tap_mysql/discover_utils.py index 143fa7a..885cfae 100644 --- a/tap_mysql/discover_utils.py +++ b/tap_mysql/discover_utils.py @@ -1,6 +1,8 @@ # pylint: disable=missing-docstring,too-many-locals import collections +from decimal import Decimal, BasicContext, localcontext, Context + import itertools import pendulum import pymysql @@ -269,6 +271,19 @@ def schema_for_column(column): # pylint: disable=too-many-branches if data_type == 'decimal': result.multipleOf = 10 ** (0 - column.numeric_scale) + # This is complex. + # Emax specifies the maximum allowable exponent. + # For example, with 10 digits, 3 after decimal place (7 before) we have: + # >>> setcontext(Context(prec=10, Emax=7)) + # >>> Decimal('1.0E+7').next_minus() + # Decimal('9999999.999') + before_dp = column.numeric_precision-column.numeric_scale + with localcontext(Context(Emax=before_dp, prec=column.numeric_precision)): + largest_decimal = Decimal('1.0E+' + str(before_dp)).next_minus() + + result.maximum = float(largest_decimal) + # TODO: Unsigned. + result.minimum = float(-largest_decimal) elif data_type in JSON_TYPES: result.type = ['null', 'object'] diff --git a/tests/integration/test_tap_mysql.py b/tests/integration/test_tap_mysql.py index b7c459f..8487703 100644 --- a/tests/integration/test_tap_mysql.py +++ b/tests/integration/test_tap_mysql.py @@ -83,7 +83,10 @@ def test_decimal(self): self.assertEqual(self.schema.properties['c_decimal'], Schema(['null', 'number'], inclusion='available', - multipleOf=1)) + multipleOf=1, + maximum=float('9'*10), # Default is DECIMAL(10,0) + minimum=-float('9'*10), + )) self.assertEqual(self.get_metadata_for_column('c_decimal'), {'selected-by-default': True, 'sql-datatype': 'decimal(10,0)', @@ -93,7 +96,10 @@ def test_decimal_unsigned(self): self.assertEqual(self.schema.properties['c_decimal_2_unsigned'], Schema(['null', 'number'], inclusion='available', - multipleOf=0.01)) + multipleOf=0.01, + maximum=float('9'*3 + '.99'), + minimum=0 + ),) self.assertEqual(self.get_metadata_for_column('c_decimal_2_unsigned'), {'selected-by-default': True, 'sql-datatype': 'decimal(5,2) unsigned', @@ -103,7 +109,10 @@ def test_decimal_with_defined_scale_and_precision(self): self.assertEqual(self.schema.properties['c_decimal_2'], Schema(['null', 'number'], inclusion='available', - multipleOf=0.01)) + multipleOf=0.01, + maximum=float('9'*9 + '.99'), + minimum=-float('9'*9 + '.99'), + )) self.assertEqual(self.get_metadata_for_column('c_decimal_2'), {'selected-by-default': True, 'sql-datatype': 'decimal(11,2)',