Skip to content

Commit f1530dc

Browse files
authored
Updates for aztables metadata (#22472)
Include returned metadata in more APIs. Make the amount of returned metadata configurable.
1 parent fa064d6 commit f1530dc

File tree

11 files changed

+169
-29
lines changed

11 files changed

+169
-29
lines changed

sdk/data/aztables/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
# Release History
22

3-
## 1.1.1 (Unreleased)
3+
## 1.2.0 (Unreleased)
44

55
### Features Added
6+
* Methods `Client.AddEntity` and `ServiceClient.NewListTablesPager` now include OData metadata in their responses.
7+
* The amount of OData metadata returned has been made configurable for the following methods:
8+
* `Client.AddEntity`, `Client.GetEntity`, `Client.NewListEntitiesPager`, and `ServiceClient.NewListTablesPager`.
9+
* Use one of the following constants to specify the amount: `MetadataFormatFull`, `MetadataFormatMinimal`, or `MetadataFormatNone`.
610

711
### Breaking Changes
812

sdk/data/aztables/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "go",
44
"TagPrefix": "go/data/aztables",
5-
"Tag": "go/data/aztables_45893b48dc"
5+
"Tag": "go/data/aztables_ec73894009"
66
}

sdk/data/aztables/client.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313

1414
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
1515
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
16-
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
1716
generated "github.com/Azure/azure-sdk-for-go/sdk/data/aztables/internal"
1817
)
1918

@@ -220,8 +219,9 @@ func (t *Client) GetEntity(ctx context.Context, partitionKey string, rowKey stri
220219
options = &GetEntityOptions{}
221220
}
222221

223-
genOptions, queryOptions := options.toGenerated()
224-
resp, err := t.client.QueryEntityWithPartitionAndRowKey(ctx, t.name, prepareKey(partitionKey), prepareKey(rowKey), genOptions, queryOptions)
222+
resp, err := t.client.QueryEntityWithPartitionAndRowKey(ctx, t.name, prepareKey(partitionKey), prepareKey(rowKey), nil, &generated.QueryOptions{
223+
Format: options.Format,
224+
})
225225
if err != nil {
226226
return GetEntityResponse{}, err
227227
}
@@ -254,18 +254,30 @@ func (t *Client) AddEntity(ctx context.Context, entity []byte, options *AddEntit
254254
if err != nil {
255255
return AddEntityResponse{}, err
256256
}
257-
resp, err := t.client.InsertEntity(ctx, t.name, &generated.TableClientInsertEntityOptions{TableEntityProperties: mapEntity, ResponsePreference: to.Ptr(generated.ResponseFormatReturnNoContent)}, nil)
257+
258+
if options == nil {
259+
options = &AddEntityOptions{}
260+
}
261+
262+
resp, err := t.client.InsertEntity(ctx, t.name, &generated.TableClientInsertEntityOptions{TableEntityProperties: mapEntity}, &generated.QueryOptions{
263+
Format: options.Format,
264+
})
258265
if err != nil {
259266
err = checkEntityForPkRk(&mapEntity, err)
260267
return AddEntityResponse{}, err
261268
}
269+
marshalledValue, err := json.Marshal(resp.Value)
270+
if err != nil {
271+
return AddEntityResponse{}, err
272+
}
262273

263274
var ETag azcore.ETag
264275
if resp.ETag != nil {
265276
ETag = azcore.ETag(*resp.ETag)
266277
}
267278
return AddEntityResponse{
268-
ETag: ETag,
279+
ETag: ETag,
280+
Value: marshalledValue,
269281
}, nil
270282
}
271283

sdk/data/aztables/client_test.go

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ func TestCreateTable(t *testing.T) {
5454
}
5555
}
5656

57+
type mdforAddGet struct {
58+
Metadata string `json:"odata.metadata"`
59+
Type string `json:"odata.type"` // only for full metadata
60+
}
61+
5762
func TestAddEntity(t *testing.T) {
5863
for _, service := range services {
5964
t.Run(fmt.Sprintf("%v_%v", t.Name(), service), func(t *testing.T) {
@@ -66,8 +71,13 @@ func TestAddEntity(t *testing.T) {
6671

6772
marshalledEntity, err := json.Marshal(simpleEntity)
6873
require.NoError(t, err)
69-
_, err = client.AddEntity(ctx, marshalledEntity, nil)
74+
resp, err := client.AddEntity(ctx, marshalledEntity, nil)
7075
require.NoError(t, err)
76+
require.NotEmpty(t, resp.Value)
77+
var md mdforAddGet
78+
require.NoError(t, json.Unmarshal(resp.Value, &md))
79+
require.NotEmpty(t, md.Metadata)
80+
require.Empty(t, md.Type)
7181
})
7282
}
7383
}
@@ -83,8 +93,18 @@ func TestAddComplexEntity(t *testing.T) {
8393
marshalledEntity, err := json.Marshal(entity)
8494
require.NoError(t, err)
8595

86-
_, err = client.AddEntity(ctx, marshalledEntity, nil)
96+
resp, err := client.AddEntity(ctx, marshalledEntity, &AddEntityOptions{
97+
Format: to.Ptr(MetadataFormatFull),
98+
})
8799
require.NoError(t, err)
100+
require.NotEmpty(t, resp.Value)
101+
var md mdforAddGet
102+
require.NoError(t, json.Unmarshal(resp.Value, &md))
103+
require.NotEmpty(t, md.Metadata)
104+
if service == "storage" {
105+
// cosmos doesn't send full metadata
106+
require.NotEmpty(t, md.Type)
107+
}
88108
})
89109
}
90110
}
@@ -165,6 +185,11 @@ func TestMergeEntity(t *testing.T) {
165185

166186
preMerge, err := client.GetEntity(ctx, entityToCreate.PartitionKey, entityToCreate.RowKey, nil)
167187
require.NoError(t, err)
188+
require.NotEmpty(t, preMerge.Value)
189+
var md mdforAddGet
190+
require.NoError(t, json.Unmarshal(preMerge.Value, &md))
191+
require.NotEmpty(t, md.Metadata)
192+
require.Empty(t, md.Type)
168193

169194
var unMarshalledPreMerge map[string]any
170195
err = json.Unmarshal(preMerge.Value, &unMarshalledPreMerge)
@@ -245,8 +270,18 @@ func TestInsertEntity(t *testing.T) {
245270
list := &ListEntitiesOptions{Filter: &filter}
246271

247272
// 2. Query for basic Entity
248-
preMerge, err := client.GetEntity(ctx, entityToCreate.PartitionKey, entityToCreate.RowKey, nil)
273+
preMerge, err := client.GetEntity(ctx, entityToCreate.PartitionKey, entityToCreate.RowKey, &GetEntityOptions{
274+
Format: to.Ptr(MetadataFormatFull),
275+
})
249276
require.NoError(t, err)
277+
require.NotEmpty(t, preMerge.Value)
278+
var md mdforAddGet
279+
require.NoError(t, json.Unmarshal(preMerge.Value, &md))
280+
require.NotEmpty(t, md.Metadata)
281+
if service == "storage" {
282+
// cosmos doesn't send full metadata
283+
require.NotEmpty(t, md.Type)
284+
}
250285

251286
var unMarshalledPreMerge map[string]any
252287
err = json.Unmarshal(preMerge.Value, &unMarshalledPreMerge)
@@ -304,6 +339,11 @@ func TestInsertEntityTwice(t *testing.T) {
304339
}
305340
}
306341

342+
type mdForListEntities struct {
343+
Timestamp time.Time `json:"Timestamp"`
344+
ID string `json:"odata.id"` // only for full metadata
345+
}
346+
307347
func TestQuerySimpleEntity(t *testing.T) {
308348
for _, service := range services {
309349
t.Run(fmt.Sprintf("%v_%v", t.Name(), service), func(t *testing.T) {
@@ -328,7 +368,8 @@ func TestQuerySimpleEntity(t *testing.T) {
328368
var resp ListEntitiesResponse
329369
pager := client.NewListEntitiesPager(list)
330370
for pager.More() {
331-
resp, err := pager.NextPage(ctx)
371+
var err error
372+
resp, err = pager.NextPage(ctx)
332373
require.NoError(t, err)
333374
require.Equal(t, len(resp.Entities), expectedCount)
334375
}
@@ -353,6 +394,11 @@ func TestQuerySimpleEntity(t *testing.T) {
353394
require.Equal(t, b.String, (*entitiesToCreate)[i].String)
354395
require.Equal(t, b.Integer, (*entitiesToCreate)[i].Integer)
355396
require.Equal(t, b.Bool, (*entitiesToCreate)[i].Bool)
397+
398+
var md mdForListEntities
399+
require.NoError(t, json.Unmarshal(e, &md))
400+
require.False(t, md.Timestamp.IsZero())
401+
require.Empty(t, md.ID)
356402
}
357403
})
358404
}
@@ -375,7 +421,10 @@ func TestQueryComplexEntity(t *testing.T) {
375421

376422
filter := "RowKey lt '5'"
377423
expectedCount := 4
378-
options := &ListEntitiesOptions{Filter: &filter}
424+
options := &ListEntitiesOptions{
425+
Filter: &filter,
426+
Format: to.Ptr(MetadataFormatFull),
427+
}
379428

380429
pager := client.NewListEntitiesPager(options)
381430
for pager.More() {
@@ -396,6 +445,14 @@ func TestQueryComplexEntity(t *testing.T) {
396445
require.Equal(t, model.Float, (entitiesToCreate)[idx].Float)
397446
require.Equal(t, model.DateTime, (entitiesToCreate)[idx].DateTime)
398447
require.Equal(t, model.Byte, (entitiesToCreate)[idx].Byte)
448+
449+
var md mdForListEntities
450+
require.NoError(t, json.Unmarshal(entity, &md))
451+
require.False(t, md.Timestamp.IsZero())
452+
if service == "storage" {
453+
// cosmos doesn't send full metadata
454+
require.NotEmpty(t, md.ID)
455+
}
399456
}
400457
}
401458
})

sdk/data/aztables/constants.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ func toGeneratedStatusType(g *generated.GeoReplicationStatusType) *GeoReplicatio
5656
return nil
5757
}
5858

59+
// MetadataFormat specifies the level of OData metadata returned with an entity.
60+
// https://learn.microsoft.com/rest/api/storageservices/payload-format-for-table-service-operations#json-format-applicationjson-versions-2013-08-15-and-later
61+
type MetadataFormat = generated.ODataMetadataFormat
62+
63+
const (
64+
MetadataFormatFull MetadataFormat = generated.ODataMetadataFormatApplicationJSONODataFullmetadata
65+
MetadataFormatMinimal MetadataFormat = generated.ODataMetadataFormatApplicationJSONODataMinimalmetadata
66+
MetadataFormatNone MetadataFormat = generated.ODataMetadataFormatApplicationJSONODataNometadata
67+
)
68+
5969
// SASProtocol indicates the SAS protocol
6070
type SASProtocol string
6171

sdk/data/aztables/internal/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ package internal
88

99
const (
1010
ModuleName = "github.com/Azure/azure-sdk-for-go/sdk/data/aztables"
11-
Version = "v1.1.1"
11+
Version = "v1.2.0"
1212
)

sdk/data/aztables/models.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ func (t *ServiceProperties) toGenerated() *generated.TableServiceProperties {
105105
type TableProperties struct {
106106
// The name of the table.
107107
Name *string `json:"TableName,omitempty"`
108+
109+
// The OData properties of the table in JSON format.
110+
Value []byte
108111
}
109112

110113
// RetentionPolicy - The retention policy.

sdk/data/aztables/options.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ package aztables
55

66
import (
77
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
8-
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
98
generated "github.com/Azure/azure-sdk-for-go/sdk/data/aztables/internal"
109
)
1110

1211
// AddEntityOptions contains optional parameters for Client.AddEntity
1312
type AddEntityOptions struct {
14-
// placeholder for future optional parameters
13+
// Format specifies the amount of metadata returned.
14+
// The default is MetadataFormatMinimal.
15+
Format *MetadataFormat
1516
}
1617

1718
// CreateTableOptions contains optional parameters for Client.Create and ServiceClient.CreateTable
@@ -52,11 +53,9 @@ func (g *GetAccessPolicyOptions) toGenerated() *generated.TableClientGetAccessPo
5253

5354
// GetEntityOptions contains optional parameters for Client.GetEntity
5455
type GetEntityOptions struct {
55-
// placeholder for future optional parameters
56-
}
57-
58-
func (g *GetEntityOptions) toGenerated() (*generated.TableClientQueryEntityWithPartitionAndRowKeyOptions, *generated.QueryOptions) {
59-
return &generated.TableClientQueryEntityWithPartitionAndRowKeyOptions{}, &generated.QueryOptions{Format: to.Ptr(generated.ODataMetadataFormatApplicationJSONODataMinimalmetadata)}
56+
// Format specifies the amount of metadata returned.
57+
// The default is MetadataFormatMinimal.
58+
Format *MetadataFormat
6059
}
6160

6261
// GetPropertiesOptions contains optional parameters for Client.GetProperties
@@ -94,6 +93,10 @@ type ListEntitiesOptions struct {
9493

9594
// The NextRowKey to start paging from
9695
NextRowKey *string
96+
97+
// Format specifies the amount of metadata returned.
98+
// The default is MetadataFormatMinimal.
99+
Format *MetadataFormat
97100
}
98101

99102
func (l *ListEntitiesOptions) toQueryOptions() *generated.QueryOptions {
@@ -103,7 +106,7 @@ func (l *ListEntitiesOptions) toQueryOptions() *generated.QueryOptions {
103106

104107
return &generated.QueryOptions{
105108
Filter: l.Filter,
106-
Format: to.Ptr(generated.ODataMetadataFormatApplicationJSONODataMinimalmetadata),
109+
Format: l.Format,
107110
Select: l.Select,
108111
Top: l.Top,
109112
}
@@ -122,6 +125,10 @@ type ListTablesOptions struct {
122125

123126
// NextTableName is the continuation token for the next table to page from
124127
NextTableName *string
128+
129+
// Format specifies the amount of metadata returned.
130+
// The default is MetadataFormatMinimal.
131+
Format *MetadataFormat
125132
}
126133

127134
func (l *ListTablesOptions) toQueryOptions() *generated.QueryOptions {
@@ -131,7 +138,7 @@ func (l *ListTablesOptions) toQueryOptions() *generated.QueryOptions {
131138

132139
return &generated.QueryOptions{
133140
Filter: l.Filter,
134-
Format: to.Ptr(generated.ODataMetadataFormatApplicationJSONODataMinimalmetadata),
141+
Format: l.Format,
135142
Select: l.Select,
136143
Top: l.Top,
137144
}

sdk/data/aztables/responses.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import "github.com/Azure/azure-sdk-for-go/sdk/azcore"
77

88
// AddEntityResponse contains response fields for Client.AddEntityResponse
99
type AddEntityResponse struct {
10+
// ETag contains the information returned from the ETag header response.
1011
ETag azcore.ETag
12+
13+
// The OData properties of the table entity in JSON format.
14+
Value []byte
1115
}
1216

1317
// CreateTableResponse contains response fields for Client.Create and ServiceClient.CreateTable
@@ -36,7 +40,7 @@ type GetEntityResponse struct {
3640
// ETag contains the information returned from the ETag header response.
3741
ETag azcore.ETag
3842

39-
// The properties of the table entity.
43+
// The OData properties of the table entity in JSON format.
4044
Value []byte
4145
}
4246

sdk/data/aztables/service_client.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package aztables
55

66
import (
77
"context"
8+
"encoding/json"
89
"errors"
910
"strings"
1011
"time"
@@ -162,8 +163,26 @@ func (t *ServiceClient) NewListTablesPager(listOptions *ListTablesOptions) *runt
162163

163164
tableProps := make([]*TableProperties, len(resp.Value))
164165
for i := range resp.Value {
166+
odataValues := map[string]any{}
167+
if resp.Value[i].ODataEditLink != nil {
168+
odataValues["odata.editLink"] = *resp.Value[i].ODataEditLink
169+
}
170+
if resp.Value[i].ODataID != nil {
171+
odataValues["odata.id"] = *resp.Value[i].ODataID
172+
}
173+
if resp.Value[i].ODataType != nil {
174+
odataValues["odata.type"] = *resp.Value[i].ODataType
175+
}
176+
var odataJSON []byte
177+
if len(odataValues) > 0 {
178+
odataJSON, err = json.Marshal(odataValues)
179+
if err != nil {
180+
return ListTablesResponse{}, err
181+
}
182+
}
165183
tableProps[i] = &TableProperties{
166-
Name: resp.Value[i].TableName,
184+
Name: resp.Value[i].TableName,
185+
Value: odataJSON,
167186
}
168187
}
169188

0 commit comments

Comments
 (0)