From 8ac430eba896bb1ab2b6acb238151852d842298f Mon Sep 17 00:00:00 2001 From: wolandscat Date: Mon, 6 May 2024 23:31:34 -0600 Subject: [PATCH] Improve instance generator to output Locatable.archetype_details field properly. --- .../openehr/src/am/archetype/archetype_id.e | 18 ++- .../constraint_model/c_instance_generator.e | 94 +++++++++----- .../dt_object_node_modifier.e | 115 ++++++++++++++++++ .../src/rm/common/archetyped/archetyped.e | 15 ++- .../support/identification/access_group_ref.e | 5 +- 5 files changed, 208 insertions(+), 39 deletions(-) create mode 100644 libraries/openehr/src/am/archetype/constraint_model/dt_object_node_modifier.e diff --git a/libraries/openehr/src/am/archetype/archetype_id.e b/libraries/openehr/src/am/archetype/archetype_id.e index fceb875aa..a7f65f305 100755 --- a/libraries/openehr/src/am/archetype/archetype_id.e +++ b/libraries/openehr/src/am/archetype/archetype_id.e @@ -18,18 +18,26 @@ note class ARCHETYPE_ID inherit - RM_CONCEPT_ID + OBJECT_ID create - make, - make_from_string, - make_new, - default_create + make_from_string feature -- Definitions Default_id: STRING = "openehr-ehr-ENTRY.any.v1" +feature -- Status Report + + valid_id (an_id: STRING): BOOLEAN + -- + local + arch_hrid: ARCHETYPE_HRID + do + create arch_hrid.default_create + Result := arch_hrid.valid_adl2_id (an_id) + end + feature {NONE} -- Implementation id_pattern_regex: RX_PCRE_REGULAR_EXPRESSION diff --git a/libraries/openehr/src/am/archetype/constraint_model/c_instance_generator.e b/libraries/openehr/src/am/archetype/constraint_model/c_instance_generator.e index 16eb44701..ff8cffcd1 100644 --- a/libraries/openehr/src/am/archetype/constraint_model/c_instance_generator.e +++ b/libraries/openehr/src/am/archetype/constraint_model/c_instance_generator.e @@ -89,7 +89,6 @@ feature -- Visitor node_id := a_node.node_id dt_attribute_nodes.item.put_child (prototype_value) end - add_locatable_attrs (prototype_value, node_id) dt_object_nodes.extend (prototype_value) else @@ -122,7 +121,6 @@ feature -- Visitor if not c_attribute_completed.item then create prototype_value.make_anonymous prototype_value.set_im_type_name (a_node.rm_type_name) - add_locatable_attrs (prototype_value, a_node.node_id) dt_object_nodes.extend (prototype_value) dt_attribute_nodes.item.put_child (prototype_value) @@ -135,7 +133,7 @@ feature -- Visitor if not c_attribute_completed.item then dt_object_nodes.remove - -- for single valued node, marke completed after one object node + -- for single valued node, mark completed after one object node if attached a_node.parent as ca_parent and then ca_parent.is_single then c_attribute_completed.replace (True) end @@ -156,7 +154,6 @@ feature -- Visitor create prototype_value.make_anonymous prototype_value.set_im_type_name (a_node.rm_type_name) - add_locatable_attrs (prototype_value, a_node.node_id) dt_object_nodes.extend (prototype_value) dt_attribute_nodes.item.put_child (prototype_value) @@ -168,10 +165,9 @@ feature -- Visitor do if not c_attribute_completed.item then add_non_constrained_attrs (a_node, depth) - dt_object_nodes.remove - -- for single valued node, marke completed after one object node + -- for single valued node, mark completed after one object node if attached a_node.parent as ca_parent and then ca_parent.is_single then c_attribute_completed.replace (True) end @@ -191,7 +187,6 @@ feature -- Visitor if not c_attribute_completed.item then create prototype_value.make_anonymous prototype_value.set_im_type_name (a_node.rm_type_name) - add_locatable_attrs (prototype_value, a_node.node_id) dt_object_nodes.extend (prototype_value) dt_attribute_nodes.item.put_child (prototype_value) @@ -204,7 +199,7 @@ feature -- Visitor if not c_attribute_completed.item then dt_object_nodes.remove - -- for single valued node, marke completed after one object node + -- for single valued node, mark completed after one object node if attached a_node.parent as ca_parent and then ca_parent.is_single then c_attribute_completed.replace (True) end @@ -262,7 +257,7 @@ feature -- Visitor do if not c_attribute_completed.item then dt_obj := dt_object_converter.object_to_dt (a_node.prototype_value) - dt_obj.set_im_type_name (case_corrected (dt_obj.im_type_name)) + dt_obj.set_im_type_name (convert_to_snake_case (dt_obj.im_type_name)) dt_attribute_nodes.item.put_child (dt_obj) end end @@ -338,21 +333,6 @@ feature {NONE} -- Implementation create Result end - add_locatable_attrs (a_dt_object: DT_COMPLEX_OBJECT; a_node_id: STRING) - do - -- if LOCATABLE then add some attributes - if ref_model.is_descendant_of (a_dt_object.im_type_name, archetype_parent_class) then - - -- add an attribute for LOCATABLE.code - add_primitive_dt_attribute (a_dt_object, {OPENEHR_DEFINITIONS}.Locatable_node_attribute, a_node_id) - - if terminology.has_id_code (a_node_id) then - -- add an attribute for LOCATABLE.name - add_primitive_dt_attribute (a_dt_object, {OPENEHR_DEFINITIONS}.Locatable_name_attribute, terminology.term_definition (language, a_node_id).text) - end - end - end - add_primitive_dt_attribute (a_dt_object: DT_COMPLEX_OBJECT; attr_name: STRING; attr_val: ANY) local dt_attr: DT_ATTRIBUTE @@ -370,12 +350,15 @@ feature {NONE} -- Implementation local dt_attr: DT_ATTRIBUTE dt_object: DT_COMPLEX_OBJECT + dt_iterator: DT_VISITOR_ITERATOR do create dt_attr.make_single (attr_name) dt_object := dt_object_converter.object_to_dt (attr_val) dt_attr.put_child (dt_object) + -- convert type name to mixed snake case - dt_object.set_im_type_name (dt_object.im_type_name.item (1).out + dt_object.im_type_name.substring (2, dt_object.im_type_name.count).as_lower) + create dt_iterator.make (dt_object, dt_case_corrector) + dt_iterator.do_all a_dt_object.put_attribute (dt_attr) end @@ -397,6 +380,21 @@ feature {NONE} -- Implementation instantiated_attrs.extend (dt_attr_csr.item.im_attr_name) end + -- if LOCATABLE then add some attributes + if ref_model.is_descendant_of (dt_object_nodes.item.im_type_name, archetype_parent_class) then + -- add an attribute for LOCATABLE.archetype_node_id + if not instantiated_attrs.has ({OPENEHR_DEFINITIONS}.Locatable_node_attribute) then + add_primitive_dt_attribute (dt_object_nodes.item, {OPENEHR_DEFINITIONS}.Locatable_node_attribute, a_node.node_id) + instantiated_attrs.extend ({OPENEHR_DEFINITIONS}.Locatable_node_attribute) + end + + if not instantiated_attrs.has ({OPENEHR_DEFINITIONS}.Locatable_name_attribute) and terminology.has_id_code (a_node.node_id) then + -- add an attribute for LOCATABLE.name + add_primitive_dt_attribute (dt_object_nodes.item, {OPENEHR_DEFINITIONS}.Locatable_name_attribute, terminology.term_definition (language, a_node.node_id).text) + instantiated_attrs.extend ({OPENEHR_DEFINITIONS}.Locatable_name_attribute) + end + end + bmm_class := ref_model.class_definition (a_node.rm_type_name) across bmm_class.flat_properties as bmm_prop_csr loop prop_name := bmm_prop_csr.item.name @@ -431,6 +429,10 @@ feature {NONE} -- Implementation val := bmm_enum.item_values.first add_primitive_dt_attribute (dt_object_nodes.item, prop_name, val) + elseif attached {C_ARCHETYPE_ROOT} a_node as car and prop_type.is_case_insensitive_equal ("Archetyped") then + val := create {ARCHETYPED}.make (car.archetype_ref) + add_complex_dt_attribute (dt_object_nodes.item, prop_name, val) + -- deal with true primitive types elseif bmm_prop_csr.item.bmm_type.is_primitive then -- date/times @@ -511,12 +513,11 @@ feature {NONE} -- Implementation attrs_list.compare_objects attrs_list.extend ("null_flavour") attrs_list.extend ("uid") - Result.put (attrs_list, "Element") + Result.put (attrs_list, "Node") create attrs_list.make(0) attrs_list.compare_objects attrs_list.extend ("uid") - Result.put (attrs_list, "Cluster") Result.put (attrs_list, "Event_context") Result.put (attrs_list, "Folder") Result.put (attrs_list, "Section") @@ -536,18 +537,51 @@ feature {NONE} -- Implementation create attrs_list.make(0) attrs_list.compare_objects - attrs_list.extend ("code") attrs_list.extend ("result_time") - Result.put (attrs_list, "Element") + attrs_list.extend ("archetype_details") + attrs_list.extend ("code") + Result.put (attrs_list, "Lab_result") + Result.put (attrs_list, "Imaging") + + create attrs_list.make(0) + attrs_list.compare_objects + attrs_list.extend ("archetype_details") + attrs_list.extend ("code") + attrs_list.extend ("uid") + Result.put (attrs_list, "Direct_observation") + Result.put (attrs_list, "Assessment") + Result.put (attrs_list, "Questionnaire_result") + Result.put (attrs_list, "Composition") + + create attrs_list.make(0) + attrs_list.compare_objects + attrs_list.extend ("archetype_details") + attrs_list.extend ("code") + Result.put (attrs_list, "Node") + + create attrs_list.make(0) + attrs_list.compare_objects + attrs_list.extend ("value_status") + Result.put (attrs_list, "Measured") end - case_corrected (a_class_name: STRING): STRING + convert_to_snake_case (a_class_name: STRING): STRING -- convert class name case to correct form for BMM model -- TODO: build in class name style to BMM schemas do Result := a_class_name.item (1).out + a_class_name.substring (2, a_class_name.count).as_lower end + set_dt_node_type_to_snake_case (a_node: DT_OBJECT_ITEM) + do + a_node.set_im_type_name (convert_to_snake_case (a_node.im_type_name)) + end + + dt_case_corrector: DT_OBJECT_NODE_MODIFIER + once + create Result.make (agent set_dt_node_type_to_snake_case) + end + end diff --git a/libraries/openehr/src/am/archetype/constraint_model/dt_object_node_modifier.e b/libraries/openehr/src/am/archetype/constraint_model/dt_object_node_modifier.e new file mode 100644 index 000000000..3c5b052da --- /dev/null +++ b/libraries/openehr/src/am/archetype/constraint_model/dt_object_node_modifier.e @@ -0,0 +1,115 @@ +note + component: "ADL Workbench data synthesiser" + description: "Change IM type names to mixed snake-case" + keywords: "visitor, Data Tree" + author: "Thomas Beale" + support: "Graphite Health " + copyright: "Copyright (c) 2024 S2health.org" + license: "Apache 2.0 License " + +class DT_OBJECT_NODE_MODIFIER + +inherit + DT_VISITOR + +create + make + +feature -- Initialisation + + make (an_agent: like modifier_agent) + do + modifier_agent := an_agent + end + +feature -- Visitor + + start_complex_object_node (a_node: DT_COMPLEX_OBJECT; depth: INTEGER) + -- start serialising an DT_COMPLEX_OBJECT_NODE + do + modifier_agent.call ([a_node]) + end + + end_complex_object_node (a_node: DT_COMPLEX_OBJECT; depth: INTEGER) + -- end serialising an DT_COMPLEX_OBJECT_NODE + do + end + + start_attribute_node (a_node: DT_ATTRIBUTE; depth: INTEGER) + -- start serialising an DT_ATTRIBUTE_NODE + do + end + + end_attribute_node (a_node: DT_ATTRIBUTE; depth: INTEGER) + -- end serialising an DT_ATTRIBUTE_NODE + do + end + + start_primitive_object (a_node: DT_PRIMITIVE_OBJECT; depth: INTEGER) + -- start serialising a DT_OBJECT_SIMPLE + do + end + + end_primitive_object (a_node: DT_PRIMITIVE_OBJECT; depth: INTEGER) + -- end serialising a DT_OBJECT_SIMPLE + do + end + + start_primitive_object_list (a_node: DT_PRIMITIVE_OBJECT_LIST; depth: INTEGER) + -- start serialising an DT_OBJECT_SIMPLE_LIST + do + end + + end_primitive_object_list (a_node: DT_PRIMITIVE_OBJECT_LIST; depth: INTEGER) + -- end serialising an DT_OBJECT_SIMPLE_LIST + do + end + + start_primitive_object_interval (a_node: DT_PRIMITIVE_OBJECT_INTERVAL; depth: INTEGER) + -- start serialising a DT_OBJECT_SIMPLE + do + end + + end_primitive_object_interval (a_node: DT_PRIMITIVE_OBJECT_INTERVAL; depth: INTEGER) + -- end serialising a DT_OBJECT_SIMPLE + do + end + + start_primitive_object_interval_list (a_node: DT_PRIMITIVE_OBJECT_INTERVAL_LIST; depth: INTEGER) + -- start serialising a DT_OBJECT_SIMPLE + do + end + + end_primitive_object_interval_list (a_node: DT_PRIMITIVE_OBJECT_INTERVAL_LIST; depth: INTEGER) + -- end serialising a DT_OBJECT_SIMPLE + do + end + + start_object_reference (a_node: DT_OBJECT_REFERENCE; depth: INTEGER) + -- start serialising a DT_OBJECT_REFERENCE + do + end + + end_object_reference (a_node: DT_OBJECT_REFERENCE; depth: INTEGER) + -- end serialising a DT_OBJECT_REFERENCE + do + end + + start_object_reference_list (a_node: DT_OBJECT_REFERENCE_LIST; depth: INTEGER) + -- start serialising a DT_OBJECT_REFERENCE_LIST + do + end + + end_object_reference_list (a_node: DT_OBJECT_REFERENCE_LIST; depth: INTEGER) + -- end serialising a DT_OBJECT_REFERENCE_LIST + do + end + +feature {NONE} -- Implementation + + modifier_agent: PROCEDURE [ANY, TUPLE[DT_OBJECT_ITEM]] + +end + + + diff --git a/libraries/openehr/src/rm/common/archetyped/archetyped.e b/libraries/openehr/src/rm/common/archetyped/archetyped.e index a67c11df5..117be1be8 100755 --- a/libraries/openehr/src/rm/common/archetyped/archetyped.e +++ b/libraries/openehr/src/rm/common/archetyped/archetyped.e @@ -10,19 +10,28 @@ note copyright: "Copyright (c) 2000-2006 The openEHR Foundation " license: "Apache 2.0 License " - class ARCHETYPED +create + make + +feature -- Initialisation + + make (an_archetype_id: STRING) + do + create archetype_id.make_from_string (an_archetype_id) + end + feature -- Access - archetype_id: ARCHETYPE_HRID + archetype_id: ARCHETYPE_ID -- id of the archetype in the global archetype library rm_version: STRING = "1" -- relevant for exchange and implementations the version of the RM at the time of creation -- of this archetyped object. - access_control: ACCESS_GROUP_REF + access_control: detachable ACCESS_GROUP_REF -- Access control settings for this archetyped structure end diff --git a/libraries/openehr/src/rm/support/identification/access_group_ref.e b/libraries/openehr/src/rm/support/identification/access_group_ref.e index 8cd83df47..af4e2f2df 100644 --- a/libraries/openehr/src/rm/support/identification/access_group_ref.e +++ b/libraries/openehr/src/rm/support/identification/access_group_ref.e @@ -1,6 +1,6 @@ note component: "openEHR ADL Tools" - + description: "[ Reference to an ACCESS_GROUP object, e.g. in an access control service ]" @@ -19,6 +19,9 @@ class ACCESS_GROUP_REF inherit OBJECT_REF +create + make + invariant namespace_validity: namespace.is_equal("access_control") type_validity: type.is_equal("ACCESS_GROUP")