Exemple #1
0
 def do_sub(self, id_, name, silent, *params):
     """Subscribe the current thread to the specified publication."""
     try:
         pub = self.get_pub_by_name(name)
     except KeyError:
         if not silent:
             raise MeteorError(404, 'Subscription not found')
         return
     sub, created = Subscription.objects.get_or_create(
         connection_id=this.ws.connection.pk,
         sub_id=id_,
         user_id=getattr(this, 'user_id', None),
         defaults={
             'publication': pub.name,
             'params_ejson': ejson.dumps(params),
         },
     )
     this.subs.setdefault(sub.publication, set()).add(sub.pk)
     if not created:
         if not silent:
             this.send({'msg': 'ready', 'subs': [id_]})
         return
     # re-read from DB so we can get transaction ID (xmin)
     sub = Subscription.objects.extra(**XMIN).get(pk=sub.pk)
     for col, qs in self.sub_unique_objects(
             sub, params, pub, xmin__lte=sub.xmin,
     ):
         sub.collections.create(
             model_name=model_name(qs.model),
             collection_name=col.name,
         )
         if isinstance(col.model._meta.pk, AleaIdField):
             meteor_ids = None
         elif len([
             field
             for field
             in col.model._meta.local_fields
             if (
                 isinstance(field, AleaIdField)
             ) and (
                 field.unique
             ) and (
                 not field.null
             )
         ]) == 1:
             meteor_ids = None
         else:
             meteor_ids = get_meteor_ids(
                 qs.model, qs.values_list('pk', flat=True),
             )
         for obj in qs.select_related():
             payload = col.obj_change_as_msg(obj, ADDED, meteor_ids)
             this.send(payload)
     if not silent:
         this.send({'msg': 'ready', 'subs': [id_]})
Exemple #2
0
 def do_sub(self, id_, name, silent, *params):
     """Subscribe the current thread to the specified publication."""
     try:
         pub = self.get_pub_by_name(name)
     except KeyError:
         if not silent:
             raise MeteorError(404, 'Subscription not found')
         return
     sub, created = Subscription.objects.get_or_create(
         connection_id=this.ws.connection.pk,
         sub_id=id_,
         user_id=getattr(this, 'user_id', None),
         defaults={
             'publication': pub.name,
             'params_ejson': ejson.dumps(params),
         },
     )
     this.subs.setdefault(sub.publication, set()).add(sub.pk)
     if not created:
         if not silent:
             this.send({'msg': 'ready', 'subs': [id_]})
         return
     # re-read from DB so we can get transaction ID (xmin)
     sub = Subscription.objects.extra(**XMIN).get(pk=sub.pk)
     for col, qs in self.sub_unique_objects(
             sub,
             params,
             pub,
             xmin__lte=sub.xmin,
     ):
         sub.collections.create(
             model_name=model_name(qs.model),
             collection_name=col.name,
         )
         if isinstance(col.model._meta.pk, AleaIdField):
             meteor_ids = None
         elif len([
                 field for field in col.model._meta.local_fields
                 if (isinstance(field, AleaIdField)) and (
                     field.unique) and (not field.null)
         ]) == 1:
             meteor_ids = None
         else:
             meteor_ids = get_meteor_ids(
                 qs.model,
                 qs.values_list('pk', flat=True),
             )
         for obj in qs.select_related():
             payload = col.obj_change_as_msg(obj, ADDED, meteor_ids)
             this.send(payload)
     if not silent:
         this.send({'msg': 'ready', 'subs': [id_]})
Exemple #3
0
    def serialize(self, obj, meteor_ids):
        """Generate a DDP msg for obj with specified msg type."""
        # check for F expressions
        exps = [
            name for name, val in vars(obj).items()
            if isinstance(val, ExpressionNode)
        ]
        if exps:
            # clone/update obj with values but only for the expression fields
            obj = deepcopy(obj)
            for name, val in self.model.objects.values(*exps).get(
                    pk=obj.pk,
            ).items():
                setattr(obj, name, val)

        # run serialization now all fields are "concrete" (not F expressions)
        data = this.serializer.serialize([obj])[0]
        fields = data['fields']
        del data['pk'], data['model']
        # Django supports model._meta -> pylint: disable=W0212
        meta = self.model._meta
        for field in meta.local_fields:
            rel = getattr(field, 'rel', None)
            if rel:
                # use field value which should set by select_related()
                fields[field.column] = get_meteor_id(
                    getattr(obj, field.name),
                )
                fields.pop(field.name)
            elif isinstance(field, django.contrib.postgres.fields.ArrayField):
                fields[field.name] = field.to_python(fields.pop(field.name))
            elif (
                isinstance(field, AleaIdField)
            ) and (
                not field.null
            ) and (
                field.name == 'aid'
            ):
                # This will be sent as the `id`, don't send it in `fields`.
                fields.pop(field.name)
        for field in meta.local_many_to_many:
            fields['%s_ids' % field.name] = get_meteor_ids(
                field.rel.to, fields.pop(field.name),
            ).values()
        return data
Exemple #4
0
    def serialize(self, obj, meteor_ids):
        """Generate a DDP msg for obj with specified msg type."""
        # check for F expressions
        exps = [
            name for name, val in vars(obj).items()
            if isinstance(val, ExpressionNode)
        ]
        if exps:
            # clone/update obj with values but only for the expression fields
            obj = deepcopy(obj)
            for name, val in self.model.objects.values(*exps).get(
                    pk=obj.pk,
            ).items():
                setattr(obj, name, val)

        # run serialization now all fields are "concrete" (not F expressions)
        data = this.serializer.serialize([obj])[0]
        fields = data['fields']
        del data['pk'], data['model']
        # Django supports model._meta -> pylint: disable=W0212
        meta = self.model._meta
        for field in meta.local_fields:
            rel = getattr(field, 'rel', None)
            if rel:
                # use field value which should set by select_related()
                fields[field.column] = get_meteor_id(
                    getattr(obj, field.name),
                )
                fields.pop(field.name)
            elif isinstance(field, django.contrib.postgres.fields.ArrayField):
                fields[field.name] = field.to_python(fields.pop(field.name))
            elif (
                isinstance(field, AleaIdField)
            ) and (
                not field.null
            ) and (
                field.name == 'aid'
            ):
                # This will be sent as the `id`, don't send it in `fields`.
                fields.pop(field.name)
        for field in meta.local_many_to_many:
            fields['%s_ids' % field.name] = get_meteor_ids(
                field.rel.to, fields.pop(field.name),
            ).values()
        return data
Exemple #5
0
 def do_unsub(self, id_, silent):
     """Unsubscribe the current thread from the specified subscription id."""
     sub = Subscription.objects.get(
         connection=this.ws.connection, sub_id=id_,
     )
     for col, qs in self.sub_unique_objects(sub):
         if isinstance(col.model._meta.pk, AleaIdField):
             meteor_ids = None
         else:
             meteor_ids = get_meteor_ids(
                 qs.model, qs.values_list('pk', flat=True),
             )
         for obj in qs:
             payload = col.obj_change_as_msg(obj, REMOVED, meteor_ids)
             this.send(payload)
     this.subs[sub.publication].remove(sub.pk)
     sub.delete()
     if not silent:
         this.send({'msg': 'nosub', 'id': id_})
Exemple #6
0
 def do_unsub(self, id_, silent):
     """Unsubscribe the current thread from the specified subscription id."""
     sub = Subscription.objects.get(
         connection=this.ws.connection, sub_id=id_,
     )
     for col, qs in self.sub_unique_objects(sub):
         if isinstance(col.model._meta.pk, AleaIdField):
             meteor_ids = None
         else:
             meteor_ids = get_meteor_ids(
                 qs.model, qs.values_list('pk', flat=True),
             )
         for obj in qs:
             payload = col.obj_change_as_msg(obj, REMOVED, meteor_ids)
             this.send(payload)
     this.subs[sub.publication].remove(sub.pk)
     sub.delete()
     if not silent:
         this.send({'msg': 'nosub', 'id': id_})