From b52ffb256b7a3b27319a0f61a7eb175ab050c1f8 Mon Sep 17 00:00:00 2001 From: matt garber Date: Tue, 5 Sep 2023 10:11:31 -0400 Subject: [PATCH] Updated countgen interface (#116) * Updated countgen interface * tweaked docstring * put default min_count in wrapper functions --- .sqlfluffignore | 3 + cumulus_library/.sqlfluff | 2 +- cumulus_library/__init__.py | 2 +- cumulus_library/schema/counts.py | 165 +++++++++++++++-- cumulus_library/studies/core/count_core.py | 23 +-- cumulus_library/studies/core/count_core.sql | 185 +++++++++---------- cumulus_library/template_sql/count.sql.jinja | 16 +- cumulus_library/template_sql/templates.py | 21 ++- tests/test_schema_counts.py | 70 ++++--- tests/test_templates.py | 4 +- 10 files changed, 334 insertions(+), 157 deletions(-) diff --git a/.sqlfluffignore b/.sqlfluffignore index e231d048..5a506b2c 100644 --- a/.sqlfluffignore +++ b/.sqlfluffignore @@ -7,3 +7,6 @@ show_views.sql.jinja # This is a temporary ignore due to time pressure - not sure of root cause, # but the table in question builds codeable_concept_denormalize.sql.jinja + +# This is a common destination for debugging sql generation +output.sql diff --git a/cumulus_library/.sqlfluff b/cumulus_library/.sqlfluff index 5de2664d..4e2c617f 100644 --- a/cumulus_library/.sqlfluff +++ b/cumulus_library/.sqlfluff @@ -21,12 +21,12 @@ col_type_list = ["a string","b string"] cc_columns = [{"name": "baz", "is_array": True}, {"name": "foobar", "is_array": False}] cc_column = 'code' column_name = 'bar' -cnt_encounter = False conditions = ["1 > 0", "1 < 2"] dataset = [["foo","foo"],["bar","bar"]] ext_systems = ["omb", "text"] field = 'column_name' fhir_extension = fhir_extension +fhir_resource = patient id = 'id' medication_datasources = {"by_contained_ref" : True, "by_external_ref" : True} prefix = Test diff --git a/cumulus_library/__init__.py b/cumulus_library/__init__.py index 0f32f694..b52060b0 100644 --- a/cumulus_library/__init__.py +++ b/cumulus_library/__init__.py @@ -1,2 +1,2 @@ """Package metadata""" -__version__ = "1.3.0" +__version__ = "1.3.1" diff --git a/cumulus_library/schema/counts.py b/cumulus_library/schema/counts.py index 91307cd8..cf5d06eb 100644 --- a/cumulus_library/schema/counts.py +++ b/cumulus_library/schema/counts.py @@ -32,7 +32,11 @@ def __init__(self, study_prefix: str = None): super().__init__() def get_table_name(self, table_name: str, duration=None) -> str: - """Convenience method for constructing table name""" + """Convenience method for constructing table name + + :param table_name: table name to add after the study prefix + :param duration: a time period reflecting the table binning strategy + """ if duration: return f"{self.study_prefix}__{table_name}_{duration}" else: @@ -41,7 +45,12 @@ def get_table_name(self, table_name: str, duration=None) -> str: def get_where_clauses( self, clause: Union[list, str, None] = None, min_subject: int = 10 ) -> str: - """convenience method for constructing where clauses""" + """Convenience method for constructing arbitrary where clauses. + + :param clause: either a string or a list of sql where statements + :param min_subject: if clause is none, the bin size for a cnt_subject filter + (deprecated, use count_[fhir_resource](min_subject) instead) + """ if clause is None: return [f"cnt_subject >= {min_subject}"] elif isinstance(clause, str): @@ -54,45 +63,177 @@ def get_where_clauses( def get_count_query( self, table_name: str, source_table: str, table_cols: list, **kwargs ) -> str: - """Wrapper method for generating a counts table from a template""" + """Generates a counts table using a template + + :param table_name: The name of the table to create. Must start with study prefix + :param source_table: The table to create counts data from + :param table_cols: The columns from the source table to add to the count table + :keyword where_clauses: An array of where clauses to use for filtering the data + :keyword min_subject: An integer setting the minimum bin size for inclusion + (default: 10) + :keyword fhir_resource: The type of FHIR resource to count (see + template_sql/templates.CountableFhirResource) + """ if not table_name or not source_table or not table_cols: raise CountsBuilderError( "count_query missing required arguments. " f"output table: {table_name}" ) for key in kwargs: - if key not in ["min_subject", "where_clauses", "cnt_encounter"]: + if key not in ["min_subject", "where_clauses", "fhir_resource"]: raise CountsBuilderError(f"count_query received unexpected key: {key}") return templates.get_count_query(table_name, source_table, table_cols, **kwargs) - def count_patient( + # ---------------------------------------------------------------------- + # The following function all wrap get_count_query as convenience methods. + # We're not trying to be overly clever about this to persist the docstrings as the + # primary interface that study authors would see when using these functions. + + def count_condition( self, table_name: str, source_table: str, table_cols: list, - where_clauses=None, + where_clauses: Union[list, None] = None, + min_subject: int = 10, ) -> str: - """wrapper method for constructing patient counts tables""" + """wrapper method for constructing condition counts tables + + :param table_name: The name of the table to create. Must start with study prefix + :param source_table: The table to create counts data from + :param table_cols: The columns from the source table to add to the count table + :param where_clauses: An array of where clauses to use for filtering the data + :param min_subject: An integer setting the minimum bin size for inclusion + (default: 10) + """ return self.get_count_query( - table_name, source_table, table_cols, where_clauses=where_clauses + table_name, + source_table, + table_cols, + where_clauses=where_clauses, + min_subject=min_subject, + fhir_resource="condition", + ) + + def count_document( + self, + table_name: str, + source_table: str, + table_cols: list, + where_clauses: Union[list, None] = None, + min_subject: int = 10, + ) -> str: + """wrapper method for constructing document counts tables + + :param table_name: The name of the table to create. Must start with study prefix + :param source_table: The table to create counts data from + :param table_cols: The columns from the source table to add to the count table + :param where_clauses: An array of where clauses to use for filtering the data + :param min_subject: An integer setting the minimum bin size for inclusion + (default: 10) + """ + return self.get_count_query( + table_name, + source_table, + table_cols, + where_clauses=where_clauses, + min_subject=min_subject, + fhir_resource="document", ) def count_encounter( - self, table_name: str, source_table: str, table_cols: list, where_clauses=None + self, + table_name: str, + source_table: str, + table_cols: list, + where_clauses: Union[list, None] = None, + min_subject: int = 10, + ) -> str: + """wrapper method for constructing encounter counts tables + + :param table_name: The name of the table to create. Must start with study prefix + :param source_table: The table to create counts data from + :param table_cols: The columns from the source table to add to the count table + :param where_clauses: An array of where clauses to use for filtering the data + :param min_subject: An integer setting the minimum bin size for inclusion + (default: 10) + """ + return self.get_count_query( + table_name, + source_table, + table_cols, + where_clauses=where_clauses, + min_subject=min_subject, + fhir_resource="encounter", + ) + + def count_observation( + self, + table_name: str, + source_table: str, + table_cols: list, + where_clauses: Union[list, None] = None, + min_subject: int = 10, ) -> str: - """wrapper method for constructing encounter counts tables""" + """wrapper method for constructing observation counts tables + + :param table_name: The name of the table to create. Must start with study prefix + :param source_table: The table to create counts data from + :param table_cols: The columns from the source table to add to the count table + :param where_clauses: An array of where clauses to use for filtering the data + :param min_subject: An integer setting the minimum bin size for inclusion + (default: 10) + """ return self.get_count_query( table_name, source_table, table_cols, where_clauses=where_clauses, - cnt_encounter=True, + min_subject=min_subject, + fhir_resource="observation", ) + def count_patient( + self, + table_name: str, + source_table: str, + table_cols: list, + where_clauses: Union[list, None] = None, + min_subject: int = 10, + ) -> str: + """wrapper method for constructing patient counts tables + + :param table_name: The name of the table to create. Must start with study prefix + :param source_table: The table to create counts data from + :param table_cols: The columns from the source table to add to the count table + :param where_clauses: An array of where clauses to use for filtering the data + :param min_subject: An integer setting the minimum bin size for inclusion + (default: 10) + """ + return self.get_count_query( + table_name, + source_table, + table_cols, + where_clauses=where_clauses, + min_subject=min_subject, + fhir_resource="patient", + ) + + # End of wrapper section + # ---------------------------------------------------------------------- + def write_counts(self, filepath: str): - """Convenience method for writing counts queries to disk""" + """Convenience method for writing counts queries to disk + + :param filepath: path to file to write queries out to. + """ self.prepare_queries(cursor=None, schema=None) self.comment_queries() self.write_queries(filename=filepath) def prepare_queries(self, cursor: object = None, schema: str = None): + """Stub implementing abstract base class + + This should be overridden in any count generator. See core study count_core.py + for an example + """ pass diff --git a/cumulus_library/studies/core/count_core.py b/cumulus_library/studies/core/count_core.py index bbfed709..c8038e74 100644 --- a/cumulus_library/studies/core/count_core.py +++ b/cumulus_library/studies/core/count_core.py @@ -6,16 +6,13 @@ class CoreCountsBuilder(CountsBuilder): display_text = "Creating core counts..." - def __init__(self): - super().__init__() - def count_core_patient(self): table_name = self.get_table_name("count_patient") from_table = self.get_table_name("patient") cols = ["age", "gender", "race_display", "ethnicity_display"] return self.count_patient(table_name, from_table, cols) - def count_core_encounter(self, duration=None): + def count_core_encounter(self, duration: str = None): table_name = self.get_table_name("count_encounter", duration=duration) from_table = self.get_table_name("encounter") @@ -30,7 +27,9 @@ def count_core_encounter(self, duration=None): return self.count_encounter(table_name, from_table, cols) - def _count_core_encounter_type(self, table_name, cols, duration): + def _count_core_encounter_type( + self, table_name: str, cols: list, duration: str = None + ): """ Encounter Type information is for every visit, and therefore this SQL should be precise in which fields to select (This is a BIG query). @@ -38,7 +37,7 @@ def _count_core_encounter_type(self, table_name, cols, duration): :param table_name: name of the view from "core__encounter_type" :param cols: from "core__encounter_type" :param duration: None or ''month', 'year' - :return: SQL commands + :return: A SQL statement as a string """ table_name = self.get_table_name(table_name, duration) from_table = self.get_table_name("encounter_type") @@ -46,11 +45,9 @@ def _count_core_encounter_type(self, table_name, cols, duration): if duration: cols.append(f"start_{duration}") - where = self.get_where_clauses(min_subject=10) - - return self.count_encounter(table_name, from_table, cols, where_clauses=where) + return self.count_encounter(table_name, from_table, cols) - def count_core_encounter_type(self, duration=None): + def count_core_encounter_type(self, duration: str = None): cols = [ "enc_class_display", "enc_type_display", @@ -59,19 +56,19 @@ def count_core_encounter_type(self, duration=None): ] return self._count_core_encounter_type("count_encounter_type", cols, duration) - def count_core_encounter_enc_type(self, duration="month"): + def count_core_encounter_enc_type(self, duration: str = "month"): cols = ["enc_class_display", "enc_type_display"] return self._count_core_encounter_type( "count_encounter_enc_type", cols, duration ) - def count_core_encounter_service(self, duration="month"): + def count_core_encounter_service(self, duration: str = "month"): cols = ["enc_class_display", "enc_service_display"] return self._count_core_encounter_type( "count_encounter_service", cols, duration ) - def count_core_encounter_priority(self, duration="month"): + def count_core_encounter_priority(self, duration: str = "month"): cols = ["enc_class_display", "enc_priority_display"] return self._count_core_encounter_type( "count_encounter_priority", cols, duration diff --git a/cumulus_library/studies/core/count_core.sql b/cumulus_library/studies/core/count_core.sql index 6f2deef1..43c8f9f3 100644 --- a/cumulus_library/studies/core/count_core.sql +++ b/cumulus_library/studies/core/count_core.sql @@ -4,26 +4,26 @@ CREATE TABLE core__count_patient AS ( WITH powerset AS ( SELECT count(DISTINCT subject_ref) AS cnt_subject, - age, - gender, - race_display, - ethnicity_display + "age", + "gender", + "race_display", + "ethnicity_display" FROM core__patient GROUP BY cube( - age, - gender, - race_display, - ethnicity_display + "age", + "gender", + "race_display", + "ethnicity_display" ) ) SELECT cnt_subject AS cnt, - age, - gender, - race_display, - ethnicity_display + "age", + "gender", + "race_display", + "ethnicity_display" FROM powerset WHERE cnt_subject >= 10 @@ -31,37 +31,37 @@ CREATE TABLE core__count_patient AS ( -- ########################################################### -CREATE TABLE core__count_encounter AS ( +CREATE TABLE core__count_encounter_month AS ( WITH powerset AS ( SELECT count(DISTINCT subject_ref) AS cnt_subject, count(DISTINCT encounter_ref) AS cnt_encounter, - start_month, - enc_class_display, - age_at_visit, - gender, - race_display, - ethnicity_display + "start_month", + "enc_class_display", + "age_at_visit", + "gender", + "race_display", + "ethnicity_display" FROM core__encounter GROUP BY cube( - start_month, - enc_class_display, - age_at_visit, - gender, - race_display, - ethnicity_display + "start_month", + "enc_class_display", + "age_at_visit", + "gender", + "race_display", + "ethnicity_display" ) ) SELECT cnt_encounter AS cnt, - start_month, - enc_class_display, - age_at_visit, - gender, - race_display, - ethnicity_display + "start_month", + "enc_class_display", + "age_at_visit", + "gender", + "race_display", + "ethnicity_display" FROM powerset WHERE cnt_subject >= 10 @@ -74,30 +74,29 @@ CREATE TABLE core__count_encounter_type AS ( SELECT count(DISTINCT subject_ref) AS cnt_subject, count(DISTINCT encounter_ref) AS cnt_encounter, - enc_class_display, - enc_type_display, - enc_service_display, - enc_priority_display + "enc_class_display", + "enc_type_display", + "enc_service_display", + "enc_priority_display" FROM core__encounter_type GROUP BY cube( - enc_class_display, - enc_type_display, - enc_service_display, - enc_priority_display + "enc_class_display", + "enc_type_display", + "enc_service_display", + "enc_priority_display" ) ) SELECT cnt_encounter AS cnt, - enc_class_display, - enc_type_display, - enc_service_display, - enc_priority_display + "enc_class_display", + "enc_type_display", + "enc_service_display", + "enc_priority_display" FROM powerset - WHERE + WHERE cnt_subject >= 10 - ); -- ########################################################### @@ -107,33 +106,32 @@ CREATE TABLE core__count_encounter_type_month AS ( SELECT count(DISTINCT subject_ref) AS cnt_subject, count(DISTINCT encounter_ref) AS cnt_encounter, - enc_class_display, - enc_type_display, - enc_service_display, - enc_priority_display, - start_month + "enc_class_display", + "enc_type_display", + "enc_service_display", + "enc_priority_display", + "start_month" FROM core__encounter_type GROUP BY cube( - enc_class_display, - enc_type_display, - enc_service_display, - enc_priority_display, - start_month + "enc_class_display", + "enc_type_display", + "enc_service_display", + "enc_priority_display", + "start_month" ) ) SELECT cnt_encounter AS cnt, - enc_class_display, - enc_type_display, - enc_service_display, - enc_priority_display, - start_month + "enc_class_display", + "enc_type_display", + "enc_service_display", + "enc_priority_display", + "start_month" FROM powerset - WHERE + WHERE cnt_subject >= 10 - ); -- ########################################################### @@ -143,27 +141,26 @@ CREATE TABLE core__count_encounter_enc_type_month AS ( SELECT count(DISTINCT subject_ref) AS cnt_subject, count(DISTINCT encounter_ref) AS cnt_encounter, - enc_class_display, - enc_type_display, - start_month + "enc_class_display", + "enc_type_display", + "start_month" FROM core__encounter_type GROUP BY cube( - enc_class_display, - enc_type_display, - start_month + "enc_class_display", + "enc_type_display", + "start_month" ) ) SELECT cnt_encounter AS cnt, - enc_class_display, - enc_type_display, - start_month + "enc_class_display", + "enc_type_display", + "start_month" FROM powerset - WHERE + WHERE cnt_subject >= 10 - ); -- ########################################################### @@ -173,27 +170,26 @@ CREATE TABLE core__count_encounter_service_month AS ( SELECT count(DISTINCT subject_ref) AS cnt_subject, count(DISTINCT encounter_ref) AS cnt_encounter, - enc_class_display, - enc_service_display, - start_month + "enc_class_display", + "enc_service_display", + "start_month" FROM core__encounter_type GROUP BY cube( - enc_class_display, - enc_service_display, - start_month + "enc_class_display", + "enc_service_display", + "start_month" ) ) SELECT cnt_encounter AS cnt, - enc_class_display, - enc_service_display, - start_month + "enc_class_display", + "enc_service_display", + "start_month" FROM powerset - WHERE + WHERE cnt_subject >= 10 - ); -- ########################################################### @@ -203,25 +199,24 @@ CREATE TABLE core__count_encounter_priority_month AS ( SELECT count(DISTINCT subject_ref) AS cnt_subject, count(DISTINCT encounter_ref) AS cnt_encounter, - enc_class_display, - enc_priority_display, - start_month + "enc_class_display", + "enc_priority_display", + "start_month" FROM core__encounter_type GROUP BY cube( - enc_class_display, - enc_priority_display, - start_month + "enc_class_display", + "enc_priority_display", + "start_month" ) ) SELECT cnt_encounter AS cnt, - enc_class_display, - enc_priority_display, - start_month + "enc_class_display", + "enc_priority_display", + "start_month" FROM powerset - WHERE + WHERE cnt_subject >= 10 - ); diff --git a/cumulus_library/template_sql/count.sql.jinja b/cumulus_library/template_sql/count.sql.jinja index 179e80be..644746b4 100644 --- a/cumulus_library/template_sql/count.sql.jinja +++ b/cumulus_library/template_sql/count.sql.jinja @@ -7,8 +7,14 @@ CREATE TABLE {{ table_name }} AS ( WITH powerset AS ( SELECT count(DISTINCT subject_ref) AS cnt_subject, - {%- if cnt_encounter %} + {%- if fhir_resource=='condition' %} + count(DISTINCT condition_ref) AS cnt_condition, + {%- elif fhir_resource=='document' %} + count(DISTINCT document_ref) AS cnt_document, + {%- elif fhir_resource=='encounter' %} count(DISTINCT encounter_ref) AS cnt_encounter, + {%- elif fhir_resource=='observation' %} + count(DISTINCT observation_ref) AS cnt_observation, {%- endif -%} {% for col in table_cols %} "{{ col }}" @@ -29,8 +35,14 @@ CREATE TABLE {{ table_name }} AS ( ) SELECT - {%- if cnt_encounter %} + {%- if fhir_resource=='condition' %} + cnt_condition + {%- elif fhir_resource=='document' %} + cnt_document + {%- elif fhir_resource=='encounter' %} cnt_encounter + {%- elif fhir_resource=='observation' %} + cnt_observation {%- else %} cnt_subject {%- endif %} AS cnt, diff --git a/cumulus_library/template_sql/templates.py b/cumulus_library/template_sql/templates.py index f008a2f6..88014e99 100644 --- a/cumulus_library/template_sql/templates.py +++ b/cumulus_library/template_sql/templates.py @@ -5,6 +5,8 @@ from jinja2 import Template +from cumulus_library.errors import CountsBuilderError + class TableView(Enum): """Convenience enum for building drop queries""" @@ -13,6 +15,17 @@ class TableView(Enum): VIEW = "VIEW" +class CountableFhirResource(Enum): + """Contains FHIR types for which we have count table generation support""" + + CONDITION = "condition" + DOCUMENT = "document" + ENCOUNTER = "encounter" + NONE = None # This is treated as an implicit patient + OBSERVATION = "observation" + PATIENT = "patient" + + class CodeableConceptConfig: """Convenience class for holding parameters for generating codableconcept tables. @@ -137,10 +150,14 @@ def get_count_query( table_cols: list, min_subject: int = 10, where_clauses: Optional[list] = None, - cnt_encounter: Optional[bool] = None, + fhir_resource: Optional[str] = None, ) -> str: """Generates count tables for generating study outputs""" path = Path(__file__).parent + if fhir_resource not in [e.value for e in CountableFhirResource]: + raise CountsBuilderError( + f"Tried to create counts table for invalid resource {fhir_resource}." + ) with open(f"{path}/count.sql.jinja") as count_query: query = Template(count_query.read()).render( table_name=table_name, @@ -148,7 +165,7 @@ def get_count_query( table_cols=table_cols, min_subject=min_subject, where_clauses=where_clauses, - cnt_encounter=cnt_encounter, + fhir_resource=fhir_resource, ) # workaround for conflicting sqlfluff enforcement return query.replace("-- noqa: disable=LT02\n", "") diff --git a/tests/test_schema_counts.py b/tests/test_schema_counts.py index 9ac5fd80..4fb78054 100644 --- a/tests/test_schema_counts.py +++ b/tests/test_schema_counts.py @@ -55,7 +55,11 @@ def test_get_where_clauses(clause, min_subject, expected, raises): "table", "source", ["a", "b"], - {"min_subject": 10, "where_clauses": "where True", "cnt_encounter": True}, + { + "min_subject": 5, + "where_clauses": "where True", + "fhir_resource": "encounter", + }, does_not_raise(), ), ( @@ -85,44 +89,52 @@ def test_get_count_query( @pytest.mark.parametrize( - "table_name,source_table,table_cols,where", + "table_name,source_table,table_cols,where,min_subject,method,fhir_resource", [ - ("table", "source", ["a", "b"], None), - ("table", "source", ["a", "b"], "a = True"), + ("table", "source", ["a", "b"], None, None, "count_condition", "condition"), + ("table", "source", ["a", "b"], "a = True", 5, "count_condition", "condition"), + ("table", "source", ["a", "b"], None, None, "count_document", "document"), + ("table", "source", ["a", "b"], "a = True", 5, "count_document", "document"), + ("table", "source", ["a", "b"], None, None, "count_encounter", "encounter"), + ("table", "source", ["a", "b"], "a = True", 5, "count_encounter", "encounter"), + ("table", "source", ["a", "b"], None, None, "count_patient", "patient"), + ("table", "source", ["a", "b"], "a = True", 5, "count_patient", "patient"), + ("table", "source", ["a", "b"], None, None, "count_observation", "observation"), + ( + "table", + "source", + ["a", "b"], + "a = True", + 5, + "count_observation", + "observation", + ), ], ) @mock.patch("cumulus_library.template_sql.templates.get_count_query") -def test_count_patient(mock_count, table_name, source_table, table_cols, where): +def test_count_wrappers( + mock_count, + table_name, + source_table, + table_cols, + where, + min_subject, + method, + fhir_resource, +): kwargs = {} if where is not None: kwargs["where_clauses"] = where + if min_subject is not None: + kwargs["min_subject"] = min_subject builder = CountsBuilder(study_prefix=TEST_PREFIX) - builder.count_patient(table_name, source_table, table_cols, **kwargs) + wrapper = getattr(builder, method) + wrapper(table_name, source_table, table_cols, **kwargs) assert mock_count.called call_args, call_kwargs = mock_count.call_args assert call_args == (table_name, source_table, table_cols) - assert call_kwargs["where_clauses"] == where - - -@pytest.mark.parametrize( - "table_name,source_table,table_cols,where", - [ - ("table", "source", ["a", "b"], None), - ("table", "source", ["a", "b"], "a = True"), - ], -) -@mock.patch("cumulus_library.template_sql.templates.get_count_query") -def test_count_encounter(mock_count, table_name, source_table, table_cols, where): - kwargs = {} + assert call_kwargs["fhir_resource"] == fhir_resource if where is not None: - kwargs["where_clauses"] = where - builder = CountsBuilder(study_prefix=TEST_PREFIX) - builder.count_encounter(table_name, source_table, table_cols, **kwargs) - assert mock_count.called - call_args, call_kwargs = mock_count.call_args - assert call_args == (table_name, source_table, table_cols) - if where is None: - assert call_kwargs["cnt_encounter"] == True - else: - assert call_kwargs["cnt_encounter"] == True assert call_kwargs["where_clauses"] == where + if min_subject is not None: + assert call_kwargs["min_subject"] == min_subject diff --git a/tests/test_templates.py b/tests/test_templates.py index ac9f1e8e..748bbfa5 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -242,7 +242,7 @@ def test_count_query(): table_cols: list, min_subject: int = 10, where_clauses: Optional[list] = None, - cnt_encounter: Optional[str] = None,""" + fhir_resource: Optional[str] = None,""" query = get_count_query("test_table", "test_source", ["age", "sex"]) with open("output.sql", "w") as f: f.write(query) @@ -281,7 +281,7 @@ def test_count_query(): "test_source", ["age", "sex"], where_clauses=["age > 10", "sex == 'F'"], - cnt_encounter=True, + fhir_resource="encounter", ) assert query == expected