Skip to content

Commit 9f03df7

Browse files
authored
IFC-1445 Add relationships + attributes to generic template (#6304)
1 parent 71528cc commit 9f03df7

File tree

3 files changed

+49
-37
lines changed

3 files changed

+49
-37
lines changed

backend/infrahub/core/schema/schema_branch.py

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,10 +1909,8 @@ def manage_object_template_relationships(self) -> None:
19091909

19101910
self.set(name=node_name, schema=node_schema)
19111911

1912-
def add_relationships_to_template(self, node: NodeSchema) -> None:
1912+
def add_relationships_to_template(self, node: NodeSchema | GenericSchema) -> None:
19131913
template_schema = self.get(name=self._get_object_template_kind(node_kind=node.kind), duplicate=False)
1914-
if template_schema.is_generic_schema:
1915-
return
19161914

19171915
# Remove previous relationships to account for new ones
19181916
template_schema.relationships = [
@@ -1954,11 +1952,16 @@ def add_relationships_to_template(self, node: NodeSchema) -> None:
19541952
label=f"{relationship.name} template".title()
19551953
if relationship.kind in [RelationshipKind.COMPONENT, RelationshipKind.PARENT]
19561954
else relationship.name.title(),
1955+
inherited=relationship.inherited,
19571956
)
19581957
)
19591958

19601959
parent_hfid = f"{relationship.name}__template_name__value"
1961-
if relationship.kind == RelationshipKind.PARENT and parent_hfid not in template_schema.human_friendly_id:
1960+
if (
1961+
not node.is_generic_schema
1962+
and relationship.kind == RelationshipKind.PARENT
1963+
and parent_hfid not in template_schema.human_friendly_id
1964+
):
19621965
template_schema.human_friendly_id = [parent_hfid] + template_schema.human_friendly_id
19631966
template_schema.uniqueness_constraints[0].append(relationship.name)
19641967

@@ -1983,9 +1986,6 @@ def generate_object_template_from_node(
19831986
need_template_kinds = [n.kind for n in need_templates]
19841987

19851988
if node.is_generic_schema:
1986-
# When needing a template for a generic, we generate an empty shell mostly to make sure that schemas (including the GraphQL one) will
1987-
# look right. We don't really care about applying inheritance of fields as it was already processed and actual templates will have the
1988-
# correct attributes and relationships
19891989
template = GenericSchema(
19901990
name=node.kind,
19911991
namespace="Template",
@@ -2001,44 +2001,43 @@ def generate_object_template_from_node(
20012001
if used in need_template_kinds:
20022002
template.used_by.append(self._get_object_template_kind(node_kind=used))
20032003

2004-
return template
2005-
2006-
template = TemplateSchema(
2007-
name=node.kind,
2008-
namespace="Template",
2009-
label=f"Object template {node.label}",
2010-
description=f"Object template for {node.kind}",
2011-
branch=node.branch,
2012-
include_in_menu=False,
2013-
display_labels=["template_name__value"],
2014-
human_friendly_id=["template_name__value"],
2015-
uniqueness_constraints=[["template_name__value"]],
2016-
inherit_from=[InfrahubKind.LINEAGESOURCE, InfrahubKind.NODE, core_template_schema.kind],
2017-
default_filter="template_name__value",
2018-
attributes=[template_name_attr],
2019-
relationships=[
2020-
RelationshipSchema(
2021-
name="related_nodes",
2022-
identifier="node__objecttemplate",
2023-
peer=node.kind,
2024-
kind=RelationshipKind.TEMPLATE,
2025-
cardinality=RelationshipCardinality.MANY,
2026-
branch=BranchSupportType.AWARE,
2027-
)
2028-
],
2029-
)
2004+
else:
2005+
template = TemplateSchema(
2006+
name=node.kind,
2007+
namespace="Template",
2008+
label=f"Object template {node.label}",
2009+
description=f"Object template for {node.kind}",
2010+
branch=node.branch,
2011+
include_in_menu=False,
2012+
display_labels=["template_name__value"],
2013+
human_friendly_id=["template_name__value"],
2014+
uniqueness_constraints=[["template_name__value"]],
2015+
inherit_from=[InfrahubKind.LINEAGESOURCE, InfrahubKind.NODE, core_template_schema.kind],
2016+
default_filter="template_name__value",
2017+
attributes=[template_name_attr],
2018+
relationships=[
2019+
RelationshipSchema(
2020+
name="related_nodes",
2021+
identifier="node__objecttemplate",
2022+
peer=node.kind,
2023+
kind=RelationshipKind.TEMPLATE,
2024+
cardinality=RelationshipCardinality.MANY,
2025+
branch=BranchSupportType.AWARE,
2026+
)
2027+
],
2028+
)
20302029

2031-
for inherited in node.inherit_from:
2032-
if inherited in need_template_kinds:
2033-
template.inherit_from.append(self._get_object_template_kind(node_kind=inherited))
2030+
for inherited in node.inherit_from:
2031+
if inherited in need_template_kinds:
2032+
template.inherit_from.append(self._get_object_template_kind(node_kind=inherited))
20342033

20352034
for node_attr in node.attributes:
20362035
if node_attr.unique or node_attr.read_only:
20372036
continue
20382037

20392038
attr = AttributeSchema(
20402039
optional=node_attr.optional if is_autogenerated_subtemplate else True,
2041-
**node_attr.model_dump(exclude=["id", "unique", "optional", "read_only", "inherited"]),
2040+
**node_attr.model_dump(exclude=["id", "unique", "optional", "read_only"]),
20422041
)
20432042
template.attributes.append(attr)
20442043

backend/tests/unit/core/schema_manager/test_manager_schema.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3068,6 +3068,18 @@ async def test_manage_object_templates_with_component_relationships():
30683068
# Optional value in component template should match original's
30693069
assert attr.optional == template_attr.optional
30703070

3071+
# Verify the generic by checking its attributes and relationships
3072+
test_interface_template = schema_branch.get(name=f"Template{TestKind.INTERFACE}", duplicate=False)
3073+
assert test_interface_template.is_generic_schema
3074+
test_interface = schema_branch.get(name=TestKind.INTERFACE, duplicate=False)
3075+
assert test_interface.is_generic_schema
3076+
for attr in test_interface.attributes:
3077+
template_attr = test_interface_template.get_attribute(name=attr.name)
3078+
assert attr.optional == template_attr.optional
3079+
for rel in test_interface.relationships:
3080+
template_rel = test_interface_template.get_relationship(name=rel.name)
3081+
assert template_rel.peer == f"Template{rel.peer}"
3082+
30713083
# Verify when a node is marked as absent
30723084
ABSENT_VIRTUAL_INTERFACE = copy.deepcopy(DEVICE_SCHEMA)
30733085
ABSENT_VIRTUAL_INTERFACE.get(name=TestKind.VIRTUAL_INTERFACE).state = HashableModelState.ABSENT

changelog/6287.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add attributes and relationships to generic templates to ensure proper GraphQL schema generation

0 commit comments

Comments
 (0)