code: def query(self, query, *args, prefetch=None, timeout=None):
          
          compiled_q, compiled_args = compile_query(query)
          query, args = compiled_q, compiled_args or args
  
          return QueryContextManager(self.pool, query, args,
                                     prefetch=prefetch, timeout=timeout)
docs: make a read only query. Ideal for select statements.
          This method converts the query to a prepared statement
          and uses a cursor to return the results. So you only get
          so many rows at a time. This can dramatically increase performance
          for queries that have a lot of results/responses as not everything has
          to be loaded into memory at once.
          You can use this with the `await` keyword to not use a cursor.
  
          Use the following syntax for a cursor
          async with query() as cursor:
              async for row in cursor:
                  a = row['col_name']
  
          or the following for a all results and no cursor/transaction:
          results = await query()
  
          :param query: query to be performed
          :param args: parameters to query (if a string)
          :param callback: a callback to call with the responses
          :param int prefetch: The number of rows the *cursor iterator*
                               will prefetch (defaults to ``50``.)
          :param float timeout: Optional timeout in seconds.
          :return: