def _build_boolean_expression_filter(spec, context): wrapped = BooleanExpressionFilterSpec.wrap(spec) return SinglePropertyValueFilter( expression=ExpressionFactory.from_spec(wrapped.expression, context), operator=get_operator(wrapped.operator), reference_expression=ExpressionFactory.from_spec(wrapped.property_value, context), )
def test_property_path_empty_path(self): for empty_path in ([], None): with self.assertRaises(BadSpecError): ExpressionFactory.from_spec({ 'type': 'property_path', 'property_path': empty_path, })
def setUp(self): # we have to set the fake database before any other calls self.orig_db = CommCareCase.get_db() self.database = FakeCouchDb() CommCareCase.set_db(self.database) self.spec = { "type": "related_doc", "related_doc_type": "CommCareCase", "doc_id_expression": {"type": "property_name", "property_name": "parent_id"}, "value_expression": {"type": "property_name", "property_name": "related_property"}, } self.expression = ExpressionFactory.from_spec(self.spec) self.nested_expression = ExpressionFactory.from_spec( { "type": "related_doc", "related_doc_type": "CommCareCase", "doc_id_expression": {"type": "property_name", "property_name": "parent_id"}, "value_expression": { "type": "related_doc", "related_doc_type": "CommCareCase", "doc_id_expression": {"type": "property_name", "property_name": "parent_id"}, "value_expression": {"type": "property_name", "property_name": "related_property"}, }, } )
def test_diff_days_expression(self, source_doc, to_date_expression, expected_value): from_date_expression = { 'type': 'property_name', 'property_name': 'dob', } expression = ExpressionFactory.from_spec({ 'type': 'diff_days', 'from_date_expression': from_date_expression, 'to_date_expression': to_date_expression }) self.assertEqual(expected_value, expression(source_doc)) # test named_expression for 'from_date_expression' context = FactoryContext( {"from_date_name": ExpressionFactory.from_spec(from_date_expression)}, {} ) named_expression = ExpressionFactory.from_spec({ 'type': 'diff_days', 'from_date_expression': { "type": "named", "name": "from_date_name" }, 'to_date_expression': to_date_expression }, context) self.assertEqual(expected_value, named_expression(source_doc))
def test_invalid_eval_expression(self, source_doc, statement, context): with self.assertRaises(BadSpecError): ExpressionFactory.from_spec({ "type": "evaluator", "statement": statement, "context_variables": context })
def diff_calendar_months(spec, context): wrapped = DiffCalendarMonthsExpressionSpec.wrap(spec) wrapped.configure( from_date_expression=ExpressionFactory.from_spec(wrapped.from_date_expression, context), to_date_expression=ExpressionFactory.from_spec(wrapped.to_date_expression, context), ) return wrapped
def ancestor_location(spec, context): wrapped = AncestorLocationExpression.wrap(spec) wrapped.configure( ExpressionFactory.from_spec(wrapped.location_id, context), ExpressionFactory.from_spec(wrapped.location_type, context), ) return wrapped
def test_non_string_keys(self): with self.assertRaises(BadSpecError): ExpressionFactory.from_spec({ "type": "dict", "properties": { (1, 2): 2 }, })
def test_fail_on_bad_doc_type(self): spec = { "type": "related_doc", "related_doc_type": "BadDocument", "doc_id_expression": {"type": "property_name", "property_name": "parent_id"}, "value_expression": {"type": "property_name", "property_name": "related_property"}, } with self.assertRaises(BadSpecError): ExpressionFactory.from_spec(spec)
def test_datatype(self): spec = { "type": "evaluator", "statement": '1.0 + a', "context_variables": {'a': 1.0} } self.assertEqual(type(ExpressionFactory.from_spec(spec)({})), float) spec['datatype'] = 'integer' self.assertEqual(type(ExpressionFactory.from_spec(spec)({})), int)
def test_bad_order_raises_badspec(self): expression = { 'type': 'sort_items', 'items_expression': [1, 6, 2, 3], 'sort_expression': {'type': 'identity'}, 'order': 'complex' } with self.assertRaises(BadSpecError): ExpressionFactory.from_spec(expression)
def get_case_history(spec, context): wrapped = GetCaseHistorySpec.wrap(spec) wrapped.configure( case_id_expression=ExpressionFactory.from_spec(wrapped.case_id_expression, context), case_forms_expression=ExpressionFactory.from_spec({ 'type': 'get_case_forms', 'case_id_expression': wrapped.case_id_expression }, context) ) return wrapped
def test_reduce_items_bad_spec(self, items_ex, reduce_ex): expression = { 'type': 'reduce_items', } if items_ex is not None: expression['items_expression'] = items_ex if reduce_ex is not None: expression['aggregation_fn'] = reduce_ex with self.assertRaises(BadSpecError): ExpressionFactory.from_spec(expression)(items_ex, reduce_ex)
def test_filter_items_bad_spec(self, items_ex, filter_ex): expression = { 'type': 'filter_items', } if items_ex is not None: expression['items_expression'] = items_ex if filter_ex is not None: expression['filter_expression'] = filter_ex with self.assertRaises(BadSpecError): ExpressionFactory.from_spec(expression)
def test_sort_items_bad_spec(self, items_ex, sort_ex): expression = { 'type': 'sort_items', } if items_ex is not None: expression['items_expression'] = items_ex if sort_ex is not None: expression['sort_expression'] = sort_ex with self.assertRaises(BadSpecError): ExpressionFactory.from_spec(expression)(items_ex, sort_ex)
def test_name_in_value(self): expression = ExpressionFactory.from_spec( { "type": "nested", "argument_expression": { "type": "identity", }, "value_expression": { "type": "named", "name": "three" } }, context=FactoryContext({'three': ExpressionFactory.from_spec(3)}, {}) ) self.assertEqual(3, expression({}))
def test_property_path_expression(self): getter = ExpressionFactory.from_spec({ 'type': 'property_path', 'property_path': ['path', 'to', 'foo'], }) self.assertEqual(PropertyPathGetterSpec, type(getter)) self.assertEqual(['path', 'to', 'foo'], getter.property_path)
def test_filter(self): expression = ExpressionFactory.from_spec({ "type": "reduce_items", "aggregation_fn": "count", "items_expression": { "type": "ext_get_case_history_by_date", "case_id_expression": { "type": "constant", "constant": self.test_case_id }, "filter": { "type": "boolean_expression", "operator": "eq", "expression": { "type": "property_path", "property_path": ["update", "foo"] }, "property_value": "a" } } }) self.assertEqual( 2, expression( {"some_item": "item_value"}, context=EvaluationContext({"domain": self.domain}, 0), ) )
def test_property_name_expression(self): getter = ExpressionFactory.from_spec({ 'type': 'property_name', 'property_name': 'foo', }) self.assertEqual(PropertyNameGetterSpec, type(getter)) self.assertEqual('foo', getter.property_name)
def test_end(self): context = EvaluationContext( {"domain": self.domain, "end_date": "2015-02-28"}, 0) expression = ExpressionFactory.from_spec({ "type": "reduce_items", "aggregation_fn": "count", "items_expression": { "type": "ext_get_case_history_by_date", "case_id_expression": { "type": "constant", "constant": self.test_case_id }, "end_date": { "type": "ext_root_property_name", "property_name": "end_date", "datatype": "date", }, } }) self.assertEqual( 5, expression( {"some_item": "item_value"}, context=context, ) )
def parent_id(spec, context): spec = { 'type': 'nested', 'argument_expression': { 'type': 'array_index', 'array_expression': { 'type': 'filter_items', 'items_expression': { 'type': 'ext_root_property_name', 'property_name': 'indices', 'datatype': 'array', }, 'filter_expression': { 'type': 'boolean_expression', 'operator': 'eq', 'property_value': 'parent', 'expression': { 'type': 'property_name', 'property_name': 'identifier' } } }, 'index_expression': { 'type': 'constant', 'constant': 0 } }, 'value_expression': { 'type': 'property_name', 'property_name': 'referenced_id' } } return ExpressionFactory.from_spec(spec, context)
def test_reduce_items_basic(self, doc, items_ex, reduce_ex, expected): expression = ExpressionFactory.from_spec({ 'type': 'reduce_items', 'items_expression': items_ex, 'aggregation_fn': reduce_ex }) self.assertEqual(expression(doc), expected)
def setUp(self): # this expression is the equivalent to: # doc.true_value if doc.test == 'match' else doc.false_value spec = { 'type': 'conditional', 'test': { # any valid filter can go here 'type': 'boolean_expression', 'expression': { 'type': 'property_name', 'property_name': 'test', }, 'operator': 'eq', 'property_value': 'match', }, 'expression_if_true': { 'type': 'property_name', 'property_name': 'true_value', }, 'expression_if_false': { 'type': 'property_name', 'property_name': 'false_value', }, } self.expression = ExpressionFactory.from_spec(spec)
def test_datatype(self): for expected, datatype, original in [ (5, "integer", "5"), (5, "integer", "5.3"), (None, "integer", "five"), (Decimal(5), "decimal", "5"), (Decimal("5.3"), "decimal", "5.3"), ("5", "string", "5"), ("5", "string", 5), (u"fo\u00E9", "string", u"fo\u00E9"), (date(2015, 9, 30), "date", "2015-09-30"), (None, "date", "09/30/2015"), (datetime(2015, 9, 30, 19, 4, 27), "datetime", "2015-09-30T19:04:27Z"), (datetime(2015, 9, 30, 19, 4, 27, 113609), "datetime", "2015-09-30T19:04:27.113609Z"), (None, "datetime", "2015-09-30 19:04:27Z"), (date(2015, 9, 30), "date", "2015-09-30T19:04:27Z"), (date(2015, 9, 30), "date", datetime(2015, 9, 30)), (None, "datetime", "2015-09-30"), ]: getter = ExpressionFactory.from_spec({ 'type': 'property_name', 'property_name': 'foo', 'datatype': datatype }) self.assertEqual(expected, getter({'foo': original}))
def test_filtered_child_cases(self): context = EvaluationContext({"domain": self.domain}, 0) expression = ExpressionFactory.from_spec({ "type": "reduce_items", "aggregation_fn": "count", "items_expression": { "type": "filter_items", "filter_expression": { "type": "boolean_expression", "operator": "eq", "expression": { "type": "property_name", "property_name": "type" }, "property_value": "child_1" }, "items_expression": { "type": "icds_get_child_cases", "case_id_expression": { "type": "constant", "constant": self.test_case_id } } } }) self.assertEqual(1, expression({"some_field", "some_value"}, context))
def setUpClass(cls): cls.domain_name = "test-domain" cls.domain_obj = create_domain(cls.domain_name) cls.location_type = LocationType( domain=cls.domain_name, name="state", code="state", ) cls.location_type.save() cls.location = SQLLocation( domain="test-domain", name="Braavos", location_type=cls.location_type ) cls.location.save() cls.unique_id = cls.location.location_id cls.spec = { "type": "location_type_name", "location_id_expression": { "type": "property_name", "property_name": "_id" } } cls.expression = ExpressionFactory.from_spec(cls.spec)
def test_parent_case_id(self): expression = ExpressionFactory.from_spec({ "type": "nested", "argument_expression": { "type": "array_index", "array_expression": { "type": "property_name", "property_name": "indices" }, "index_expression": { "type": "constant", "constant": 0 } }, "value_expression": { "type": "property_name", "property_name": "referenced_id" } }) self.assertEqual( 'my_parent_id', expression({ "indices": [ { "doc_type": "CommCareCaseIndex", "identifier": "parent", "referenced_type": "pregnancy", "referenced_id": "my_parent_id" } ], }) )
def test_filter_items_basic(self, doc, items_ex, filter_ex, expected): expression = ExpressionFactory.from_spec({ 'type': 'filter_items', 'items_expression': items_ex, 'filter_expression': filter_ex }) self.assertEqual(expression(doc), expected)
def test_latest_property(self): doc = { "forms": [ {"received_on": datetime.date(2015, 4, 5), "weight": 21}, {"received_on": datetime.date(2015, 1, 5), "weight": 18}, {"received_on": datetime.date(2015, 3, 5), "weight": 20}, ] } # nested(weight) <- reduce(last_item) <- sort(by received_on) <- forms expression = ExpressionFactory.from_spec({ "type": "nested", "argument_expression": { "type": "reduce_items", "items_expression": { "type": "sort_items", "items_expression": {"type": "property_name", "property_name": "forms"}, "sort_expression": {"type": "property_name", "property_name": "received_on"} }, "aggregation_fn": "last_item" }, "value_expression": { "type": "property_name", "property_name": "weight" } }) self.assertEqual(expression(doc), doc["forms"][0]["weight"])
def test_sort_items_basic(self, doc, items_ex, sort_ex, expected): expression = ExpressionFactory.from_spec({ 'type': 'sort_items', 'items_expression': items_ex, 'sort_expression': sort_ex }) self.assertEqual(expression(doc), expected)
def test_descending_order(self): expression = { 'type': 'sort_items', 'items_expression': [1, 6, 2, 3], 'sort_expression': { 'type': 'identity' }, 'order': 'DESC' } self.assertEqual( ExpressionFactory.from_spec(expression)({}), [6, 3, 2, 1])
def test_not_closed(self): expression = ExpressionFactory.from_spec({ "type": "ext_iterate_from_opened_date", }) self.assertEqual([0, 1, 2, 3, 4, 5, 6, 7, 8], expression({ "opened_on": "2015-06-03T01:10:15.241903Z", "modified_on": "2015-11-10T01:10:15.241903Z", "closed": False }))
def child_age_in_months_month_end(spec, context): spec = { 'type': 'evaluator', 'statement': 'age_in_days / 30.4', 'context_variables': { 'age_in_days': { 'type': 'icds_child_age_in_days' } } } return ExpressionFactory.from_spec(spec, context)
def test_literals(self): spec = copy.copy(self.spec) spec['expression_if_true'] = 'true literal' spec['expression_if_false'] = 'false literal' expression_with_literals = ExpressionFactory.from_spec(spec) self.assertEqual('true literal', expression_with_literals({ 'test': 'match', })) self.assertEqual('false literal', expression_with_literals({ 'test': 'non-match', }))
def test_location_dne(self): context = EvaluationContext({'domain': self.domain}) expression = ExpressionFactory.from_spec( { 'type': 'ancestor_location', 'location_id': "gibberish", 'location_type': "kingdom", }, context) ancestor_location = expression({}, context) self.assertIsNone(ancestor_location)
def test_caching(self): self.test_simple_lookup() my_doc = self.database.get('my-id') self.database.mock_docs.clear() self.assertEqual({}, self.database.mock_docs) self.assertEqual('foo', self.expression(my_doc, EvaluationContext(my_doc, 0))) same_expression = ExpressionFactory.from_spec(self.spec) self.assertEqual('foo', same_expression(my_doc, EvaluationContext(my_doc, 0)))
def root_property_name(spec, context): RootPropertyNameSpec.wrap(spec) spec = { 'type': 'root_doc', 'expression': { 'type': 'property_name', 'property_name': spec['property_name'], 'datatype': spec['datatype'] } } return ExpressionFactory.from_spec(spec, context)
def setUpClass(cls): super(TestLocationParentIdExpression, cls).setUpClass() cls.evaluation_context = EvaluationContext({"domain": cls.domain}) cls.expression_spec = { "type": "location_parent_id", "location_id_expression": { "type": "property_name", "property_name": "location_id", } } cls.expression = ExpressionFactory.from_spec(cls.expression_spec)
def test_reach_village_owner_id(self, case): expression = ExpressionFactory.from_spec({ "type": "icds_village_owner_id", "case_id_expression": { "type": "property_name", "property_name": "case_id", }, }) context = EvaluationContext({"domain": self.domain_name}, 0) self.assertEqual(self.village_owner_id, expression(getattr(self, case).to_json(), context))
def parsed_expression(self, context): from corehq.apps.userreports.expressions.factory import ExpressionFactory expression = ExpressionFactory.from_spec(self.expression, context) datatype_transform = transform_from_datatype(self.datatype) if self.transform: generic_transform = TransformFactory.get_transform( self.transform).get_transform_function() inner_getter = TransformedGetter(expression, generic_transform) else: inner_getter = expression return TransformedGetter(inner_getter, datatype_transform)
def get_expression(self, column_id, column_type): column = self.get_column(column_id) if column['type'] == 'boolean': return FilterFactory.from_spec(column['filter'], context=FactoryContext( self.named_expressions, {})) else: self.assertEqual(column['datatype'], column_type) return ExpressionFactory.from_spec(column['expression'], context=FactoryContext( self.named_expressions, {}))
def test_ethiopian_to_gregorian_expression_constant(self, expression, expected_value): """ Used to fail with BadValueError: datetime.date(2020, 9, 9) is not a date-formatted string """ wrapped_expression = ExpressionFactory.from_spec({ 'type': 'ethiopian_date_to_gregorian_date', 'date_expression': expression, }) self.assertEqual(expected_value, wrapped_expression({"foo": "bar"}))
def get_last_form_repeat(spec, context): GetLastFormRepeatSpec.wrap(spec) if spec['case_id_expression'] is None: case_id_expression = { "type": "root_doc", "expression": { "type": "property_name", "property_name": "_id" } } else: case_id_expression = spec['case_id_expression'] repeat_filters = [] repeat_filters.append({ 'type': 'boolean_expression', 'operator': 'eq', 'expression': { 'type': 'property_path', 'property_path': spec['case_id_path'] }, 'property_value': case_id_expression }) if spec['repeat_filter'] is not None: repeat_filters.append(spec['repeat_filter']) spec = { 'type': 'reduce_items', 'aggregation_fn': 'last_item', 'items_expression': { 'type': 'filter_items', 'filter_expression': { 'type': 'and', 'filters': repeat_filters }, 'items_expression': { 'type': 'nested', 'argument_expression': { 'type': 'reduce_items', 'aggregation_fn': 'last_item', 'items_expression': spec['forms_expression'] }, 'value_expression': { 'type': 'property_path', 'datatype': 'array', 'property_path': spec['repeat_path'] }, } } } return ExpressionFactory.from_spec(spec, context)
def setUp(self): self.expression_spec = { "type": "dict", "properties": { "name": "the_name", "value": { "type": "property_name", "property_name": "prop" } } } self.expression = ExpressionFactory.from_spec(self.expression_spec)
def test_property_path_bad_type(self): getter = ExpressionFactory.from_spec({ 'type': 'property_path', 'property_path': ['path', 'to', 'foo'], }) self.assertEqual(PropertyPathGetterSpec, type(getter)) for bad_value in [None, '', []]: self.assertEqual(None, getter({ 'path': { 'to': bad_value } }))
def location_parent_id(spec, context): LocationParentIdSpec.wrap(spec) # this is just for validation spec = { "type": "related_doc", "related_doc_type": "Location", "doc_id_expression": spec['location_id_expression'], "value_expression": { "type": "property_name", "property_name": "parent_location_id", } } return ExpressionFactory.from_spec(spec, context)
def test_no_datatype(self): expression = ExpressionFactory.from_spec({ "type": "ext_root_property_name", "property_name": "foo", }) self.assertEqual( "foo_value", expression( {"some_item": "item_value"}, context=EvaluationContext({"foo": "foo_value"}, 0) ) )
def setUp(self): super(TestGetSubcasesExpression, self).setUp() self.domain = uuid.uuid4().hex self.factory = CaseFactory(domain=self.domain) self.expression = ExpressionFactory.from_spec({ "type": "get_subcases", "case_id_expression": { "type": "property_name", "property_name": "_id" }, }) self.context = EvaluationContext({"domain": self.domain})
def setUp(self): super(TestGetReportingGroupsExpression, self).setUp() self.domain = uuid.uuid4().hex self.second_domain = uuid.uuid4().hex self.expression = ExpressionFactory.from_spec({ "type": "get_reporting_groups", "user_id_expression": { "type": "property_name", "property_name": "user_id" }, }) self.context = EvaluationContext({"domain": self.domain})
def _build_property_match_filter(spec, context): warnings.warn( "property_match are deprecated. Use boolean_expression instead.", DeprecationWarning, ) wrapped = PropertyMatchFilterSpec.wrap(spec) return SinglePropertyValueFilter( expression=wrapped.getter, operator=equal, reference_expression=ExpressionFactory.from_spec( wrapped.property_value), )
def _make_expression(self, from_statement=None, to_statement=None, xmlns=None, count=False): spec = { "type": "icds_get_case_forms_in_date", "case_id_expression": { "type": "property_name", "property_name": "_id" }, } if from_statement: spec["from_date_expression"] = { "type": "add_months", "datatype": "datetime", "date_expression": { "type": "property_name", "property_name": "server_modified_on" }, "months_expression": { "type": "evaluator", "statement": from_statement, "context_variables": { "iteration": { "type": "base_iteration_number" } } }, } if to_statement: spec["to_date_expression"] = { "type": "add_months", "datatype": "datetime", "date_expression": { "type": "property_name", "property_name": "server_modified_on" }, "months_expression": { "type": "evaluator", "statement": to_statement, "context_variables": { "iteration": { "type": "base_iteration_number" } } }, } if xmlns: spec['xmlns'] = [xmlns] spec['count'] = count return ExpressionFactory.from_spec(spec)
def test_gregorian_to_ethiopian_expression(self, source_doc, expected_value): date_expression = { 'type': 'property_name', 'property_name': 'dob', } expression = ExpressionFactory.from_spec({ 'type': 'gregorian_date_to_ethiopian_date', 'date_expression': date_expression, }) self.assertEqual(expected_value, expression(source_doc))
def setUp(self): # we have to set the fake database before any other calls self.orig_db = CommCareCase.get_db() self.database = FakeCouchDb() CommCareCase.set_db(self.database) self.spec = { "type": "related_doc", "related_doc_type": "CommCareCase", "doc_id_expression": { "type": "property_name", "property_name": "parent_id" }, "value_expression": { "type": "property_name", "property_name": "related_property" } } self.expression = ExpressionFactory.from_spec(self.spec) self.nested_expression = ExpressionFactory.from_spec({ "type": "related_doc", "related_doc_type": "CommCareCase", "doc_id_expression": { "type": "property_name", "property_name": "parent_id" }, "value_expression": { "type": "related_doc", "related_doc_type": "CommCareCase", "doc_id_expression": { "type": "property_name", "property_name": "parent_id" }, "value_expression": { "type": "property_name", "property_name": "related_property" } } })
def test_ancestor_location_exists(self): context = EvaluationContext({}) expression = ExpressionFactory.from_spec( { 'type': 'ancestor_location', 'location_id': self.city.location_id, 'location_type': "continent", }, context) ancestor_location = expression({}, context) self.assertIsNotNone(ancestor_location) self.assertEqual(ancestor_location.get("location_id"), self.continent.location_id)
def setUp(self): self.spec = { 'type': 'coalesce', 'expression': { 'type': 'property_name', 'property_name': 'expression' }, 'default_expression': { 'type': 'property_name', 'property_name': 'default_expression' }, } self.expression = ExpressionFactory.from_spec(self.spec)
def test_add_hours_to_datetime_expression(self, source_doc, count_expression, expected_value): expression = ExpressionFactory.from_spec({ 'type': 'add_hours', 'date_expression': { 'type': 'property_name', 'property_name': 'visit_date', }, 'count_expression': count_expression }) self.assertEqual(expected_value, expression(source_doc))
def _get_expression(doc_type): return ExpressionFactory.from_spec({ "type": "related_doc", "related_doc_type": doc_type, "doc_id_expression": { "type": "property_name", "property_name": "related_id" }, "value_expression": { "type": "property_name", "property_name": "_id" } })
def test_month_end_date(self): expression = ExpressionFactory.from_spec({ "type": "ext_month_end", }) self.assertEqual( date(2015, 7, 31), expression( {"some_item": "item_value"}, context=EvaluationContext( { "opened_on": "2015-06-03T01:10:15.241903Z", }, 1), ))
def test_add_months_to_date_expression(self, source_doc, months_expression, expected_value): expression = ExpressionFactory.from_spec({ 'type': 'add_months', 'date_expression': { 'type': 'property_name', 'property_name': 'dob', }, 'months_expression': months_expression }) self.assertEqual(expected_value, expression(source_doc))
def setUpClass(cls): cls.expression_spec = { 'type': 'array_index', 'array_expression': { 'type': 'property_name', 'property_name': 'my_array' }, 'index_expression': { 'type': 'property_name', 'property_name': 'my_index', }, } cls.expression = ExpressionFactory.from_spec(cls.expression_spec)