public Field(string name, string type, string mode, Field[] fields = null)
 {
     Name = name;
     Type = type;
     Mode = mode;
     Fields = fields;
 }
        public QueryResponse(Field[] fields, Row[] rows, string jobId, long totalRows)
        {
            if (fields == null) throw new ArgumentNullException("fields");
            if (rows == null) throw new ArgumentNullException("rows");
            if (String.IsNullOrWhiteSpace(jobId)) throw new ArgumentNullException("jobId");

            Fields = fields;
            Rows = rows;
            JobId = jobId;
            TotalRows = totalRows;
            JobComplete = true;

        }
        private static JObject GetFieldSchema(Field f)
        {
            var ret = new JObject {{"name", f.Name}, {"type", f.Type}, {"mode", f.Mode}};
            if (f.Fields != null && f.Fields.Length > 0)
            {
                JProperty nestedFields = GetFields(f.Fields);
                ret.Add(nestedFields);
            }

            return ret;
        }
 public static JProperty GetFields(Field[] fields)
 {
     var jArray = new JArray(fields.Select(GetFieldSchema).ToArray());
     return new JProperty("fields", jArray);
 }
        public static async Task<string> StartLoadJobAsync(string projectId, string sourceUri, string datasetId, string tableId, string accessToken, Field[] fields, long maxBadRecords = 0)
        {
            var uris = new JProperty("sourceUris", new JArray(sourceUri));
            var destinationTable = new JProperty("destinationTable", new JObject(new JProperty("projectId", projectId), new JProperty("datasetId", datasetId), new JProperty("tableId", tableId)));

            var allowQuotedLines = new JProperty("sourceFormat", "NEWLINE_DELIMITED_JSON");
            var badRecords = new JProperty("maxBadRecords", maxBadRecords);
            var configuration = new JObject {new JProperty("load", new JObject(uris, new JProperty("schema", new JObject(GetFields(fields))), destinationTable, allowQuotedLines, badRecords))};

            var doc = new JObject {{"projectId", projectId}, {"configuration", configuration}};

            string uri = string.Format("https://www.googleapis.com/bigquery/v2/projects/{0}/jobs", projectId);
            var request = (HttpWebRequest) WebRequest.Create(uri);
            request.Method = "POST";
            request.Headers.Add("Authorization", "Bearer " + accessToken);
            request.ContentType = "application/json";

            string requestJson = doc.ToString();
            byte[] buffer = Encoding.UTF8.GetBytes(requestJson);
            request.ContentLength = buffer.Length;
            request.GetRequestStream().Write(buffer, 0, buffer.Length);
            string responseJson;

            try
            {
                using (WebResponse response = await request.GetResponseAsync())
                {
                    responseJson = new StreamReader(response.GetResponseStream()).ReadToEnd();
                    var ret = JsonConvert.DeserializeObject<JObject>(responseJson);
                    return ret.Value<JObject>("jobReference").Value<string>("jobId");
                }
            }
            catch (WebException ex)
            {
                if (ex.Response == null)
                {
                    throw;
                }
                var status = (int) ((HttpWebResponse) ex.Response).StatusCode;
                if (status == 400)
                {
                    responseJson = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
                    var errorMessage = JsonConvert.DeserializeObject<JObject>(responseJson).Value<JObject>("error").Value<string>("message");
                    throw new Exception(errorMessage);
                }
                throw;
            }
        }
        private static Row[] ParseRowsFromResponse(JObject ret, Field[] fields)
        {
            var rows = ret.Value<JArray>("rows");
            if (rows == null)
                return new Row[0];

            return rows.Select(row => row.Value<JArray>("f")).Select(f =>
                {
                    JValue[] values = f.Values<JValue>("v").ToArray();

                    object[] parsedValues = values.Select((v, i) =>
                        {
                            string type = fields[i].Type;
                            switch (type)
                            {
                                case "INTEGER":
                                    return (Object) ((int?) v);

                                case "STRING":
                                    return (Object) ((string) v);

                                case "FLOAT":
                                    return (Object) ((double?) v);

                                case "BOOLEAN":
                                    return (Object) ((bool?) v);

                                default:
                                    throw new NotImplementedException();
                            }
                        }).ToArray();

                    return new Row(parsedValues);
                }).ToArray();
        }