code: def parse_list_batches_query_v2(
      user: str, q: str, last_batch_id: Optional[int]
  ) -> Tuple[str, List[Any]]:
      queries: List[Query] = []
  
      # logic to make time interval queries fast
      min_start_gt_query: Optional[BatchStartTimeQuery] = None
      max_end_lt_query: Optional[BatchEndTimeQuery] = None
  
      if q:
          terms = q.rstrip().lstrip().split("\n")
          for _term in terms:
              _term = pad_maybe_operator(_term)
              statement = _term.split()
              if len(statement) == 1:
                  word = statement[0]
                  if word[0] == '"':
                      queries.append(
                          BatchQuotedExactMatchQuery.parse(word)
                      )
                  else:
                      queries.append(
                          BatchUnquotedPartialMatchQuery.parse(word)
                      )
              elif len(statement) == 3:
                  left, op, right = statement
                  if left == "batch_id":
                      queries.append(BatchIdQuery.parse(op, right))
                  elif left == "billing_project":
                      queries.append(
                          BatchBillingProjectQuery.parse(op, right)
                      )
                  elif left == "user":
                      queries.append(BatchUserQuery.parse(op, right))
                  elif left == "state":
                      queries.append(BatchStateQuery.parse(op, right))
                  elif left == "start_time":
                      st_query = BatchStartTimeQuery.parse(op, right)
                      queries.append(st_query)
                      if (
                          type(st_query.operator)
                          in [
                              GreaterThanOperator,
                              GreaterThanEqualOperator,
                          ]
                      ) and (
                          min_start_gt_query is None
                          or min_start_gt_query.time_msecs
                          >= st_query.time_msecs
                      ):
                          min_start_gt_query = st_query
                  elif left == "end_time":
                      et_query = BatchEndTimeQuery.parse(op, right)
                      queries.append(et_query)
                      if (
                          type(et_query.operator)
                          in [LessThanOperator, LessThanEqualOperator]
                      ) and (
                          max_end_lt_query is None
                          or max_end_lt_query.time_msecs
                          <= et_query.time_msecs
                      ):
                          max_end_lt_query = et_query
                  elif left == "duration":
                      queries.append(
                          BatchDurationQuery.parse(op, right)
                      )
                  elif left == "cost":
                      queries.append(BatchCostQuery.parse(op, right))
                  else:
                      queries.append(
                          BatchKeywordQuery.parse(op, left, right)
                      )
              else:
                  raise QueryError(f'could not parse term "{_term}"')
  
      # this is to make time interval queries fast by using the bounds on both indices
      if (
          min_start_gt_query
          and max_end_lt_query
          and min_start_gt_query.time_msecs
          <= max_end_lt_query.time_msecs
      ):
          queries.append(
              BatchStartTimeQuery(
                  max_end_lt_query.operator, max_end_lt_query.time_msecs
              )
          )
          queries.append(
              BatchEndTimeQuery(
                  min_start_gt_query.operator,
                  min_start_gt_query.time_msecs,
              )
          )
  
      # batch has already been validated
      where_conditions = [
          "(billing_project_users.`user` = %s)",
          "NOT deleted",
      ]
      where_args: List[Any] = [user]
  
      if last_batch_id is not None:
          where_conditions.append("(batches.id < %s)")
          where_args.append(last_batch_id)
  
      for query in queries:
          cond, args = query.query()
          where_conditions.append(f"({cond})")
          where_args += args
  
      sql = f"""
  SELECT batches.*,
    job_groups_cancelled.id IS NOT NULL AS cancelled,
    job_groups_n_jobs_in_complete_states.n_completed,
    job_groups_n_jobs_in_complete_states.n_succeeded,
    job_groups_n_jobs_in_complete_states.n_failed,
    job_groups_n_jobs_in_complete_states.n_cancelled,
    cost_t.cost, cost_t.cost_breakdown
  FROM batches
  LEFT JOIN billing_projects ON batches.billing_project = billing_projects.name
  LEFT JOIN job_groups_n_jobs_in_complete_states ON batches.id = job_groups_n_jobs_in_complete_states.id
  LEFT JOIN job_groups_cancelled ON batches.id = job_groups_cancelled.id
  STRAIGHT_JOIN billing_project_users ON batches.billing_project = billing_project_users.billing_project
  LEFT JOIN LATERAL (
    SELECT COALESCE(SUM(`usage` * rate), 0) AS cost, JSON_OBJECTAGG(resources.resource, COALESCE(`usage` * rate, 0)) AS cost_breakdown
    FROM (
      SELECT batch_id, resource_id, CAST(COALESCE(SUM(`usage`), 0) AS SIGNED) AS `usage`
      FROM aggregated_job_group_resources_v3
      WHERE batches.id = aggregated_job_group_resources_v3.batch_id
      GROUP BY batch_id, resource_id
    ) AS usage_t
    LEFT JOIN resources ON usage_t.resource_id = resources.resource_id
    GROUP BY batch_id
  ) AS cost_t ON TRUE
  WHERE {' AND '.join(where_conditions)}
  ORDER BY id DESC
  LIMIT 51;
  """
  
      return (sql, where_args)
  
imports: from typing import Any, List, Optional, Tuple
  from ...exceptions import QueryError
  from .operators import GreaterThanEqualOperator, GreaterThanOperator, LessThanEqualOperator, LessThanOperator, pad_maybe_operator
  from .query import BatchBillingProjectQuery, BatchCostQuery, BatchDurationQuery, BatchEndTimeQuery, BatchIdQuery, BatchKeywordQuery, BatchQuotedExactMatchQuery, BatchStartTimeQuery, BatchStateQuery, BatchUnquotedPartialMatchQuery, BatchUserQuery, JobCostQuery, JobDurationQuery, JobEndTimeQuery, JobIdQuery, JobInstanceCollectionQuery, JobInstanceQuery, JobKeywordQuery, JobQuotedExactMatchQuery, JobStartTimeQuery, JobStateQuery, JobUnquotedPartialMatchQuery, Query
label_desc: Use image node_id 1 for calling a global function with example usage: parse_list_batches_query_v2(user, q, last_batch_id) and returns: sql,  where_args