Source code for squabble.rules.disallow_timestamp_precision

import pglast

import squabble.rule
from squabble.lint import Severity
from squabble.message import Message
from squabble.rules import BaseRule
from squabble.util import format_type_name


[docs]class DisallowTimestampPrecision(BaseRule): """ Prevent using ``TIMESTAMP(p)`` due to rounding behavior. For both ``TIMESTAMP(p)`` and ``TIMESTAMP WITH TIME ZONE(p)``, (as well as the corresponding ``TIME`` types) the optional precision parameter ``p`` rounds the value instead of truncating. This means that it is possible to store values that are half a second in the future for ``p == 0``. To only enforce this rule for certain values of ``p``, set the configuration option ``allow_precision_greater_than``. Configuration :: { "DisallowTimestampPrecision": { "allow_precision_greater_than": 0 } } """ _CHECKED_TYPES = { 'pg_catalog.time', 'pg_catalog.timetz', 'pg_catalog.timestamp', 'pg_catalog.timestamptz', } _DEFAULT_MIN_PRECISION = 9999
[docs] class NoTimestampPrecision(Message): """ Specifying a fixed precision for ``TIMESTAMP`` and ``TIME`` types will cause the database to round inserted values (instead of truncating, as one would expect). This rounding behavior means that some values that get inserted may be in the future, up to half a second with a precision of ``0``. Instead, explicitly using ``date_trunc('granularity', time)`` may be a better option. """ TEMPLATE = "use `date_trunc` instead of fixed precision timestamps" CODE = 1014
def enable(self, root_ctx, config): min_precision = int( config.get( 'allow_precision_greater_than', self._DEFAULT_MIN_PRECISION)) root_ctx.register('ColumnDef', self._check_column_def(min_precision)) @squabble.rule.node_visitor def _check_column_def(self, ctx, node, min_precision): col_type = format_type_name(node.typeName) if col_type not in self._CHECKED_TYPES: return modifiers = node.typeName.typmods if modifiers == pglast.Missing or \ len(modifiers) != 1 or \ modifiers[0].val.node_tag != 'Integer': return if modifiers[0].val.ival.value <= min_precision: ctx.report( self.NoTimestampPrecision(), node=node.typeName, severity=Severity.LOW)