func GetClient(project string) (*bigquery.Client, error) {
	return bigquery.NewClient(context.Background(), project)
}
===============================================================================
GetClient returns an appropriate bigquery client.
package bq
import (
	"context"
	"encoding/json"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"reflect"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"cloud.google.com/go/bigquery"
	"google.golang.org/api/googleapi"
	"github.com/m-lab/go/cloud/bqx"
	"github.com/m-lab/etl/etl"
	"github.com/m-lab/etl/factory"
	"github.com/m-lab/etl/metrics"
	"github.com/m-lab/etl/row"
)
const insertsBeforeRowJSONCount = 100
var tableInsertCounts = sync.Map{}
func init() {
}
const (
	maxPutRetryDelay = time.Minute
	putContextTimeout = 60 * time.Second
)
func NewInserter(dt etl.DataType, partition time.Time) (etl.Inserter, error) {
	suffix := ""
	if etl.IsBatchService() || time.Since(partition) > 30*24*time.Hour {
		suffix = "_" + partition.Format("20060102")
	} else {
		suffix = "$" + partition.Format("20060102")
	}
	bqProject := dt.BigqueryProject()
	dataset := dt.Dataset()
	table := dt.Table()
	return NewBQInserter(
		etl.InserterParams{Project: bqProject, Dataset: dataset, Table: table, Suffix: suffix,
			PutTimeout: putContextTimeout, MaxRetryDelay: maxPutRetryDelay,
			BufferSize: dt.BQBufferSize()},
		nil)
}
func NewColumnPartitionedInserter(pdt bqx.PDT) (row.Sink, error) {
	client, err := GetClient(pdt.Project)
	if err != nil {
		return nil, err
	}
	uploader := client.Dataset(pdt.Dataset).Table(pdt.Table).Uploader()
	uploader.SkipInvalidRows = true
	return NewColumnPartitionedInserterWithUploader(pdt, uploader)
}
func NewColumnPartitionedInserterWithUploader(pdt bqx.PDT, uploader etl.Uploader) (row.Sink, error) {
	token := make(chan struct{}, 1)
	token <- struct{}{}
	fl := sink{uploader: uploader, putTimeout: putContextTimeout, maxRetryDelay: maxPutRetryDelay, token: token}
	sink := (row.Sink)(&fl)
	return sink, nil
}
func NewBQInserter(params etl.InserterParams, uploader etl.Uploader) (etl.Inserter, error) {
	if uploader == nil {
		client, err := GetClient(params.Project)
		if err != nil {
			return nil, err
		}
		table := params.Table
		if params.Suffix[0] == '$' {
			table += params.Suffix
		}
		u := client.Dataset(params.Dataset).Table(table).Uploader()
		if params.Suffix[0] == '_' {
			u.TableTemplateSuffix = params.Suffix
		}
		u.SkipInvalidRows = true
		uploader = u
	}
	token := make(chan struct{}, 1)
	token <- struct{}{}
	rows := make([]interface{}, 0, params.BufferSize)
	sink := sink{uploader: uploader, putTimeout: params.PutTimeout, maxRetryDelay: params.MaxRetryDelay, token: token}
	in := BQInserter{sink: sink, params: params, rows: rows}
	return &in, nil
}