Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API for creating hierarchical PartitionKeys #23577

Merged
merged 26 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
08925bf
Add a builder for creating hierarchical partition keys
Pietrrrek Oct 14, 2024
ff2ff23
Add CRUD tests for hierarchical partition key
Pietrrrek Oct 14, 2024
02c2108
Add license
Pietrrrek Oct 14, 2024
9719b57
Add feature description
Pietrrrek Oct 14, 2024
7f29baf
Add license
Pietrrrek Oct 14, 2024
3bb7ba5
Add doc comments
Pietrrrek Oct 14, 2024
e4cfecb
Use append-style methods instead of a builder
Pietrrrek Oct 16, 2024
ea78ea8
remove lint
jhendrixMSFT Oct 16, 2024
9732324
Add Kind property w/ inferrence in (de)serialization
Pietrrrek Oct 21, 2024
6d56e65
Set Kind property
Pietrrrek Oct 21, 2024
44f6cc8
Merge branch 'main' of github.com:Pietrrrek/azure-sdk-for-go
Pietrrrek Oct 21, 2024
1571d81
Add PartitionKeyKind type documentation
Pietrrrek Oct 21, 2024
081a14a
Specify PartitionKeyDefinition.Version
Pietrrrek Oct 21, 2024
2adac98
Prefix enum options with type name
Pietrrrek Oct 21, 2024
cf3674e
Prefix enum options with type name
Pietrrrek Oct 21, 2024
4ef94b6
Use appropriate partition-key
Pietrrrek Oct 22, 2024
50568ec
Merge branch 'main' of github.com:Pietrrrek/azure-sdk-for-go
Pietrrrek Oct 22, 2024
bb49a1f
Use appropriate partition-key
Pietrrrek Oct 22, 2024
fba6134
Remove cross-partition query
Pietrrrek Oct 28, 2024
8e7faae
Add assertions for returned items
Pietrrrek Oct 28, 2024
0bec8da
Merge branch 'main' of github.com:Pietrrrek/azure-sdk-for-go
Pietrrrek Oct 28, 2024
9731ddb
Remove UnmarshalJSON impl
Pietrrrek Oct 28, 2024
38037a6
Merge branch 'main' of https://github.com/Azure/azure-sdk-for-go
Pietrrrek Oct 28, 2024
6c9f657
Remove deserialization tests
Pietrrrek Oct 28, 2024
a0fe3d6
Remove dangling `WHERE` clause to fix tests
analogrelay Nov 1, 2024
46284d8
Merge branch 'main' into main
analogrelay Nov 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk/data/azcosmos/emulator_cosmos_item_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ func TestItemCRUDHierarchicalPartitionKey(t *testing.T) {
ID: "aContainer",
PartitionKeyDefinition: PartitionKeyDefinition{
Paths: []string{"/id", "/type"},
Kind: MultiHash,
},
}

Expand Down
73 changes: 73 additions & 0 deletions sdk/data/azcosmos/partition_key_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,84 @@

package azcosmos

import (
"encoding/json"
"fmt"
)

type PartitionKeyKind string

const (
Hash PartitionKeyKind = "Hash"
MultiHash PartitionKeyKind = "MultiHash"
Pietrrrek marked this conversation as resolved.
Show resolved Hide resolved
)

// PartitionKeyDefinition represents a partition key definition in the Azure Cosmos DB database service.
// A partition key definition defines the path for the partition key property.
type PartitionKeyDefinition struct {
// Kind returns the kind of partition key definition.
Kind PartitionKeyKind `json:"kind"`
// Paths returns the list of partition key paths of the container.
Paths []string `json:"paths"`
// Version returns the version of the hash partitioning of the container.
Version int `json:"version,omitempty"`
}

// MarshalJSON implements the json.Marshaler interface
// If the Kind is not set, it will be inferred based on the number of paths.
func (pkd PartitionKeyDefinition) MarshalJSON() ([]byte, error) {
var paths_length = len(pkd.Paths)

var kind PartitionKeyKind
if pkd.Kind != "" {
kind = pkd.Kind
} else if pkd.Kind == "" && paths_length == 1 {
kind = Hash
} else if pkd.Kind == "" && paths_length > 1 {
kind = MultiHash
}

return json.Marshal(struct {
Kind PartitionKeyKind `json:"kind"`
Paths []string `json:"paths"`
Version int `json:"version,omitempty"`
}{
Kind: kind,
Paths: pkd.Paths,
Version: pkd.Version,
})

}

// UnmarshalJSON implements the json.Unmarshaler interface
func (pkd *PartitionKeyDefinition) UnmarshalJSON(data []byte) error {
var rawMsg map[string]json.RawMessage
if err := json.Unmarshal(data, &rawMsg); err != nil {
return fmt.Errorf("unmarshalling type %T: %v", pkd, err)
}

for key, value := range rawMsg {
switch key {
case "kind":
if err := json.Unmarshal(value, &pkd.Kind); err != nil {
return fmt.Errorf("unmarshalling type %T: %v", pkd, err)
}
case "paths":
if err := json.Unmarshal(value, &pkd.Paths); err != nil {
return fmt.Errorf("unmarshalling type %T: %v", pkd, err)
}
case "version":
if err := json.Unmarshal(value, &pkd.Version); err != nil {
return fmt.Errorf("unmarshalling type %T: %v", pkd, err)
}
}
}

if pkd.Kind == "" && len(pkd.Paths) == 1 {
pkd.Kind = Hash
} else if pkd.Kind == "" && len(pkd.Paths) > 1 {
pkd.Kind = MultiHash
}
analogrelay marked this conversation as resolved.
Show resolved Hide resolved

return nil
}
145 changes: 145 additions & 0 deletions sdk/data/azcosmos/partition_key_definition_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package azcosmos

import (
"reflect"
"testing"
)

func TestPartitionKeyDefinitionSerialization(t *testing.T) {
pkd_kind_unset_len_one := PartitionKeyDefinition{
Paths: []string{"somePath"},
Version: 2,
}

jsonString, err := pkd_kind_unset_len_one.MarshalJSON()
if err != nil {
t.Fatal(err)
}

expected := `{"kind":"Hash","paths":["somePath"],"version":2}`
if string(jsonString) != expected {
t.Errorf("Expected serialization %v, but got %v", expected, string(jsonString))
}

pkd_kind_unset_len_two := PartitionKeyDefinition{
Paths: []string{"somePath", "someOtherPath"},
Version: 2,
}

jsonString, err = pkd_kind_unset_len_two.MarshalJSON()
if err != nil {
t.Fatal(err)
}

expected = `{"kind":"MultiHash","paths":["somePath","someOtherPath"],"version":2}`
if string(jsonString) != expected {
t.Errorf("Expected serialization %v, but got %v", expected, string(jsonString))
}

pkd_kind_set := PartitionKeyDefinition{
Kind: MultiHash,
Paths: []string{"somePath"},
Version: 2,
}

jsonString, err = pkd_kind_set.MarshalJSON()
if err != nil {
t.Fatal(err)
}

expected = `{"kind":"MultiHash","paths":["somePath"],"version":2}`
if string(jsonString) != expected {
t.Errorf("Expected serialization %v, but got %v", expected, string(jsonString))
}
}

func TestPartitionKeyDefinitionDeserialization(t *testing.T) {
def := PartitionKeyDefinition{
Paths: []string{"somePath"},
Version: 2,
}

jsonString, err := def.MarshalJSON()
if err != nil {
t.Fatal(err)
}

var otherDef PartitionKeyDefinition
err = otherDef.UnmarshalJSON(jsonString)

if err != nil {
t.Fatal(err, string(jsonString))
}

// Kind is inferred based on the number of paths
if otherDef.Kind != Hash {
t.Errorf("Expected Kind to be %v, but got %v", def.Kind, otherDef.Kind)
}

if !reflect.DeepEqual(def.Paths, otherDef.Paths) {
t.Errorf("Expected Paths to be %v, but got %v", def.Paths, otherDef.Paths)
}

if def.Version != otherDef.Version {
t.Errorf("Expected Version to be %v, but got %v", def.Version, otherDef.Version)
}

def = PartitionKeyDefinition{
Paths: []string{"somePath", "someOtherPath"},
Version: 2,
}

jsonString, err = def.MarshalJSON()
if err != nil {
t.Fatal(err)
}

err = otherDef.UnmarshalJSON(jsonString)
if err != nil {
t.Fatal(err, string(jsonString))
}

// Kind is inferred based on the number of paths
if otherDef.Kind != MultiHash {
t.Errorf("Expected Kind to be %v, but got %v", MultiHash, otherDef.Kind)
}

if !reflect.DeepEqual(def.Paths, otherDef.Paths) {
t.Errorf("Expected Paths to be %v, but got %v", def.Paths, otherDef.Paths)
}

if def.Version != otherDef.Version {
t.Errorf("Expected Version to be %v, but got %v", def.Version, otherDef.Version)
}

def = PartitionKeyDefinition{
Kind: MultiHash,
Paths: []string{"somePath"},
Version: 2,
}

jsonString, err = def.MarshalJSON()
if err != nil {
t.Fatal(err)
}

err = otherDef.UnmarshalJSON(jsonString)
if err != nil {
t.Fatal(err, string(jsonString))
}

if def.Kind != otherDef.Kind {
t.Errorf("Expected Kind to be %v, but got %v", def.Kind, otherDef.Kind)
}

if !reflect.DeepEqual(def.Paths, otherDef.Paths) {
t.Errorf("Expected Paths to be %v, but got %v", def.Paths, otherDef.Paths)
}

if def.Version != otherDef.Version {
t.Errorf("Expected Version to be %v, but got %v", def.Version, otherDef.Version)
}
}
Loading