Esempio n. 1
0
class ExpressionIndicatorSpec(IndicatorSpecBase):
    type = TypeProperty('expression')
    datatype = DataTypeProperty(required=True)
    is_nullable = BooleanProperty(default=True)
    is_primary_key = BooleanProperty(default=False)
    create_index = BooleanProperty(default=False)
    expression = DefaultProperty(required=True)
    transform = DictProperty(required=False)

    def parsed_expression(self, context):
        from corehq.apps.userreports.expressions.factory import ExpressionFactory
        expression = ExpressionFactory.from_spec(self.expression, context)
        datatype_transform = transform_for_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 readable_output(self, context):
        from corehq.apps.userreports.expressions.factory import ExpressionFactory
        expression_object = ExpressionFactory.from_spec(
            self.expression, context)
        return str(expression_object)
Esempio n. 2
0
class PropertyPathGetterSpec(JsonObject):
    """
    This expression returns ``doc["child"]["age"]``:

    .. code:: json

       {
           "type": "property_path",
           "property_path": ["child", "age"]
       }

    An optional ``"datatype"`` attribute may be specified, which will
    attempt to cast the property to the given data type. The options are
    "date", "datetime", "string", "integer", and "decimal". If no datatype
    is specified, "string" will be used.
    """
    type = TypeProperty('property_path')
    property_path = ListProperty(str, required=True)
    datatype = DataTypeProperty(required=False)

    def __call__(self, item, context=None):
        transform = transform_from_datatype(self.datatype)
        return transform(safe_recursive_lookup(item, self.property_path))

    def __str__(self):
        value = "/".join(self.property_path)
        if self.datatype:
            "({datatype}){value}".format(datatype=self.datatype, value=value)
        return value
Esempio n. 3
0
class PropertyNameGetterSpec(JsonObject):
    """
    This expression returns ``doc["age"]``:

    .. code:: json

       {
           "type": "property_name",
           "property_name": "age"
       }

    An optional ``"datatype"`` attribute may be specified, which will
    attempt to cast the property to the given data type. The options are
    "date", "datetime", "string", "integer", and "decimal". If no datatype
    is specified, "string" will be used.
    """
    type = TypeProperty('property_name')
    property_name = DefaultProperty(required=True)
    datatype = DataTypeProperty(required=False)

    def configure(self, property_name_expression):
        self._property_name_expression = property_name_expression

    def __call__(self, item, context=None):
        raw_value = item.get(self._property_name_expression(
            item, context)) if isinstance(item, dict) else None
        return transform_from_datatype(self.datatype)(raw_value)

    def __str__(self):
        value = self.property_name
        if self.datatype:
            "({datatype}){value}".format(datatype=self.datatype, value=value)
        return value
Esempio n. 4
0
class EvalExpressionSpec(JsonObject):
    type = TypeProperty('evaluator')
    statement = StringProperty(required=True)
    context_variables = DictProperty()
    datatype = DataTypeProperty(required=False)

    def configure(self, context_variables):
        self._context_variables = context_variables

    def __call__(self, item, context=None):
        var_dict = self.get_variables(item, context)
        try:
            untransformed_value = eval_statements(self.statement, var_dict)
            return transform_from_datatype(self.datatype)(untransformed_value)
        except (InvalidExpression, SyntaxError, TypeError, ZeroDivisionError):
            return None

    def get_variables(self, item, context):
        var_dict = {
            slug: variable_expression(item, context)
            for slug, variable_expression in self._context_variables.items()
        }
        return var_dict

    def __str__(self):
        value = self.statement
        for name, exp in self._context_variables.items():
            value.replace(name, str(exp))
        if self.datatype:
            value = "({}){}".format(self.datatype, value)
        return value
Esempio n. 5
0
class RawIndicatorSpec(PropertyReferenceIndicatorSpecBase):
    type = TypeProperty('raw')
    datatype = DataTypeProperty(required=True)
    is_nullable = BooleanProperty(default=True)
    is_primary_key = BooleanProperty(default=False)
    create_index = BooleanProperty(default=False)

    @property
    def getter(self):
        transform = transform_for_datatype(self.datatype)
        getter = getter_from_property_reference(self)
        return TransformedGetter(getter, transform)
Esempio n. 6
0
class DynamicChoiceListFilterSpec(FilterSpec):
    type = TypeProperty('dynamic_choice_list')
    show_all = BooleanProperty(default=True)
    datatype = DataTypeProperty(default='string')
    choice_provider = DictProperty()
    ancestor_expression = DictProperty(default={}, required=False)

    def get_choice_provider_spec(self):
        return self.choice_provider or {'type': DATA_SOURCE_COLUMN}

    @property
    def choices(self):
        return []
Esempio n. 7
0
class PropertyPathGetterSpec(JsonObject):
    type = TypeProperty('property_path')
    property_path = ListProperty(six.text_type, required=True)
    datatype = DataTypeProperty(required=False)

    def __call__(self, item, context=None):
        transform = transform_from_datatype(self.datatype)
        return transform(safe_recursive_lookup(item, self.property_path))

    def __str__(self):
        value = "/".join(self.property_path)
        if self.datatype:
            "({datatype}){value}".format(datatype=self.datatype, value=value)
        return value
Esempio n. 8
0
class PropertyNameGetterSpec(JsonObject):
    type = TypeProperty('property_name')
    property_name = DefaultProperty(required=True)
    datatype = DataTypeProperty(required=False)

    def configure(self, property_name_expression):
        self._property_name_expression = property_name_expression

    def __call__(self, item, context=None):
        raw_value = item.get(self._property_name_expression(item, context)) if isinstance(item, dict) else None
        return transform_from_datatype(self.datatype)(raw_value)

    def __str__(self):
        value = self.property_name
        if self.datatype:
            "({datatype}){value}".format(datatype=self.datatype, value=value)
        return value
Esempio n. 9
0
class FilterSpec(JsonObject):
    """
    This is the spec for a report filter - a thing that should show up as a UI filter element
    in a report (like a date picker or a select list).
    """
    type = StringProperty(required=True,
                          choices=[
                              'date', 'quarter', 'numeric', 'pre',
                              'choice_list', 'dynamic_choice_list',
                              'multi_field_dynamic_choice_list',
                              'location_drilldown', 'village_choice_list'
                          ])
    # this shows up as the ID in the filter HTML.
    slug = StringProperty(required=True)
    field = StringProperty(
        required=True)  # this is the actual column that is queried
    display = DefaultProperty()
    datatype = DataTypeProperty(default='string')

    def get_display(self):
        return self.display or self.slug
Esempio n. 10
0
class FilterSpec(JsonObject):
    """
    This is the spec for a report filter - a thing that should show up as a UI filter element
    in a report (like a date picker or a select list).
    """
    type = StringProperty(
        required=True,
        choices=[
            'date', 'quarter', 'numeric', 'pre', 'choice_list', 'dynamic_choice_list',
            'multi_field_dynamic_choice_list', 'location_drilldown',
            'village_choice_list'
        ]
    )
    # this shows up as the ID in the filter HTML.
    slug = StringProperty(required=True)
    field = StringProperty(required=True)  # this is the actual column that is queried
    display = DefaultProperty()
    datatype = DataTypeProperty(default='string')

    def get_display(self):
        return self.display or self.slug

    @classmethod
    def wrap(cls, *args, **kwargs):
        # Because pre_value is set to DefaultProperty, pre_value is automatically
        # interpreted to be a datatype when it's fetched by jsonobject.
        # This fails hard when the spec expects a string
        # and gets something else...like a date.
        doc = args[0]
        if 'pre_value' in doc:
            pre_value = doc['pre_value']
            data_type = doc.get('datatype')
            if data_type == 'string':
                doc['pre_value'] = str(pre_value)

        return super().wrap(*args, **kwargs)
Esempio n. 11
0
class ChoiceListFilterSpec(FilterSpec):
    type = TypeProperty('choice_list')
    show_all = BooleanProperty(default=True)
    datatype = DataTypeProperty(default='string')
    choices = ListProperty(FilterChoice)
Esempio n. 12
0
class SqlColumnProperties(jsonobject.JsonObject):
    datatype = DataTypeProperty(required=True)
    statement = jsonobject.StringProperty(required=True)
    statement_params = jsonobject.DictProperty()
Esempio n. 13
0
class EvalExpressionSpec(JsonObject):
    """
    ``evaluator`` expression can be used to evaluate statements that contain
    arithmetic (and simple python like statements). It evaluates the
    statement specified by ``statement`` which can contain variables as
    defined in ``context_variables``.

    .. code:: json

       {
           "type": "evaluator",
           "statement": "a + b - c + 6",
           "context_variables": {
               "a": 1,
               "b": 20,
               "c": 2
           }
       }

    This returns 25 (1 + 20 - 2 + 6).

    ``statement`` can be any statement that returns a valid number. All
    python math
    `operators <https://en.wikibooks.org/wiki/Python_Programming/Basic_Math#Mathematical_Operators>`__
    except power operator are available for use.

    ``context_variables`` is a dictionary of Expressions where keys are
    names of variables used in the ``statement`` and values are expressions
    to generate those variables. Variables can be any valid numbers (Python
    datatypes ``int``, ``float`` and ``long`` are considered valid numbers.)
    or also expressions that return numbers. In addition to numbers the
    following types are supported:

    -  ``date``
    -  ``datetime``

    Only the following functions are permitted:

    -  ``rand()``: generate a random number between 0 and 1
    -  ``randint(max)``: generate a random integer between 0 and ``max``
    -  ``int(value)``: convert ``value`` to an int. Value can be a number or
       a string representation of a number
    -  ``float(value)``: convert ``value`` to a floating point number
    -  ``str(value)``: convert ``value`` to a string
    -  ``timedelta_to_seconds(time_delta)``: convert a TimeDelta object into
       seconds. This is useful for getting the number of seconds between two
       dates.

       -  e.g. ``timedelta_to_seconds(time_end - time_start)``

    -  ``range(start, [stop], [skip])``: the same as the python ```range``
       function <https://docs.python.org/2/library/functions.html#range>`__.
       Note that for performance reasons this is limited to 100 items or
       less.
    """
    type = TypeProperty('evaluator')
    statement = StringProperty(required=True)
    context_variables = DictProperty()
    datatype = DataTypeProperty(required=False)

    def configure(self, context_variables):
        self._context_variables = context_variables

    def __call__(self, item, context=None):
        var_dict = self.get_variables(item, context)
        try:
            untransformed_value = eval_statements(self.statement, var_dict)
            return transform_from_datatype(self.datatype)(untransformed_value)
        except (InvalidExpression, SyntaxError, TypeError, ZeroDivisionError):
            return None

    def get_variables(self, item, context):
        var_dict = {
            slug: variable_expression(item, context)
            for slug, variable_expression in self._context_variables.items()
        }
        return var_dict

    def __str__(self):
        value = self.statement
        for name, exp in self._context_variables.items():
            value.replace(name, str(exp))
        if self.datatype:
            value = "({}){}".format(self.datatype, value)
        return value