Skip to content

Commit 6df7437

Browse files
authored
Merge pull request #143 from forcedotcom/support-dlo-output-object-schema
support dlo output object schema
2 parents b2d3a64 + 47b47ee commit 6df7437

2 files changed

Lines changed: 116 additions & 6 deletions

File tree

‎src/datacustomcode/deploy.py‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -516,15 +516,13 @@ def create_data_transform(
516516
"version": "56.0",
517517
}
518518

519-
# outputDataObjects is only set for DMO-backed transforms. The server requires
520-
# the schema of any DMO created/updated by the transform; DLO transforms use
521-
# an existing materialized table and must not include this field.
522-
if isinstance(data_transform_config.permissions.write, DmoPermission):
523-
if not data_transform_config.dataObjects:
519+
if not data_transform_config.dataObjects:
520+
if isinstance(data_transform_config.permissions.write, DmoPermission):
524521
raise ValueError(
525522
"DMO transforms require 'dataObjects' in config.json describing "
526523
"the schema of each output DMO."
527524
)
525+
else:
528526
definition["outputDataObjects"] = [
529527
_data_object_to_output(obj) for obj in data_transform_config.dataObjects
530528
]

‎tests/test_deploy.py‎

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,37 @@ def test_get_config_dmo_with_data_objects(self, mock_file):
10181018
assert obj.fields[0].dataType == "text"
10191019
assert obj.fields[0].keyQualifierFieldName == "KQ_Id1__c"
10201020

1021+
@patch(
1022+
"builtins.open",
1023+
new_callable=mock_open,
1024+
read_data=(
1025+
'{"sdkVersion": "0.1.14", "entryPoint": "entrypoint.py", '
1026+
'"dataspace": "default", '
1027+
'"permissions": {"read": {"dlo": ["input_dlo"]}, '
1028+
'"write": {"dlo": ["output_dlo"]}}, '
1029+
'"dataObjects": [{'
1030+
'"name": "output_dlo", '
1031+
'"label": "Output DLO", '
1032+
'"type": "dataLakeObject", '
1033+
'"category": "profile", '
1034+
'"fields": [{"name": "Id__c", "label": "Id", '
1035+
'"dataType": "text", "isPrimaryKey": true, '
1036+
'"keyQualifierFieldName": "KQ_Id1__c"}]'
1037+
"}]}"
1038+
),
1039+
)
1040+
def test_get_config_dlo_with_data_objects(self, mock_file):
1041+
"""config.json parses the optional dataObjects schema for DLO writes."""
1042+
result = get_config("/test/dir")
1043+
assert isinstance(result, DataTransformConfig)
1044+
assert result.dataObjects is not None
1045+
assert len(result.dataObjects) == 1
1046+
obj = result.dataObjects[0]
1047+
assert obj.name == "output_dlo"
1048+
assert obj.category == "profile"
1049+
assert obj.fields[0].dataType == "text"
1050+
assert obj.fields[0].keyQualifierFieldName == "KQ_Id1__c"
1051+
10211052

10221053
class TestCreateDataTransform:
10231054
@patch("datacustomcode.deploy.get_config")
@@ -1286,12 +1317,93 @@ def test_create_data_transform_dmo_emits_output_data_objects(
12861317
}
12871318
]
12881319

1320+
@patch("datacustomcode.deploy.get_config")
1321+
@patch("datacustomcode.deploy._make_api_call")
1322+
def test_create_data_transform_dlo_emits_output_data_objects(
1323+
self, mock_make_api_call, mock_get_config
1324+
):
1325+
"""DLO transforms include outputDataObjects with transformed field names."""
1326+
access_token = AccessTokenResponse(
1327+
access_token="test_token", instance_url="https://instance.example.com"
1328+
)
1329+
metadata = CodeExtensionMetadata(
1330+
name="test_package",
1331+
version="1.0.0",
1332+
description="DLO with schema",
1333+
computeType="CPU_M",
1334+
codeType="script",
1335+
)
1336+
1337+
data_transform_config = DataTransformConfig(
1338+
sdkVersion="0.1.14",
1339+
entryPoint="entrypoint.py",
1340+
dataspace="default",
1341+
permissions=Permissions(
1342+
read=DloPermission(dlo=["input_dlo"]),
1343+
write=DloPermission(dlo=["output_dlo"]),
1344+
),
1345+
dataObjects=[
1346+
DataObject(
1347+
name="output_dlo",
1348+
label="Output DLO",
1349+
type="dataLakeObject",
1350+
category="profile",
1351+
fields=[
1352+
DataObjectField(
1353+
name="Id__c",
1354+
label="Id",
1355+
dataType="text",
1356+
isPrimaryKey=True,
1357+
keyQualifierFieldName="KQ_Id1__c",
1358+
),
1359+
DataObjectField(
1360+
name="KQ_Id1__c",
1361+
label="Key Qualifier Id",
1362+
dataType="text",
1363+
isPrimaryKey=False,
1364+
keyQualifierFieldName=None,
1365+
),
1366+
],
1367+
)
1368+
],
1369+
)
1370+
mock_make_api_call.return_value = {"id": "transform_id"}
1371+
1372+
create_data_transform(
1373+
"/test/dir", access_token, metadata, data_transform_config
1374+
)
1375+
1376+
request_body = mock_make_api_call.call_args[1]["json"]
1377+
assert request_body["definition"]["outputDataObjects"] == [
1378+
{
1379+
"category": "profile",
1380+
"fields": [
1381+
{
1382+
"isPrimaryKey": True,
1383+
"keyQualifierField": "KQ_Id1__c",
1384+
"label": "Id",
1385+
"name": "Id__c",
1386+
"type": "text",
1387+
},
1388+
{
1389+
"isPrimaryKey": False,
1390+
"label": "Key Qualifier Id",
1391+
"name": "KQ_Id1__c",
1392+
"type": "text",
1393+
},
1394+
],
1395+
"label": "Output DLO",
1396+
"name": "output_dlo",
1397+
"type": "dataLakeObject",
1398+
}
1399+
]
1400+
12891401
@patch("datacustomcode.deploy.get_config")
12901402
@patch("datacustomcode.deploy._make_api_call")
12911403
def test_create_data_transform_dlo_omits_output_data_objects(
12921404
self, mock_make_api_call, mock_get_config
12931405
):
1294-
"""DLO transforms must not include outputDataObjects in the payload."""
1406+
"""DLO transforms without dataObjects omit outputDataObjects from the payload"""
12951407
access_token = AccessTokenResponse(
12961408
access_token="test_token", instance_url="https://instance.example.com"
12971409
)

0 commit comments

Comments
 (0)