Skip to content

Commit 2c4c5ff

Browse files
Merge pull request #90 from skyflowapi/release/23.7.2
SK-865 Release/23.7.2
2 parents 1f4972f + 4d0a5e4 commit 2c4c5ff

File tree

7 files changed

+398
-2
lines changed

7 files changed

+398
-2
lines changed

samples/delete_by_id_sample.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'''
2+
Copyright (c) 2022 Skyflow, Inc.
3+
'''
4+
from skyflow.errors import SkyflowError
5+
from skyflow.service_account import generate_bearer_token, is_expired
6+
from skyflow.vault import Client, Configuration,DeleteOptions
7+
8+
9+
# cache token for reuse
10+
bearerToken = ''
11+
12+
13+
def token_provider():
14+
global bearerToken
15+
if is_expired(bearerToken):
16+
bearerToken, _ = generate_bearer_token('<YOUR_CREDENTIALS_FILE_PATH>')
17+
return bearerToken
18+
19+
20+
try:
21+
config = Configuration(
22+
'<YOUR_VAULT_ID>', '<YOUR_VAULT_URL>', token_provider)
23+
client = Client(config)
24+
options = DeleteOptions(False)
25+
26+
data = {"records": [
27+
{
28+
"id": "<SKYFLOW_ID1>",
29+
"table": "<TABLE_NAME>",
30+
},
31+
{
32+
"id": "<SKYFLOW_ID2>",
33+
"table": "<TABLE_NAME>",
34+
}
35+
]}
36+
37+
response = client.delete_by_id(data,options=options)
38+
print('Response:', response)
39+
except SkyflowError as e:
40+
print('Error Occurred:', e)

skyflow/_utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ class InfoMessages(Enum):
7575
UPDATE_DATA_SUCCESS = "Data has been updated successfully"
7676
GET_TRIGGERED = "Get triggered."
7777
GET_SUCCESS = "Data fetched successfully."
78+
DELETE_BY_ID_TRIGGERED = "Delete by ID triggered."
79+
DELETE_DATA_SUCCESS = "Data has been deleted successfully."
7880

7981

8082
class InterfaceName(Enum):
@@ -89,6 +91,7 @@ class InterfaceName(Enum):
8991

9092
IS_TOKEN_VALID = "service_account.isTokenValid"
9193
IS_EXPIRED = "service_account.is_expired"
94+
DELETE_BY_ID = "client.delete_by_id"
9295

9396

9497
def http_build_query(data):

skyflow/errors/_skyflow_errors.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
class SkyflowErrorCodes(Enum):
99
INVALID_INPUT = 400
10+
INVALID_INDEX = 404
1011
SERVER_ERROR = 500
1112
PARTIAL_SUCCESS = 500
1213

@@ -43,11 +44,18 @@ class SkyflowErrorMessages(Enum):
4344
INVALID_RECORDS_TYPE = "Records key has value of type %s, expected list"
4445
INVALID_FIELDS_TYPE = "Fields key has value of type %s, expected dict"
4546
INVALID_TABLE_TYPE = "Table key has value of type %s, expected string"
47+
INVALID_TABLE_TYPE_DELETE = "Table of type string is required at index %s in records array"
4648
INVALID_IDS_TYPE = "Ids key has value of type %s, expected list"
4749
INVALID_ID_TYPE = "Id key has value of type %s, expected string"
50+
INVALID_ID_TYPE_DELETE = "Id of type string is required at index %s in records array"
4851
INVALID_REDACTION_TYPE = "Redaction key has value of type %s, expected Skyflow.Redaction"
4952
INVALID_COLUMN_NAME = "Column name has value of type %s, expected string"
5053
INVALID_COLUMN_VALUE = "Column values has value of type %s, expected list"
54+
INVALID_RECORDS_IN_DELETE = "Invalid records. records object should be an array"
55+
EMPTY_RECORDS_IN_DELETE = "records array cannot be empty"
56+
EMPTY_ID_IN_DELETE = "Id cannot be empty in records array at index %s"
57+
EMPTY_TABLE_IN_DELETE = "Table cannot be empty in records array at index %s"
58+
RECORDS_KEY_NOT_FOUND_DELETE = "records object is required"
5159

5260
INVALID_REQUEST_BODY = "Given request body is not valid"
5361
INVALID_RESPONSE_BODY = "Given response body is not valid"

skyflow/vault/_client.py

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
import json
55
import types
66
import requests
7+
8+
from ._delete_by_id import deleteProcessResponse
79
from ._insert import getInsertRequestBody, processResponse, convertResponse
810
from ._update import sendUpdateRequests, createUpdateResponseBody
9-
from ._config import Configuration
11+
from ._config import Configuration, DeleteOptions
1012
from ._config import InsertOptions, ConnectionConfig, UpdateOptions
1113
from ._connection import createRequest
1214
from ._detokenize import sendDetokenizeRequests, createDetokenizeResponseBody
@@ -172,4 +174,85 @@ def update(self, updateInput, options: UpdateOptions = UpdateOptions()):
172174
SkyflowErrorMessages.PARTIAL_SUCCESS, result, interface=interface)
173175
else:
174176
log_info(InfoMessages.UPDATE_DATA_SUCCESS.value, interface)
175-
return result
177+
return result
178+
179+
def delete_by_id(self, records: dict,options: DeleteOptions = DeleteOptions()):
180+
interface = InterfaceName.DELETE_BY_ID.value
181+
log_info(InfoMessages.DELETE_BY_ID_TRIGGERED.value, interface=interface)
182+
183+
self._checkConfig(interface)
184+
185+
self.storedToken = tokenProviderWrapper(
186+
self.storedToken, self.tokenProvider, interface)
187+
headers = {
188+
"Authorization": "Bearer " + self.storedToken,
189+
"sky-metadata": json.dumps(getMetrics())
190+
}
191+
error_list = []
192+
result_list = []
193+
errors = {}
194+
result = {}
195+
error = {}
196+
try:
197+
if not isinstance(records, dict) or "records" not in records:
198+
error = {"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value,
199+
"description": SkyflowErrorMessages.RECORDS_KEY_NOT_FOUND_DELETE.value}}
200+
return error
201+
records_list = records["records"]
202+
if not isinstance(records_list, list):
203+
error.update({"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value,
204+
"description": SkyflowErrorMessages.INVALID_RECORDS_IN_DELETE.value}})
205+
return error
206+
elif len(records_list) == 0:
207+
error = {"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value,
208+
"description": SkyflowErrorMessages.EMPTY_RECORDS_IN_DELETE.value}}
209+
return error
210+
except KeyError:
211+
raise SkyflowError(SkyflowErrorCodes.INVALID_INPUT,
212+
SkyflowErrorMessages.RECORDS_KEY_ERROR, interface=interface)
213+
try:
214+
for index,record in enumerate(records["records"]):
215+
record_list = record["id"]
216+
if not isinstance(record_list, str):
217+
error.update({"error": {"code": SkyflowErrorCodes.INVALID_INDEX.value,
218+
"description": SkyflowErrorMessages.INVALID_ID_TYPE_DELETE.value % (index)}})
219+
return error
220+
elif record_list == "":
221+
error.update({"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value,
222+
"description": SkyflowErrorMessages.EMPTY_ID_IN_DELETE.value % (index)}})
223+
return error
224+
except KeyError:
225+
error.update({"error": {"code": SkyflowErrorCodes.INVALID_INDEX.value,
226+
"description": SkyflowErrorMessages.IDS_KEY_ERROR.value}})
227+
return error
228+
try:
229+
for index,record in enumerate(records["records"]):
230+
record_table = record["table"]
231+
if not isinstance(record_table, str):
232+
error.update({"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value,
233+
"description": SkyflowErrorMessages.INVALID_TABLE_TYPE_DELETE.value % (index)}})
234+
return error
235+
elif record_table == "":
236+
error.update({"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value,
237+
"description": SkyflowErrorMessages.EMPTY_TABLE_IN_DELETE.value % (index)}})
238+
return error
239+
except KeyError:
240+
error.update({"error": {"code": SkyflowErrorCodes.INVALID_INDEX.value,
241+
"description": SkyflowErrorMessages.TABLE_KEY_ERROR.value}})
242+
return error
243+
for record in records["records"]:
244+
request_url = self._get_complete_vault_url() + "/" + record["table"] + "/" + record["id"]
245+
response = requests.delete(request_url, headers=headers)
246+
processed_response = deleteProcessResponse(response, records)
247+
if processed_response is not None and processed_response.get('code') == 404:
248+
errors.update({'id': record["id"], 'error': processed_response})
249+
error_list.append(errors)
250+
else:
251+
result_list.append(processed_response)
252+
if result_list:
253+
result.update({'records': result_list})
254+
if errors:
255+
result.update({'errors': error_list})
256+
257+
log_info(InfoMessages.DELETE_DATA_SUCCESS.value, interface)
258+
return result

skyflow/vault/_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ class UpdateOptions:
3838
def __init__(self, tokens: bool=True):
3939
self.tokens = tokens
4040

41+
class DeleteOptions:
42+
def __init__(self, tokens: bool=False):
43+
self.tokens = tokens
44+
4145
class RequestMethod(Enum):
4246
GET = 'GET'
4347
POST = 'POST'

skyflow/vault/_delete_by_id.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'''
2+
Copyright (c) 2022 Skyflow, Inc.
3+
'''
4+
import json
5+
6+
import requests
7+
from requests.models import HTTPError
8+
from skyflow.errors._skyflow_errors import SkyflowError, SkyflowErrorCodes, SkyflowErrorMessages
9+
from skyflow._utils import InterfaceName
10+
11+
interface = InterfaceName.DELETE_BY_ID.value
12+
13+
14+
def deleteProcessResponse(response: requests.Response, interface=interface):
15+
statusCode = response.status_code
16+
content = response.content
17+
try:
18+
response.raise_for_status()
19+
if statusCode == 204:
20+
return None
21+
try:
22+
return json.loads(content)
23+
except:
24+
raise SkyflowError(
25+
statusCode, SkyflowErrorMessages.RESPONSE_NOT_JSON.value % content, interface=interface)
26+
except HTTPError:
27+
message = SkyflowErrorMessages.API_ERROR.value % statusCode
28+
if response is not None and response.content is not None:
29+
try:
30+
errorResponse = json.loads(content)
31+
if 'error' in errorResponse and type(errorResponse['error']) == dict and 'message' in errorResponse[
32+
'error']:
33+
message = errorResponse['error']['message']
34+
except:
35+
message = SkyflowErrorMessages.RESPONSE_NOT_JSON.value % content
36+
error = {}
37+
if 'x-request-id' in response.headers:
38+
message += ' - request id: ' + response.headers['x-request-id']
39+
error.update({"code": statusCode, "description": message})
40+
return error
41+

0 commit comments

Comments
 (0)