def get_graph(method, name, params): Action = action.MetaAction.new( name, ActionCategories.retrieve, effects=[call.model_perform(method.__name__)], params=params, result_info=value.InterfaceValue(graph.IGraph)) annotate.injectClassCallback(name, 4, 'annotate_action', name, Action) return method
def testParameterfiltering(self): model = Dummy() context = {"model": model} eff = call.model_perform("param_filtering", 1) res = yield eff(0, context, tata=2) self.assertEqual(res, (0, 1, 2, None, None)) res = yield eff(0, context, tata=2, tutu=3) self.assertEqual(res, (0, 1, 2, None, 3)) res = yield eff(0, context, tata=2, spam=42) self.assertEqual(res, (0, 1, 2, None, None)) eff = call.model_perform("param_filtering", 1, tata=2) res = yield eff(0, context) self.assertEqual(res, (0, 1, 2, None, None)) res = yield eff(0, context, foo=33) self.assertEqual(res, (0, 1, 2, None, None)) res = yield eff(0, context, tutu=3) self.assertEqual(res, (0, 1, 2, None, 3)) res = yield eff(0, context, tata=88) self.assertEqual(res, (0, 1, 88, None, None))
def testDelayCall(self): model = Dummy() context = {"model": model} eff = effect.delay(call.model_perform("perform"), "nop", 0.1) self.assertEqual(model.value, None) d = eff("spam", context) self.assertEqual(model.value, None) res = yield d self.assertEqual(res, "nop") self.assertEqual(model.value, None) yield common.delay(None, 0.1) self.assertEqual(model.value, "spam")
def __init__(cls, name, bases, dct): cls._query_target = None cls._query_model = None cls._connection_getter = None cls._static_conditions = None cls._factory = None cls._fetch_documents_set = False cls._fetch_documents = staticmethod(effect.identity) cls._item_field = None # this processes all the annotations super(QueryViewMeta, cls).__init__(name, bases, dct) if cls._factory is None: # The class is not annotated with view_factory() annotations # This is only valid in the base class, althought no actions # should be created. return # validate that the required annotations have been called if cls._query_target is None: raise ValueError("This model needs to be annotated with " "query_target(source|view)") if not callable(cls._connection_getter): raise ValueError("This model needs to be annotated with " "db_connection(effect) annotation") # define the Select and Count actions name = utils.mk_class_name(cls._factory.name, "Query") QueryValue = MetaQueryValue.new(name, cls._factory, cls._allowed_fields, cls._include_value) result_info = value.Model() name = utils.mk_class_name(cls._factory.name, "IncludeValue") IncludeValue = value.MetaCollection.new( name, [value.FixedValues(cls._allowed_fields)]) name = utils.mk_class_name(cls._factory.name, "AggregateValue") AggregateValue = value.MetaCollection.new( name, [value.FixedValues(cls._model_aggregations.keys())]) build_query = parse_incoming_query(cls._factory, cls._static_conditions, cls._include_value, cls._model_aggregations) def render_select_response(value, context, *args, **kwargs): cls = type(context['model']) if not cls._query_set_factory: # query set collection is created only once per class type factory = MetaQueryResult.new(cls) factory.annotate_meta('json', 'render-as-list') cls._query_set_factory = factory if cls._fetch_documents_set: context['result'].update(value) # convert all the aggregate values using their IValueInfo if kwargs.get('aggregate'): raw_values = context['result'].aggregations context['result'].aggregations = dict() for index, name in enumerate(kwargs['aggregate']): value_info = cls._model_aggregations[name][0] v = raw_values[index] try: published = value_info.publish(v) except Exception as e: error.handle_exception( None, e, "Failed publishing the result %r", v) else: context['result'].aggregations[name] = published result = cls._query_set_factory(context['source'], context['result']) return result.initiate(view=context['view'], officer=context.get('officer'), aspect=context.get('aspect')) def store_select_result(value, context, *args, **kwargs): context['result'], context['responses'] = value return value[0] def do_include_value(value, context, *args, **kwargs): # If there was a custom routing for fetching items defined, # we need to call the include_value() explicitely. If # query.select() was used, there is no need for that. cls = context['model'] if context['query'].include_value and cls._fetch_documents_set: return query.include_values(value, context['responses'], context['query']) else: return value SelectAction = action.MetaAction.new( utils.mk_class_name(cls._factory.name, "Select"), ActionCategories.retrieve, is_idempotent=False, result_info=result_info, effects=( build_query, call.model_perform('do_select'), store_select_result, cls._fetch_documents, do_include_value, render_select_response, ), params=[action.Param('query', QueryValue()), action.Param('include_value', IncludeValue(), is_required=False), action.Param('sorting', SortField(cls._allowed_fields), is_required=False), action.Param('skip', value.Integer(0), is_required=False), action.Param('limit', value.Integer(), is_required=False), action.Param('aggregate', AggregateValue(), is_required=False), ]) cls.annotate_action(u"select", SelectAction) # define count action CountAction = action.MetaAction.new( utils.mk_class_name(cls._factory.name, "Count"), ActionCategories.retrieve, effects=[ build_query, call.model_perform('do_count')], result_info=value.Integer(), is_idempotent=False, params=[action.Param('query', QueryValue())]) cls.annotate_action(u"count", CountAction) # define values action (fetch the values for the range) ValuesAction = action.MetaAction.new( utils.mk_class_name(cls._factory.name, "Values"), ActionCategories.retrieve, effects=[ build_query, call.model_perform('fetch_values')], # FIXME: the result is a dictionary of name -> [values], # consider creating the IValidator for this structure result_info=value.Value(), is_idempotent=False, params=[action.Param('query', QueryValue()), action.Param('fields', IncludeValue())]) cls.annotate_action(u"values", ValuesAction) # define how to fetch items if cls._item_field: def fetch_names(value, context): model = context['model'] d = build_query(None, context, query=cls._factory()) d.addCallback(defer.inject_param, 1, query.values, model.connection, cls._item_field) return d cls.annotate_child_names(fetch_names) def fetch_matching(value, context): c = query.Condition( cls._item_field, query.Evaluator.equals, context['key']) q = cls._factory(c) d = build_query(None, context, query=q) d.addCallback(context['model'].do_select, skip=0) # the result on this points (rows, responses) d.addCallback(lambda (r, _): r) d.addCallback(cls._fetch_documents, context) def unpack(result): if result: return result[0] d.addCallback(unpack) return d def fetch_source(value, context): if cls._query_target == 'source': return fetch_matching(value, context) else: return context['model'].source cls.annotate_child_source(fetch_source) def fetch_view(value, context): if cls._query_target == 'view': return fetch_matching(value, context) else: return context['view'] cls.annotate_child_view(fetch_view)
def annotate_view_factory(cls, factory, allowed_fields=[], static_conditions=None, fetch_documents=None): cls._view = IQueryViewFactory(factory) cls._static_conditions = (static_conditions and model._validate_effect(static_conditions)) if not fetch_documents: cls._fetch_documents_set = False fetch_documents = effect.identity else: cls._fetch_documents_set = True fetch_documents = fetch_documents for x in allowed_fields: if not cls._view.has_field(x): raise ValueError("%r doesn't define a field: '%s'" % (cls, x)) cls._allowed_fields = allowed_fields # define query action name = utils.mk_class_name(cls._view.name, "Query") QueryValue = MetaQueryValue.new(name, cls._view, cls._allowed_fields) name = utils.mk_class_name(cls._view.name, "Sorting") SortingValue = MetaSortingValue.new(name, cls._allowed_fields) result_info = value.Model() def get_static_conditions(value, context, *args, **kwargs): def build_query(static_conditions, factory, q): subquery = query.Query(factory, *static_conditions) return query.Query(factory, q, query.Operator.AND, subquery) cls = type(context['model']) if cls._static_conditions: d = cls._static_conditions(None, context) d.addCallback(build_query, cls._view, kwargs['query']) return d return defer.succeed(kwargs['query']) SelectAction = action.MetaAction.new( utils.mk_class_name(cls._view.name, "Select"), ActionCategories.retrieve, is_idempotent=False, result_info=result_info, effects=[ get_static_conditions, call.model_perform('do_select'), fetch_documents, call.model_filter('render_select_response')], params=[action.Param('query', QueryValue()), action.Param('sorting', SortingValue(), is_required=False), action.Param('skip', value.Integer(0), is_required=False), action.Param('limit', value.Integer(), is_required=False)]) cls.annotate_action(u"select", SelectAction) # define count action CountAction = action.MetaAction.new( utils.mk_class_name(cls._view.name, "Count"), ActionCategories.retrieve, effects=[ get_static_conditions, call.model_perform('do_count')], result_info=value.Integer(), is_idempotent=False, params=[action.Param('query', QueryValue())]) cls.annotate_action(u"count", CountAction)