docstr: Take a list of datasources, find and invalidate the associated cache records
  and remove the database records.
  ---
  post:
    summary: Invalidate cache records and remove the database records
    description: >-
      Takes a list of datasources, finds and invalidates the associated cache
      records and removes the database records.
    requestBody:
      description: >-
        A list of datasources uuid or the tuples of database and datasource names
      required: true
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/CacheInvalidationRequestSchema"
    responses:
      201:
        description: cache was successfully invalidated
      400:
        $ref: '#/components/responses/400'
      500:
        $ref: '#/components/responses/500'
docstr_tok: ["Take","a","list","of","datasources",",","find","and","invalidate","the","associated","cache","records","and","remove","the","database","records",".","--","-","post",":","summary",":","Invalidate","cache","records","and","remove","the","database","records","description",":",">","-","Takes","a","list","of","datasources",",","finds","and","invalidates","the","associated","cache","records","and","removes","the","database","records",".","requestBody",":","description",":",">","-","A","list","of","datasources","uuid","or","the","tuples","of","database","and","datasource","names","required",":","true","content",":","application\/json",":","schema",":","$","ref",":","``","#","\/components\/schemas\/CacheInvalidationRequestSchema","''","responses",":","201",":","description",":","cache","was","successfully","invalidated","400",":","$","ref",":","'","#","\/components\/responses\/400'","500",":","$","ref",":","'","#","\/components\/responses\/500","'"]
code: def invalidate(self) -> Response:
      """
      Take a list of datasources, find and invalidate the associated cache records
      and remove the database records.
      ---
      post:
        summary: Invalidate cache records and remove the database records
        description: >-
          Takes a list of datasources, finds and invalidates the associated cache
          records and removes the database records.
        requestBody:
          description: >-
            A list of datasources uuid or the tuples of database and datasource names
          required: true
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CacheInvalidationRequestSchema"
        responses:
          201:
            description: cache was successfully invalidated
          400:
            $ref: '#/components/responses/400'
          500:
            $ref: '#/components/responses/500'
      """
      try:
          datasources = CacheInvalidationRequestSchema().load(
              request.json
          )
      except KeyError:
          return self.response_400(message="Request is incorrect")
      except ValidationError as error:
          return self.response_400(message=str(error))
      datasource_uids = set(datasources.get("datasource_uids", []))
      for ds in datasources.get("datasources", []):
          ds_obj = SqlaTable.get_datasource_by_name(
              session=db.session,
              datasource_name=ds.get("datasource_name"),
              schema=ds.get("schema"),
              database_name=ds.get("database_name"),
          )
  
          if ds_obj:
              datasource_uids.add(ds_obj.uid)
  
      cache_key_objs = (
          db.session.query(CacheKey)
          .filter(CacheKey.datasource_uid.in_(datasource_uids))
          .all()
      )
      cache_keys = [c.cache_key for c in cache_key_objs]
      if cache_key_objs:
          all_keys_deleted = cache_manager.cache.delete_many(
              *cache_keys
          )
  
          if not all_keys_deleted:
              # expected behavior as keys may expire and cache is not a
              # persistent storage
              logger.info(
                  "Some of the cache keys were not deleted in the list %s",
                  cache_keys,
              )
  
          try:
              delete_stmt = CacheKey.__table__.delete().where(  # pylint: disable=no-member
                  CacheKey.cache_key.in_(cache_keys)
              )
              db.session.execute(delete_stmt)
              db.session.commit()
              stats_logger_manager.instance.gauge(
                  "invalidated_cache", len(cache_keys)
              )
              logger.info(
                  "Invalidated %s cache records for %s datasources",
                  len(cache_keys),
                  len(datasource_uids),
              )
          except SQLAlchemyError as ex:  # pragma: no cover
              logger.error(ex, exc_info=True)
              db.session.rollback()
              return self.response_500(str(ex))
          db.session.commit()
      return self.response(201)
  
file_path: superset/superset/cachekeys/api.py
imports: import logging
  from flask import request, Response
  from flask_appbuilder import expose
  from flask_appbuilder.api import safe
  from flask_appbuilder.models.sqla.interface import SQLAInterface
  from flask_appbuilder.security.decorators import protect
  from marshmallow.exceptions import ValidationError
  from sqlalchemy.exc import SQLAlchemyError
  from superset.cachekeys.schemas import CacheInvalidationRequestSchema
  from superset.connectors.sqla.models import SqlaTable
  from superset.extensions import cache_manager, db, event_logger, stats_logger_manager
  from superset.models.cache import CacheKey
  from superset.views.base_api import BaseSupersetModelRestApi, statsd_metrics
label_desc: Use image node_id 1 for calling the CacheRestApi obj's underlying member method code with example usage: obj.invalidate() and returns: self, self, self, self