1 package storage
2
3
4
5
6 import (
7 "encoding/json"
8 "fmt"
9 "io/ioutil"
10 "net/http"
11 "net/url"
12 "strconv"
13 )
14
15 const (
16 headerAccept = "Accept"
17 headerEtag = "Etag"
18 headerPrefer = "Prefer"
19 headerXmsContinuation = "x-ms-Continuation-NextTableName"
20 )
21
22
23
24 type TableServiceClient struct {
25 client Client
26 auth authentication
27 }
28
29
30 type TableOptions struct {
31 RequestID string
32 }
33
34 func (options *TableOptions) addToHeaders(h map[string]string) map[string]string {
35 if options != nil {
36 h = addToHeaders(h, "x-ms-client-request-id", options.RequestID)
37 }
38 return h
39 }
40
41
42
43 type QueryNextLink struct {
44 NextLink *string
45 ml MetadataLevel
46 }
47
48
49
50 func (t *TableServiceClient) GetServiceProperties() (*ServiceProperties, error) {
51 return t.client.getServiceProperties(tableServiceName, t.auth)
52 }
53
54
55
56 func (t *TableServiceClient) SetServiceProperties(props ServiceProperties) error {
57 return t.client.setServiceProperties(props, tableServiceName, t.auth)
58 }
59
60
61 func (t *TableServiceClient) GetTableReference(name string) *Table {
62 return &Table{
63 tsc: t,
64 Name: name,
65 }
66 }
67
68
69 type QueryTablesOptions struct {
70 Top uint
71 Filter string
72 RequestID string
73 }
74
75 func (options *QueryTablesOptions) getParameters() (url.Values, map[string]string) {
76 query := url.Values{}
77 headers := map[string]string{}
78 if options != nil {
79 if options.Top > 0 {
80 query.Add(OdataTop, strconv.FormatUint(uint64(options.Top), 10))
81 }
82 if options.Filter != "" {
83 query.Add(OdataFilter, options.Filter)
84 }
85 headers = addToHeaders(headers, "x-ms-client-request-id", options.RequestID)
86 }
87 return query, headers
88 }
89
90
91
92
93
94 func (t *TableServiceClient) QueryTables(ml MetadataLevel, options *QueryTablesOptions) (*TableQueryResult, error) {
95 query, headers := options.getParameters()
96 uri := t.client.getEndpoint(tableServiceName, tablesURIPath, query)
97 return t.queryTables(uri, headers, ml)
98 }
99
100
101
102
103
104
105 func (tqr *TableQueryResult) NextResults(options *TableOptions) (*TableQueryResult, error) {
106 if tqr == nil {
107 return nil, errNilPreviousResult
108 }
109 if tqr.NextLink == nil {
110 return nil, errNilNextLink
111 }
112 headers := options.addToHeaders(map[string]string{})
113
114 return tqr.tsc.queryTables(*tqr.NextLink, headers, tqr.ml)
115 }
116
117
118
119 type TableQueryResult struct {
120 OdataMetadata string `json:"odata.metadata"`
121 Tables []Table `json:"value"`
122 QueryNextLink
123 tsc *TableServiceClient
124 }
125
126 func (t *TableServiceClient) queryTables(uri string, headers map[string]string, ml MetadataLevel) (*TableQueryResult, error) {
127 if ml == EmptyPayload {
128 return nil, errEmptyPayload
129 }
130 headers = mergeHeaders(headers, t.client.getStandardHeaders())
131 headers[headerAccept] = string(ml)
132
133 resp, err := t.client.exec(http.MethodGet, uri, headers, nil, t.auth)
134 if err != nil {
135 return nil, err
136 }
137 defer resp.Body.Close()
138
139 if err := checkRespCode(resp, []int{http.StatusOK}); err != nil {
140 return nil, err
141 }
142
143 respBody, err := ioutil.ReadAll(resp.Body)
144 if err != nil {
145 return nil, err
146 }
147 var out TableQueryResult
148 err = json.Unmarshal(respBody, &out)
149 if err != nil {
150 return nil, err
151 }
152
153 for i := range out.Tables {
154 out.Tables[i].tsc = t
155 }
156 out.tsc = t
157
158 nextLink := resp.Header.Get(http.CanonicalHeaderKey(headerXmsContinuation))
159 if nextLink == "" {
160 out.NextLink = nil
161 } else {
162 originalURI, err := url.Parse(uri)
163 if err != nil {
164 return nil, err
165 }
166 v := originalURI.Query()
167 v.Set(nextTableQueryParameter, nextLink)
168 newURI := t.client.getEndpoint(tableServiceName, tablesURIPath, v)
169 out.NextLink = &newURI
170 out.ml = ml
171 }
172
173 return &out, nil
174 }
175
176 func addBodyRelatedHeaders(h map[string]string, length int) map[string]string {
177 h[headerContentType] = "application/json"
178 h[headerContentLength] = fmt.Sprintf("%v", length)
179 h[headerAcceptCharset] = "UTF-8"
180 return h
181 }
182
183 func addReturnContentHeaders(h map[string]string, ml MetadataLevel) map[string]string {
184 if ml != EmptyPayload {
185 h[headerPrefer] = "return-content"
186 h[headerAccept] = string(ml)
187 } else {
188 h[headerPrefer] = "return-no-content"
189
190 h[headerAccept] = string(NoMetadata)
191 }
192 return h
193 }
194
View as plain text