Skip to content

Commit 2f8310e

Browse files
authored
feat: add configurable use_parent_params field to dynamic streams (#633)
1 parent 4644271 commit 2f8310e

File tree

4 files changed

+191
-1
lines changed

4 files changed

+191
-1
lines changed

‎airbyte_cdk/sources/declarative/declarative_component_schema.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4235,6 +4235,11 @@ definitions:
42354235
- "$ref": "#/definitions/HttpComponentsResolver"
42364236
- "$ref": "#/definitions/ConfigComponentsResolver"
42374237
- "$ref": "#/definitions/ParametrizedComponentsResolver"
4238+
use_parent_parameters:
4239+
title: Use Parent Parameters
4240+
description: Whether or not to prioritize parent parameters over component parameters when constructing dynamic streams. Defaults to true for backward compatibility.
4241+
type: boolean
4242+
default: true
42384243
required:
42394244
- type
42404245
- stream_template

‎airbyte_cdk/sources/declarative/manifest_declarative_source.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,9 +553,13 @@ def _dynamic_stream_configs(
553553
for dynamic_stream in components_resolver.resolve_components(
554554
stream_template_config=stream_template_config
555555
):
556+
# Get the use_parent_parameters configuration from the dynamic definition
557+
# Default to True for backward compatibility, since connectors were already using it by default when this param was added
558+
use_parent_parameters = dynamic_definition.get("use_parent_parameters", True)
559+
556560
dynamic_stream = {
557561
**ManifestComponentTransformer().propagate_types_and_parameters(
558-
"", dynamic_stream, {}, use_parent_parameters=True
562+
"", dynamic_stream, {}, use_parent_parameters=use_parent_parameters
559563
)
560564
}
561565

‎airbyte_cdk/sources/declarative/models/declarative_component_schema.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
2+
13
# generated by datamodel-codegen:
24
# filename: declarative_component_schema.yaml
35

@@ -2958,6 +2960,11 @@ class DynamicDeclarativeStream(BaseModel):
29582960
description="Component resolve and populates stream templates with components values.",
29592961
title="Components Resolver",
29602962
)
2963+
use_parent_parameters: Optional[bool] = Field(
2964+
True,
2965+
description="Whether or not to prioritize parent parameters over component parameters when constructing dynamic streams. Defaults to true for backward compatibility.",
2966+
title="Use Parent Parameters",
2967+
)
29612968

29622969

29632970
ComplexFieldType.update_forward_refs()

‎unit_tests/sources/declarative/parsers/test_manifest_component_transformer.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,3 +569,177 @@ def test_propagate_property_chunking():
569569
transformer = ManifestComponentTransformer()
570570
actual_component = transformer.propagate_types_and_parameters("", component, {})
571571
assert actual_component == expected_component
572+
573+
574+
@pytest.mark.parametrize(
575+
"use_parent_parameters, expected_retriever_name, expected_requester_name, expected_requester_params_name",
576+
[
577+
pytest.param(
578+
True,
579+
"parent_priority",
580+
"component_priority",
581+
"parent_priority",
582+
id="use_parent_parameters_true",
583+
),
584+
pytest.param(
585+
False,
586+
"parent_priority",
587+
"component_priority",
588+
"component_priority",
589+
id="use_parent_parameters_false",
590+
),
591+
],
592+
)
593+
def test_use_parent_parameters_configuration(
594+
use_parent_parameters,
595+
expected_retriever_name,
596+
expected_requester_name,
597+
expected_requester_params_name,
598+
):
599+
"""Test that use_parent_parameters configuration controls parameter precedence."""
600+
component_with_parent_priority = {
601+
"type": "DeclarativeStream",
602+
"retriever": {
603+
"type": "SimpleRetriever",
604+
"requester": {
605+
"type": "HttpRequester",
606+
"name": "component_priority",
607+
"url_base": "https://coffee.example.io/v1/",
608+
"http_method": "GET",
609+
"primary_key": "id",
610+
"$parameters": {
611+
"name": "component_priority",
612+
},
613+
},
614+
"$parameters": {
615+
"name": "parent_priority",
616+
},
617+
},
618+
}
619+
620+
expected_component = {
621+
"type": "DeclarativeStream",
622+
"retriever": {
623+
"type": "SimpleRetriever",
624+
"name": expected_retriever_name,
625+
"requester": {
626+
"type": "HttpRequester",
627+
"name": expected_requester_name,
628+
"url_base": "https://coffee.example.io/v1/",
629+
"http_method": "GET",
630+
"primary_key": "id",
631+
"$parameters": {
632+
"name": expected_requester_params_name,
633+
},
634+
},
635+
"$parameters": {
636+
"name": "parent_priority",
637+
},
638+
},
639+
}
640+
641+
transformer = ManifestComponentTransformer()
642+
actual_component = transformer.propagate_types_and_parameters(
643+
"", component_with_parent_priority, {}, use_parent_parameters=use_parent_parameters
644+
)
645+
assert actual_component == expected_component
646+
647+
648+
def test_use_parent_parameters_none_behavior():
649+
"""Test that use_parent_parameters=None maintains backward compatibility."""
650+
component = {
651+
"type": "DeclarativeStream",
652+
"retriever": {
653+
"type": "SimpleRetriever",
654+
"requester": {
655+
"type": "HttpRequester",
656+
"name": "component_priority",
657+
"url_base": "https://coffee.example.io/v1/",
658+
"http_method": "GET",
659+
"primary_key": "id",
660+
"$parameters": {
661+
"name": "component_priority",
662+
},
663+
},
664+
"$parameters": {
665+
"name": "parent_priority",
666+
},
667+
},
668+
}
669+
670+
expected_component_priority = {
671+
"type": "DeclarativeStream",
672+
"retriever": {
673+
"type": "SimpleRetriever",
674+
"name": "parent_priority", # Parent parameter takes precedence (default behavior)
675+
"requester": {
676+
"type": "HttpRequester",
677+
"name": "component_priority", # Component parameter takes precedence
678+
"url_base": "https://coffee.example.io/v1/",
679+
"http_method": "GET",
680+
"primary_key": "id",
681+
"$parameters": {
682+
"name": "component_priority",
683+
},
684+
},
685+
"$parameters": {
686+
"name": "parent_priority",
687+
},
688+
},
689+
}
690+
691+
transformer = ManifestComponentTransformer()
692+
actual = transformer.propagate_types_and_parameters(
693+
"", component, {}, use_parent_parameters=None
694+
)
695+
assert actual == expected_component_priority
696+
697+
698+
def test_dynamic_stream_use_parent_parameters_configuration():
699+
"""Test that use_parent_parameters configuration is properly read from dynamic stream definitions."""
700+
701+
transformer = ManifestComponentTransformer()
702+
703+
# Only parent has $parameters
704+
component = {
705+
"type": "DeclarativeStream",
706+
"retriever": {
707+
"type": "SimpleRetriever",
708+
},
709+
"$parameters": {"name": "parent_name"},
710+
}
711+
712+
# When use_parent_parameters=False, component parameters should take precedence (but there are none)
713+
result_false = transformer.propagate_types_and_parameters(
714+
"", component, {}, use_parent_parameters=False
715+
)
716+
# When use_parent_parameters=True, parent parameters should take precedence (and are used)
717+
result_true = transformer.propagate_types_and_parameters(
718+
"", component, {}, use_parent_parameters=True
719+
)
720+
721+
# In both cases, since only the parent has $parameters, the retriever should get "parent_name"
722+
assert result_false["retriever"]["name"] == "parent_name"
723+
assert result_true["retriever"]["name"] == "parent_name"
724+
725+
# Now, add a $parameters to the retriever to see the difference
726+
component_with_both = {
727+
"type": "DeclarativeStream",
728+
"retriever": {
729+
"type": "SimpleRetriever",
730+
"$parameters": {"name": "retriever_name"},
731+
},
732+
"$parameters": {"name": "parent_name"},
733+
}
734+
735+
result_false = transformer.propagate_types_and_parameters(
736+
"", component_with_both, {}, use_parent_parameters=False
737+
)
738+
result_true = transformer.propagate_types_and_parameters(
739+
"", component_with_both, {}, use_parent_parameters=True
740+
)
741+
742+
# When use_parent_parameters=False, retriever's own $parameters win
743+
assert result_false["retriever"]["name"] == "retriever_name"
744+
# When use_parent_parameters=True, parent's $parameters win
745+
assert result_true["retriever"]["name"] == "parent_name"

0 commit comments

Comments
 (0)