# Path: oslo_db/sqlalchemy/utils.py
# LOG = logging.getLogger(__name__)
# _DBURL_REGEX = re.compile(r"[^:]+://([^:]+):([^@]+)@.+")
# _VALID_SORT_DIR = [
#     "-".join(x) for x in itertools.product(["asc", "desc"],
#                                            ["nullsfirst", "nullslast"])]
# def sanitize_db_url(url):
# def get_unique_keys(model):
# def _stable_sorting_order(model, sort_keys):
# def paginate_query(query, model, limit, sort_keys, marker=None,
#                    sort_dir=None, sort_dirs=None):
# def to_list(x, default=None):
# def _read_deleted_filter(query, db_model, deleted):
# def _project_filter(query, db_model, project_id):
# def model_query(model, session, args=None, **kwargs):
# def get_table(engine, name):
# def _get_not_supported_column(col_name_col_instance, column_name):
# def drop_old_duplicate_entries_from_table(engine, table_name,
#                                           use_soft_delete, *uc_column_names):
# def _get_default_deleted_value(table):
# def _restore_indexes_on_deleted_columns(engine, table_name, indexes):
# def change_deleted_column_type_to_boolean(engine, table_name,
#                                           **col_name_col_instance):
# def _change_deleted_column_type_to_boolean_sqlite(engine, table_name,
#                                                   **col_name_col_instance):
# def change_deleted_column_type_to_id_type(engine, table_name,
#                                           **col_name_col_instance):
# def _is_deleted_column_constraint(constraint):
# def _change_deleted_column_type_to_id_type_sqlite(engine, table_name,
#                                                   **col_name_col_instance):
# def get_db_connection_info(conn_pieces):
# def get_indexes(engine, table_name):
# def index_exists(engine, table_name, index_name):
# def index_exists_on_columns(engine, table_name, columns):
# def add_index(engine, table_name, index_name, idx_columns):
# def drop_index(engine, table_name, index_name):
# def change_index_columns(engine, table_name, index_name, new_columns):
# def column_exists(engine, table_name, column):
#     def dispatch_for_dialect(cls, expr, multiple=False):
#     def dispatch_for(self, expr):
#         def decorate(fn):
#     def _parse_dispatch(self, text):
#     def __call__(self, *arg, **kw):
#     def _url_from_target(self, target):
#     def dispatch_on_drivername(self, drivername):
#         def go(*arg, **kw):
#     def _dispatch_on(self, url, target, arg, kw):
#     def _invoke_fn(self, fn, arg, kw):
#     def __init__(self):
#     def _register(self, expr, dbname, driver, fn):
#     def _matches(self, dbname, driver):
#     def _dispatch_on_db_driver(self, dbname, driver, arg, kw):
#     def __init__(self):
#     def _register(self, expr, dbname, driver, fn):
#     def _matches(self, dbname, driver):
#     def _dispatch_on_db_driver(self, dbname, driver, arg, kw):
# def get_non_innodb_tables(connectable, skip_tables=('migrate_version',
#                                                     'alembic_version')):
# def get_non_ndbcluster_tables(connectable, skip_tables=None):
# def get_foreign_key_constraint_name(engine, table_name, column_name):
# def suspend_fk_constraints_for_col_alter(
#         engine, table_name, column_name, referents=[]):
# class DialectFunctionDispatcher(object):
# class DialectSingleFunctionDispatcher(DialectFunctionDispatcher):
# class DialectMultiFunctionDispatcher(DialectFunctionDispatcher):


import copy
from sqlalchemy import inspect
from sqlalchemy import orm
from sqlalchemy import sql
from sqlalchemy import types as sqltypes
from oslo_db.sqlalchemy import utils
    will be compared to a tuple using IN.   The scalar value or
    tuple can also contain None which translates to an IS NULL, that is
    properly joined with OR against an IN expression if appropriate.

    :param cls: a mapped class, or actual :class:`.Mapper` object.

    :param values: dictionary of values.

    """

    mapper = inspect(mapped)

    # organize keys using mapped attribute ordering, which is deterministic
    value_keys = set(values)
    keys = [k for k in mapper.column_attrs.keys() if k in value_keys]
    return sql.and_(*[
        _sql_crit(mapper.column_attrs[key].expression, values[key])
        for key in keys
    ])


def _sql_crit(expression, value):
    """Produce an equality expression against the given value.

    This takes into account a value that is actually a collection
    of values, as well as a value of None or collection that contains
    None.

    """


# Path: oslo_db/sqlalchemy/utils.py
# LOG = logging.getLogger(__name__)
# _DBURL_REGEX = re.compile(r"[^:]+://([^:]+):([^@]+)@.+")
# _VALID_SORT_DIR = [
#     "-".join(x) for x in itertools.product(["asc", "desc"],
#                                            ["nullsfirst", "nullslast"])]
# def sanitize_db_url(url):
# def get_unique_keys(model):
# def _stable_sorting_order(model, sort_keys):
# def paginate_query(query, model, limit, sort_keys, marker=None,
#                    sort_dir=None, sort_dirs=None):
# def to_list(x, default=None):
# def _read_deleted_filter(query, db_model, deleted):
# def _project_filter(query, db_model, project_id):
# def model_query(model, session, args=None, **kwargs):
# def get_table(engine, name):
# def _get_not_supported_column(col_name_col_instance, column_name):
# def drop_old_duplicate_entries_from_table(engine, table_name,
#                                           use_soft_delete, *uc_column_names):
# def _get_default_deleted_value(table):
# def _restore_indexes_on_deleted_columns(engine, table_name, indexes):
# def change_deleted_column_type_to_boolean(engine, table_name,
#                                           **col_name_col_instance):
# def _change_deleted_column_type_to_boolean_sqlite(engine, table_name,
#                                                   **col_name_col_instance):
# def change_deleted_column_type_to_id_type(engine, table_name,
#                                           **col_name_col_instance):
# def _is_deleted_column_constraint(constraint):
# def _change_deleted_column_type_to_id_type_sqlite(engine, table_name,
#                                                   **col_name_col_instance):
# def get_db_connection_info(conn_pieces):
# def get_indexes(engine, table_name):
# def index_exists(engine, table_name, index_name):
# def index_exists_on_columns(engine, table_name, columns):
# def add_index(engine, table_name, index_name, idx_columns):
# def drop_index(engine, table_name, index_name):
# def change_index_columns(engine, table_name, index_name, new_columns):
# def column_exists(engine, table_name, column):
#     def dispatch_for_dialect(cls, expr, multiple=False):
#     def dispatch_for(self, expr):
#         def decorate(fn):
#     def _parse_dispatch(self, text):
#     def __call__(self, *arg, **kw):
#     def _url_from_target(self, target):
#     def dispatch_on_drivername(self, drivername):
#         def go(*arg, **kw):
#     def _dispatch_on(self, url, target, arg, kw):
#     def _invoke_fn(self, fn, arg, kw):
#     def __init__(self):
#     def _register(self, expr, dbname, driver, fn):
#     def _matches(self, dbname, driver):
#     def _dispatch_on_db_driver(self, dbname, driver, arg, kw):
#     def __init__(self):
#     def _register(self, expr, dbname, driver, fn):
#     def _matches(self, dbname, driver):
#     def _dispatch_on_db_driver(self, dbname, driver, arg, kw):
# def get_non_innodb_tables(connectable, skip_tables=('migrate_version',
#                                                     'alembic_version')):
# def get_non_ndbcluster_tables(connectable, skip_tables=None):
# def get_foreign_key_constraint_name(engine, table_name, column_name):
# def suspend_fk_constraints_for_col_alter(
#         engine, table_name, column_name, referents=[]):
# class DialectFunctionDispatcher(object):
# class DialectSingleFunctionDispatcher(DialectFunctionDispatcher):
# class DialectMultiFunctionDispatcher(DialectFunctionDispatcher):


# Path: oslo_db/sqlalchemy/update_match.py
import copy
from sqlalchemy import inspect
from sqlalchemy import orm
from sqlalchemy import sql
from sqlalchemy import types as sqltypes
from oslo_db.sqlalchemy import utils

    will be compared to a tuple using IN.   The scalar value or
    tuple can also contain None which translates to an IS NULL, that is
    properly joined with OR against an IN expression if appropriate.

    :param cls: a mapped class, or actual :class:`.Mapper` object.

    :param values: dictionary of values.

    """

    mapper = inspect(mapped)

    # organize keys using mapped attribute ordering, which is deterministic
    value_keys = set(values)
    keys = [k for k in mapper.column_attrs.keys() if k in value_keys]
    return sql.and_(*[
        _sql_crit(mapper.column_attrs[key].expression, values[key])
        for key in keys
    ])


def _sql_crit(expression, value):
    """Produce an equality expression against the given value.

    This takes into account a value that is actually a collection
    of values, as well as a value of None or collection that contains
    None.

    """


    values = utils.to_list(value, default=(None, ))