Skip to content

Commit faa0d61

Browse files
committed
feat: use_parent_params configurable
1 parent 1733ec3 commit faa0d61

File tree

4 files changed

+234
-1
lines changed

4 files changed

+234
-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: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,3 +569,220 @@ 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+
def test_use_parent_parameters_configuration():
575+
"""Test that use_parent_parameters configuration controls parameter precedence."""
576+
# Test with use_parent_parameters=True (parent parameters take precedence)
577+
component_with_parent_priority = {
578+
"type": "DeclarativeStream",
579+
"retriever": {
580+
"type": "SimpleRetriever",
581+
"requester": {
582+
"type": "HttpRequester",
583+
"name": "component_priority",
584+
"url_base": "https://coffee.example.io/v1/",
585+
"http_method": "GET",
586+
"primary_key": "id",
587+
"$parameters": {
588+
"name": "component_priority",
589+
},
590+
},
591+
"$parameters": {
592+
"name": "parent_priority",
593+
},
594+
},
595+
}
596+
597+
expected_with_parent_priority = {
598+
"type": "DeclarativeStream",
599+
"retriever": {
600+
"type": "SimpleRetriever",
601+
"name": "parent_priority", # Parent parameter takes precedence
602+
"requester": {
603+
"type": "HttpRequester",
604+
"name": "component_priority", # Explicit value is not overridden
605+
"url_base": "https://coffee.example.io/v1/",
606+
"http_method": "GET",
607+
"primary_key": "id",
608+
"$parameters": {
609+
"name": "parent_priority", # Parent parameter propagated to nested component
610+
},
611+
},
612+
"$parameters": {
613+
"name": "parent_priority",
614+
},
615+
},
616+
}
617+
618+
transformer = ManifestComponentTransformer()
619+
actual_with_parent_priority = transformer.propagate_types_and_parameters(
620+
"", component_with_parent_priority, {}, use_parent_parameters=True
621+
)
622+
assert actual_with_parent_priority == expected_with_parent_priority
623+
624+
# Test with use_parent_parameters=False (component parameters take precedence)
625+
expected_with_component_priority = {
626+
"type": "DeclarativeStream",
627+
"retriever": {
628+
"type": "SimpleRetriever",
629+
"name": "parent_priority", # Parent parameter takes precedence at this level
630+
"requester": {
631+
"type": "HttpRequester",
632+
"name": "component_priority", # Component parameter takes precedence
633+
"url_base": "https://coffee.example.io/v1/",
634+
"http_method": "GET",
635+
"primary_key": "id",
636+
"$parameters": {
637+
"name": "component_priority",
638+
},
639+
},
640+
"$parameters": {
641+
"name": "parent_priority",
642+
},
643+
},
644+
}
645+
646+
actual_with_component_priority = transformer.propagate_types_and_parameters(
647+
"", component_with_parent_priority, {}, use_parent_parameters=False
648+
)
649+
assert actual_with_component_priority == expected_with_component_priority
650+
651+
652+
def test_use_parent_parameters_none_behavior():
653+
"""Test that use_parent_parameters=None maintains backward compatibility."""
654+
component = {
655+
"type": "DeclarativeStream",
656+
"retriever": {
657+
"type": "SimpleRetriever",
658+
"requester": {
659+
"type": "HttpRequester",
660+
"name": "component_priority",
661+
"url_base": "https://coffee.example.io/v1/",
662+
"http_method": "GET",
663+
"primary_key": "id",
664+
"$parameters": {
665+
"name": "component_priority",
666+
},
667+
},
668+
"$parameters": {
669+
"name": "parent_priority",
670+
},
671+
},
672+
}
673+
674+
expected_component_priority = {
675+
"type": "DeclarativeStream",
676+
"retriever": {
677+
"type": "SimpleRetriever",
678+
"name": "parent_priority", # Parent parameter takes precedence (default behavior)
679+
"requester": {
680+
"type": "HttpRequester",
681+
"name": "component_priority", # Component parameter takes precedence
682+
"url_base": "https://coffee.example.io/v1/",
683+
"http_method": "GET",
684+
"primary_key": "id",
685+
"$parameters": {
686+
"name": "component_priority",
687+
},
688+
},
689+
"$parameters": {
690+
"name": "parent_priority",
691+
},
692+
},
693+
}
694+
695+
transformer = ManifestComponentTransformer()
696+
actual = transformer.propagate_types_and_parameters(
697+
"", component, {}, use_parent_parameters=None
698+
)
699+
assert actual == expected_component_priority
700+
701+
702+
def test_dynamic_stream_use_parent_parameters_configuration():
703+
"""Test that use_parent_parameters configuration is properly read from dynamic stream definitions."""
704+
705+
transformer = ManifestComponentTransformer()
706+
707+
# Only parent has $parameters
708+
component = {
709+
"type": "DeclarativeStream",
710+
"retriever": {
711+
"type": "SimpleRetriever",
712+
},
713+
"$parameters": {"name": "parent_name"},
714+
}
715+
716+
# When use_parent_parameters=False, component parameters should take precedence (but there are none)
717+
result_false = transformer.propagate_types_and_parameters(
718+
"", component, {}, use_parent_parameters=False
719+
)
720+
# When use_parent_parameters=True, parent parameters should take precedence (and are used)
721+
result_true = transformer.propagate_types_and_parameters(
722+
"", component, {}, use_parent_parameters=True
723+
)
724+
725+
# In both cases, since only the parent has $parameters, the retriever should get "parent_name"
726+
assert result_false["retriever"]["name"] == "parent_name"
727+
assert result_true["retriever"]["name"] == "parent_name"
728+
729+
# Now, add a $parameters to the retriever to see the difference
730+
component_with_both = {
731+
"type": "DeclarativeStream",
732+
"retriever": {
733+
"type": "SimpleRetriever",
734+
"$parameters": {"name": "retriever_name"},
735+
},
736+
"$parameters": {"name": "parent_name"},
737+
}
738+
739+
result_false = transformer.propagate_types_and_parameters(
740+
"", component_with_both, {}, use_parent_parameters=False
741+
)
742+
result_true = transformer.propagate_types_and_parameters(
743+
"", component_with_both, {}, use_parent_parameters=True
744+
)
745+
746+
# When use_parent_parameters=False, retriever's own $parameters win
747+
assert result_false["retriever"]["name"] == "retriever_name"
748+
# When use_parent_parameters=True, parent's $parameters win
749+
assert result_true["retriever"]["name"] == "parent_name"
750+
751+
752+
def test_use_parent_parameters_simple():
753+
"""Simple test to understand the use_parent_parameters behavior."""
754+
component = {
755+
"type": "DeclarativeStream",
756+
"retriever": {
757+
"type": "SimpleRetriever",
758+
"$parameters": {
759+
"name": "component_name",
760+
},
761+
},
762+
"$parameters": {
763+
"name": "parent_name",
764+
},
765+
}
766+
767+
transformer = ManifestComponentTransformer()
768+
769+
# Test with use_parent_parameters=True
770+
result_true = transformer.propagate_types_and_parameters(
771+
"", component, {}, use_parent_parameters=True
772+
)
773+
print("use_parent_parameters=True:", result_true)
774+
775+
# Test with use_parent_parameters=False
776+
result_false = transformer.propagate_types_and_parameters(
777+
"", component, {}, use_parent_parameters=False
778+
)
779+
print("use_parent_parameters=False:", result_false)
780+
781+
# Test with use_parent_parameters=None (default)
782+
result_none = transformer.propagate_types_and_parameters(
783+
"", component, {}, use_parent_parameters=None
784+
)
785+
print("use_parent_parameters=None:", result_none)
786+
787+
# For now, just assert that the results are different
788+
assert result_true != result_false

0 commit comments

Comments
 (0)