1package entities
2
3import (
4	"context"
5	"fmt"
6	"net/http"
7	"strings"
8
9	"github.com/Azure/go-autorest/autorest"
10	"github.com/Azure/go-autorest/autorest/azure"
11	"github.com/Azure/go-autorest/autorest/validation"
12	"github.com/tombuildsstuff/giovanni/storage/internal/endpoints"
13)
14
15type QueryEntitiesInput struct {
16	// An optional OData filter
17	Filter *string
18
19	// An optional comma-separated
20	PropertyNamesToSelect *[]string
21
22	// An optional OData top
23	Top *int
24
25	PartitionKey string
26	RowKey       string
27
28	// The Level of MetaData which should be returned
29	MetaDataLevel MetaDataLevel
30
31	// The Next Partition Key used to load data from a previous point
32	NextPartitionKey *string
33
34	// The Next Row Key used to load data from a previous point
35	NextRowKey *string
36}
37
38type QueryEntitiesResult struct {
39	autorest.Response
40
41	NextPartitionKey string
42	NextRowKey       string
43
44	MetaData string                   `json:"odata.metadata,omitempty"`
45	Entities []map[string]interface{} `json:"value"`
46}
47
48// Query queries entities in a table and includes the $filter and $select options.
49func (client Client) Query(ctx context.Context, accountName, tableName string, input QueryEntitiesInput) (result QueryEntitiesResult, err error) {
50	if accountName == "" {
51		return result, validation.NewError("entities.Client", "Query", "`accountName` cannot be an empty string.")
52	}
53	if tableName == "" {
54		return result, validation.NewError("entities.Client", "Query", "`tableName` cannot be an empty string.")
55	}
56
57	req, err := client.QueryPreparer(ctx, accountName, tableName, input)
58	if err != nil {
59		err = autorest.NewErrorWithError(err, "entities.Client", "Query", nil, "Failure preparing request")
60		return
61	}
62
63	resp, err := client.QuerySender(req)
64	if err != nil {
65		result.Response = autorest.Response{Response: resp}
66		err = autorest.NewErrorWithError(err, "entities.Client", "Query", resp, "Failure sending request")
67		return
68	}
69
70	result, err = client.QueryResponder(resp)
71	if err != nil {
72		err = autorest.NewErrorWithError(err, "entities.Client", "Query", resp, "Failure responding to request")
73		return
74	}
75
76	return
77}
78
79// QueryPreparer prepares the Query request.
80func (client Client) QueryPreparer(ctx context.Context, accountName, tableName string, input QueryEntitiesInput) (*http.Request, error) {
81
82	pathParameters := map[string]interface{}{
83		"tableName":            autorest.Encode("path", tableName),
84		"additionalParameters": "",
85	}
86
87	//PartitionKey='<partition-key>',RowKey='<row-key>'
88	additionalParams := make([]string, 0)
89	if input.PartitionKey != "" {
90		additionalParams = append(additionalParams, fmt.Sprintf("PartitionKey='%s'", input.PartitionKey))
91	}
92	if input.RowKey != "" {
93		additionalParams = append(additionalParams, fmt.Sprintf("RowKey='%s'", input.RowKey))
94	}
95	if len(additionalParams) > 0 {
96		pathParameters["additionalParameters"] = autorest.Encode("path", strings.Join(additionalParams, ","))
97	}
98
99	queryParameters := map[string]interface{}{}
100
101	if input.Filter != nil {
102		queryParameters["$filter"] = autorest.Encode("query", *input.Filter)
103	}
104
105	if input.PropertyNamesToSelect != nil {
106		queryParameters["$select"] = autorest.Encode("query", strings.Join(*input.PropertyNamesToSelect, ","))
107	}
108
109	if input.Top != nil {
110		queryParameters["$top"] = autorest.Encode("query", *input.Top)
111	}
112
113	if input.NextPartitionKey != nil {
114		queryParameters["NextPartitionKey"] = *input.NextPartitionKey
115	}
116
117	if input.NextRowKey != nil {
118		queryParameters["NextRowKey"] = *input.NextRowKey
119	}
120
121	headers := map[string]interface{}{
122		"x-ms-version":          APIVersion,
123		"Accept":                fmt.Sprintf("application/json;odata=%s", input.MetaDataLevel),
124		"DataServiceVersion":    "3.0;NetFx",
125		"MaxDataServiceVersion": "3.0;NetFx",
126	}
127
128	// GET /myaccount/Customers()?$filter=(Rating%20ge%203)%20and%20(Rating%20le%206)&$select=PartitionKey,RowKey,Address,CustomerSince
129	preparer := autorest.CreatePreparer(
130		autorest.AsGet(),
131		autorest.WithBaseURL(endpoints.GetTableEndpoint(client.BaseURI, accountName)),
132		autorest.WithPathParameters("/{tableName}({additionalParameters})", pathParameters),
133		autorest.WithQueryParameters(queryParameters),
134		autorest.WithHeaders(headers))
135	return preparer.Prepare((&http.Request{}).WithContext(ctx))
136}
137
138// QuerySender sends the Query request. The method will close the
139// http.Response Body if it receives an error.
140func (client Client) QuerySender(req *http.Request) (*http.Response, error) {
141	return autorest.SendWithSender(client, req,
142		azure.DoRetryWithRegistration(client.Client))
143}
144
145// QueryResponder handles the response to the Query request. The method always
146// closes the http.Response Body.
147func (client Client) QueryResponder(resp *http.Response) (result QueryEntitiesResult, err error) {
148	if resp != nil && resp.Header != nil {
149		result.NextPartitionKey = resp.Header.Get("x-ms-continuation-NextPartitionKey")
150		result.NextRowKey = resp.Header.Get("x-ms-continuation-NextRowKey")
151	}
152
153	err = autorest.Respond(
154		resp,
155		client.ByInspecting(),
156		azure.WithErrorUnlessStatusCode(http.StatusOK),
157		autorest.ByUnmarshallingJSON(&result),
158		autorest.ByClosing())
159	result.Response = autorest.Response{Response: resp}
160
161	return
162}
163