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_]})
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_]})
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
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_})