function runQuery(queryString, connection = {}) {
  const timeoutSeconds = getTimeoutSeconds() - 1; // A little less than the SQLPad timeout
  const bigquery = newBigQuery(connection);
  let incomplete = false;
  const t1 = process.hrtime();

  const isMaxRowsSpecified =
    connection.hasOwnProperty('maxRows') && connection.maxRows !== null;

  const query = {
    query: queryString,
  };

  const datasets = splitDatasets(connection.datasetName);
  // Set the default dataset if only one dataset is present.
  if (datasets.length === 1) {
    query.defaultDataset = { datasetId: datasets[0] };
  }

  // TODO: should maxRows apply to non-SELECT statements?
  return bigquery
    .createQueryJob(query)
    .then(([job]) => {
      // Wait for the query to finish.
      const options = {
        timeoutMs: timeoutSeconds * 1000,
        wrapIntegers: {
          integerTypeCastFunction: (val) => val.toString(),
        },
      };
      if (isMaxRowsSpecified) {
        options.maxResults = connection.maxRows + 1;
      }
      return retry(
        // Function that returns a promise for getting query results.
        () => job.getQueryResults(options),
        {
          // Delay between retries.
          delay: 1000,
          // If not a request timeout, raise the error.
          check: (error) => error.type !== 'request-timeout',
        }
      );
    })
    .then(([rows, nextPage]) => {
      if (rows.length === 0) {
        const t2 = process.hrtime(t1);
        if (t2[0] >= timeoutSeconds) {
          throw new Error(`Query timed out after ${timeoutSeconds} seconds.`);
        }
      }

      if (isMaxRowsSpecified && rows.length > connection.maxRows) {
        rows.splice(connection.maxRows);
        incomplete = true;
      } else if (nextPage) {
        incomplete = true;
      }

      return {
        incomplete,
        rows,
      };
    });
}
Run query for connection
Should return { rows, incomplete }
@param {string} queryString
@param {object} connection