Source code for pgmock.config

"""
pgmock.config
-------------

Configuration functions for ``pgmock``
"""

# Sentinel value, guaranteed to be unique
UNDEFINED_VALUE = object()


class _ContextableConfigValue:
    """
    Allows setting configuration variables that can be used
    as context managers

    Examples:

        Make a setter for a configuration variable:

        .. code-block:: python

            set_value = _ContextableConfigurationValue('default')

        Set the value globally:

        .. code-block:: python

            set_value('other_value')

        Set the value within a context manager:

        .. code-block:: python

            with set_value('yet_another_value'):
                ...

        A getter for the configuration variable can be made like:

        .. code-block:: python

            get_value = lambda: set_value.value
    """
    def __init__(self, initial_value):
        self.value = initial_value
        self._value_stack = []
        self._old_value = UNDEFINED_VALUE

    def __call__(self, new_value):
        self._old_value = self.value
        self.value = new_value
        return self

    def __enter__(self):
        if self._old_value is UNDEFINED_VALUE:
            raise TypeError('value cannot be directly used as a context manager')
        self._value_stack.append(self._old_value)
        self._old_value = UNDEFINED_VALUE
        return self

    def __exit__(self, *args):
        self.value = self._value_stack.pop()


set_safe_mode = _ContextableConfigValue(False)
"""Sets whether safe mode is turned on or off in ``pgmock``.

If ``safe_mode`` is ``True``, all selectors will be applied
to a stripped version of SQL that excludes comments and
string literals. This improves the accuracy of ``pgmock``
matching but comes with a performance hit.

Safe mode is set to ``False`` by default.

Examples:

    .. code-block:: python

        # Set the global setting
        pgmock.config.set_safe_mode(True)

        # Only set the configuration while in use of the
        # context manager. Revert it back to the original
        # value when the context manager exits
        with pgmock.config.set_safe_mode(False):
           ...
"""

get_safe_mode = lambda: set_safe_mode.value  # flake8: noqa
"""Returns the configured safe mode"""

set_replace_new_patch_aliases = _ContextableConfigValue(True)
"""Sets whether new patch aliases should be replaced in SQL when found

Since ``pgmock`` turns expressions into ``VALUES`` expressions when patching,
it is not always possible to preserve the original name of what's being patched.

If the name of the expression being patched cannot be used as a valid
patch alias (e.g. a table with a schema name in it), this setting ensures
that all references to the new patch alias will be updated.

This setting primarily applies to SQL in this style::

    SELECT schema.table_name.col from schema.table_name

When patching ``schema.table_name`` with a ``VALUES`` list, it is
impossible to alias the ``VALUES`` list with ``schema.table_name``
since ``.`` is an invalid alias character. To get around this,
``pgmock`` makes the alias of the ``VALUES`` list be the table name
without the schema name. When this setting is turned on, it will
ensure that the ``SELECT schema.table_name.col`` will also be
valid. The patch will look like this when the setting is on::

    SELECT table_name.col from (VALUES(...) AS table_name)

and it will look like this when off::

    SELECT schema.table_name.col from (VALUES(...) AS table_name)

The latter example is invalid SQL, so this setting should be turned
on if the full schema name is present when referencing columns.

.. note::

    This setting incurs a performance overhead
    (10-20% slower depending on the SQL length) only when using the
    ``pgmock.table`` selector.

    This setting does a global search and replace on the query.
    In the example above, it would replace every instance of
    ``schema.table_name.`` with ``table_name.``. Keep this in mind
    as it could potentially have adverse side effects on other
    SQL that might reference the schema and table name followed
    by a period.

    This setting does not handle the case when double quotes are
    used to reference anything (e.g. ``"schema"."table_name"."col"``).

Examples:

    .. code-block:: python

        # Set the global setting
        pgmock.config.set_replace_new_patch_aliases(True)

        # Only set the configuration while in use of the
        # context manager. Revert it back to the original
        # value when the context manager exits
        with pgmock.config.set_replace_new_patch_aliases(False):
            ...
"""

get_replace_new_patch_aliases = lambda: set_replace_new_patch_aliases.value  # flake8: noqa
"""Returns the configured replacement of new patch aliases"""