diff --git a/sdk/tables/aztables/CHANGELOG.md b/sdk/tables/aztables/CHANGELOG.md new file mode 100644 index 000000000000..b8c2e452d173 --- /dev/null +++ b/sdk/tables/aztables/CHANGELOG.md @@ -0,0 +1,3 @@ +# Release History + +## v0.1.0 (Unreleased) diff --git a/sdk/tables/aztables/LICENSE b/sdk/tables/aztables/LICENSE new file mode 100644 index 000000000000..d1ca00f20a89 --- /dev/null +++ b/sdk/tables/aztables/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE \ No newline at end of file diff --git a/sdk/tables/aztables/README.md b/sdk/tables/aztables/README.md new file mode 100644 index 000000000000..18eb9c67c656 --- /dev/null +++ b/sdk/tables/aztables/README.md @@ -0,0 +1,145 @@ +# Azure Tables client library for Go + +Azure Table storage is a service that stores large amounts of structured NoSQL data in the cloud, providing +a key/attribute store with a schema-less design. + +Azure Cosmos DB provides a Table API for applications that are written for Azure Table storage that need premium capabilities like: + +- Turnkey global distribution. +- Dedicated throughput worldwide. +- Single-digit millisecond latencies at the 99th percentile. +- Guaranteed high availability. +- Automatic secondary indexing. + +The Azure Tables client library can seamlessly target either Azure Table storage or Azure Cosmos DB table service endpoints with no code changes. + +## Getting started + +### Install the package +Install the Azure Tables client library for Go : + +### Prerequisites +* An [Azure subscription][azure_sub]. +* An existing Azure storage account or Azure Cosmos DB database with Azure Table API specified. + +If you need to create either of these, you can use the [Azure CLI][azure_cli]. + +#### Creating a storage account + +Create a storage account `mystorageaccount` in resource group `MyResourceGroup` +in the subscription `MySubscription` in the West US region. + + +#### Creating a Cosmos DB + +Create a Cosmos DB account `MyCosmosDBDatabaseAccount` in resource group `MyResourceGroup` +in the subscription `MySubscription` and a table named `MyTableName` in the account. + + +### Authenticate the Client + +Learn more about options for authentication _(including Connection Strings, Shared Key, and Shared Key Signatures)_ in our samples. + +## Key concepts + +- `TableServiceClient` - Client that provides methods to interact at the Table Service level such as creating, listing, and deleting tables +- `TableClient` - Client that provides methods to interact at an table entity level such as creating, querying, and deleting entities within a table. +- `Table` - Tables store data as collections of entities. +- `Entity` - Entities are similar to rows. An entity has a primary key and a set of properties. A property is a name value pair, similar to a column. + +Common uses of the Table service include: + +- Storing TBs of structured data capable of serving web scale applications +- Storing datasets that don't require complex joins, foreign keys, or stored procedures and can be de-normalized for fast access +- Quickly querying data using a clustered index +### Create the Table service client + +First, we need to construct a `TableServiceClient`. + +### Create an Azure table +Next, we can create a new table. + + +### Get an Azure table +The set of existing Azure tables can be queries using an OData filter. + + +### Delete an Azure table + +Individual tables can be deleted from the service. + + +### Create the Table client + +To interact with table entities, we must first construct a `TableClient`. + + +### Add table entities + +Let's define a new `TableEntity` so that we can add it to the table. + +Using the `TableClient` we can now add our new entity to the table. + + +### Query table entities + +To inspect the set of existing table entities, we can query the table using an OData filter. + + +If you prefer LINQ style query expressions, we can query the table using that syntax as well. + + +### Delete table entities + +If we no longer need our new table entity, it can be deleted. + + +## Troubleshooting + +When you interact with the Azure table library using the .NET SDK, errors returned by the service correspond to the same HTTP +status codes returned for [REST API][tables_rest] requests. + +For example, if you try to create a table that already exists, a `409` error is returned, indicating "Conflict". + + +### Setting up console logging + +The simplest way to see the logs is to enable the console logging. +To create an Azure SDK log listener that outputs messages to console use AzureEventSourceListener.CreateConsoleLogger method. + + +To learn more about other logging mechanisms see [here][logging]. + +## Next steps + +Get started with our [Table samples][table_client_samples]. + +## Known Issues + +A list of currently known issues relating to Cosmos DB table endpoints can be found [here](https://aka.ms/tablesknownissues). + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require +you to agree to a Contributor License Agreement (CLA) declaring that you have +the right to, and actually do, grant us the rights to use your contribution. For +details, visit [cla.microsoft.com][cla]. + +This project has adopted the [Microsoft Open Source Code of Conduct][coc]. +For more information see the [Code of Conduct FAQ][coc_faq] or contact +[opencode@microsoft.com][coc_contact] with any additional questions or comments. + + +[tables_rest]: https://docs.microsoft.com/rest/api/storageservices/table-service-rest-api +[azure_cli]: https://docs.microsoft.com/cli/azure +[azure_sub]: https://azure.microsoft.com/free/ +[table_client_nuget_package]: https://www.nuget.org/packages?q=Azure.Data.Tables +[table_client_samples]: https://github\.com/Azure/azure-sdk-for-go +[table_client_src]: https://github\.com/Azure/azure-sdk-for-go +[logging]: https://github\.com/Azure/azure-sdk-for-go +[cla]: https://cla.microsoft.com +[coc]: https://opensource.microsoft.com/codeofconduct/ +[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ +[coc_contact]: mailto:opencode@microsoft.com + +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Ftables%2FAzure.Data.Tables%2FREADME.png) diff --git a/sdk/tables/aztables/ci.yml b/sdk/tables/aztables/ci.yml new file mode 100644 index 000000000000..900004ccf8bc --- /dev/null +++ b/sdk/tables/aztables/ci.yml @@ -0,0 +1,15 @@ +# NOTE: Please refer to https://aka.ms/azsdk/engsys/ci-yaml before editing this file. +trigger: + paths: + include: + - sdk/tables/aztables/ + +pr: + paths: + include: + - sdk/tables/aztables/ + +stages: +- template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + ServiceDirectory: 'tables' \ No newline at end of file diff --git a/sdk/tables/aztables/go.mod b/sdk/tables/aztables/go.mod new file mode 100644 index 000000000000..a37066df4bb0 --- /dev/null +++ b/sdk/tables/aztables/go.mod @@ -0,0 +1,8 @@ +module github.com/Azure/azure-sdk-for-go/sdk/tables/aztables + +go 1.13 + +require ( + github.com/Azure/azure-sdk-for-go/sdk/azcore v0.14.1 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c +) diff --git a/sdk/tables/aztables/go.sum b/sdk/tables/aztables/go.sum new file mode 100644 index 000000000000..369497e547f8 --- /dev/null +++ b/sdk/tables/aztables/go.sum @@ -0,0 +1,23 @@ +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.14.1 h1:7JdDsau2B5IZc0d0CPvSMn8DxJ3GRBxtFS7OrZPIJdA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.14.1/go.mod h1:pElNP+u99BvCZD+0jOlhI9OC/NB2IDTOTGZOZH0Qhq8= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.5.0 h1:HG1ggl8L3ZkV/Ydanf7lKr5kkhhPGCpWdnr1J6v7cO4= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.5.0/go.mod h1:k4KbFSunV/+0hOHL1vyFaPsiYQ1Vmvy1TBpmtvCDLZM= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb h1:mUVeFHoDKis5nxCAzoAi7E8Ghb86EXh/RK6wtvJIqRY= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/sdk/tables/aztables/shared_policy_shared_key_credential.go b/sdk/tables/aztables/shared_policy_shared_key_credential.go new file mode 100644 index 000000000000..88745e14f667 --- /dev/null +++ b/sdk/tables/aztables/shared_policy_shared_key_credential.go @@ -0,0 +1,161 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package aztables + +import ( + "bytes" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "fmt" + "net/http" + "net/url" + "sort" + "strings" + "sync/atomic" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +// NewSharedKeyCredential creates an immutable SharedKeyCredential containing the +// storage account's name and either its primary or secondary key. +func NewSharedKeyCredential(accountName, accountKey string) (*SharedKeyCredential, error) { + c := SharedKeyCredential{accountName: accountName} + if err := c.SetAccountKey(accountKey); err != nil { + return nil, err + } + return &c, nil +} + +// SharedKeyCredential contains an account's name and its primary or secondary key. +// It is immutable making it shareable and goroutine-safe. +type SharedKeyCredential struct { + // Only the NewSharedKeyCredential method should set these; all other methods should treat them as read-only + accountName string + accountKey atomic.Value // []byte +} + +// AccountName returns the Storage account's name. +func (c *SharedKeyCredential) AccountName() string { + return c.accountName +} + +// SetAccountKey replaces the existing account key with the specified account key. +func (c *SharedKeyCredential) SetAccountKey(accountKey string) error { + bytes, err := base64.StdEncoding.DecodeString(accountKey) + if err != nil { + return fmt.Errorf("decode account key: %w", err) + } + c.accountKey.Store(bytes) + return nil +} + +// computeHMACSHA256 generates a hash signature for an HTTP request or for a SAS. +func (c *SharedKeyCredential) ComputeHMACSHA256(message string) (base64String string) { + h := hmac.New(sha256.New, c.accountKey.Load().([]byte)) + h.Write([]byte(message)) + return base64.StdEncoding.EncodeToString(h.Sum(nil)) +} + +func (c *SharedKeyCredential) buildStringToSign(req *http.Request) (string, error) { + // https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services + headers := req.Header + contentLength := headers.Get(azcore.HeaderContentLength) + if contentLength == "0" { + contentLength = "" + } + + canonicalizedResource, err := c.buildCanonicalizedResource(req.URL) + if err != nil { + return "", err + } + + stringToSign := strings.Join([]string{ + headers.Get(azcore.HeaderXmsDate), + canonicalizedResource, + }, "\n") + return stringToSign, nil +} + +func (c *SharedKeyCredential) buildCanonicalizedHeader(headers http.Header) string { + cm := map[string][]string{} + for k, v := range headers { + headerName := strings.TrimSpace(strings.ToLower(k)) + if strings.HasPrefix(headerName, "x-ms-") { + cm[headerName] = v // NOTE: the value must not have any whitespace around it. + } + } + if len(cm) == 0 { + return "" + } + + keys := make([]string, 0, len(cm)) + for key := range cm { + keys = append(keys, key) + } + sort.Strings(keys) + ch := bytes.NewBufferString("") + for i, key := range keys { + if i > 0 { + ch.WriteRune('\n') + } + ch.WriteString(key) + ch.WriteRune(':') + ch.WriteString(strings.Join(cm[key], ",")) + } + return string(ch.Bytes()) +} + +func (c *SharedKeyCredential) buildCanonicalizedResource(u *url.URL) (string, error) { + // https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services + cr := bytes.NewBufferString("/") + cr.WriteString(c.accountName) + + if len(u.Path) > 0 { + // Any portion of the CanonicalizedResource string that is derived from + // the resource's URI should be encoded exactly as it is in the URI. + // -- https://msdn.microsoft.com/en-gb/library/azure/dd179428.aspx + cr.WriteString(u.EscapedPath()) + } else { + // a slash is required to indicate the root path + cr.WriteString("/") + } + + // params is a map[string][]string; param name is key; params values is []string + params, err := url.ParseQuery(u.RawQuery) // Returns URL decoded values + if err != nil { + return "", fmt.Errorf("failed to parse query params: %w", err) + } + + if compVal, ok := params["comp"]; ok { + //do something here + cr.WriteString("?" + "comp=" + compVal[0]) + } + return string(cr.Bytes()), nil +} + +// AuthenticationPolicy implements the Credential interface on SharedKeyCredential. +func (c *SharedKeyCredential) AuthenticationPolicy(azcore.AuthenticationPolicyOptions) azcore.Policy { + return azcore.PolicyFunc(func(req *azcore.Request) (*azcore.Response, error) { + // Add a x-ms-date header if it doesn't already exist + if d := req.Request.Header.Get(azcore.HeaderXmsDate); d == "" { + req.Request.Header.Set(azcore.HeaderXmsDate, time.Now().UTC().Format(http.TimeFormat)) + } + stringToSign, err := c.buildStringToSign(req.Request) + if err != nil { + return nil, err + } + signature := c.ComputeHMACSHA256(stringToSign) + authHeader := strings.Join([]string{"SharedKeyLite ", c.AccountName(), ":", signature}, "") + req.Request.Header.Set(azcore.HeaderAuthorization, authHeader) + + response, err := req.Next() + if err != nil && response != nil && response.StatusCode == http.StatusForbidden { + // Service failed to authenticate request, log it + azcore.Log().Write(azcore.LogResponse, "===== HTTP Forbidden status, String-to-Sign:\n"+stringToSign+"\n===============================\n") + } + return response, err + }) +} diff --git a/sdk/tables/aztables/tableClient.go b/sdk/tables/aztables/tableClient.go new file mode 100644 index 000000000000..edc74ece6075 --- /dev/null +++ b/sdk/tables/aztables/tableClient.go @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package aztables + +import ( + "context" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +// A TableClient represents a URL to an Azure Storage blob; the blob may be a block blob, append blob, or page blob. +type TableClient struct { + client *tableClient + cred SharedKeyCredential +} + +// NewTableClient creates a TableClient object using the specified URL and request policy pipeline. +func NewTableClient(serviceURL string, cred azcore.Credential, options *TableClientOptions) (*TableClient, error) { + con := newConnection(serviceURL, cred, options.getConnectionOptions()) + + c, _ := cred.(*SharedKeyCredential) + + return &TableClient{client: &tableClient{con}, cred: *c}, nil +} + +// Create +func (t TableClient) Create(ctx context.Context, name string) (TableResponseResponse, error) { + resp, err := t.client.Create(ctx, TableProperties{&name}, nil, nil) + if resp == nil { + return TableResponseResponse{}, err + } else { + return resp.(TableResponseResponse), err + } +} + +// Delete +func (t TableClient) Delete(ctx context.Context, name string) (TableDeleteResponse, error) { + return t.client.Delete(ctx, name, nil) +} diff --git a/sdk/tables/aztables/tableClient_test.go b/sdk/tables/aztables/tableClient_test.go new file mode 100644 index 000000000000..0b76e48fd15d --- /dev/null +++ b/sdk/tables/aztables/tableClient_test.go @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package aztables + +import ( + chk "gopkg.in/check.v1" // go get gopkg.in/check.v1 +) + +func (s *aztestsSuite) TestContainerCreateAccessContainer(c *chk.C) { + // TODO +} diff --git a/sdk/tables/aztables/zc_client_options.go b/sdk/tables/aztables/zc_client_options.go new file mode 100644 index 000000000000..cf24278fd2d2 --- /dev/null +++ b/sdk/tables/aztables/zc_client_options.go @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package aztables + +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +type TableClientOptions struct { + // HTTPClient sets the transport for making HTTP requests. + HTTPClient azcore.Transport + // Retry configures the built-in retry policy behavior. + Retry azcore.RetryOptions + // Telemetry configures the built-in telemetry policy behavior. + Telemetry azcore.TelemetryOptions +} + +func (o *TableClientOptions) getConnectionOptions() *connectionOptions { + if o == nil { + return nil + } + + return &connectionOptions{ + HTTPClient: o.HTTPClient, + Retry: o.Retry, + Telemetry: o.Telemetry, + } +} \ No newline at end of file diff --git a/sdk/tables/aztables/zt_test.go b/sdk/tables/aztables/zt_test.go new file mode 100644 index 000000000000..c9e649bca203 --- /dev/null +++ b/sdk/tables/aztables/zt_test.go @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package aztables + +import ( + "context" + "errors" + "fmt" + "os" + "testing" + "time" + + chk "gopkg.in/check.v1" +) + +// For testing docs, see: https://labix.org/gocheck +// To test a specific test: go test -check.f MyTestSuite + +// Hookup to the testing framework +func Test(t *testing.T) { chk.TestingT(t) } + +type aztestsSuite struct{} + +var _ = chk.Suite(&aztestsSuite{}) + +const ( + storageAccountNameEnvVar = "TABLES_STORAGE_ACCOUNT_NAME" + cosmosAccountNameEnnVar = "TABLES_COSMOS_ACCOUNT_NAME" + accountKeyEnvVar = "TABLES_PRIMARY_STORAGE_ACCOUNT_KEY" + storageEndpointSuffixEnvVar = "STORAGE_ENDPOINT_SUFFIX" + cosmosEndpointSuffixEnvVar = "COSMOS_TABLES_ENDPOINT_SUFFIX" + storageAccountKeyEnvVar = "TABLES_PRIMARY_STORAGE_ACCOUNT_KEY" + cosmosAccountKeyEnvVar = "TABLES_PRIMARY_COSMOS_ACCOUNT_KEY" + tableNamePrefix = "gotable" + DefaultStorageSuffix = "core.windows.net" + DefaultCosmosSuffix = "cosmos.azure.com" +) + +type EndpointType string + +const ( + StorageEndpoint EndpointType = "storage" + CosmosEndpoint EndpointType = "cosmos" +) + +var ctx = context.Background() + +func getRequiredEnv(name string) string { + env, ok := os.LookupEnv(name) + if ok { + return env + } else { + panic("Required environment variable not set: " + name) + } +} + +func storageURI() string { + return "https://" + storageAccountName() + ".table." + storageEndpointSuffix() +} + +func cosmosURI() string { + return "https://" + cosmosAccountName() + ".table" + cosmosAccountName() +} + +func storageAccountName() string { + return getRequiredEnv(storageAccountNameEnvVar) +} + +func cosmosAccountName() string { + return getRequiredEnv(cosmosAccountNameEnnVar) +} + +func cosmosAccountKey() string { + return getRequiredEnv(cosmosAccountKeyEnvVar) +} + +func storageAccountKey() string { + return getRequiredEnv(storageAccountKeyEnvVar) +} + +func storageEndpointSuffix() string { + suffix, ok := os.LookupEnv(storageEndpointSuffixEnvVar) + if ok { + return suffix + } else { + return DefaultStorageSuffix + } +} + +func cosmosEndpointSuffix() string { + suffix, ok := os.LookupEnv(cosmosEndpointSuffix()) + if ok { + return suffix + } else { + return DefaultCosmosSuffix + } +} + +func createTableClient(endpointType EndpointType) (*TableClient, error) { + if endpointType == StorageEndpoint { + storageCred, _ := NewSharedKeyCredential(storageAccountName(), storageAccountKey()) + return NewTableClient(storageURI(), storageCred, nil) + } else { + cosmosCred, _ := NewSharedKeyCredential(cosmosAccountName(), cosmosAccountKey()) + return NewTableClient(cosmosURI(), cosmosCred, nil) + } +} + +func getGenericCredential(accountType string) (*SharedKeyCredential, error) { + + accountName, accountKey := getRequiredEnv(storageAccountNameEnvVar), getRequiredEnv(accountKeyEnvVar) + if accountName == "" || accountKey == "" { + return nil, errors.New(storageAccountNameEnvVar + " and/or " + accountKeyEnvVar + " environment variables not specified.") + } + return NewSharedKeyCredential(accountName, accountKey) +} + +func generateName() string { + currentTime := time.Now() + name := fmt.Sprintf("%s%d%d%d", tableNamePrefix, currentTime.Minute(), currentTime.Second(), currentTime.Nanosecond()) + return name +} diff --git a/sdk/tables/aztables/zz_generated_connection.go b/sdk/tables/aztables/zz_generated_connection.go new file mode 100644 index 000000000000..990122c2b6e3 --- /dev/null +++ b/sdk/tables/aztables/zz_generated_connection.go @@ -0,0 +1,73 @@ +// +build go1.13 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package aztables + +import ( + "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +const scope = "foo" +const telemetryInfo = "azsdk-go-tables/" +// connectionOptions contains configuration settings for the connection's pipeline. +// All zero-value fields will be initialized with their default values. +type connectionOptions struct { + // HTTPClient sets the transport for making HTTP requests. + HTTPClient azcore.Transport + // Retry configures the built-in retry policy behavior. + Retry azcore.RetryOptions + // Telemetry configures the built-in telemetry policy behavior. + Telemetry azcore.TelemetryOptions + // Logging configures the built-in logging policy behavior. + Logging azcore.LogOptions +} + +func (c *connectionOptions) telemetryOptions() *azcore.TelemetryOptions { + to := c.Telemetry + if to.Value == "" { + to.Value = telemetryInfo + } else { + to.Value = fmt.Sprintf("%s %s", telemetryInfo, to.Value) + } + return &to +} + +type connection struct { + u string + p azcore.Pipeline +} + +// newConnection creates an instance of the connection type with the specified endpoint. +// Pass nil to accept the default options; this is the same as passing a zero-value options. +func newConnection(endpoint string, cred azcore.Credential, options *connectionOptions) *connection { + if options == nil { + options = &connectionOptions{} + } + p := azcore.NewPipeline(options.HTTPClient, + azcore.NewTelemetryPolicy(options.telemetryOptions()), + azcore.NewRetryPolicy(&options.Retry), + cred.AuthenticationPolicy(azcore.AuthenticationPolicyOptions{Options: azcore.TokenRequestOptions{Scopes: []string{scope}}}), + azcore.NewLogPolicy(&options.Logging)) + return newConnectionWithPipeline(endpoint, p) +} + +// newConnectionWithPipeline creates an instance of the connection type with the specified endpoint and pipeline. +func newConnectionWithPipeline(endpoint string, p azcore.Pipeline) *connection { + return &connection{u: endpoint, p: p} +} + +// Endpoint returns the connection's endpoint. +func (c *connection) Endpoint() string { + return c.u +} + +// Pipeline returns the connection's pipeline. +func (c *connection) Pipeline() (azcore.Pipeline) { + return c.p +} + diff --git a/sdk/tables/aztables/zz_generated_constants.go b/sdk/tables/aztables/zz_generated_constants.go new file mode 100644 index 000000000000..f117e6efcbe9 --- /dev/null +++ b/sdk/tables/aztables/zz_generated_constants.go @@ -0,0 +1,73 @@ +// +build go1.13 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package aztables + +// GeoReplicationStatusType - The status of the secondary location. +type GeoReplicationStatusType string + +const ( + GeoReplicationStatusTypeBootstrap GeoReplicationStatusType = "bootstrap" + GeoReplicationStatusTypeLive GeoReplicationStatusType = "live" + GeoReplicationStatusTypeUnavailable GeoReplicationStatusType = "unavailable" +) + +// PossibleGeoReplicationStatusTypeValues returns the possible values for the GeoReplicationStatusType const type. +func PossibleGeoReplicationStatusTypeValues() []GeoReplicationStatusType { + return []GeoReplicationStatusType{ + GeoReplicationStatusTypeBootstrap, + GeoReplicationStatusTypeLive, + GeoReplicationStatusTypeUnavailable, + } +} + +// ToPtr() returns a *GeoReplicationStatusType pointing to the current value. +func (c GeoReplicationStatusType) ToPtr() *GeoReplicationStatusType { + return &c +} + +type OdataMetadataFormat string + +const ( + OdataMetadataFormatApplicationJSONOdataFullmetadata OdataMetadataFormat = "application/json;odata=fullmetadata" + OdataMetadataFormatApplicationJSONOdataMinimalmetadata OdataMetadataFormat = "application/json;odata=minimalmetadata" + OdataMetadataFormatApplicationJSONOdataNometadata OdataMetadataFormat = "application/json;odata=nometadata" +) + +// PossibleOdataMetadataFormatValues returns the possible values for the OdataMetadataFormat const type. +func PossibleOdataMetadataFormatValues() []OdataMetadataFormat { + return []OdataMetadataFormat{ + OdataMetadataFormatApplicationJSONOdataFullmetadata, + OdataMetadataFormatApplicationJSONOdataMinimalmetadata, + OdataMetadataFormatApplicationJSONOdataNometadata, + } +} + +// ToPtr() returns a *OdataMetadataFormat pointing to the current value. +func (c OdataMetadataFormat) ToPtr() *OdataMetadataFormat { + return &c +} + +type ResponseFormat string + +const ( + ResponseFormatReturnContent ResponseFormat = "return-content" + ResponseFormatReturnNoContent ResponseFormat = "return-no-content" +) + +// PossibleResponseFormatValues returns the possible values for the ResponseFormat const type. +func PossibleResponseFormatValues() []ResponseFormat { + return []ResponseFormat{ + ResponseFormatReturnContent, + ResponseFormatReturnNoContent, + } +} + +// ToPtr() returns a *ResponseFormat pointing to the current value. +func (c ResponseFormat) ToPtr() *ResponseFormat { + return &c +} diff --git a/sdk/tables/aztables/zz_generated_models.go b/sdk/tables/aztables/zz_generated_models.go new file mode 100644 index 000000000000..00bbe531834a --- /dev/null +++ b/sdk/tables/aztables/zz_generated_models.go @@ -0,0 +1,741 @@ +// +build go1.13 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package aztables + +import ( + "encoding/xml" + "fmt" + "net/http" + "time" +) + +// An Access policy. +type AccessPolicy struct { + // The datetime that the policy expires. + Expiry *time.Time `xml:"Expiry"` + + // The permissions for the acl policy. + Permission *string `xml:"Permission"` + + // The start datetime from which the policy is active. + Start *time.Time `xml:"Start"` +} + +// MarshalXML implements the xml.Marshaller interface for type AccessPolicy. +func (a AccessPolicy) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type alias AccessPolicy + aux := &struct { + *alias + Expiry *timeRFC3339 `xml:"Expiry"` + Start *timeRFC3339 `xml:"Start"` + }{ + alias: (*alias)(&a), + Expiry: (*timeRFC3339)(a.Expiry), + Start: (*timeRFC3339)(a.Start), + } + return e.EncodeElement(aux, start) +} + +// UnmarshalXML implements the xml.Unmarshaller interface for type AccessPolicy. +func (a *AccessPolicy) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type alias AccessPolicy + aux := &struct { + *alias + Expiry *timeRFC3339 `xml:"Expiry"` + Start *timeRFC3339 `xml:"Start"` + }{ + alias: (*alias)(a), + } + if err := d.DecodeElement(aux, &start); err != nil { + return err + } + a.Expiry = (*time.Time)(aux.Expiry) + a.Start = (*time.Time)(aux.Start) + return nil +} + +// CORS is an HTTP feature that enables a web application running under one domain to access resources in another domain. Web browsers implement a security +// restriction known as same-origin policy that +// prevents a web page from calling APIs in a different domain; CORS provides a secure way to allow one domain (the origin domain) to call APIs in another +// domain. +type CorsRule struct { + // The request headers that the origin domain may specify on the CORS request. + AllowedHeaders *string `xml:"AllowedHeaders"` + + // The methods (HTTP request verbs) that the origin domain may use for a CORS request. (comma separated) + AllowedMethods *string `xml:"AllowedMethods"` + + // The origin domains that are permitted to make a request against the service via CORS. The origin domain is the domain from which the request originates. + // Note that the origin must be an exact + // case-sensitive match with the origin that the user age sends to the service. You can also use the wildcard character '*' to allow all origin domains + // to make requests via CORS. + AllowedOrigins *string `xml:"AllowedOrigins"` + + // The response headers that may be sent in the response to the CORS request and exposed by the browser to the request issuer. + ExposedHeaders *string `xml:"ExposedHeaders"` + + // The maximum amount time that a browser should cache the preflight OPTIONS request. + MaxAgeInSeconds *int32 `xml:"MaxAgeInSeconds"` +} + +type GeoReplication struct { + // A GMT date/time value, to the second. All primary writes preceding this value are guaranteed to be available for read operations at the secondary. Primary + // writes after this point in time may or may + // not be available for reads. + LastSyncTime *time.Time `xml:"LastSyncTime"` + + // The status of the secondary location. + Status *GeoReplicationStatusType `xml:"Status"` +} + +// MarshalXML implements the xml.Marshaller interface for type GeoReplication. +func (g GeoReplication) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type alias GeoReplication + aux := &struct { + *alias + LastSyncTime *timeRFC1123 `xml:"LastSyncTime"` + }{ + alias: (*alias)(&g), + LastSyncTime: (*timeRFC1123)(g.LastSyncTime), + } + return e.EncodeElement(aux, start) +} + +// UnmarshalXML implements the xml.Unmarshaller interface for type GeoReplication. +func (g *GeoReplication) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type alias GeoReplication + aux := &struct { + *alias + LastSyncTime *timeRFC1123 `xml:"LastSyncTime"` + }{ + alias: (*alias)(g), + } + if err := d.DecodeElement(aux, &start); err != nil { + return err + } + g.LastSyncTime = (*time.Time)(aux.LastSyncTime) + return nil +} + +// Azure Analytics Logging settings. +type Logging struct { + // Indicates whether all delete requests should be logged. + Delete *bool `xml:"Delete"` + + // Indicates whether all read requests should be logged. + Read *bool `xml:"Read"` + + // The retention policy. + RetentionPolicy *RetentionPolicy `xml:"RetentionPolicy"` + + // The version of Analytics to configure. + Version *string `xml:"Version"` + + // Indicates whether all write requests should be logged. + Write *bool `xml:"Write"` +} + +// MapOfInterfaceResponse is the response envelope for operations that return a map[string]interface{} type. +type MapOfInterfaceResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // ContentType contains the information returned from the Content-Type header response. + ContentType *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // ETag contains the information returned from the ETag header response. + ETag *string + + // PreferenceApplied contains the information returned from the Preference-Applied header response. + PreferenceApplied *string + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // The other properties of the table entity. + Value map[string]interface{} + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + +type Metrics struct { + // Indicates whether metrics are enabled for the Table service. + Enabled *bool `xml:"Enabled"` + + // Indicates whether metrics should generate summary statistics for called API operations. + IncludeAPIs *bool `xml:"IncludeAPIs"` + + // The retention policy. + RetentionPolicy *RetentionPolicy `xml:"RetentionPolicy"` + + // The version of Analytics to configure. + Version *string `xml:"Version"` +} + +// QueryOptions contains a group of parameters for the Table.Query method. +type QueryOptions struct { + // OData filter expression. + Filter *string + // Specifies the media type for the response. + Format *OdataMetadataFormat + // Select expression using OData notation. Limits the columns on each record to just those requested, e.g. "$select=PolicyAssignmentId, ResourceId". + Select *string + // Maximum number of records to return. + Top *int32 +} + +// The retention policy. +type RetentionPolicy struct { + // Indicates the number of days that metrics or logging or soft-deleted data should be retained. All data older than this value will be deleted. + Days *int32 `xml:"Days"` + + // Indicates whether a retention policy is enabled for the service. + Enabled *bool `xml:"Enabled"` +} + +// ServiceGetPropertiesOptions contains the optional parameters for the Service.GetProperties method. +type ServiceGetPropertiesOptions struct { + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// ServiceGetStatisticsOptions contains the optional parameters for the Service.GetStatistics method. +type ServiceGetStatisticsOptions struct { + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// ServiceSetPropertiesOptions contains the optional parameters for the Service.SetProperties method. +type ServiceSetPropertiesOptions struct { + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// ServiceSetPropertiesResponse contains the response from method Service.SetProperties. +type ServiceSetPropertiesResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + +// A signed identifier. +type SignedIdentifier struct { + // The access policy. + AccessPolicy *AccessPolicy `xml:"AccessPolicy"` + + // A unique id. + ID *string `xml:"Id"` +} + +// SignedIdentifierArrayResponse is the response envelope for operations that return a []SignedIdentifier type. +type SignedIdentifierArrayResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string `xml:"ClientRequestID"` + + // Date contains the information returned from the Date header response. + Date *time.Time `xml:"Date"` + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string `xml:"RequestID"` + + // A collection of signed identifiers. + SignedIdentifiers []SignedIdentifier `xml:"SignedIdentifier"` + + // Version contains the information returned from the x-ms-version header response. + Version *string `xml:"Version"` +} + +// TableCreateOptions contains the optional parameters for the Table.Create method. +type TableCreateOptions struct { + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // Specifies whether the response should include the inserted entity in the payload. Possible values are return-no-content and return-content. + ResponsePreference *ResponseFormat +} + +// TableCreateResponse contains the response from method Table.Create. +type TableCreateResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // PreferenceApplied contains the information returned from the Preference-Applied header response. + PreferenceApplied *string + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + +// TableDeleteEntityOptions contains the optional parameters for the Table.DeleteEntity method. +type TableDeleteEntityOptions struct { + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// TableDeleteEntityResponse contains the response from method Table.DeleteEntity. +type TableDeleteEntityResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + +// TableDeleteOptions contains the optional parameters for the Table.Delete method. +type TableDeleteOptions struct { + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string +} + +// TableDeleteResponse contains the response from method Table.Delete. +type TableDeleteResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + +// The properties for the table entity query response. +type TableEntityQueryResponse struct { + // The metadata response of the table. + OdataMetadata *string `json:"odata.metadata,omitempty"` + + // List of table entities. + Value *[]map[string]interface{} `json:"value,omitempty"` +} + +// TableEntityQueryResponseResponse is the response envelope for operations that return a TableEntityQueryResponse type. +type TableEntityQueryResponseResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // ETag contains the information returned from the ETag header response. + ETag *string + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // The properties for the table entity query response. + TableEntityQueryResponse *TableEntityQueryResponse + + // Version contains the information returned from the x-ms-version header response. + Version *string + + // XMSContinuationNextPartitionKey contains the information returned from the x-ms-continuation-NextPartitionKey header response. + XMSContinuationNextPartitionKey *string + + // XMSContinuationNextRowKey contains the information returned from the x-ms-continuation-NextRowKey header response. + XMSContinuationNextRowKey *string +} + +// TableGetAccessPolicyOptions contains the optional parameters for the Table.GetAccessPolicy method. +type TableGetAccessPolicyOptions struct { + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// TableInsertEntityOptions contains the optional parameters for the Table.InsertEntity method. +type TableInsertEntityOptions struct { + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // Specifies whether the response should include the inserted entity in the payload. Possible values are return-no-content and return-content. + ResponsePreference *ResponseFormat + // The properties for the table entity. + TableEntityProperties *map[string]interface{} + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// TableInsertEntityResponse contains the response from method Table.InsertEntity. +type TableInsertEntityResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // ContentType contains the information returned from the Content-Type header response. + ContentType *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // ETag contains the information returned from the ETag header response. + ETag *string + + // PreferenceApplied contains the information returned from the Preference-Applied header response. + PreferenceApplied *string + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + +// TableMergeEntityOptions contains the optional parameters for the Table.MergeEntity method. +type TableMergeEntityOptions struct { + // Match condition for an entity to be updated. If specified and a matching entity is not found, an error will be raised. To force an unconditional update, + // set to the wildcard character (*). If not specified, an insert will be performed when no existing entity is found to update and a merge will be performed + // if an existing entity is found. + IfMatch *string + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // The properties for the table entity. + TableEntityProperties *map[string]interface{} + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// TableMergeEntityResponse contains the response from method Table.MergeEntity. +type TableMergeEntityResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // ETag contains the information returned from the ETag header response. + ETag *string + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + +// The properties for creating a table. +type TableProperties struct { + // The name of the table to create. + TableName *string `json:"TableName,omitempty"` +} + +// TableQueryEntitiesOptions contains the optional parameters for the Table.QueryEntities method. +type TableQueryEntitiesOptions struct { + // An entity query continuation token from a previous call. + NextPartitionKey *string + // An entity query continuation token from a previous call. + NextRowKey *string + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// TableQueryEntitiesWithPartitionAndRowKeyOptions contains the optional parameters for the Table.QueryEntitiesWithPartitionAndRowKey method. +type TableQueryEntitiesWithPartitionAndRowKeyOptions struct { + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// TableQueryOptions contains the optional parameters for the Table.Query method. +type TableQueryOptions struct { + // A table query continuation token from a previous call. + NextTableName *string + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string +} + +// The properties for the table query response. +type TableQueryResponse struct { + // The metadata response of the table. + OdataMetadata *string `json:"odata.metadata,omitempty"` + + // List of tables. + Value *[]TableResponseProperties `json:"value,omitempty"` +} + +// TableQueryResponseResponse is the response envelope for operations that return a TableQueryResponse type. +type TableQueryResponseResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // The properties for the table query response. + TableQueryResponse *TableQueryResponse + + // Version contains the information returned from the x-ms-version header response. + Version *string + + // XMSContinuationNextTableName contains the information returned from the x-ms-continuation-NextTableName header response. + XMSContinuationNextTableName *string +} + +// The response for a single table. +type TableResponse struct { + TableResponseProperties + // The metadata response of the table. + OdataMetadata *string `json:"odata.metadata,omitempty"` +} + +// The properties for the table response. +type TableResponseProperties struct { + // The edit link of the table. + OdataEditLink *string `json:"odata.editLink,omitempty"` + + // The id of the table. + OdataID *string `json:"odata.id,omitempty"` + + // The odata type of the table. + OdataType *string `json:"odata.type,omitempty"` + + // The name of the table. + TableName *string `json:"TableName,omitempty"` +} + +// TableResponseResponse is the response envelope for operations that return a TableResponse type. +type TableResponseResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // PreferenceApplied contains the information returned from the Preference-Applied header response. + PreferenceApplied *string + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // The response for a single table. + TableResponse *TableResponse + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + +// Table Service error. +type TableServiceError struct { + // The error message. + Message *string `json:"Message,omitempty"` +} + +// Error implements the error interface for type TableServiceError. +func (e TableServiceError) Error() string { + msg := "" + if e.Message != nil { + msg += fmt.Sprintf("Message: %v\n", *e.Message) + } + if msg == "" { + msg = "missing error info" + } + return msg +} + +// Table Service Properties. +type TableServiceProperties struct { + // The set of CORS rules. + Cors *[]CorsRule `xml:"Cors>CorsRule"` + + // A summary of request statistics grouped by API in hourly aggregates for tables. + HourMetrics *Metrics `xml:"HourMetrics"` + + // Azure Analytics Logging settings. + Logging *Logging `xml:"Logging"` + + // A summary of request statistics grouped by API in minute aggregates for tables. + MinuteMetrics *Metrics `xml:"MinuteMetrics"` +} + +// MarshalXML implements the xml.Marshaller interface for type TableServiceProperties. +func (t TableServiceProperties) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + start.Name.Local = "StorageServiceProperties" + type alias TableServiceProperties + aux := &struct { + *alias + }{ + alias: (*alias)(&t), + } + return e.EncodeElement(aux, start) +} + +// TableServicePropertiesResponse is the response envelope for operations that return a TableServiceProperties type. +type TableServicePropertiesResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string `xml:"ClientRequestID"` + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string `xml:"RequestID"` + + // Table Service Properties. + StorageServiceProperties *TableServiceProperties `xml:"StorageServiceProperties"` + + // Version contains the information returned from the x-ms-version header response. + Version *string `xml:"Version"` +} + +// Stats for the service. +type TableServiceStats struct { + // Geo-Replication information for the Secondary Storage Service. + GeoReplication *GeoReplication `xml:"GeoReplication"` +} + +// TableServiceStatsResponse is the response envelope for operations that return a TableServiceStats type. +type TableServiceStatsResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string `xml:"ClientRequestID"` + + // Date contains the information returned from the Date header response. + Date *time.Time `xml:"Date"` + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string `xml:"RequestID"` + + // Stats for the service. + StorageServiceStats *TableServiceStats `xml:"StorageServiceStats"` + + // Version contains the information returned from the x-ms-version header response. + Version *string `xml:"Version"` +} + +// TableSetAccessPolicyOptions contains the optional parameters for the Table.SetAccessPolicy method. +type TableSetAccessPolicyOptions struct { + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // The acls for the table. + TableACL *[]SignedIdentifier + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// TableSetAccessPolicyResponse contains the response from method Table.SetAccessPolicy. +type TableSetAccessPolicyResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + +// TableUpdateEntityOptions contains the optional parameters for the Table.UpdateEntity method. +type TableUpdateEntityOptions struct { + // Match condition for an entity to be updated. If specified and a matching entity is not found, an error will be raised. To force an unconditional update, + // set to the wildcard character (*). If not specified, an insert will be performed when no existing entity is found to update and a replace will be performed + // if an existing entity is found. + IfMatch *string + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when analytics logging is enabled. + RequestID *string + // The properties for the table entity. + TableEntityProperties *map[string]interface{} + // The timeout parameter is expressed in seconds. + Timeout *int32 +} + +// TableUpdateEntityResponse contains the response from method Table.UpdateEntity. +type TableUpdateEntityResponse struct { + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string + + // Date contains the information returned from the Date header response. + Date *time.Time + + // ETag contains the information returned from the ETag header response. + ETag *string + + // RawResponse contains the underlying HTTP response. + RawResponse *http.Response + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // Version contains the information returned from the x-ms-version header response. + Version *string +} diff --git a/sdk/tables/aztables/zz_generated_service.go b/sdk/tables/aztables/zz_generated_service.go new file mode 100644 index 000000000000..182f446e1484 --- /dev/null +++ b/sdk/tables/aztables/zz_generated_service.go @@ -0,0 +1,224 @@ +// +build go1.13 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package aztables + +import ( + "context" + "net/http" + "strconv" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +type serviceClient struct { + con *connection +} + +// GetProperties - Gets the properties of an account's Table service, including properties for Analytics and CORS (Cross-Origin Resource Sharing) rules. +func (client *serviceClient) GetProperties(ctx context.Context, options *ServiceGetPropertiesOptions) (TableServicePropertiesResponse, error) { + req, err := client.getPropertiesCreateRequest(ctx, options) + if err != nil { + return TableServicePropertiesResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return TableServicePropertiesResponse{}, err + } + if !resp.HasStatusCode(http.StatusOK) { + return TableServicePropertiesResponse{}, client.getPropertiesHandleError(resp) + } + return client.getPropertiesHandleResponse(resp) +} + +// getPropertiesCreateRequest creates the GetProperties request. +func (client *serviceClient) getPropertiesCreateRequest(ctx context.Context, options *ServiceGetPropertiesOptions) (*azcore.Request, error) { + req, err := azcore.NewRequest(ctx, http.MethodGet, client.con.Endpoint()) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + query.Set("restype", "service") + query.Set("comp", "properties") + if options != nil && options.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if options != nil && options.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *options.RequestID) + } + req.Header.Set("Accept", "application/xml") + return req, nil +} + +// getPropertiesHandleResponse handles the GetProperties response. +func (client *serviceClient) getPropertiesHandleResponse(resp *azcore.Response) (TableServicePropertiesResponse, error) { + var val *TableServiceProperties + if err := resp.UnmarshalAsXML(&val); err != nil { + return TableServicePropertiesResponse{}, err + } + result := TableServicePropertiesResponse{RawResponse: resp.Response, StorageServiceProperties: val} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + return result, nil +} + +// getPropertiesHandleError handles the GetProperties error response. +func (client *serviceClient) getPropertiesHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// GetStatistics - Retrieves statistics related to replication for the Table service. It is only available on the secondary location endpoint when read-access +// geo-redundant replication is enabled for the account. +func (client *serviceClient) GetStatistics(ctx context.Context, options *ServiceGetStatisticsOptions) (TableServiceStatsResponse, error) { + req, err := client.getStatisticsCreateRequest(ctx, options) + if err != nil { + return TableServiceStatsResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return TableServiceStatsResponse{}, err + } + if !resp.HasStatusCode(http.StatusOK) { + return TableServiceStatsResponse{}, client.getStatisticsHandleError(resp) + } + return client.getStatisticsHandleResponse(resp) +} + +// getStatisticsCreateRequest creates the GetStatistics request. +func (client *serviceClient) getStatisticsCreateRequest(ctx context.Context, options *ServiceGetStatisticsOptions) (*azcore.Request, error) { + req, err := azcore.NewRequest(ctx, http.MethodGet, client.con.Endpoint()) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + query.Set("restype", "service") + query.Set("comp", "stats") + if options != nil && options.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if options != nil && options.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *options.RequestID) + } + req.Header.Set("Accept", "application/xml") + return req, nil +} + +// getStatisticsHandleResponse handles the GetStatistics response. +func (client *serviceClient) getStatisticsHandleResponse(resp *azcore.Response) (TableServiceStatsResponse, error) { + var val *TableServiceStats + if err := resp.UnmarshalAsXML(&val); err != nil { + return TableServiceStatsResponse{}, err + } + result := TableServiceStatsResponse{RawResponse: resp.Response, StorageServiceStats: val} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableServiceStatsResponse{}, err + } + result.Date = &date + } + return result, nil +} + +// getStatisticsHandleError handles the GetStatistics error response. +func (client *serviceClient) getStatisticsHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// SetProperties - Sets properties for an account's Table service endpoint, including properties for Analytics and CORS (Cross-Origin Resource Sharing) +// rules. +func (client *serviceClient) SetProperties(ctx context.Context, tableServiceProperties TableServiceProperties, options *ServiceSetPropertiesOptions) (ServiceSetPropertiesResponse, error) { + req, err := client.setPropertiesCreateRequest(ctx, tableServiceProperties, options) + if err != nil { + return ServiceSetPropertiesResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return ServiceSetPropertiesResponse{}, err + } + if !resp.HasStatusCode(http.StatusAccepted) { + return ServiceSetPropertiesResponse{}, client.setPropertiesHandleError(resp) + } + return client.setPropertiesHandleResponse(resp) +} + +// setPropertiesCreateRequest creates the SetProperties request. +func (client *serviceClient) setPropertiesCreateRequest(ctx context.Context, tableServiceProperties TableServiceProperties, options *ServiceSetPropertiesOptions) (*azcore.Request, error) { + req, err := azcore.NewRequest(ctx, http.MethodPut, client.con.Endpoint()) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + query.Set("restype", "service") + query.Set("comp", "properties") + if options != nil && options.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if options != nil && options.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *options.RequestID) + } + req.Header.Set("Accept", "application/xml") + return req, req.MarshalAsXML(tableServiceProperties) +} + +// setPropertiesHandleResponse handles the SetProperties response. +func (client *serviceClient) setPropertiesHandleResponse(resp *azcore.Response) (ServiceSetPropertiesResponse, error) { + result := ServiceSetPropertiesResponse{RawResponse: resp.Response} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + return result, nil +} + +// setPropertiesHandleError handles the SetProperties error response. +func (client *serviceClient) setPropertiesHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} diff --git a/sdk/tables/aztables/zz_generated_table.go b/sdk/tables/aztables/zz_generated_table.go new file mode 100644 index 000000000000..b7bf3cd8a88d --- /dev/null +++ b/sdk/tables/aztables/zz_generated_table.go @@ -0,0 +1,1004 @@ +// +build go1.13 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package aztables + +import ( + "context" + "encoding/xml" + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +type tableClient struct { + con *connection +} + +// Create - Creates a new table under the given account. +// Possible return types are *TableResponseResponse, *TableCreateResponse +func (client *tableClient) Create(ctx context.Context, tableProperties TableProperties, tableCreateOptions *TableCreateOptions, queryOptions *QueryOptions) (interface{}, error) { + req, err := client.createCreateRequest(ctx, tableProperties, tableCreateOptions, queryOptions) + if err != nil { + return nil, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return nil, err + } + if !resp.HasStatusCode(http.StatusCreated, http.StatusNoContent) { + return nil, client.createHandleError(resp) + } + return client.createHandleResponse(resp) +} + +// createCreateRequest creates the Create request. +func (client *tableClient) createCreateRequest(ctx context.Context, tableProperties TableProperties, tableCreateOptions *TableCreateOptions, queryOptions *QueryOptions) (*azcore.Request, error) { + urlPath := "/Tables" + req, err := azcore.NewRequest(ctx, http.MethodPost, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + if queryOptions != nil && queryOptions.Format != nil { + query.Set("$format", string(*queryOptions.Format)) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if tableCreateOptions != nil && tableCreateOptions.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *tableCreateOptions.RequestID) + } + req.Header.Set("DataServiceVersion", "3.0") + if tableCreateOptions != nil && tableCreateOptions.ResponsePreference != nil { + req.Header.Set("Prefer", string(*tableCreateOptions.ResponsePreference)) + } + req.Header.Set("Accept", "application/json;odata=minimalmetadata") + return req, req.MarshalAsJSON(tableProperties) +} + +// createHandleResponse handles the Create response. +func (client *tableClient) createHandleResponse(resp *azcore.Response) (interface{}, error) { + switch resp.StatusCode { + case http.StatusCreated: + var val *TableResponse + if err := resp.UnmarshalAsJSON(&val); err != nil { + return nil, err + } + result := TableResponseResponse{RawResponse: resp.Response, TableResponse: val} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableResponseResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("Preference-Applied"); val != "" { + result.PreferenceApplied = &val + } + return result, nil + case http.StatusNoContent: + result := TableCreateResponse{RawResponse: resp.Response} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableCreateResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("Preference-Applied"); val != "" { + result.PreferenceApplied = &val + } + return result, nil + default: + return nil, fmt.Errorf("unhandled HTTP status code %d", resp.StatusCode) + } +} + +// createHandleError handles the Create error response. +func (client *tableClient) createHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// Delete - Operation permanently deletes the specified table. +func (client *tableClient) Delete(ctx context.Context, table string, options *TableDeleteOptions) (TableDeleteResponse, error) { + req, err := client.deleteCreateRequest(ctx, table, options) + if err != nil { + return TableDeleteResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return TableDeleteResponse{}, err + } + if !resp.HasStatusCode(http.StatusNoContent) { + return TableDeleteResponse{}, client.deleteHandleError(resp) + } + return client.deleteHandleResponse(resp) +} + +// deleteCreateRequest creates the Delete request. +func (client *tableClient) deleteCreateRequest(ctx context.Context, table string, options *TableDeleteOptions) (*azcore.Request, error) { + urlPath := "/Tables('{table}')" + urlPath = strings.ReplaceAll(urlPath, "{table}", url.PathEscape(table)) + req, err := azcore.NewRequest(ctx, http.MethodDelete, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + req.Header.Set("x-ms-version", "2019-02-02") + if options != nil && options.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *options.RequestID) + } + req.Header.Set("Accept", "application/json") + return req, nil +} + +// deleteHandleResponse handles the Delete response. +func (client *tableClient) deleteHandleResponse(resp *azcore.Response) (TableDeleteResponse, error) { + result := TableDeleteResponse{RawResponse: resp.Response} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableDeleteResponse{}, err + } + result.Date = &date + } + return result, nil +} + +// deleteHandleError handles the Delete error response. +func (client *tableClient) deleteHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// DeleteEntity - Deletes the specified entity in a table. +func (client *tableClient) DeleteEntity(ctx context.Context, table string, partitionKey string, rowKey string, ifMatch string, tableDeleteEntityOptions *TableDeleteEntityOptions, queryOptions *QueryOptions) (TableDeleteEntityResponse, error) { + req, err := client.deleteEntityCreateRequest(ctx, table, partitionKey, rowKey, ifMatch, tableDeleteEntityOptions, queryOptions) + if err != nil { + return TableDeleteEntityResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return TableDeleteEntityResponse{}, err + } + if !resp.HasStatusCode(http.StatusNoContent) { + return TableDeleteEntityResponse{}, client.deleteEntityHandleError(resp) + } + return client.deleteEntityHandleResponse(resp) +} + +// deleteEntityCreateRequest creates the DeleteEntity request. +func (client *tableClient) deleteEntityCreateRequest(ctx context.Context, table string, partitionKey string, rowKey string, ifMatch string, tableDeleteEntityOptions *TableDeleteEntityOptions, queryOptions *QueryOptions) (*azcore.Request, error) { + urlPath := "/{table}(PartitionKey='{partitionKey}',RowKey='{rowKey}')" + urlPath = strings.ReplaceAll(urlPath, "{table}", url.PathEscape(table)) + urlPath = strings.ReplaceAll(urlPath, "{partitionKey}", url.PathEscape(partitionKey)) + urlPath = strings.ReplaceAll(urlPath, "{rowKey}", url.PathEscape(rowKey)) + req, err := azcore.NewRequest(ctx, http.MethodDelete, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + if tableDeleteEntityOptions != nil && tableDeleteEntityOptions.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*tableDeleteEntityOptions.Timeout), 10)) + } + if queryOptions != nil && queryOptions.Format != nil { + query.Set("$format", string(*queryOptions.Format)) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if tableDeleteEntityOptions != nil && tableDeleteEntityOptions.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *tableDeleteEntityOptions.RequestID) + } + req.Header.Set("DataServiceVersion", "3.0") + req.Header.Set("If-Match", ifMatch) + req.Header.Set("Accept", "application/json;odata=minimalmetadata") + return req, nil +} + +// deleteEntityHandleResponse handles the DeleteEntity response. +func (client *tableClient) deleteEntityHandleResponse(resp *azcore.Response) (TableDeleteEntityResponse, error) { + result := TableDeleteEntityResponse{RawResponse: resp.Response} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableDeleteEntityResponse{}, err + } + result.Date = &date + } + return result, nil +} + +// deleteEntityHandleError handles the DeleteEntity error response. +func (client *tableClient) deleteEntityHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// GetAccessPolicy - Retrieves details about any stored access policies specified on the table that may be used with Shared Access Signatures. +func (client *tableClient) GetAccessPolicy(ctx context.Context, table string, options *TableGetAccessPolicyOptions) (SignedIdentifierArrayResponse, error) { + req, err := client.getAccessPolicyCreateRequest(ctx, table, options) + if err != nil { + return SignedIdentifierArrayResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return SignedIdentifierArrayResponse{}, err + } + if !resp.HasStatusCode(http.StatusOK) { + return SignedIdentifierArrayResponse{}, client.getAccessPolicyHandleError(resp) + } + return client.getAccessPolicyHandleResponse(resp) +} + +// getAccessPolicyCreateRequest creates the GetAccessPolicy request. +func (client *tableClient) getAccessPolicyCreateRequest(ctx context.Context, table string, options *TableGetAccessPolicyOptions) (*azcore.Request, error) { + urlPath := "/{table}" + urlPath = strings.ReplaceAll(urlPath, "{table}", url.PathEscape(table)) + req, err := azcore.NewRequest(ctx, http.MethodGet, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + if options != nil && options.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) + } + query.Set("comp", "acl") + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if options != nil && options.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *options.RequestID) + } + req.Header.Set("Accept", "application/xml") + return req, nil +} + +// getAccessPolicyHandleResponse handles the GetAccessPolicy response. +func (client *tableClient) getAccessPolicyHandleResponse(resp *azcore.Response) (SignedIdentifierArrayResponse, error) { + result := SignedIdentifierArrayResponse{RawResponse: resp.Response} + if err := resp.UnmarshalAsXML(&result); err != nil { + return SignedIdentifierArrayResponse{}, err + } + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return SignedIdentifierArrayResponse{}, err + } + result.Date = &date + } + return result, nil +} + +// getAccessPolicyHandleError handles the GetAccessPolicy error response. +func (client *tableClient) getAccessPolicyHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// InsertEntity - Insert entity in a table. +// Possible return types are *MapOfInterfaceResponse, *TableInsertEntityResponse +func (client *tableClient) InsertEntity(ctx context.Context, table string, tableInsertEntityOptions *TableInsertEntityOptions, queryOptions *QueryOptions) (interface{}, error) { + req, err := client.insertEntityCreateRequest(ctx, table, tableInsertEntityOptions, queryOptions) + if err != nil { + return nil, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return nil, err + } + if !resp.HasStatusCode(http.StatusCreated, http.StatusNoContent) { + return nil, client.insertEntityHandleError(resp) + } + return client.insertEntityHandleResponse(resp) +} + +// insertEntityCreateRequest creates the InsertEntity request. +func (client *tableClient) insertEntityCreateRequest(ctx context.Context, table string, tableInsertEntityOptions *TableInsertEntityOptions, queryOptions *QueryOptions) (*azcore.Request, error) { + urlPath := "/{table}" + urlPath = strings.ReplaceAll(urlPath, "{table}", url.PathEscape(table)) + req, err := azcore.NewRequest(ctx, http.MethodPost, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + if tableInsertEntityOptions != nil && tableInsertEntityOptions.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*tableInsertEntityOptions.Timeout), 10)) + } + if queryOptions != nil && queryOptions.Format != nil { + query.Set("$format", string(*queryOptions.Format)) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if tableInsertEntityOptions != nil && tableInsertEntityOptions.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *tableInsertEntityOptions.RequestID) + } + req.Header.Set("DataServiceVersion", "3.0") + if tableInsertEntityOptions != nil && tableInsertEntityOptions.ResponsePreference != nil { + req.Header.Set("Prefer", string(*tableInsertEntityOptions.ResponsePreference)) + } + req.Header.Set("Accept", "application/json;odata=minimalmetadata") + if tableInsertEntityOptions != nil { + return req, req.MarshalAsJSON(tableInsertEntityOptions.TableEntityProperties) + } + return req, nil +} + +// insertEntityHandleResponse handles the InsertEntity response. +func (client *tableClient) insertEntityHandleResponse(resp *azcore.Response) (interface{}, error) { + switch resp.StatusCode { + case http.StatusCreated: + var val map[string]interface{} + if err := resp.UnmarshalAsJSON(&val); err != nil { + return nil, err + } + result := MapOfInterfaceResponse{RawResponse: resp.Response, Value: val} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return MapOfInterfaceResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("ETag"); val != "" { + result.ETag = &val + } + if val := resp.Header.Get("Preference-Applied"); val != "" { + result.PreferenceApplied = &val + } + if val := resp.Header.Get("Content-Type"); val != "" { + result.ContentType = &val + } + return result, nil + case http.StatusNoContent: + result := TableInsertEntityResponse{RawResponse: resp.Response} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableInsertEntityResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("ETag"); val != "" { + result.ETag = &val + } + if val := resp.Header.Get("Preference-Applied"); val != "" { + result.PreferenceApplied = &val + } + if val := resp.Header.Get("Content-Type"); val != "" { + result.ContentType = &val + } + return result, nil + default: + return nil, fmt.Errorf("unhandled HTTP status code %d", resp.StatusCode) + } +} + +// insertEntityHandleError handles the InsertEntity error response. +func (client *tableClient) insertEntityHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// MergeEntity - Merge entity in a table. +func (client *tableClient) MergeEntity(ctx context.Context, table string, partitionKey string, rowKey string, tableMergeEntityOptions *TableMergeEntityOptions, queryOptions *QueryOptions) (TableMergeEntityResponse, error) { + req, err := client.mergeEntityCreateRequest(ctx, table, partitionKey, rowKey, tableMergeEntityOptions, queryOptions) + if err != nil { + return TableMergeEntityResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return TableMergeEntityResponse{}, err + } + if !resp.HasStatusCode(http.StatusNoContent) { + return TableMergeEntityResponse{}, client.mergeEntityHandleError(resp) + } + return client.mergeEntityHandleResponse(resp) +} + +// mergeEntityCreateRequest creates the MergeEntity request. +func (client *tableClient) mergeEntityCreateRequest(ctx context.Context, table string, partitionKey string, rowKey string, tableMergeEntityOptions *TableMergeEntityOptions, queryOptions *QueryOptions) (*azcore.Request, error) { + urlPath := "/{table}(PartitionKey='{partitionKey}',RowKey='{rowKey}')" + urlPath = strings.ReplaceAll(urlPath, "{table}", url.PathEscape(table)) + urlPath = strings.ReplaceAll(urlPath, "{partitionKey}", url.PathEscape(partitionKey)) + urlPath = strings.ReplaceAll(urlPath, "{rowKey}", url.PathEscape(rowKey)) + req, err := azcore.NewRequest(ctx, http.MethodPatch, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + if tableMergeEntityOptions != nil && tableMergeEntityOptions.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*tableMergeEntityOptions.Timeout), 10)) + } + if queryOptions != nil && queryOptions.Format != nil { + query.Set("$format", string(*queryOptions.Format)) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if tableMergeEntityOptions != nil && tableMergeEntityOptions.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *tableMergeEntityOptions.RequestID) + } + req.Header.Set("DataServiceVersion", "3.0") + if tableMergeEntityOptions != nil && tableMergeEntityOptions.IfMatch != nil { + req.Header.Set("If-Match", *tableMergeEntityOptions.IfMatch) + } + req.Header.Set("Accept", "application/json") + if tableMergeEntityOptions != nil { + return req, req.MarshalAsJSON(tableMergeEntityOptions.TableEntityProperties) + } + return req, nil +} + +// mergeEntityHandleResponse handles the MergeEntity response. +func (client *tableClient) mergeEntityHandleResponse(resp *azcore.Response) (TableMergeEntityResponse, error) { + result := TableMergeEntityResponse{RawResponse: resp.Response} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableMergeEntityResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("ETag"); val != "" { + result.ETag = &val + } + return result, nil +} + +// mergeEntityHandleError handles the MergeEntity error response. +func (client *tableClient) mergeEntityHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// Query - Queries tables under the given account. +func (client *tableClient) Query(ctx context.Context, tableQueryOptions *TableQueryOptions, queryOptions *QueryOptions) (TableQueryResponseResponse, error) { + req, err := client.queryCreateRequest(ctx, tableQueryOptions, queryOptions) + if err != nil { + return TableQueryResponseResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return TableQueryResponseResponse{}, err + } + if !resp.HasStatusCode(http.StatusOK) { + return TableQueryResponseResponse{}, client.queryHandleError(resp) + } + return client.queryHandleResponse(resp) +} + +// queryCreateRequest creates the Query request. +func (client *tableClient) queryCreateRequest(ctx context.Context, tableQueryOptions *TableQueryOptions, queryOptions *QueryOptions) (*azcore.Request, error) { + urlPath := "/Tables" + req, err := azcore.NewRequest(ctx, http.MethodGet, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + if queryOptions != nil && queryOptions.Format != nil { + query.Set("$format", string(*queryOptions.Format)) + } + if queryOptions != nil && queryOptions.Top != nil { + query.Set("$top", strconv.FormatInt(int64(*queryOptions.Top), 10)) + } + if queryOptions != nil && queryOptions.Select != nil { + query.Set("$select", *queryOptions.Select) + } + if queryOptions != nil && queryOptions.Filter != nil { + query.Set("$filter", *queryOptions.Filter) + } + if tableQueryOptions != nil && tableQueryOptions.NextTableName != nil { + query.Set("NextTableName", *tableQueryOptions.NextTableName) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if tableQueryOptions != nil && tableQueryOptions.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *tableQueryOptions.RequestID) + } + req.Header.Set("DataServiceVersion", "3.0") + req.Header.Set("Accept", "application/json;odata=minimalmetadata") + return req, nil +} + +// queryHandleResponse handles the Query response. +func (client *tableClient) queryHandleResponse(resp *azcore.Response) (TableQueryResponseResponse, error) { + var val *TableQueryResponse + if err := resp.UnmarshalAsJSON(&val); err != nil { + return TableQueryResponseResponse{}, err + } + result := TableQueryResponseResponse{RawResponse: resp.Response, TableQueryResponse: val} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableQueryResponseResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("x-ms-continuation-NextTableName"); val != "" { + result.XMSContinuationNextTableName = &val + } + return result, nil +} + +// queryHandleError handles the Query error response. +func (client *tableClient) queryHandleError(resp *azcore.Response) error { + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("%s; failed to read response body: %w", resp.Status, err) + } + if len(body) == 0 { + return azcore.NewResponseError(errors.New(resp.Status), resp.Response) + } + return azcore.NewResponseError(errors.New(string(body)), resp.Response) +} + +// QueryEntities - Queries entities in a table. +func (client *tableClient) QueryEntities(ctx context.Context, table string, tableQueryEntitiesOptions *TableQueryEntitiesOptions, queryOptions *QueryOptions) (TableEntityQueryResponseResponse, error) { + req, err := client.queryEntitiesCreateRequest(ctx, table, tableQueryEntitiesOptions, queryOptions) + if err != nil { + return TableEntityQueryResponseResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return TableEntityQueryResponseResponse{}, err + } + if !resp.HasStatusCode(http.StatusOK) { + return TableEntityQueryResponseResponse{}, client.queryEntitiesHandleError(resp) + } + return client.queryEntitiesHandleResponse(resp) +} + +// queryEntitiesCreateRequest creates the QueryEntities request. +func (client *tableClient) queryEntitiesCreateRequest(ctx context.Context, table string, tableQueryEntitiesOptions *TableQueryEntitiesOptions, queryOptions *QueryOptions) (*azcore.Request, error) { + urlPath := "/{table}()" + urlPath = strings.ReplaceAll(urlPath, "{table}", url.PathEscape(table)) + req, err := azcore.NewRequest(ctx, http.MethodGet, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + if tableQueryEntitiesOptions != nil && tableQueryEntitiesOptions.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*tableQueryEntitiesOptions.Timeout), 10)) + } + if queryOptions != nil && queryOptions.Format != nil { + query.Set("$format", string(*queryOptions.Format)) + } + if queryOptions != nil && queryOptions.Top != nil { + query.Set("$top", strconv.FormatInt(int64(*queryOptions.Top), 10)) + } + if queryOptions != nil && queryOptions.Select != nil { + query.Set("$select", *queryOptions.Select) + } + if queryOptions != nil && queryOptions.Filter != nil { + query.Set("$filter", *queryOptions.Filter) + } + if tableQueryEntitiesOptions != nil && tableQueryEntitiesOptions.NextPartitionKey != nil { + query.Set("NextPartitionKey", *tableQueryEntitiesOptions.NextPartitionKey) + } + if tableQueryEntitiesOptions != nil && tableQueryEntitiesOptions.NextRowKey != nil { + query.Set("NextRowKey", *tableQueryEntitiesOptions.NextRowKey) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if tableQueryEntitiesOptions != nil && tableQueryEntitiesOptions.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *tableQueryEntitiesOptions.RequestID) + } + req.Header.Set("DataServiceVersion", "3.0") + req.Header.Set("Accept", "application/json;odata=minimalmetadata") + return req, nil +} + +// queryEntitiesHandleResponse handles the QueryEntities response. +func (client *tableClient) queryEntitiesHandleResponse(resp *azcore.Response) (TableEntityQueryResponseResponse, error) { + var val *TableEntityQueryResponse + if err := resp.UnmarshalAsJSON(&val); err != nil { + return TableEntityQueryResponseResponse{}, err + } + result := TableEntityQueryResponseResponse{RawResponse: resp.Response, TableEntityQueryResponse: val} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableEntityQueryResponseResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("x-ms-continuation-NextPartitionKey"); val != "" { + result.XMSContinuationNextPartitionKey = &val + } + if val := resp.Header.Get("x-ms-continuation-NextRowKey"); val != "" { + result.XMSContinuationNextRowKey = &val + } + if val := resp.Header.Get("ETag"); val != "" { + result.ETag = &val + } + return result, nil +} + +// queryEntitiesHandleError handles the QueryEntities error response. +func (client *tableClient) queryEntitiesHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// QueryEntitiesWithPartitionAndRowKey - Queries entities in a table. +func (client *tableClient) QueryEntitiesWithPartitionAndRowKey(ctx context.Context, table string, partitionKey string, rowKey string, tableQueryEntitiesWithPartitionAndRowKeyOptions *TableQueryEntitiesWithPartitionAndRowKeyOptions, queryOptions *QueryOptions) (TableEntityQueryResponseResponse, error) { + req, err := client.queryEntitiesWithPartitionAndRowKeyCreateRequest(ctx, table, partitionKey, rowKey, tableQueryEntitiesWithPartitionAndRowKeyOptions, queryOptions) + if err != nil { + return TableEntityQueryResponseResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return TableEntityQueryResponseResponse{}, err + } + if !resp.HasStatusCode(http.StatusOK) { + return TableEntityQueryResponseResponse{}, client.queryEntitiesWithPartitionAndRowKeyHandleError(resp) + } + return client.queryEntitiesWithPartitionAndRowKeyHandleResponse(resp) +} + +// queryEntitiesWithPartitionAndRowKeyCreateRequest creates the QueryEntitiesWithPartitionAndRowKey request. +func (client *tableClient) queryEntitiesWithPartitionAndRowKeyCreateRequest(ctx context.Context, table string, partitionKey string, rowKey string, tableQueryEntitiesWithPartitionAndRowKeyOptions *TableQueryEntitiesWithPartitionAndRowKeyOptions, queryOptions *QueryOptions) (*azcore.Request, error) { + urlPath := "/{table}(PartitionKey='{partitionKey}',RowKey='{rowKey}')" + urlPath = strings.ReplaceAll(urlPath, "{table}", url.PathEscape(table)) + urlPath = strings.ReplaceAll(urlPath, "{partitionKey}", url.PathEscape(partitionKey)) + urlPath = strings.ReplaceAll(urlPath, "{rowKey}", url.PathEscape(rowKey)) + req, err := azcore.NewRequest(ctx, http.MethodGet, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + if tableQueryEntitiesWithPartitionAndRowKeyOptions != nil && tableQueryEntitiesWithPartitionAndRowKeyOptions.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*tableQueryEntitiesWithPartitionAndRowKeyOptions.Timeout), 10)) + } + if queryOptions != nil && queryOptions.Format != nil { + query.Set("$format", string(*queryOptions.Format)) + } + if queryOptions != nil && queryOptions.Select != nil { + query.Set("$select", *queryOptions.Select) + } + if queryOptions != nil && queryOptions.Filter != nil { + query.Set("$filter", *queryOptions.Filter) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if tableQueryEntitiesWithPartitionAndRowKeyOptions != nil && tableQueryEntitiesWithPartitionAndRowKeyOptions.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *tableQueryEntitiesWithPartitionAndRowKeyOptions.RequestID) + } + req.Header.Set("DataServiceVersion", "3.0") + req.Header.Set("Accept", "application/json;odata=minimalmetadata") + return req, nil +} + +// queryEntitiesWithPartitionAndRowKeyHandleResponse handles the QueryEntitiesWithPartitionAndRowKey response. +func (client *tableClient) queryEntitiesWithPartitionAndRowKeyHandleResponse(resp *azcore.Response) (TableEntityQueryResponseResponse, error) { + var val *TableEntityQueryResponse + if err := resp.UnmarshalAsJSON(&val); err != nil { + return TableEntityQueryResponseResponse{}, err + } + result := TableEntityQueryResponseResponse{RawResponse: resp.Response, TableEntityQueryResponse: val} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableEntityQueryResponseResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("x-ms-continuation-NextPartitionKey"); val != "" { + result.XMSContinuationNextPartitionKey = &val + } + if val := resp.Header.Get("x-ms-continuation-NextRowKey"); val != "" { + result.XMSContinuationNextRowKey = &val + } + if val := resp.Header.Get("ETag"); val != "" { + result.ETag = &val + } + return result, nil +} + +// queryEntitiesWithPartitionAndRowKeyHandleError handles the QueryEntitiesWithPartitionAndRowKey error response. +func (client *tableClient) queryEntitiesWithPartitionAndRowKeyHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// SetAccessPolicy - Sets stored access policies for the table that may be used with Shared Access Signatures. +func (client *tableClient) SetAccessPolicy(ctx context.Context, table string, options *TableSetAccessPolicyOptions) (TableSetAccessPolicyResponse, error) { + req, err := client.setAccessPolicyCreateRequest(ctx, table, options) + if err != nil { + return TableSetAccessPolicyResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return TableSetAccessPolicyResponse{}, err + } + if !resp.HasStatusCode(http.StatusNoContent) { + return TableSetAccessPolicyResponse{}, client.setAccessPolicyHandleError(resp) + } + return client.setAccessPolicyHandleResponse(resp) +} + +// setAccessPolicyCreateRequest creates the SetAccessPolicy request. +func (client *tableClient) setAccessPolicyCreateRequest(ctx context.Context, table string, options *TableSetAccessPolicyOptions) (*azcore.Request, error) { + urlPath := "/{table}" + urlPath = strings.ReplaceAll(urlPath, "{table}", url.PathEscape(table)) + req, err := azcore.NewRequest(ctx, http.MethodPut, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + if options != nil && options.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) + } + query.Set("comp", "acl") + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if options != nil && options.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *options.RequestID) + } + req.Header.Set("Accept", "application/xml") + type wrapper struct { + XMLName xml.Name `xml:"SignedIdentifiers"` + TableACL *[]SignedIdentifier `xml:"SignedIdentifier"` + } + if options != nil { + return req, req.MarshalAsXML(wrapper{TableACL: options.TableACL}) + } + return req, nil +} + +// setAccessPolicyHandleResponse handles the SetAccessPolicy response. +func (client *tableClient) setAccessPolicyHandleResponse(resp *azcore.Response) (TableSetAccessPolicyResponse, error) { + result := TableSetAccessPolicyResponse{RawResponse: resp.Response} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableSetAccessPolicyResponse{}, err + } + result.Date = &date + } + return result, nil +} + +// setAccessPolicyHandleError handles the SetAccessPolicy error response. +func (client *tableClient) setAccessPolicyHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} + +// UpdateEntity - Update entity in a table. +func (client *tableClient) UpdateEntity(ctx context.Context, table string, partitionKey string, rowKey string, tableUpdateEntityOptions *TableUpdateEntityOptions, queryOptions *QueryOptions) (TableUpdateEntityResponse, error) { + req, err := client.updateEntityCreateRequest(ctx, table, partitionKey, rowKey, tableUpdateEntityOptions, queryOptions) + if err != nil { + return TableUpdateEntityResponse{}, err + } + resp, err := client.con.Pipeline().Do(req) + if err != nil { + return TableUpdateEntityResponse{}, err + } + if !resp.HasStatusCode(http.StatusNoContent) { + return TableUpdateEntityResponse{}, client.updateEntityHandleError(resp) + } + return client.updateEntityHandleResponse(resp) +} + +// updateEntityCreateRequest creates the UpdateEntity request. +func (client *tableClient) updateEntityCreateRequest(ctx context.Context, table string, partitionKey string, rowKey string, tableUpdateEntityOptions *TableUpdateEntityOptions, queryOptions *QueryOptions) (*azcore.Request, error) { + urlPath := "/{table}(PartitionKey='{partitionKey}',RowKey='{rowKey}')" + urlPath = strings.ReplaceAll(urlPath, "{table}", url.PathEscape(table)) + urlPath = strings.ReplaceAll(urlPath, "{partitionKey}", url.PathEscape(partitionKey)) + urlPath = strings.ReplaceAll(urlPath, "{rowKey}", url.PathEscape(rowKey)) + req, err := azcore.NewRequest(ctx, http.MethodPut, azcore.JoinPaths(client.con.Endpoint(), urlPath)) + if err != nil { + return nil, err + } + req.Telemetry(telemetryInfo) + query := req.URL.Query() + if tableUpdateEntityOptions != nil && tableUpdateEntityOptions.Timeout != nil { + query.Set("timeout", strconv.FormatInt(int64(*tableUpdateEntityOptions.Timeout), 10)) + } + if queryOptions != nil && queryOptions.Format != nil { + query.Set("$format", string(*queryOptions.Format)) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("x-ms-version", "2019-02-02") + if tableUpdateEntityOptions != nil && tableUpdateEntityOptions.RequestID != nil { + req.Header.Set("x-ms-client-request-id", *tableUpdateEntityOptions.RequestID) + } + req.Header.Set("DataServiceVersion", "3.0") + if tableUpdateEntityOptions != nil && tableUpdateEntityOptions.IfMatch != nil { + req.Header.Set("If-Match", *tableUpdateEntityOptions.IfMatch) + } + req.Header.Set("Accept", "application/json") + if tableUpdateEntityOptions != nil { + return req, req.MarshalAsJSON(tableUpdateEntityOptions.TableEntityProperties) + } + return req, nil +} + +// updateEntityHandleResponse handles the UpdateEntity response. +func (client *tableClient) updateEntityHandleResponse(resp *azcore.Response) (TableUpdateEntityResponse, error) { + result := TableUpdateEntityResponse{RawResponse: resp.Response} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return TableUpdateEntityResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("ETag"); val != "" { + result.ETag = &val + } + return result, nil +} + +// updateEntityHandleError handles the UpdateEntity error response. +func (client *tableClient) updateEntityHandleError(resp *azcore.Response) error { + var err TableServiceError + if err := resp.UnmarshalAsJSON(&err); err != nil { + return err + } + return azcore.NewResponseError(&err, resp.Response) +} diff --git a/sdk/tables/aztables/zz_generated_time_rfc1123.go b/sdk/tables/aztables/zz_generated_time_rfc1123.go new file mode 100644 index 000000000000..618f7cf33fb5 --- /dev/null +++ b/sdk/tables/aztables/zz_generated_time_rfc1123.go @@ -0,0 +1,41 @@ +// +build go1.13 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package aztables + +import ( + "strings" + "time" +) + +const ( + rfc1123JSON = `"` + time.RFC1123 + `"` +) + +type timeRFC1123 time.Time + +func (t timeRFC1123) MarshalJSON() ([]byte, error) { + b := []byte(time.Time(t).Format(rfc1123JSON)) + return b, nil +} + +func (t timeRFC1123) MarshalText() ([]byte, error) { + b := []byte(time.Time(t).Format(time.RFC1123)) + return b, nil +} + +func (t *timeRFC1123) UnmarshalJSON(data []byte) error { + p, err := time.Parse(rfc1123JSON, strings.ToUpper(string(data))) + *t = timeRFC1123(p) + return err +} + +func (t *timeRFC1123) UnmarshalText(data []byte) error { + p, err := time.Parse(time.RFC1123, string(data)) + *t = timeRFC1123(p) + return err +} diff --git a/sdk/tables/aztables/zz_generated_time_rfc3339.go b/sdk/tables/aztables/zz_generated_time_rfc3339.go new file mode 100644 index 000000000000..f4161ad815bb --- /dev/null +++ b/sdk/tables/aztables/zz_generated_time_rfc3339.go @@ -0,0 +1,57 @@ +// +build go1.13 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package aztables + +import ( + "regexp" + "strings" + "time" +) + +const ( + utcLayoutJSON = `"2006-01-02T15:04:05.999999999"` + utcLayout = "2006-01-02T15:04:05.999999999" + rfc3339JSON = `"` + time.RFC3339Nano + `"` +) + +// Azure reports time in UTC but it doesn't include the 'Z' time zone suffix in some cases. +var tzOffsetRegex = regexp.MustCompile(`(Z|z|\+|-)(\d+:\d+)*"*$`) + +type timeRFC3339 time.Time + +func (t timeRFC3339) MarshalJSON() (json []byte, err error) { + tt := time.Time(t) + return tt.MarshalJSON() +} + +func (t timeRFC3339) MarshalText() (text []byte, err error) { + tt := time.Time(t) + return tt.MarshalText() +} + +func (t *timeRFC3339) UnmarshalJSON(data []byte) error { + layout := utcLayoutJSON + if tzOffsetRegex.Match(data) { + layout = rfc3339JSON + } + return t.Parse(layout, string(data)) +} + +func (t *timeRFC3339) UnmarshalText(data []byte) (err error) { + layout := utcLayout + if tzOffsetRegex.Match(data) { + layout = time.RFC3339Nano + } + return t.Parse(layout, string(data)) +} + +func (t *timeRFC3339) Parse(layout, value string) error { + p, err := time.Parse(layout, strings.ToUpper(value)) + *t = timeRFC3339(p) + return err +}