code: def upgrade():
      """
      Adds the granularity param to charts without it populated. This is required for
      time range filtering to work properly. Uses the following approach:
  
      - Find all charts without a granularity or granularity_sqla param.
      - Get the dataset that backs the chart.
      - If the dataset has the main dttm column set, use it.
      - Otherwise, find all the dttm columns in the dataset and use the first one (this
        matches the behavior of Explore view on the frontend)
      - If no dttm columns exist in the dataset, don't change the chart.
      """
      bind = op.get_bind()
      session = db.Session(bind=bind)
  
      slices_changed = 0
  
      for slc in (
          session.query(Slice)
          .filter(
              and_(
                  Slice.datasource_type == "table",
                  Slice.params.notlike('%"granularity%'),
              )
          )
          .all()
      ):
          try:
              params = json.loads(slc.params)
              if (
                  "granularity" in params
                  or "granularity_sqla" in params
              ):
                  continue
  
              table = session.query(SqlaTable).get(slc.datasource_id)
              if not table:
                  continue
  
              if table.main_dttm_col:
                  params["granularity"] = table.main_dttm_col
                  slc.params = json.dumps(params, sort_keys=True)
                  print(
                      f"Set granularity for slice {slc.id} to {table.main_dttm_col}"
                  )
                  slices_changed += 1
                  continue
  
              table_columns = (
                  session.query(TableColumn)
                  .filter(TableColumn.table_id == table.id)
                  .filter(TableColumn.is_dttm == True)
                  .all()
              )
              if len(table_columns):
                  params["granularity"] = table_columns[0].column_name
                  slc.params = json.dumps(params, sort_keys=True)
                  print(
                      f"Set granularity for slice {slc.id} to {table_columns[0].column_name}"
                  )
                  slices_changed += 1
          except Exception as e:
              print(e)
              print(f"Parsing params for slice {slc.id} failed.")
              pass
  
      print(f"{slices_changed} slices altered")
      session.commit()
      session.close()
  
file_path: superset/superset/migrations/versions/2021-02-04_09-34_070c043f2fdb_add_granularity_to_charts_where_missing.py
imports: import json
  from alembic import op
  from sqlalchemy import and_, Boolean, Column, Integer, String, Text
  from sqlalchemy.ext.declarative import declarative_base
  from superset import db
label_desc: Use image node_id 1 for calling a global function with example usage: upgrade() without return types