1
1
import dataclasses
2
+ import logging
2
3
import uuid
3
4
from typing import Callable
4
5
5
6
import azure .cosmos .cosmos_client as cosmos_client
6
7
import azure .cosmos .exceptions as exceptions
7
- from azure .cosmos import ContainerProxy
8
+ from azure .cosmos import ContainerProxy , PartitionKey
8
9
from flask import Flask
9
10
10
11
11
12
class CosmosDBFacade :
12
- def __init__ (self , app : Flask ): # pragma: no cover
13
- self .app = app
13
+ def __init__ (self , client , db_id : str , logger = None ): # pragma: no cover
14
+ self .client = client
15
+ self .db = self .client .get_database_client (db_id )
16
+ if logger is None :
17
+ self .logger = logging .getLogger (CosmosDBFacade .__name__ )
18
+ else :
19
+ self .logger = logger
14
20
15
- db_uri = app .config .get ('DATABASE_URI' )
21
+ @classmethod
22
+ def from_flask_config (cls , app : Flask ):
23
+ db_uri = app .config .get ('COSMOS_DATABASE_URI' )
16
24
if db_uri is None :
17
- app .logger .warn ("DATABASE_URI was not found. Looking for alternative variables." )
25
+ app .logger .warn ("COSMOS_DATABASE_URI was not found. Looking for alternative variables." )
18
26
account_uri = app .config .get ('DATABASE_ACCOUNT_URI' )
19
27
if account_uri is None :
20
28
raise EnvironmentError ("DATABASE_ACCOUNT_URI is not defined in the environment" )
@@ -23,31 +31,26 @@ def __init__(self, app: Flask): # pragma: no cover
23
31
if master_key is None :
24
32
raise EnvironmentError ("DATABASE_MASTER_KEY is not defined in the environment" )
25
33
26
- self . client = cosmos_client .CosmosClient (account_uri , {'masterKey' : master_key },
27
- user_agent = "CosmosDBDotnetQuickstart" ,
28
- user_agent_overwrite = True )
34
+ client = cosmos_client .CosmosClient (account_uri , {'masterKey' : master_key },
35
+ user_agent = "CosmosDBDotnetQuickstart" ,
36
+ user_agent_overwrite = True )
29
37
else :
30
- self . client = cosmos_client .CosmosClient .from_connection_string (db_uri )
38
+ client = cosmos_client .CosmosClient .from_connection_string (db_uri )
31
39
32
40
db_id = app .config .get ('DATABASE_NAME' )
33
41
if db_id is None :
34
42
raise EnvironmentError ("DATABASE_NAME is not defined in the environment" )
35
43
36
- self . db = self . client . get_database_client ( db_id )
44
+ return cls ( client , db_id , logger = app . logger )
37
45
38
46
def create_container (self , container_definition : dict ):
39
- try :
40
- return self .db .create_container (** container_definition )
47
+ return self .db .create_container (** container_definition )
41
48
42
- except exceptions . CosmosResourceExistsError : # pragma: no cover
43
- self .app . logger . info ( 'Container with id \' {0} \' was found' . format ( container_definition [ "id" ]) )
49
+ def create_container_if_not_exists ( self , container_definition : dict ):
50
+ return self .db . create_container_if_not_exists ( ** container_definition )
44
51
45
52
def delete_container (self , container_id : str ):
46
- try :
47
- return self .db .delete_container (container_id )
48
-
49
- except exceptions .CosmosHttpResponseError : # pragma: no cover
50
- self .app .logger .info ('Container with id \' {0}\' was not deleted' .format (container_id ))
53
+ return self .db .delete_container (container_id )
51
54
52
55
53
56
cosmos_helper : CosmosDBFacade = None
@@ -61,8 +64,13 @@ def __init__(self, data):
61
64
setattr (self , k , v )
62
65
63
66
67
+ def partition_key_attribute (pk : PartitionKey ) -> str :
68
+ return pk .path .strip ('/' )
69
+
70
+
64
71
class CosmosDBRepository :
65
72
def __init__ (self , container_id : str ,
73
+ partition_key_attribute : str ,
66
74
mapper : Callable = None ,
67
75
custom_cosmos_helper : CosmosDBFacade = None ):
68
76
global cosmos_helper
@@ -71,12 +79,16 @@ def __init__(self, container_id: str,
71
79
raise ValueError ("The cosmos_db module has not been initialized!" )
72
80
self .mapper = mapper
73
81
self .container : ContainerProxy = self .cosmos_helper .db .get_container_client (container_id )
82
+ self .partition_key_attribute : str = partition_key_attribute
74
83
75
84
@classmethod
76
85
def from_definition (cls , container_definition : dict ,
77
86
mapper : Callable = None ,
78
87
custom_cosmos_helper : CosmosDBFacade = None ):
79
- return cls (container_definition ['id' ], mapper , custom_cosmos_helper )
88
+ pk_attrib = partition_key_attribute (container_definition ['partition_key' ])
89
+ return cls (container_definition ['id' ], pk_attrib ,
90
+ mapper = mapper ,
91
+ custom_cosmos_helper = custom_cosmos_helper )
80
92
81
93
def create (self , data : dict , mapper : Callable = None ):
82
94
function_mapper = self .get_mapper_or_dict (mapper )
@@ -93,11 +105,12 @@ def find_all(self, partition_key_value: str, max_count=None, offset=0,
93
105
max_count = self .get_page_size_or (max_count )
94
106
result = self .container .query_items (
95
107
query = """
96
- SELECT * FROM c WHERE c.tenant_id=@tenant_id AND {visibility_condition}
108
+ SELECT * FROM c WHERE c.{partition_key_attribute}=@partition_key_value AND {visibility_condition}
97
109
OFFSET @offset LIMIT @max_count
98
- """ .format (visibility_condition = self .create_sql_condition_for_visibility (visible_only )),
110
+ """ .format (partition_key_attribute = self .partition_key_attribute ,
111
+ visibility_condition = self .create_sql_condition_for_visibility (visible_only )),
99
112
parameters = [
100
- {"name" : "@tenant_id " , "value" : partition_key_value },
113
+ {"name" : "@partition_key_value " , "value" : partition_key_value },
101
114
{"name" : "@offset" , "value" : offset },
102
115
{"name" : "@max_count" , "value" : max_count },
103
116
],
@@ -122,6 +135,9 @@ def delete(self, id: str, partition_key_value: str, mapper: Callable = None):
122
135
'deleted' : str (uuid .uuid4 ())
123
136
}, partition_key_value , visible_only = True , mapper = mapper )
124
137
138
+ def delete_permanently (self , id : str , partition_key_value : str ) -> None :
139
+ self .container .delete_item (id , partition_key_value )
140
+
125
141
def check_visibility (self , item , throw_not_found_if_deleted ):
126
142
if throw_not_found_if_deleted and item .get ('deleted' ) is not None :
127
143
raise exceptions .CosmosResourceNotFoundError (message = 'Deleted item' ,
@@ -146,4 +162,4 @@ def get_page_size_or(self, custom_page_size: int) -> int:
146
162
147
163
def init_app (app : Flask ) -> None :
148
164
global cosmos_helper
149
- cosmos_helper = CosmosDBFacade (app )
165
+ cosmos_helper = CosmosDBFacade . from_flask_config (app )
0 commit comments