text: # Copyright 2014 IBM Corp.
  #
  # Licensed under the Apache License, Version 2.0 (the "License"); you may
  # not use this file except in compliance with the License. You may obtain
  # a copy of the License at
  #
  #      http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  # License for the specific language governing permissions and limitations
  # under the License.
  
  from keystone.common import sql
  from keystone.identity.mapping_backends import base
  from keystone.identity.mapping_backends import mapping as identity_mapping
  
  
  class IDMapping(sql.ModelBase, sql.ModelDictMixin):
      __tablename__ = 'id_mapping'
      public_id = sql.Column(sql.String(64), primary_key=True)
      domain_id = sql.Column(sql.String(64), nullable=False)
      local_id = sql.Column(sql.String(64), nullable=False)
      # NOTE(henry-nash): Postgres requires a name to be defined for an Enum
      entity_type = sql.Column(
          sql.Enum(identity_mapping.EntityType.USER,
                   identity_mapping.EntityType.GROUP,
                   name='entity_type'),
          nullable=False)
      # Unique constraint to ensure you can't store more than one mapping to the
      # same underlying values
      __table_args__ = (
          sql.UniqueConstraint('domain_id', 'local_id', 'entity_type'),)
  
  
  class Mapping(base.MappingDriverBase):
  
      def get_public_id(self, local_entity):
          # NOTE(henry-nash): Since the Public ID is regeneratable, rather
          # than search for the entry using the local entity values, we
          # could create the hash and do a PK lookup.  However this would only
          # work if we hashed all the entries, even those that already generate
          # UUIDs, like SQL.  Further, this would only work if the generation
          # algorithm was immutable (e.g. it had always been sha256).
          with sql.session_for_read() as session:
              query = session.query(IDMapping.public_id)
              query = query.filter_by(domain_id=local_entity['domain_id'])
              query = query.filter_by(local_id=local_entity['local_id'])
              query = query.filter_by(entity_type=local_entity['entity_type'])
              try:
                  public_ref = query.one()
                  public_id = public_ref.public_id
                  return public_id
              except sql.NotFound:
                  return None
  
      def get_domain_mapping_list(self, domain_id):
          with sql.session_for_read() as session:
              return session.query(IDMapping).filter_by(domain_id=domain_id)
  
      def get_id_mapping(self, public_id):
          with sql.session_for_read() as session:
              mapping_ref = session.query(IDMapping).get(public_id)
              if mapping_ref:
                  return mapping_ref.to_dict()
  
      def create_id_mapping(self, local_entity, public_id=None):
          entity = local_entity.copy()
          try:
              with sql.session_for_write() as session:
                  if public_id is None:
                      public_id = self.id_generator_api.generate_public_ID(
                          entity)
                  entity['public_id'] = public_id
                  mapping_ref = IDMapping.from_dict(entity)
                  session.add(mapping_ref)
          except sql.DBDuplicateEntry:
              # something else created the mapping already. We can use it.
              public_id = self.get_public_id(local_entity)
          return public_id
  
      def delete_id_mapping(self, public_id):
          with sql.session_for_write() as session:
              try:
                  session.query(IDMapping).filter(
                      IDMapping.public_id == public_id).delete()
              except sql.NotFound:  # nosec
                  # NOTE(morganfainberg): There is nothing to delete and nothing
                  # to do.
                  pass
  
      def purge_mappings(self, purge_filter):
          with sql.session_for_write() as session:
              query = session.query(IDMapping)
              if 'domain_id' in purge_filter:
                  query = query.filter_by(domain_id=purge_filter['domain_id'])
              if 'public_id' in purge_filter:
                  query = query.filter_by(public_id=purge_filter['public_id'])
              if 'local_id' in purge_filter:
                  query = query.filter_by(local_id=purge_filter['local_id'])
              if 'entity_type' in purge_filter:
                  query = query.filter_by(
                      entity_type=purge_filter['entity_type'])
              query.delete()
  