yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/google/bigquery.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package google
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"yunion.io/x/jsonutils"
    21  	"yunion.io/x/pkg/errors"
    22  )
    23  
    24  func (self *SGoogleClient) bigqueryPost(resource string, params map[string]string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) {
    25  	resource = fmt.Sprintf("projects/%s/%s", self.projectId, resource)
    26  	return jsonRequest(self.client, "POST", GOOGLE_BIGQUERY_DOMAIN, GOOGLE_BIGQUERY_API_VERSION, resource, params, body, self.debug)
    27  }
    28  
    29  func (self *SGoogleClient) bigqueryList(resource string, params map[string]string) (jsonutils.JSONObject, error) {
    30  	return jsonRequest(self.client, "GET", GOOGLE_BIGQUERY_DOMAIN, GOOGLE_BIGQUERY_API_VERSION, resource, params, nil, self.debug)
    31  }
    32  
    33  func (self *SGoogleClient) bigqueryGet(resource string) (jsonutils.JSONObject, error) {
    34  	return jsonRequest(self.client, "GET", GOOGLE_BIGQUERY_DOMAIN, GOOGLE_BIGQUERY_API_VERSION, resource, nil, nil, self.debug)
    35  }
    36  
    37  func (region *SRegion) BigQuery(sql string) ([]jsonutils.JSONObject, error) {
    38  	req := struct {
    39  		Kind         string `json:"kind"`
    40  		Query        string `json:"query"`
    41  		MaxResults   string `json:"maxResults"`
    42  		UseLegacySql bool   `json:"useLegacySql"`
    43  	}{
    44  		Kind:         "query",
    45  		Query:        sql,
    46  		MaxResults:   "1",
    47  		UseLegacySql: false,
    48  	}
    49  	resp, err := region.client.bigqueryPost("queries", nil, jsonutils.Marshal(req))
    50  	if err != nil {
    51  		return nil, errors.Wrap(err, "bigqueryPost")
    52  	}
    53  	result := SBigQueryResult{}
    54  	err = resp.Unmarshal(&result)
    55  	if err != nil {
    56  		return nil, errors.Wrap(err, "jsonutils.Unmarshal")
    57  	}
    58  	rows, err := result.GetRows()
    59  	if err != nil {
    60  		return nil, errors.Wrap(err, "GetRows")
    61  	}
    62  	return rows, nil
    63  }
    64  
    65  type SBigQueryField struct {
    66  	Type string `json:"type"`
    67  	Name string `json:"name"`
    68  	Mode string `json:"mode"`
    69  
    70  	Fields []SBigQueryField `json:"fields"`
    71  }
    72  
    73  type SBigQuerySchema struct {
    74  	Fields []SBigQueryField `json:"fields"`
    75  }
    76  
    77  type SBigQueryJobReference struct {
    78  }
    79  
    80  type SBigQueryResult struct {
    81  	CacheHit            bool                   `json:"cacheHit"`
    82  	JobComplete         bool                   `json:"jobComplete"`
    83  	JobReference        SBigQueryJobReference  `json:"jobReference"`
    84  	Kind                string                 `json:"kind"`
    85  	Rows                []jsonutils.JSONObject `json:"rows"`
    86  	Schema              SBigQuerySchema        `json:"schema"`
    87  	TotalBytesProcessed int64                  `json:"totalBytesProcessed"`
    88  	totalRows           int64                  `json:"totalRows"`
    89  }
    90  
    91  func (res SBigQueryResult) GetRows() ([]jsonutils.JSONObject, error) {
    92  	rows := make([]jsonutils.JSONObject, 0)
    93  	for _, r := range res.Rows {
    94  		row, err := res.Schema.Parse(r)
    95  		if err != nil {
    96  			return nil, errors.Wrap(err, "Schema.Parse")
    97  		}
    98  		rows = append(rows, jsonutils.Marshal(row))
    99  	}
   100  	return rows, nil
   101  }
   102  
   103  func (schema SBigQuerySchema) Parse(r jsonutils.JSONObject) (map[string]jsonutils.JSONObject, error) {
   104  	f := SBigQueryField{
   105  		Type:   "RECORD",
   106  		Mode:   "NULLABLE",
   107  		Name:   "",
   108  		Fields: schema.Fields,
   109  	}
   110  	nr := jsonutils.NewDict()
   111  	nr.Add(r, "v")
   112  	return f.Parse(nr, "")
   113  }
   114  
   115  func (f SBigQueryField) Parse(r jsonutils.JSONObject, prefix string) (map[string]jsonutils.JSONObject, error) {
   116  	if len(prefix) > 0 {
   117  		prefix = prefix + "." + f.Name
   118  	} else {
   119  		prefix = f.Name
   120  	}
   121  	ret := make(map[string]jsonutils.JSONObject)
   122  	switch f.Type {
   123  	case "RECORD":
   124  		if f.Mode == "REPEATED" {
   125  			items, err := r.GetArray("v")
   126  			if err != nil {
   127  				return nil, errors.Wrapf(err, "GetArray v %s", r)
   128  			}
   129  			nf := f
   130  			nf.Mode = "NULLABLE"
   131  			val := jsonutils.NewArray()
   132  			for _, item := range items {
   133  				obj, err := nf.Parse(item, "")
   134  				if err != nil {
   135  					return nil, errors.Wrap(err, "Parse items")
   136  				}
   137  				val.Add(jsonutils.Marshal(obj))
   138  			}
   139  			ret[prefix] = val
   140  		} else {
   141  			items, err := r.GetArray("v", "f")
   142  			if err != nil {
   143  				return nil, errors.Wrap(err, "GetArray v.f")
   144  			}
   145  			if len(items) != len(f.Fields) {
   146  				return nil, errors.Wrap(errors.ErrServer, "inconsistent items and fields")
   147  			}
   148  			for i := range f.Fields {
   149  				res, err := f.Fields[i].Parse(items[i], prefix)
   150  				if err != nil {
   151  					return nil, errors.Wrapf(err, "Parse %s", prefix)
   152  				}
   153  				for k, v := range res {
   154  					ret[k] = v
   155  				}
   156  			}
   157  		}
   158  	default:
   159  		v, err := r.Get("v")
   160  		if err != nil {
   161  			return nil, errors.Wrap(err, "Get v")
   162  		}
   163  		ret[prefix] = v
   164  	}
   165  	return ret, nil
   166  }