tricc-oo 1.5.23__py3-none-any.whl → 1.5.24__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tests/build.py CHANGED
@@ -3,6 +3,10 @@ from tricc_oo.strategies.output.xlsform_cht_hf import XLSFormCHTHFStrategy
3
3
  from tricc_oo.strategies.output.xlsform_cht import XLSFormCHTStrategy
4
4
  from tricc_oo.strategies.output.xlsform_cdss import XLSFormCDSSStrategy
5
5
  from tricc_oo.strategies.output.xls_form import XLSFormStrategy
6
+ from tricc_oo.strategies.output.openmrs_form import OpenMRSStrategy
7
+ from tricc_oo.strategies.output.fhir_form import FHIRStrategy
8
+ from tricc_oo.strategies.output.html_form import HTMLStrategy
9
+
6
10
  from tricc_oo.strategies.input.drawio import DrawioStrategy
7
11
  import getopt
8
12
  import gettext
@@ -6,9 +6,13 @@ from fhir.resources.codesystem import (
6
6
 
7
7
  from fhir.resources.valueset import ValueSet
8
8
  import logging
9
+ import uuid
9
10
 
10
11
  logger = logging.getLogger("default")
11
12
 
13
+ # Namespace for deterministic UUIDs
14
+ UUID_NAMESPACE = uuid.UUID('12345678-1234-5678-9abc-def012345678')
15
+
12
16
 
13
17
  def lookup_codesystems_code(codesystems, ref):
14
18
  if ref.startswith("final."):
@@ -83,7 +87,8 @@ def check_and_add_concept(code_system: CodeSystem, code: str, display: str, attr
83
87
  new_concept = concept
84
88
  if not new_concept:
85
89
  # Add the new concept if it does not exist
86
- new_concept = CodeSystemConcept.construct(code=code, display=display)
90
+ concept_id = str(uuid.uuid5(UUID_NAMESPACE, display))
91
+ new_concept = CodeSystemConcept.construct(code=code, display=display, id=concept_id)
87
92
  if not hasattr(code_system, "concept"):
88
93
  code_system.concept = []
89
94
  code_system.concept.append(new_concept)
tricc_oo/models/tricc.py CHANGED
@@ -404,7 +404,7 @@ class TriccNodeSelectYesNo(TriccNodeSelectOne):
404
404
  pass
405
405
 
406
406
 
407
- class TriccNodeAcceptDiagnostic(TriccNodeSelectOne):
407
+ class TriccNodeAcceptDiagnostic(TriccNodeSelectYesNo):
408
408
  severity: Optional[str] = None
409
409
  priority: Union[float, int, None] = None
410
410
 
@@ -3,7 +3,7 @@ import os
3
3
 
4
4
  from tricc_oo.converters.xml_to_tricc import create_activity
5
5
  from tricc_oo.visitors.tricc import (
6
- process_calculate,
6
+ load_calculate,
7
7
  set_prev_next_node,
8
8
  replace_node,
9
9
  stashed_node_func,
@@ -47,7 +47,7 @@ class DrawioStrategy(BaseInputStrategy):
47
47
  # add save nodes and merge nodes
48
48
  stashed_node_func(
49
49
  start_page.root,
50
- process_calculate,
50
+ load_calculate,
51
51
  used_calculates=used_calculates,
52
52
  calculates=calculates,
53
53
  recursive=False,
@@ -83,6 +83,7 @@ class BaseOutPutStrategy:
83
83
  # node function
84
84
  @abc.abstractmethod
85
85
  def generate_calculate(self, node, **kwargs):
86
+ # called to generate the calculates on the project
86
87
  pass
87
88
 
88
89
  @abc.abstractmethod
@@ -91,10 +92,14 @@ class BaseOutPutStrategy:
91
92
 
92
93
  @abc.abstractmethod
93
94
  def generate_relevance(self, node, **kwargs):
95
+ # called to generate the references on the project
96
+
94
97
  pass
95
98
 
96
99
  @abc.abstractmethod
97
100
  def generate_export(self, node, **kwargs):
101
+ # called to the project export
102
+
98
103
  pass
99
104
 
100
105
  @abc.abstractmethod
@@ -102,87 +107,116 @@ class BaseOutPutStrategy:
102
107
  pass
103
108
 
104
109
  def tricc_operation_equal(self, ref_expressions):
110
+ # r[0] = r[1]
105
111
  raise NotImplementedError("This type of opreration is not supported in this strategy")
106
112
 
107
113
  def tricc_operation_not_equal(self, ref_expressions):
114
+ # r[0] != r[1]
108
115
  raise NotImplementedError("This type of opreration is not supported in this strategy")
109
116
 
110
117
  def tricc_operation_not(self, ref_expressions):
118
+ # !r[0]
111
119
  raise NotImplementedError("This type of opreration is not supported in this strategy")
112
120
 
113
121
  def tricc_operation_and(self, ref_expressions):
122
+ # r[0] and r[1] ... and r[n]
114
123
  raise NotImplementedError("This type of opreration is not supported in this strategy")
115
124
 
116
125
  def tricc_operation_or(self, ref_expressions):
126
+ # r[0] or r[1] ... or r[n]
117
127
  raise NotImplementedError("This type of opreration is not supported in this strategy")
118
128
 
119
129
  def tricc_operation_or_and(self, ref_expressions):
130
+ # (r[0] or r[1] ... or r[n-1]) and r[n]
120
131
  raise NotImplementedError("This type of opreration is not supported in this strategy")
121
132
 
122
133
  def tricc_operation_native(self, ref_expressions):
134
+ # r[0](*r[1:])
123
135
  raise NotImplementedError("This type of opreration is not supported in this strategy")
124
136
 
125
137
  def tricc_operation_istrue(self, ref_expressions):
138
+ # r[0] is true
126
139
  raise NotImplementedError("This type of opreration is not supported in this strategy")
127
140
 
128
141
  def tricc_operation_isfalse(self, ref_expressions):
142
+ # r[0] is false
129
143
  raise NotImplementedError("This type of opreration is not supported in this strategy")
130
144
 
131
145
  def tricc_operation_selected(self, ref_expressions):
146
+ # for choice question (single or multiple) it returns true if the second reference is selected
147
+ # r[1] in r[0]
132
148
  raise NotImplementedError("This type of opreration is not supported in this strategy")
133
149
 
134
150
  def tricc_operation_more_or_equal(self, ref_expressions):
151
+ # r[0] >= r[1]
135
152
  raise NotImplementedError("This type of opreration is not supported in this strategy")
136
153
 
137
154
  def tricc_operation_less_or_equal(self, ref_expressions):
155
+ # r[0] <= r[1]
138
156
  raise NotImplementedError("This type of opreration is not supported in this strategy")
139
157
 
140
158
  def tricc_operation_more(self, ref_expressions):
159
+ # r[0] > r[1]
141
160
  raise NotImplementedError("This type of opreration is not supported in this strategy")
142
161
 
143
162
  def tricc_operation_less(self, ref_expressions):
163
+ # r[0] < r[1]
144
164
  raise NotImplementedError("This type of opreration is not supported in this strategy")
145
165
 
146
166
  def tricc_operation_between(self, ref_expressions):
167
+ # r[0] between r[1] and r[2]
147
168
  raise NotImplementedError("This type of opreration is not supported in this strategy")
148
169
 
149
170
  def tricc_operation_case(self, ref_expressions):
171
+ # case r[0] when r[1][0] then r[1][1] ... when r[n-1][0] then r[n-1][1] else (r[n] or None)
150
172
  raise NotImplementedError("This type of opreration is not supported in this strategy")
151
173
 
152
174
  def tricc_operation_if(self, ref_expressions):
175
+ # if r[0][0] then r[0][1] ... elif r[n-1][0] then r[n-1][1] else (r[n] or None)
153
176
  raise NotImplementedError("This type of opreration is not supported in this strategy")
154
177
 
155
178
  def tricc_operation_contains(self, ref_expressions):
179
+ # r[0] contains r[1]
156
180
  raise NotImplementedError("This type of opreration is not supported in this strategy")
157
181
 
158
182
  def tricc_operation_exists(self, ref_expressions):
183
+ # r[0] exists
159
184
  raise NotImplementedError("This type of opreration is not supported in this strategy")
160
185
 
161
186
  def tricc_operation_has_qualifier(self, ref_expressions):
187
+ # r[0] is a class and has r[1] qualifier
162
188
  raise NotImplementedError("This type of opreration is not supported in this strategy")
163
189
 
164
190
  def tricc_operation_zscore(self, ref_expressions):
191
+ # FIXME zscore((gender=r[0], Xfy=r[1], xfY=r[2])
165
192
  raise NotImplementedError("This type of opreration is not supported in this strategy")
166
193
 
167
194
  def tricc_operation_datetime_to_decimal(self, ref_expressions):
195
+ # cast r[0] in decimal
168
196
  raise NotImplementedError("This type of opreration is not supported in this strategy")
169
197
 
170
198
  def tricc_operation_round(self, ref_expressions):
199
+ # round(r[0], r[1])
171
200
  raise NotImplementedError("This type of opreration is not supported in this strategy")
172
201
 
173
202
  def tricc_operation_izscore(self, ref_expressions):
203
+ # FIXME izscore(gender=r[0], Z=r[1], xfY=r[2])
174
204
  raise NotImplementedError("This type of opreration is not supported in this strategy")
175
205
 
176
206
  def tricc_operation_age_day(self, ref_expressions):
207
+ # Patient age in day
177
208
  raise NotImplementedError("This type of opreration is not supported in this strategy")
178
209
 
179
210
  def tricc_operation_age_month(self, ref_expressions):
211
+ # Patient age in Month
180
212
  raise NotImplementedError("This type of opreration is not supported in this strategy")
181
213
 
182
214
  def tricc_operation_age_year(self, ref_expressions):
215
+ # Patient age in Years
183
216
  raise NotImplementedError("This type of opreration is not supported in this strategy")
184
217
 
185
218
  def tricc_operation_concatenate(self, ref_expressions):
219
+ # concatenate(*r)
186
220
  raise NotImplementedError("This type of opreration is not supported in this strategy")
187
221
 
188
222
  # Utils
@@ -0,0 +1,377 @@
1
+ import logging
2
+ import os
3
+ import json
4
+ import datetime
5
+ from tricc_oo.strategies.output.base_output_strategy import BaseOutPutStrategy
6
+ from tricc_oo.models.base import (
7
+ TriccOperation,
8
+ TriccStatic, TriccReference
9
+ )
10
+ from tricc_oo.models.tricc import (
11
+ TriccNodeSelectOption,
12
+ TriccNodeInputModel,
13
+ TriccNodeBaseModel
14
+ )
15
+ from tricc_oo.converters.tricc_to_xls_form import get_export_name
16
+
17
+ logger = logging.getLogger("default")
18
+
19
+
20
+ class FHIRStrategy(BaseOutPutStrategy):
21
+ processes = ["main"]
22
+ project = None
23
+ output_path = None
24
+
25
+ def __init__(self, project, output_path):
26
+ super().__init__(project, output_path)
27
+ self.questionnaires = {} # segment -> questionnaire
28
+ self.cql_libraries = {}
29
+ self.fml_mappings = {}
30
+
31
+ def get_tricc_operation_expression(self, operation):
32
+ # For CQL
33
+ ref_expressions = []
34
+ if not hasattr(operation, "reference"):
35
+ return self.get_tricc_operation_operand(operation)
36
+ for r in operation.reference:
37
+ if isinstance(r, list):
38
+ r_expr = [
39
+ (
40
+ self.get_tricc_operation_expression(sr)
41
+ if isinstance(sr, TriccOperation)
42
+ else self.get_tricc_operation_operand(sr)
43
+ )
44
+ for sr in r
45
+ ]
46
+ elif isinstance(r, TriccOperation):
47
+ r_expr = self.get_tricc_operation_expression(r)
48
+ else:
49
+ r_expr = self.get_tricc_operation_operand(r)
50
+ if isinstance(r_expr, TriccReference):
51
+ r_expr = self.get_tricc_operation_operand(r_expr)
52
+ ref_expressions.append(r_expr)
53
+
54
+ # build lower level
55
+ if hasattr(self, f"tricc_operation_{operation.operator}"):
56
+ callable = getattr(self, f"tricc_operation_{operation.operator}")
57
+ return callable(ref_expressions)
58
+ else:
59
+ raise NotImplementedError(
60
+ f"This type of operation '{operation.operator}' is not supported in this strategy"
61
+ )
62
+
63
+ def execute(self):
64
+ version = datetime.datetime.now().strftime("%Y%m%d%H%M")
65
+ logger.info(f"build version: {version}")
66
+ if "main" in self.project.start_pages:
67
+ self.process_base(self.project.start_pages, pages=self.project.pages, version=version)
68
+ else:
69
+ logger.critical("Main process required")
70
+
71
+ logger.info("generate the relevance based on edges")
72
+ self.process_relevance(self.project.start_pages, pages=self.project.pages)
73
+
74
+ logger.info("generate the calculate based on edges")
75
+ self.process_calculate(self.project.start_pages, pages=self.project.pages)
76
+
77
+ logger.info("generate the export format")
78
+ self.process_export(self.project.start_pages, pages=self.project.pages)
79
+
80
+ logger.info("print the export")
81
+ self.export(self.project.start_pages, version=version)
82
+
83
+ def generate_base(self, node, **kwargs):
84
+ # Generate Questionnaire items per segment
85
+ segment = getattr(node, 'segment', 'main')
86
+ if segment not in self.questionnaires:
87
+ self.questionnaires[segment] = {
88
+ "resourceType": "Questionnaire",
89
+ "id": f"questionnaire-{segment}",
90
+ "url": f"http://example.com/Questionnaire/{segment}",
91
+ "status": "draft",
92
+ "item": []
93
+ }
94
+ item = {
95
+ "linkId": get_export_name(node),
96
+ "text": getattr(node, 'label', ''),
97
+ "type": self.map_tricc_type_to_fhir(node.tricc_type if hasattr(node, 'tricc_type') else 'text')
98
+ }
99
+ if hasattr(node, 'options') and node.options:
100
+ item["answerOption"] = [{"valueString": opt.name} for opt in node.options]
101
+ self.questionnaires[segment]["item"].append(item)
102
+ return True
103
+
104
+ def generate_relevance(self, node, **kwargs):
105
+ # Add enableWhen to Questionnaire item with FHIRPath
106
+ if hasattr(node, 'expression') and node.expression:
107
+ segment = getattr(node, 'segment', 'main')
108
+ if segment in self.questionnaires:
109
+ for item in self.questionnaires[segment]["item"]:
110
+ if item["linkId"] == get_export_name(node):
111
+ # Use FHIRPath expression
112
+ fhirpath_expr = self.convert_expression_to_fhirpath(node.expression)
113
+ item["enableWhen"] = [{
114
+ "question": self.get_question_link(node.expression),
115
+ "operator": "=",
116
+ "answerString": self.get_answer_value(node.expression)
117
+ }]
118
+ # Alternatively, use expression for complex logic
119
+ item["enableWhenExpression"] = {
120
+ "language": "text/fhirpath",
121
+ "expression": fhirpath_expr
122
+ }
123
+ break
124
+ return True
125
+
126
+ def generate_calculate(self, node, **kwargs):
127
+ # Add calculatedExpression to Questionnaire item with FHIRPath
128
+ if hasattr(node, 'expression') and node.expression:
129
+ segment = getattr(node, 'segment', 'main')
130
+ if segment in self.questionnaires:
131
+ for item in self.questionnaires[segment]["item"]:
132
+ if item["linkId"] == get_export_name(node):
133
+ fhirpath_expr = self.convert_expression_to_fhirpath(node.expression)
134
+ item["calculatedExpression"] = {
135
+ "language": "text/fhirpath",
136
+ "expression": fhirpath_expr
137
+ }
138
+ break
139
+ # Still add to CQL for population if needed
140
+ if segment not in self.cql_libraries:
141
+ self.cql_libraries[segment] = f"library {segment}Library version '1.0.0'\n\n"
142
+ cql_expr = self.convert_expression_to_cql(node.expression)
143
+ self.cql_libraries[segment] += f"define {get_export_name(node)}: {cql_expr}\n"
144
+ return True
145
+
146
+ def generate_export(self, node, **kwargs):
147
+ # Generate FML for saving based on content_type
148
+ content_type = getattr(node, 'content_type', 'Observation')
149
+ if content_type not in self.fml_mappings:
150
+ self.fml_mappings[content_type] = f"map \"{content_type}\" {{\n"
151
+ # Add mapping rules
152
+ self.fml_mappings[content_type] += f" {get_export_name(node)} -> {content_type}.{get_export_name(node)}\n"
153
+ return True
154
+
155
+ def export(self, start_pages, version):
156
+ form_id = start_pages["main"].root.form_id or "fhir_form"
157
+ base_path = os.path.join(self.output_path, form_id)
158
+ if not os.path.exists(base_path):
159
+ os.makedirs(base_path)
160
+
161
+ # Export Questionnaires
162
+ for segment, q in self.questionnaires.items():
163
+ file_name = f"{segment}.json"
164
+ path = os.path.join(base_path, file_name)
165
+ with open(path, 'w') as f:
166
+ json.dump(q, f, indent=2)
167
+
168
+ # Export CQL
169
+ for segment, cql in self.cql_libraries.items():
170
+ file_name = f"{segment}.cql"
171
+ path = os.path.join(base_path, file_name)
172
+ with open(path, 'w') as f:
173
+ f.write(cql)
174
+
175
+ # Export FML
176
+ for content_type, fml in self.fml_mappings.items():
177
+ fml += "}\n"
178
+ file_name = f"{content_type}.map"
179
+ path = os.path.join(base_path, file_name)
180
+ with open(path, 'w') as f:
181
+ f.write(fml)
182
+
183
+ logger.info(f"Exported FHIR resources to {base_path}")
184
+
185
+ def map_tricc_type_to_fhir(self, tricc_type):
186
+ mapping = {
187
+ 'text': 'string',
188
+ 'integer': 'integer',
189
+ 'decimal': 'decimal',
190
+ 'select_one': 'choice',
191
+ 'select_multiple': 'choice',
192
+ 'date': 'date',
193
+ 'time': 'time',
194
+ 'datetime': 'dateTime',
195
+ 'boolean': 'boolean'
196
+ }
197
+ return mapping.get(tricc_type, 'string')
198
+
199
+ def get_question_link(self, expression):
200
+ # Simplified, assume first reference
201
+ if isinstance(expression, TriccOperation) and hasattr(expression, 'reference'):
202
+ for r in expression.reference:
203
+ if isinstance(r, TriccReference):
204
+ return get_export_name(r.value)
205
+ return ""
206
+
207
+ def get_answer_value(self, expression):
208
+ # Simplified
209
+ return "true"
210
+
211
+ def get_tricc_operation_operand(self, r):
212
+ if isinstance(r, TriccOperation):
213
+ return self.get_tricc_operation_expression(r)
214
+ elif isinstance(r, TriccReference):
215
+ return get_export_name(r.value)
216
+ elif isinstance(r, TriccStatic):
217
+ if isinstance(r.value, str):
218
+ return f"'{r.value}'"
219
+ else:
220
+ return str(r.value)
221
+ elif isinstance(r, str):
222
+ return f"'{r}'"
223
+ elif isinstance(r, (int, float)):
224
+ return str(r)
225
+ elif isinstance(r, TriccNodeSelectOption):
226
+ return f"'{r.name}'"
227
+ elif issubclass(r.__class__, TriccNodeInputModel):
228
+ return get_export_name(r)
229
+ elif issubclass(r.__class__, TriccNodeBaseModel):
230
+ return get_export_name(r)
231
+ else:
232
+ raise NotImplementedError(f"This type of node {r.__class__} is not supported within an operation")
233
+
234
+ def convert_expression_to_cql(self, expression):
235
+ if isinstance(expression, TriccOperation):
236
+ return self.get_tricc_operation_expression(expression)
237
+ else:
238
+ return self.get_tricc_operation_operand(expression)
239
+
240
+ def convert_expression_to_fhirpath(self, expression):
241
+ # For FHIRPath, similar to CQL but in FHIR context
242
+ # For questionnaire, references to other questions
243
+ if isinstance(expression, TriccOperation):
244
+ return self.get_tricc_operation_expression_fhirpath(expression)
245
+ else:
246
+ return self.get_tricc_operation_operand_fhirpath(expression)
247
+
248
+ def get_tricc_operation_expression_fhirpath(self, operation):
249
+ ref_expressions = []
250
+ if not hasattr(operation, "reference"):
251
+ return self.get_tricc_operation_operand_fhirpath(operation)
252
+ for r in operation.reference:
253
+ if isinstance(r, list):
254
+ r_expr = [
255
+ (
256
+ self.get_tricc_operation_expression_fhirpath(sr)
257
+ if isinstance(sr, TriccOperation)
258
+ else self.get_tricc_operation_operand_fhirpath(sr)
259
+ )
260
+ for sr in r
261
+ ]
262
+ elif isinstance(r, TriccOperation):
263
+ r_expr = self.get_tricc_operation_expression_fhirpath(r)
264
+ else:
265
+ r_expr = self.get_tricc_operation_operand_fhirpath(r)
266
+ if isinstance(r_expr, TriccReference):
267
+ r_expr = self.get_tricc_operation_operand_fhirpath(r_expr)
268
+ ref_expressions.append(r_expr)
269
+
270
+ if hasattr(self, f"tricc_operation_fhirpath_{operation.operator}"):
271
+ callable = getattr(self, f"tricc_operation_fhirpath_{operation.operator}")
272
+ return callable(ref_expressions)
273
+ else:
274
+ # Fallback to CQL operations
275
+ if hasattr(self, f"tricc_operation_{operation.operator}"):
276
+ callable = getattr(self, f"tricc_operation_{operation.operator}")
277
+ return callable(ref_expressions)
278
+ else:
279
+ raise NotImplementedError(
280
+ f"This type of operation '{operation.operator}' is not supported"
281
+ )
282
+
283
+ def get_tricc_operation_operand_fhirpath(self, r):
284
+ if isinstance(r, TriccOperation):
285
+ return self.get_tricc_operation_expression_fhirpath(r)
286
+ elif isinstance(r, TriccReference):
287
+ # In FHIRPath, reference to another question's answer
288
+ return f"%questionnaire.item.where(linkId='{get_export_name(r.value)}').answer.value"
289
+ elif isinstance(r, TriccStatic):
290
+ if isinstance(r.value, str):
291
+ return f"'{r.value}'"
292
+ else:
293
+ return str(r.value)
294
+ elif isinstance(r, str):
295
+ return f"'{r}'"
296
+ elif isinstance(r, (int, float)):
297
+ return str(r)
298
+ elif isinstance(r, TriccNodeSelectOption):
299
+ return f"'{r.name}'"
300
+ elif issubclass(r.__class__, TriccNodeInputModel):
301
+ return f"%questionnaire.item.where(linkId='{get_export_name(r)}').answer.value"
302
+ elif issubclass(r.__class__, TriccNodeBaseModel):
303
+ return f"%questionnaire.item.where(linkId='{get_export_name(r)}').answer.value"
304
+ else:
305
+ raise NotImplementedError(f"This type of node {r.__class__} is not supported within an operation")
306
+
307
+ # FHIRPath operations, same as CQL for now
308
+ def tricc_operation_fhirpath_equal(self, ref_expressions):
309
+ return f"{ref_expressions[0]} = {ref_expressions[1]}"
310
+
311
+ def tricc_operation_fhirpath_not_equal(self, ref_expressions):
312
+ return f"{ref_expressions[0]} != {ref_expressions[1]}"
313
+
314
+ def tricc_operation_fhirpath_and(self, ref_expressions):
315
+ return " and ".join(ref_expressions)
316
+
317
+ def tricc_operation_fhirpath_or(self, ref_expressions):
318
+ return " or ".join(ref_expressions)
319
+
320
+ def tricc_operation_fhirpath_not(self, ref_expressions):
321
+ return f"not {ref_expressions[0]}"
322
+
323
+ def tricc_operation_fhirpath_plus(self, ref_expressions):
324
+ return " + ".join(ref_expressions)
325
+
326
+ def tricc_operation_fhirpath_minus(self, ref_expressions):
327
+ if len(ref_expressions) > 1:
328
+ return " - ".join(ref_expressions)
329
+ return f"-{ref_expressions[0]}"
330
+
331
+ def tricc_operation_fhirpath_more(self, ref_expressions):
332
+ return f"{ref_expressions[0]} > {ref_expressions[1]}"
333
+
334
+ def tricc_operation_fhirpath_less(self, ref_expressions):
335
+ return f"{ref_expressions[0]} < {ref_expressions[1]}"
336
+
337
+ def tricc_operation_fhirpath_more_or_equal(self, ref_expressions):
338
+ return f"{ref_expressions[0]} >= {ref_expressions[1]}"
339
+
340
+ def tricc_operation_fhirpath_less_or_equal(self, ref_expressions):
341
+ return f"{ref_expressions[0]} <= {ref_expressions[1]}"
342
+
343
+ # Operation methods for CQL
344
+ def tricc_operation_equal(self, ref_expressions):
345
+ return f"{ref_expressions[0]} = {ref_expressions[1]}"
346
+
347
+ def tricc_operation_not_equal(self, ref_expressions):
348
+ return f"{ref_expressions[0]} != {ref_expressions[1]}"
349
+
350
+ def tricc_operation_and(self, ref_expressions):
351
+ return " and ".join(ref_expressions)
352
+
353
+ def tricc_operation_or(self, ref_expressions):
354
+ return " or ".join(ref_expressions)
355
+
356
+ def tricc_operation_not(self, ref_expressions):
357
+ return f"not {ref_expressions[0]}"
358
+
359
+ def tricc_operation_plus(self, ref_expressions):
360
+ return " + ".join(ref_expressions)
361
+
362
+ def tricc_operation_minus(self, ref_expressions):
363
+ if len(ref_expressions) > 1:
364
+ return " - ".join(ref_expressions)
365
+ return f"-{ref_expressions[0]}"
366
+
367
+ def tricc_operation_more(self, ref_expressions):
368
+ return f"{ref_expressions[0]} > {ref_expressions[1]}"
369
+
370
+ def tricc_operation_less(self, ref_expressions):
371
+ return f"{ref_expressions[0]} < {ref_expressions[1]}"
372
+
373
+ def tricc_operation_more_or_equal(self, ref_expressions):
374
+ return f"{ref_expressions[0]} >= {ref_expressions[1]}"
375
+
376
+ def tricc_operation_less_or_equal(self, ref_expressions):
377
+ return f"{ref_expressions[0]} <= {ref_expressions[1]}"