docstr: Checks if limit returns the top 2 rows from the data
  after sorting
  
  data (3 batches):
  'A' 'B' 'C'
  [1, 1, 1]
  ----------
  [1, 5, 6]
  [4, 7, 10]
  ----------
  [2, 9, 7]
  [4, 1, 2]
  [4, 2, 4]
docstr_tok: ["Checks","if","limit","returns","the","top","2","rows","from","the","data","after","sorting","data","(","3","batches",")",":","'","A","'","'","B","'","'","C'","[","1",",","1",",","1","]","--","--","--","--","--","[","1",",","5",",","6","]","[","4",",","7",",","10","]","--","--","--","--","--","[","2",",","9",",","7","]","[","4",",","1",",","2","]","[","4",",","2",",","4","]"]
code: def test_should_return_top_frames_after_sorting(self):
      """
      Checks if limit returns the top 2 rows from the data
      after sorting
  
      data (3 batches):
      'A' 'B' 'C'
      [1, 1, 1]
      ----------
      [1, 5, 6]
      [4, 7, 10]
      ----------
      [2, 9, 7]
      [4, 1, 2]
      [4, 2, 4]
      """
  
      df1 = pd.DataFrame(np.array([[1, 1, 1]]), columns=["A", "B", "C"])
      df2 = pd.DataFrame(
          np.array([[1, 5, 6], [4, 7, 10]]), columns=["A", "B", "C"]
      )
      df3 = pd.DataFrame(
          np.array([[2, 9, 7], [4, 1, 2], [4, 2, 4]]),
          columns=["A", "B", "C"],
      )
  
      batches = [Batch(frames=df) for df in [df1, df2, df3]]
  
      "query: .... ORDER BY A ASC, B DESC limit 2"
  
      plan = OrderByPlan(
          [
              (
                  TupleValueExpression(col_alias="A"),
                  ParserOrderBySortType.ASC,
              ),
              (
                  TupleValueExpression(col_alias="B"),
                  ParserOrderBySortType.DESC,
              ),
          ]
      )
  
      orderby_executor = OrderByExecutor(MagicMock(), plan)
      orderby_executor.append_child(DummyExecutor(batches))
  
      sorted_batches = list(orderby_executor.exec())
  
      limit_value = 2
      plan = LimitPlan(ConstantValueExpression(limit_value))
      limit_executor = LimitExecutor(MagicMock(), plan)
      limit_executor.append_child(DummyExecutor(sorted_batches))
      reduced_batches = list(limit_executor.exec())
  
      # merge everything into one batch
      aggregated_batch = Batch.concat(reduced_batches, copy=False)
      """
             A  B   C
          0  1  5   6
          1  1  1   1
          """
  
      expected_df1 = pd.DataFrame(
          np.array([[1, 5, 6], [1, 1, 1]]), columns=["A", "B", "C"]
      )
  
      expected_batches = [Batch(frames=df) for df in [expected_df1]]
  
      self.assertEqual(expected_batches[0], aggregated_batch)
  
file_path: evadb/test/unit_tests/executor/test_limit_executor.py
imports: import unittest
  from test.unit_tests.executor.utils import DummyExecutor
  import numpy
  import pandas
  from mock import MagicMock
  from evadb.executor.limit_executor import LimitExecutor
  from evadb.executor.orderby_executor import OrderByExecutor
  from evadb.expression.constant_value_expression import ConstantValueExpression
  from evadb.expression.tuple_value_expression import TupleValueExpression
  from evadb.models.storage.batch import Batch
  from evadb.parser.types import ParserOrderBySortType
  from evadb.plan_nodes.limit_plan import LimitPlan
  from evadb.plan_nodes.orderby_plan import OrderByPlan
label_desc: Use image node_id 3 for calling the LimitExecutorTest obj's underlying member method code with example usage: obj.test_should_return_top_frames_after_sorting() without return types