Skip to content

Commit 9814a48

Browse files
SK-2954: Rename insert records->values, drop Upsert class for a dict shape, add types
BaseInsertRequest's shared field is now named values (matching PDB's terminology) instead of records, and table/values are required rather than defaulted; each variant's InsertRequest forwards them explicitly. Removes flowvault's Upsert class in favor of a plain dict (now typed via a TypedDict) to match the rest of flowvault's dict-based request shape, and adds return type hints to every method on v2's VaultController to match insert's. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent b861313 commit 9814a48

15 files changed

Lines changed: 139 additions & 149 deletions

File tree

‎common/tests/vault/data/test_base_insert.py‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@
44

55

66
class TestBaseInsertRequest(unittest.TestCase):
7-
def test_defaults(self):
8-
request = BaseInsertRequest()
9-
self.assertIsNone(request.table)
10-
self.assertIsNone(request.records)
7+
def test_table_and_values_are_required(self):
8+
with self.assertRaises(TypeError):
9+
BaseInsertRequest()
10+
11+
def test_upsert_defaults_to_none(self):
12+
request = BaseInsertRequest(table="t1", values=[{"values": {"a": 1}}])
1113
self.assertIsNone(request.upsert)
1214

1315
def test_construction(self):
14-
request = BaseInsertRequest(table="t1", records=[{"values": {"a": 1}}], upsert="upsert_val")
16+
request = BaseInsertRequest(table="t1", values=[{"values": {"a": 1}}], upsert="upsert_val")
1517
self.assertEqual(request.table, "t1")
16-
self.assertEqual(request.records, [{"values": {"a": 1}}])
18+
self.assertEqual(request.values, [{"values": {"a": 1}}])
1719
self.assertEqual(request.upsert, "upsert_val")
1820

1921

‎common/vault/base_vault_controller.py‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,3 @@ def _validate_field_values(self, values):
6060
self._skyflow_messages.Error.EMPTY_KEY_IN_INSERT_DATA.value,
6161
_INVALID_INPUT_ERROR_CODE,
6262
)
63-
# if value is None or (isinstance(value, str) and not value.strip()):
64-
# raise SkyflowError(
65-
# self._skyflow_messages.Error.EMPTY_VALUE_IN_INSERT_DATA.value,
66-
# _INVALID_INPUT_ERROR_CODE,
67-
# )
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
class BaseInsertRequest:
1+
from typing import Union
22

3-
def __init__(self, table=None, records=None, upsert=None):
3+
class BaseInsertRequest:
4+
def __init__(self, table: str, values: list, upsert: Union[str, dict] = None):
45
self.table = table
5-
self.records = records
6-
self.upsert = upsert
6+
self.values = values
7+
self.upsert = upsert

‎flowvault/skyflow_flowvault/utils/_skyflow_messages.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ class Error(Enum):
2020
INVALID_RECORDS_TYPE_IN_INSERT = f"{error_prefix} Insert failed. 'records' must be a list of dicts."
2121
INVALID_RECORD_DATA_IN_INSERT = f"{error_prefix} Insert failed. Each record's 'values' must be a non-empty dict."
2222
INVALID_TABLE_NAME_IN_INSERT = f"{error_prefix} Insert failed. 'table' must be a non-empty string."
23-
INVALID_UPSERT_TYPE_IN_INSERT = f"{error_prefix} Insert failed. 'upsert' must be an Upsert instance."
24-
INVALID_UPSERT_UNIQUE_COLUMNS_IN_INSERT = f"{error_prefix} Insert failed. Upsert.unique_columns must be a non-empty list of strings."
25-
INVALID_UPSERT_UPDATE_TYPE_IN_INSERT = f"{error_prefix} Insert failed. Upsert.update_type must be an UpsertType value."
23+
INVALID_UPSERT_TYPE_IN_INSERT = f"{error_prefix} Insert failed. 'upsert' must be a dict."
24+
INVALID_UPSERT_UNIQUE_COLUMNS_IN_INSERT = f"{error_prefix} Insert failed. Upsert's 'unique_columns' must be a non-empty list of strings."
25+
INVALID_UPSERT_UPDATE_TYPE_IN_INSERT = f"{error_prefix} Insert failed. Upsert's 'update_type' must be an UpsertType value."
2626
TOO_MANY_RECORDS_IN_INSERT = f"{error_prefix} Insert failed. A single insert request cannot contain more than 10000 records."
2727
TABLE_NAME_IN_BOTH_PLACES_IN_INSERT = (
2828
f"{error_prefix} Insert failed. 'table' cannot be set on InsertRequest at the same "

‎flowvault/skyflow_flowvault/utils/validations/_validations.py‎

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
)
99
from skyflow_flowvault.utils import SkyflowMessages
1010
from skyflow_flowvault.utils.enums import UpsertType
11-
from skyflow_flowvault.vault.data import Upsert
1211

1312
VALID_INSERT_RECORD_KEYS = ["values", "table", "upsert"]
13+
VALID_UPSERT_KEYS = ["update_type", "unique_columns"]
1414

1515
invalid_input_error_code = CommonMessages.ErrorCodes.INVALID_INPUT.value
1616

@@ -19,56 +19,59 @@
1919
# identical to v2's, confirmed, so both variants now share one implementation.
2020

2121

22-
def _validate_upsert(upsert):
22+
def _validate_upsert(logger, upsert):
2323
if upsert is None:
2424
return
25-
if not isinstance(upsert, Upsert):
25+
if not isinstance(upsert, dict):
2626
raise SkyflowError(SkyflowMessages.Error.INVALID_UPSERT_TYPE_IN_INSERT.value, invalid_input_error_code)
27-
if (not isinstance(upsert.unique_columns, list) or not upsert.unique_columns
28-
or not all(isinstance(c, str) for c in upsert.unique_columns)):
27+
validate_keys(logger, upsert, VALID_UPSERT_KEYS)
28+
unique_columns = upsert.get("unique_columns")
29+
if (not isinstance(unique_columns, list) or not unique_columns
30+
or not all(isinstance(c, str) for c in unique_columns)):
2931
raise SkyflowError(SkyflowMessages.Error.INVALID_UPSERT_UNIQUE_COLUMNS_IN_INSERT.value, invalid_input_error_code)
30-
if upsert.update_type is not None and not isinstance(upsert.update_type, UpsertType):
32+
update_type = upsert.get("update_type")
33+
if update_type is not None and not isinstance(update_type, UpsertType):
3134
raise SkyflowError(SkyflowMessages.Error.INVALID_UPSERT_UPDATE_TYPE_IN_INSERT.value, invalid_input_error_code)
3235

3336

3437
MAX_INSERT_RECORDS = 10000 # matches Java's v3 Validations.validateInsertRequest (hardcoded, not configurable)
3538

3639

3740
def validate_insert_request(logger, request):
38-
if not isinstance(request.records, list) or not all(isinstance(r, dict) for r in request.records):
41+
if not isinstance(request.values, list) or not all(isinstance(r, dict) for r in request.values):
3942
raise SkyflowError(SkyflowMessages.Error.INVALID_RECORDS_TYPE_IN_INSERT.value, invalid_input_error_code)
4043

41-
if not request.records:
44+
if not request.values:
4245
raise SkyflowError(SkyflowMessages.Error.EMPTY_RECORDS_IN_INSERT.value, invalid_input_error_code)
4346

44-
if len(request.records) > MAX_INSERT_RECORDS:
47+
if len(request.values) > MAX_INSERT_RECORDS:
4548
raise SkyflowError(SkyflowMessages.Error.TOO_MANY_RECORDS_IN_INSERT.value, invalid_input_error_code)
4649

4750
# request.table/record["table"] format and record["values"] emptiness/key/value validity are
4851
# checked by the controller via the shared BaseVaultController._validate_table_name_if_present()
4952
# / _validate_field_values() -- not here, to avoid duplicating that logic.
5053

51-
_validate_upsert(request.upsert)
54+
_validate_upsert(logger, request.upsert)
5255

53-
for record in request.records:
56+
for record in request.values:
5457
validate_keys(logger, record, VALID_INSERT_RECORD_KEYS)
55-
_validate_upsert(record.get("upsert"))
58+
_validate_upsert(logger, record.get("upsert"))
5659

5760
# table must be set in exactly one place -- request-level (every record) or per-record (no
5861
# partial mix) -- and upsert must live at that same place (mirrors Java's v3 Validations).
5962
table_at_request_level = request.table is not None
6063

6164
if table_at_request_level:
62-
for record in request.records:
65+
for record in request.values:
6366
if record.get("table") is not None:
6467
raise SkyflowError(SkyflowMessages.Error.TABLE_NAME_IN_BOTH_PLACES_IN_INSERT.value, invalid_input_error_code)
6568
else:
66-
for record in request.records:
69+
for record in request.values:
6770
if record.get("table") is None:
6871
raise SkyflowError(SkyflowMessages.Error.TABLE_NAME_MISSING_IN_INSERT.value, invalid_input_error_code)
6972

7073
if table_at_request_level:
71-
for record in request.records:
74+
for record in request.values:
7275
if record.get("upsert") is not None:
7376
raise SkyflowError(SkyflowMessages.Error.RECORD_LEVEL_UPSERT_NOT_ALLOWED_IN_INSERT.value, invalid_input_error_code)
7477
else:

‎flowvault/skyflow_flowvault/vault/controller/_vault.py‎

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,20 @@ def insert(self, request: InsertRequest) -> InsertResponse:
2323
log_info(SkyflowMessages.Info.VALIDATE_INSERT_REQUEST.value, self._vault_client.get_logger())
2424
validate_insert_request(self._vault_client.get_logger(), request)
2525
self._validate_table_name_if_present(request.table)
26-
for record in request.records:
26+
for record in request.values:
2727
self._validate_table_name_if_present(record.get("table"))
2828
self._validate_field_values(record.get("values"))
2929
log_info(SkyflowMessages.Info.INSERT_REQUEST_RESOLVED.value, self._vault_client.get_logger())
3030
self._vault_client.initialize_client_configuration()
3131

3232
insert_api = self._vault_client.get_insert_api()
3333

34-
needs_per_record_table = any(r.get("table") is not None for r in request.records)
35-
needs_per_record_upsert = any(r.get("upsert") is not None for r in request.records)
34+
needs_per_record_table = any(r.get("table") is not None for r in request.values)
35+
needs_per_record_upsert = any(r.get("upsert") is not None for r in request.values)
3636

3737
wire_records = [
3838
self.__build_wire_record(record, request, needs_per_record_table, needs_per_record_upsert)
39-
for record in request.records
39+
for record in request.values
4040
]
4141

4242
try:
@@ -57,13 +57,11 @@ def insert(self, request: InsertRequest) -> InsertResponse:
5757
inserted_fields, errors = self.__split_success_and_errors(raw_response.data.records or [], 0, request_id)
5858
except Exception as e:
5959
log_error_log(SkyflowMessages.ErrorLogs.INSERT_RECORDS_REJECTED.value, self._vault_client.get_logger())
60-
inserted_fields, errors = [], self.__errors_from_exception(e, request.records, 0)
60+
inserted_fields, errors = [], self.__errors_from_exception(e, request.values, 0)
6161

6262
log_info(SkyflowMessages.Info.INSERT_SUCCESS.value, self._vault_client.get_logger())
6363
return InsertResponse(inserted_fields=inserted_fields, errors=errors if errors else None)
6464

65-
# Not built out this round (insert-only) -- stubs exist so this class stays instantiable
66-
# under BaseVaultController's abstract contract.
6765
def get(self, request):
6866
raise NotImplementedError("VaultController.get is not implemented yet")
6967

@@ -100,9 +98,10 @@ def __build_headers(self):
10098
def __to_v1_upsert(self, upsert):
10199
if upsert is None:
102100
return None
101+
update_type = upsert.get("update_type")
103102
return V1Upsert(
104-
update_type=upsert.update_type.value if upsert.update_type else None,
105-
unique_columns=upsert.unique_columns,
103+
update_type=update_type.value if update_type else None,
104+
unique_columns=upsert.get("unique_columns"),
106105
)
107106

108107
def __extract_request_id(self, headers):
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
from common.vault.data import BaseInsertRequest
2+
from skyflow_flowvault.vault.data._upsert import Upsert
23

34

45
class InsertRequest(BaseInsertRequest):
5-
"""table/upsert are request-level defaults; individual records (plain dicts shaped
6-
{"values": {...}, "table": ..., "upsert": ...}) may override either."""
7-
8-
def __init__(self, records, table=None, upsert=None):
9-
super().__init__(table, records=records, upsert=upsert)
6+
def __init__(self, values: list, table: str = None, upsert: Upsert = None):
7+
super().__init__(table, values, upsert=upsert)
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
class Upsert:
2-
"""Mirrors the wire type V1Upsert. update_type is a skyflow_flowvault.utils.enums.UpsertType value."""
1+
from typing import Optional, TypedDict
2+
from skyflow_flowvault.utils.enums import UpsertType
33

4-
def __init__(self, update_type=None, unique_columns=None):
5-
self.update_type = update_type
6-
self.unique_columns = unique_columns
4+
class Upsert(TypedDict, total=False):
5+
update_type: Optional[UpsertType]
6+
unique_columns: list

0 commit comments

Comments
 (0)