code: def _bulk_merge_into_session(
      objs: Sequence[Base],
      # pyre-fixme[24]: Generic type `Callable` expects 2 type parameters.
      encode_func: Callable,
      # pyre-fixme[24]: Generic type `Callable` expects 2 type parameters.
      decode_func: Callable,
      encode_args_list: Optional[
          Union[List[None], List[Dict[str, Any]]]
      ] = None,
      decode_args_list: Optional[
          Union[List[None], List[Dict[str, Any]]]
      ] = None,
      # pyre-fixme[24]: Generic type `Callable` expects 2 type parameters.
      modify_sqa: Optional[Callable] = None,
      batch_size: Optional[int] = None,
  ) -> List[SQABase]:
      """Bulk version of _merge_into_session.
  
      Takes in a list of objects to merge into the session together
      (i.e. within one session scope), along with corresponding (but optional)
      lists of encode and decode arguments.
  
      If batch_size is specified, the list of objects will be chunked
      accordingly, and multiple session scopes will be used to merge
      the objects in, one batch at a time.
      """
      if len(objs) == 0:
          return []
  
      encode_args_list = encode_args_list or [
          None for _ in range(len(objs))
      ]
      decode_args_list = decode_args_list or [
          None for _ in range(len(objs))
      ]
  
      sqas = []
      for obj, encode_args in zip(objs, encode_args_list):
          sqa = encode_func(obj, **(encode_args or {}))
          if modify_sqa is not None:
              modify_sqa(sqa=sqa)
          sqas.append(sqa)
  
      # https://stackoverflow.com/a/312464
      # pyre-fixme[3]: Return type must be annotated.
      # pyre-fixme[2]: Parameter must be annotated.
      def split_into_batches(lst, n):
          for i in range(0, len(lst), n):
              yield lst[i : i + n]
  
      new_sqas = []
      batch_size = batch_size or len(sqas)
      for batch in split_into_batches(lst=sqas, n=batch_size):
          with session_scope() as session:
              for sqa in batch:
                  new_sqa = session.merge(sqa)
                  new_sqas.append(new_sqa)
              session.flush()
  
      new_objs = []
      for new_sqa, decode_args in zip(new_sqas, decode_args_list):
          new_obj = decode_func(new_sqa, **(decode_args or {}))
          new_objs.append(new_obj)
  
      for obj, new_obj in zip(objs, new_objs):
          _copy_db_ids_if_possible(obj=obj, new_obj=new_obj)
  
      return new_sqas
  
imports: import os
  from logging import Logger
  from typing import Any, Callable, Dict, List, Optional, Sequence, Union
  from ax.core.base_trial import BaseTrial
  from ax.core.experiment import Experiment
  from ax.core.generator_run import GeneratorRun
  from ax.core.metric import Metric
  from ax.core.outcome_constraint import ObjectiveThreshold, OutcomeConstraint
  from ax.core.runner import Runner
  from ax.exceptions.core import UserInputError
  from ax.exceptions.storage import SQADecodeError
  from ax.modelbridge.generation_strategy import GenerationStrategy
  from ax.storage.sqa_store.db import session_scope, SQABase
  from ax.storage.sqa_store.decoder import Decoder
  from ax.storage.sqa_store.encoder import Encoder
  from ax.storage.sqa_store.sqa_classes import SQAData, SQAGeneratorRun, SQAMetric, SQARunner, SQATrial
  from ax.storage.sqa_store.sqa_config import SQAConfig
  from ax.storage.sqa_store.utils import copy_db_ids
  from ax.utils.common.base import Base
  from ax.utils.common.logger import get_logger
  from ax.utils.common.typeutils import checked_cast, not_none
label_desc: Use image node_id 15 for calling a global function with example usage: _bulk_merge_into_session(objs, encode_func, decode_func, encode_args_list, decode_args_list, modify_sqa, batch_size) and returns: new_sqas, list