147 lines
4.1 KiB
Go
147 lines
4.1 KiB
Go
// Copyright 2015 Google Inc. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package bigquery
|
|
|
|
// TODO(mcgreevy): support dry-run mode when creating jobs.
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"golang.org/x/net/context"
|
|
bq "google.golang.org/api/bigquery/v2"
|
|
)
|
|
|
|
// A Source is a source of data for the Copy function.
|
|
type Source interface {
|
|
implementsSource()
|
|
}
|
|
|
|
// A Destination is a destination of data for the Copy function.
|
|
type Destination interface {
|
|
implementsDestination()
|
|
}
|
|
|
|
// An Option is an optional argument to Copy.
|
|
type Option interface {
|
|
implementsOption()
|
|
}
|
|
|
|
// A ReadSource is a source of data for the Read function.
|
|
type ReadSource interface {
|
|
implementsReadSource()
|
|
}
|
|
|
|
// A ReadOption is an optional argument to Read.
|
|
type ReadOption interface {
|
|
customizeRead(conf *pagingConf)
|
|
}
|
|
|
|
const Scope = "https://www.googleapis.com/auth/bigquery"
|
|
|
|
// Client may be used to perform BigQuery operations.
|
|
type Client struct {
|
|
service service
|
|
projectID string
|
|
}
|
|
|
|
// Note: many of the methods on *Client appear in the various *_op.go source files.
|
|
|
|
// NewClient constructs a new Client which can perform BigQuery operations.
|
|
// Operations performed via the client are billed to the specified GCP project.
|
|
// The supplied http.Client is used for making requests to the BigQuery server and must be capable of
|
|
// authenticating requests with Scope.
|
|
func NewClient(client *http.Client, projectID string) (*Client, error) {
|
|
bqService, err := newBigqueryService(client)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("constructing bigquery client: %v", err)
|
|
}
|
|
|
|
c := &Client{
|
|
service: bqService,
|
|
projectID: projectID,
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
// initJobProto creates and returns a bigquery Job proto.
|
|
// The proto is customized using any jobOptions in options.
|
|
// The list of Options is returned with the jobOptions removed.
|
|
func initJobProto(projectID string, options []Option) (*bq.Job, []Option) {
|
|
job := &bq.Job{}
|
|
|
|
var other []Option
|
|
for _, opt := range options {
|
|
if o, ok := opt.(jobOption); ok {
|
|
o.customizeJob(job, projectID)
|
|
} else {
|
|
other = append(other, opt)
|
|
}
|
|
}
|
|
return job, other
|
|
}
|
|
|
|
// Copy starts a BigQuery operation to copy data from a Source to a Destination.
|
|
func (c *Client) Copy(ctx context.Context, dst Destination, src Source, options ...Option) (*Job, error) {
|
|
switch dst := dst.(type) {
|
|
case *Table:
|
|
switch src := src.(type) {
|
|
case *GCSReference:
|
|
return c.load(ctx, dst, src, options)
|
|
case *Table:
|
|
return c.cp(ctx, dst, Tables{src}, options)
|
|
case Tables:
|
|
return c.cp(ctx, dst, src, options)
|
|
case *Query:
|
|
return c.query(ctx, dst, src, options)
|
|
}
|
|
case *GCSReference:
|
|
if src, ok := src.(*Table); ok {
|
|
return c.extract(ctx, dst, src, options)
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("no Copy operation matches dst/src pair: dst: %T ; src: %T", dst, src)
|
|
}
|
|
|
|
// Read fetches data from a ReadSource and returns the data via an Iterator.
|
|
func (c *Client) Read(ctx context.Context, src ReadSource, options ...ReadOption) (*Iterator, error) {
|
|
switch src := src.(type) {
|
|
case *Job:
|
|
return c.readQueryResults(src, options)
|
|
case *Query:
|
|
return c.executeQuery(ctx, src, options...)
|
|
case *Table:
|
|
return c.readTable(src, options)
|
|
}
|
|
return nil, fmt.Errorf("src (%T) does not support the Read operation", src)
|
|
}
|
|
|
|
// executeQuery submits a query for execution and returns the results via an Iterator.
|
|
func (c *Client) executeQuery(ctx context.Context, q *Query, options ...ReadOption) (*Iterator, error) {
|
|
dest := &Table{}
|
|
job, err := c.Copy(ctx, dest, q, WriteTruncate)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return c.Read(ctx, job, options...)
|
|
}
|
|
|
|
func (c *Client) Dataset(id string) *Dataset {
|
|
return &Dataset{
|
|
id: id,
|
|
client: c,
|
|
}
|
|
}
|