Skip to content

Commit 540a8e9

Browse files
author
Srinath Narayanan
committed
initial commit for createIfNotExist functionality for container and database
1 parent ee3ad2a commit 540a8e9

File tree

5 files changed

+148
-1
lines changed

5 files changed

+148
-1
lines changed

sdk/cosmos/azure-cosmos/HISTORY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Change Log azure-cosmos
22

3+
## Version 4.0.0b3:
4+
5+
- Added `create_if_not_exists()` functionality to container and database.
6+
37
## Version 4.0.0b2:
48

59
Version 4.0.0b2 is the second iteration in our efforts to build a more Pythonic client library.

sdk/cosmos/azure-cosmos/azure/cosmos/container.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def __init__(self, client_connection, database_link, id, properties=None): # py
6363
self.client_connection = client_connection
6464
self.id = id
6565
self._properties = properties
66+
self.database_link = database_link
6667
self.container_link = u"{}/colls/{}".format(database_link, self.id)
6768
self._is_system_key = None
6869
self._scripts = None # type: Optional[ScriptsProxy]
@@ -151,6 +152,79 @@ def read(
151152

152153
return cast('Dict[str, Any]', self._properties)
153154

155+
@distributed_trace
156+
def create_if_not_exists(
157+
self,
158+
partition_key, # type: Any
159+
indexing_policy=None, # type: Optional[Dict[str, Any]]
160+
default_ttl=None, # type: Optional[int]
161+
populate_query_metrics=None, # type: Optional[bool]
162+
offer_throughput=None, # type: Optional[int]
163+
unique_key_policy=None, # type: Optional[Dict[str, Any]]
164+
conflict_resolution_policy=None, # type: Optional[Dict[str, Any]]
165+
**kwargs # type: Any
166+
):
167+
# type: (...) -> ContainerProxy
168+
"""
169+
Create the container if it does not exist already.
170+
171+
If the container already exists, it is returned.
172+
173+
:param partition_key: The partition key to use for the container.
174+
:param indexing_policy: The indexing policy to apply to the container.
175+
:param default_ttl: Default time to live (TTL) for items in the container. If unspecified, items do not expire.
176+
:param session_token: Token for use with Session consistency.
177+
:param initial_headers: Initial headers to be sent as part of the request.
178+
:param access_condition: Conditions Associated with the request.
179+
:param populate_query_metrics: Enable returning query metrics in response headers.
180+
:param offer_throughput: The provisioned throughput for this offer.
181+
:param unique_key_policy: The unique key policy to apply to the container.
182+
:param conflict_resolution_policy: The conflict resolution policy to apply to the container.
183+
:param request_options: Dictionary of additional properties to be used for the request.
184+
:param response_hook: a callable invoked with the response metadata
185+
:returns: A `ContainerProxy` instance representing the container.
186+
:raise CosmosHttpResponseError: The container read or creation failed.
187+
:rtype: ~azure.cosmos.container.ContainerProxy
188+
"""
189+
190+
response_hook = kwargs.pop('response_hook', None)
191+
try:
192+
collection_link = self.container_link
193+
self._properties = self.client_connection.ReadContainer(
194+
collection_link, **kwargs
195+
)
196+
197+
if response_hook:
198+
response_hook(self.client_connection.last_response_headers, self._properties)
199+
return self
200+
except CosmosResourceNotFoundError:
201+
definition = dict(id=self.id) # type: Dict[str, Any]
202+
if partition_key:
203+
definition["partitionKey"] = partition_key
204+
if indexing_policy:
205+
definition["indexingPolicy"] = indexing_policy
206+
if default_ttl:
207+
definition["defaultTtl"] = default_ttl
208+
if unique_key_policy:
209+
definition["uniqueKeyPolicy"] = unique_key_policy
210+
if conflict_resolution_policy:
211+
definition["conflictResolutionPolicy"] = conflict_resolution_policy
212+
213+
request_options = build_options(kwargs)
214+
if populate_query_metrics is not None:
215+
request_options["populateQueryMetrics"] = populate_query_metrics
216+
if offer_throughput is not None:
217+
request_options["offerThroughput"] = offer_throughput
218+
219+
data = self.client_connection.CreateContainer(
220+
database_link=self.database_link, collection=definition, options=request_options, **kwargs
221+
)
222+
223+
if response_hook:
224+
response_hook(self.client_connection.last_response_headers, data)
225+
226+
return ContainerProxy(self.client_connection, self.database_link, data["id"], properties=data)
227+
154228
@distributed_trace
155229
def read_item(
156230
self,

sdk/cosmos/azure-cosmos/azure/cosmos/database.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,55 @@ def read(self, populate_query_metrics=None, **kwargs):
141141

142142
return cast('Dict[str, Any]', self._properties)
143143

144+
@distributed_trace
145+
def create_if_not_exists( # pylint: disable=redefined-builtin
146+
self,
147+
populate_query_metrics=None, # type: Optional[bool]
148+
offer_throughput=None, # type: Optional[int]
149+
**kwargs # type: Any
150+
):
151+
# type: (...) -> DatabaseProxy
152+
"""
153+
Create the database if it does not exist already.
154+
155+
If the database already exists, it is returned.
156+
157+
:param str session_token: Token for use with Session consistency.
158+
:param dict(str, str) initial_headers: Initial headers to be sent as part of the request.
159+
:param dict(str, str) access_condition: Conditions Associated with the request.
160+
:param bool populate_query_metrics: Enable returning query metrics in response headers.
161+
:param int offer_throughput: The provisioned throughput for this offer.
162+
:param dict(str, Any) request_options: Dictionary of additional properties to be used for the request.
163+
:param Callable response_hook: a callable invoked with the response metadata
164+
:returns: A DatabaseProxy instance representing the database.
165+
:rtype: ~azure.cosmos.database.DatabaseProxy
166+
:raise CosmosHttpResponseError: The database read or creation failed.
167+
"""
168+
response_hook = kwargs.pop('response_hook', None)
169+
try:
170+
from .cosmos_client import CosmosClient
171+
172+
database_link = CosmosClient._get_database_link(self)
173+
self._properties = self.client_connection.ReadDatabase(
174+
database_link, **kwargs
175+
)
176+
177+
if response_hook:
178+
response_hook(self.client_connection.last_response_headers, self._properties)
179+
180+
return self
181+
except CosmosResourceNotFoundError:
182+
request_options = build_options(kwargs)
183+
if populate_query_metrics is not None:
184+
request_options["populateQueryMetrics"] = populate_query_metrics
185+
if offer_throughput is not None:
186+
request_options["offerThroughput"] = offer_throughput
187+
188+
result = self.client_connection.CreateDatabase(database=dict(id=self.id), options=request_options, **kwargs)
189+
if response_hook:
190+
response_hook(self.client_connection.last_response_headers)
191+
return DatabaseProxy(self.client_connection, id=result["id"], properties=result)
192+
144193
@distributed_trace
145194
def create_container(
146195
self,

sdk/cosmos/azure-cosmos/azure/cosmos/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@
1919
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2020
# SOFTWARE.
2121

22-
VERSION = "4.0.0b2"
22+
VERSION = "4.0.0b3"

sdk/cosmos/azure-cosmos/test/crud_tests.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ def test_database_crud(self):
136136
self.__AssertHTTPFailureWithStatus(StatusCodes.NOT_FOUND,
137137
read_db.read)
138138

139+
database_proxy = read_db.create_if_not_exists(offer_throughput=10000)
140+
self.assertEqual(read_db.id, database_proxy.id)
141+
self.assertEquals(database_proxy.read_offer().offer_throughput, 10000)
142+
143+
database_proxy = read_db.create_if_not_exists(offer_throughput=9000)
144+
self.assertEqual(read_db.id, database_proxy.id)
145+
self.assertEquals(database_proxy.read_offer().offer_throughput, 10000)
146+
147+
self.client.delete_database(read_db.id)
148+
139149
@pytest.mark.skip("skipping as the TestResources subscription doesn't support this offer")
140150
def test_database_level_offer_throughput(self):
141151
# Create a database with throughput
@@ -236,6 +246,16 @@ def test_collection_crud(self):
236246
self.__AssertHTTPFailureWithStatus(StatusCodes.NOT_FOUND,
237247
created_container.read)
238248

249+
container_proxy = created_container.create_if_not_exists(partition_key=PartitionKey(path='/id', kind='Hash'))
250+
self.assertEqual(created_container.id, container_proxy.id)
251+
self.assertDictEqual(PartitionKey(path='/id', kind='Hash'), container_proxy._properties['partitionKey'])
252+
253+
container_proxy = created_container.create_if_not_exists(partition_key=created_properties['partitionKey'])
254+
self.assertEqual(created_container.id, container_proxy.id)
255+
self.assertDictEqual(PartitionKey(path='/id', kind='Hash'), container_proxy._properties['partitionKey'])
256+
257+
created_db.delete_container(created_collection.id)
258+
239259
def test_partitioned_collection(self):
240260
created_db = self.databaseForTest
241261

0 commit comments

Comments
 (0)