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 }