1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
# coding: utf-8
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
"""
FILE: sample_conditional_update_async.py
DESCRIPTION:
These samples demonstrate how to update Tables storage table conditionally. The way to update Tables cosmos table is similar.
USAGE:
python sample_conditional_update_async.py
Set the environment variables with your own values before running the sample:
1) TABLES_STORAGE_ENDPOINT_SUFFIX - the Table storage service account URL suffix
2) TABLES_STORAGE_ACCOUNT_NAME - the Tables storage account name
3) TABLES_PRIMARY_STORAGE_ACCOUNT_KEY - the Tables storage account access key
"""
import asyncio
import os
from datetime import datetime
from dotenv import find_dotenv, load_dotenv
from uuid import uuid4, UUID
from azure.data.tables.aio import TableClient
from azure.data.tables._models import UpdateMode
from azure.core import MatchConditions
from azure.core.exceptions import ResourceExistsError, ResourceModifiedError
from typing_extensions import TypedDict
class EntityType(TypedDict, total=False):
PartitionKey: str
RowKey: str
text: str
color: str
price: float
last_updated: datetime
product_id: UUID
inventory_count: int
barcode: bytes
class ConditionalUpdateSamples(object):
def __init__(self):
load_dotenv(find_dotenv())
self.access_key = os.environ["TABLES_PRIMARY_STORAGE_ACCOUNT_KEY"]
self.endpoint_suffix = os.environ["TABLES_STORAGE_ENDPOINT_SUFFIX"]
self.account_name = os.environ["TABLES_STORAGE_ACCOUNT_NAME"]
self.endpoint = f"{self.account_name}.table.{self.endpoint_suffix}"
self.connection_string = f"DefaultEndpointsProtocol=https;AccountName={self.account_name};AccountKey={self.access_key};EndpointSuffix={self.endpoint_suffix}"
self.table_name_prefix = "SampleConditionalUpdate"
self.entity1: EntityType = {
"PartitionKey": "color",
"RowKey": "brand",
"text": "Marker",
"color": "Purple",
"price": 4.99,
"last_updated": datetime.today(),
"product_id": uuid4(),
}
self.entity2: EntityType = {
"PartitionKey": "color",
"RowKey": "brand",
"color": "Red",
"inventory_count": 42,
"barcode": b"135aefg8oj0ld58", # cspell:disable-line
}
async def conditional_update_basic(self):
async with TableClient.from_connection_string(
self.connection_string, self.table_name_prefix + uuid4().hex
) as table_client:
await table_client.create_table()
metadata1 = await table_client.create_entity(entity=self.entity1)
print("Entity:")
print(self.entity1)
# Merge properties of an entity with one that already existed in a table.
# This operation will only succeed if the entity has not been modified since we last retrieved the Etag.
try:
metadata2 = await table_client.update_entity(
entity=self.entity2,
mode=UpdateMode.MERGE,
match_condition=MatchConditions.IfNotModified,
etag=metadata1["etag"],
)
except ResourceModifiedError:
print("This entity has been altered and may no longer be in the expected state.")
entity2 = await table_client.get_entity(
partition_key=self.entity1["PartitionKey"], row_key=self.entity1["RowKey"]
)
print("Entity after merge:")
print(entity2)
# Update an existing entity by replacing all of its properties with those specified.
# This operation will only succeed if the entity has not been modified since we last retrieved the Etag.
try:
await table_client.update_entity(
entity=self.entity2,
mode=UpdateMode.REPLACE,
match_condition=MatchConditions.IfNotModified,
etag=metadata2["etag"],
)
except ResourceModifiedError:
print("This entity has been altered and may no longer be in the expected state.")
entity3 = await table_client.get_entity(
partition_key=self.entity1["PartitionKey"], row_key=self.entity1["RowKey"]
)
print("Entity after replace:")
print(entity3)
await table_client.delete_table()
async def conditional_update_with_a_target_field(self):
async with TableClient.from_connection_string(
self.connection_string, self.table_name_prefix + uuid4().hex
) as table_client:
await table_client.create_table()
await table_client.create_entity(entity=self.entity1)
target_field = "barcode"
# In this scenario, will try to create an entity at first. If the entity with the same PartitionKey and RowKey already exists,
# will update the existing entity when target field is missing.
try:
await table_client.create_entity(entity=self.entity2)
except ResourceExistsError:
entity = await table_client.get_entity(
partition_key=self.entity2["PartitionKey"], row_key=self.entity2["RowKey"]
)
if target_field not in entity:
await table_client.update_entity(
entity={
"PartitionKey": self.entity2["PartitionKey"],
"RowKey": self.entity2["RowKey"],
target_field: "foo",
},
mode=UpdateMode.MERGE,
match_condition=MatchConditions.IfNotModified,
etag=entity.metadata["etag"],
)
await table_client.delete_table()
async def main():
sample = ConditionalUpdateSamples()
await sample.conditional_update_basic()
await sample.conditional_update_with_a_target_field()
if __name__ == "__main__":
asyncio.run(main())
|