diff --git a/opengeodeweb_back_schemas.json b/opengeodeweb_back_schemas.json index 9e09d762..a8a9bd9d 100644 --- a/opengeodeweb_back_schemas.json +++ b/opengeodeweb_back_schemas.json @@ -294,6 +294,24 @@ ], "additionalProperties": false }, + "geode_object_inheritance": { + "$id": "opengeodeweb_back/geode_object_inheritance", + "route": "/geode_object_inheritance", + "methods": [ + "POST" + ], + "type": "object", + "properties": { + "geode_object_type": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "geode_object_type" + ], + "additionalProperties": false + }, "export_project": { "$id": "opengeodeweb_back/export_project", "route": "/export_project", diff --git a/requirements.txt b/requirements.txt index bd1ed694..c8216d02 100644 --- a/requirements.txt +++ b/requirements.txt @@ -60,4 +60,3 @@ werkzeug==3.1.2 # flask # flask-cors -opengeodeweb-microservice==1.*,>=1.0.14 diff --git a/src/opengeodeweb_back/routes/blueprint_routes.py b/src/opengeodeweb_back/routes/blueprint_routes.py index b02299e0..f16345b3 100644 --- a/src/opengeodeweb_back/routes/blueprint_routes.py +++ b/src/opengeodeweb_back/routes/blueprint_routes.py @@ -608,3 +608,48 @@ def import_extension() -> flask.Response: }, 200, ) + + +@routes.route( + schemas_dict["geode_object_inheritance"]["route"], + methods=schemas_dict["geode_object_inheritance"]["methods"], +) +def geode_object_inheritance() -> flask.Response: + json_data = utils_functions.validate_request( + flask.request, schemas_dict["geode_object_inheritance"] + ) + params = schemas.GeodeObjectInheritance.from_dict(json_data) + geode_object_type = params.geode_object_type + target_class = geode_functions.geode_object_from_string(geode_object_type) + + def get_all_bases(geode_class: type) -> set[type]: + bases = set() + for base_class in geode_class.__bases__: + if base_class is not object: + bases.add(base_class) + bases.update(get_all_bases(base_class)) + return bases + + def get_all_subclasses(geode_class: type) -> set[type]: + subclasses = set() + for subclass_class in geode_class.__subclasses__(): + subclasses.add(subclass_class) + subclasses.update(get_all_subclasses(subclass_class)) + return subclasses + + # Extract all related Geode classes (parents and children) + base_classes = get_all_bases(target_class) + subclass_classes = get_all_subclasses(target_class) + + # Filter GeodeObjectType to only include registered related objects, excluding target + parents = [] + children = [] + for geode_object_type_str, geode_class in geode_objects.items(): + if geode_class == target_class: + continue + if geode_class in base_classes: + parents.append(geode_object_type_str) + if geode_class in subclass_classes: + children.append(geode_object_type_str) + + return flask.make_response({"parents": parents, "children": children}, 200) diff --git a/src/opengeodeweb_back/routes/schemas/__init__.py b/src/opengeodeweb_back/routes/schemas/__init__.py index 763f0a24..606f794f 100644 --- a/src/opengeodeweb_back/routes/schemas/__init__.py +++ b/src/opengeodeweb_back/routes/schemas/__init__.py @@ -12,6 +12,7 @@ from .import_extension import * from .geographic_coordinate_systems import * from .geode_objects_and_output_extensions import * +from .geode_object_inheritance import * from .export_project import * from .edge_attribute_names import * from .cell_attribute_names import * diff --git a/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.json b/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.json new file mode 100644 index 00000000..70f97d5d --- /dev/null +++ b/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.json @@ -0,0 +1,17 @@ +{ + "route": "/geode_object_inheritance", + "methods": [ + "POST" + ], + "type": "object", + "properties": { + "geode_object_type": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "geode_object_type" + ], + "additionalProperties": false +} diff --git a/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.py b/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.py new file mode 100644 index 00000000..f634434b --- /dev/null +++ b/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.py @@ -0,0 +1,10 @@ +from dataclasses_json import DataClassJsonMixin +from dataclasses import dataclass + + +@dataclass +class GeodeObjectInheritance(DataClassJsonMixin): + def __post_init__(self) -> None: + print(self, flush=True) + + geode_object_type: str diff --git a/tests/test_routes.py b/tests/test_routes.py index 215e16d7..fad9b009 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -379,3 +379,48 @@ def test_database_uri_path(client: FlaskClient) -> None: assert app.config["SQLALCHEMY_DATABASE_URI"] == expected_uri assert os.path.exists(expected_db_path) + + +def test_geode_object_inheritance(client: FlaskClient) -> None: + route = "/opengeodeweb_back/geode_object_inheritance" + # Test BRep + response = client.post(route, json={"geode_object_type": "BRep"}) + assert response.status_code == 200 + json_data = response.get_json() + parents = json_data["parents"] + children = json_data["children"] + assert "BRep" not in parents + assert "BRep" not in children + # Descendants + assert "StructuralModel" in children + assert "ImplicitStructuralModel" in children + + # Test CrossSection + response = client.post(route, json={"geode_object_type": "CrossSection"}) + assert response.status_code == 200 + json_data = response.get_json() + parents = json_data["parents"] + children = json_data["children"] + assert "CrossSection" not in parents + assert "CrossSection" not in children + # Parent + assert "Section" in parents + # Descendant + assert "ImplicitCrossSection" in children + + # Test PolyhedralSolid3D + response = client.post(route, json={"geode_object_type": "PolyhedralSolid3D"}) + assert response.status_code == 200 + json_data = response.get_json() + parents = json_data["parents"] + children = json_data["children"] + assert "PolyhedralSolid3D" not in parents + assert "PolyhedralSolid3D" not in children + # Parent + assert "VertexSet" in parents + + # Test all params + def get_full_data() -> test_utils.JsonData: + return {"geode_object_type": "BRep"} + + test_utils.test_route_wrong_params(client, route, get_full_data)