def _iterate_on_update(self, _document, _method, args, keywords): if IDocument.providedBy(_document): doc_id = _document.doc_id rev = _document.rev else: doc_id = _document['_id'] rev = _document['_rev'] try: result = _method(_document, *args, **keywords) except ResignFromModifying: return _document if result is None: d = self.delete_document(_document) else: d = self.save_document(result) if (IDocument.providedBy(_document) and _document.conflict_resolution_strategy == ConflictResolutionStrategy.merge): update_log = document.UpdateLog( handler=_method, args=args, keywords=keywords, rev_from=rev, timestamp=time.time()) d.addCallback(lambda doc: defer.DeferredList([defer.succeed(doc), self.get_database_tag(), self.get_update_seq()])) d.addCallback(self._log_update, update_log) d.addErrback(self._errback_on_update, doc_id, _method, args, keywords) return d
def save_document(self, doc): assert IDocument.providedBy(doc) or isinstance(doc, dict), repr(doc) try: self._lock_notifications() serialized = self._serializer.convert(doc) if IDocument.providedBy(doc): following_attachments = dict( (name, attachment) for name, attachment in doc.get_attachments().iteritems() if not attachment.saved) doc_id = doc.doc_id else: following_attachments = dict() doc_id = doc.get('_id') resp = yield self._database.save_doc(serialized, doc_id, following_attachments) self._update_id_and_rev(resp, doc) for attachment in following_attachments.itervalues(): attachment.set_saved() # now process all the documents which have been registered to # be saved together with this document if IDocument.providedBy(doc): while doc.links.to_save: to_link, linker_roles, linkee_roles = ( doc.links.to_save.pop(0)) to_link.links.create(doc=doc, linker_roles=linker_roles, linkee_roles=linkee_roles) yield self.save_document(to_link) defer.returnValue(doc) finally: self._unlock_notifications()
def update_document_ex(self, doc, _method, args=tuple(), keywords=dict()): if not IDocument.providedBy(doc): d = self.get_document(doc) else: d = defer.succeed(doc) d.addCallback(self._iterate_on_update, _method, args, keywords) return d
def solve(connection, doc_id): connection.info('Solving conflicts for document: %s', doc_id) plain_doc = yield connection.get_document(doc_id, raw=True, conflicts=True) if '_conflicts' not in plain_doc: connection.debug('Document:%s is not in state conflict, aborting.', doc_id) return doc = connection._unserializer.convert(plain_doc) if not IDocument.providedBy(doc): handler = _solve_alert else: strategy_handlers = { ConflictResolutionStrategy.db_winner: _solve_db_winner, ConflictResolutionStrategy.alert: _solve_alert, ConflictResolutionStrategy.merge: _solve_merge} s = type(doc).conflict_resolution_strategy handler = strategy_handlers.get(s, _solve_alert) connection.debug("Using %s strategy", handler.__name__) try: yield handler(connection, doc, plain_doc['_conflicts']) connection.debug("Solving conflict for document %s completed", doc_id) except UnsolvableConflict: raise except Exception as e: error.handle_exception(None, e, "Failed solving conflict") raise UnsolvableConflict(str(e), doc)
def keys(doc_id, type_name=None): if IDocument.providedBy(doc_id): doc_id = doc_id.doc_id if type_name is not None: return dict(key=(doc_id, type_name)) else: return dict(startkey=(doc_id, ), endkey=(doc_id, {}))
def _update_id_and_rev(self, resp, doc): if IDocument.providedBy(doc): doc.doc_id = unicode(resp.get('id', None)) doc.rev = unicode(resp.get('rev', None)) self._notice_doc_revision(doc) else: doc['_id'] = unicode(resp.get('id', None)) doc['_rev'] = unicode(resp.get('rev', None)) return doc
def _notice_doc_revision(self, doc): if IDocument.providedBy(doc): doc_id = doc.doc_id rev = doc.rev else: doc_id = doc['_id'] rev = doc['_rev'] self.log('Storing knowledge about doc rev. ID: %r, REV: %r', doc_id, rev) self._known_revisions[doc_id] = _parse_doc_revision(rev) return doc
def copy_document(self, doc_or_id, destination_id, rev=None): if isinstance(doc_or_id, (str, unicode)): doc_id = doc_or_id elif IDocument.providedBy(doc_or_id): doc_id = doc_or_id.doc_id elif isinstance(doc_or_id, dict): doc_id = doc_or_id['_id'] else: raise TypeError(type(doc_or_id)) if not doc_id: raise ValueError("Cannot determine doc id from %r" % (doc_or_id, )) return self._database.copy_doc(doc_id, destination_id, rev)
def _solve_err(self, state, fail): if fail.check(conflicts.UnsolvableConflict): doc = fail.value.doc if IDocument.providedBy(doc): doc_id = doc.doc_id else: doc_id = doc['_id'] state.unsolvable_conflicts.add(doc_id) self.warning('Cannot solve conflict for document id: %s. ' 'Reason: %s', doc_id, fail.value) self.raise_alert(ALERT_NAME, ', '.join(state.unsolvable_conflicts)) else: error.handle_failure(self, fail, 'Failed solving conflict.') msg = error.get_failure_message(fail) self.raise_alert(ALERT_NAME, msg, severity=alert.Severity.critical)
def create(self, doc_id=None, linker_roles=None, linkee_roles=None, type_name=None, doc=None): if doc is not None: if IDocument.providedBy(doc): doc_id = doc.doc_id or doc_id type_name = doc.type_name elif isinstance(doc, dict): doc_id = doc['_id'] else: raise TypeError(doc) if doc_id is None: raise ValueError("Either pass doc_id or saved document instance") if type_name is None: raise ValueError("Type name is needed to create a link") if linker_roles and not isinstance(linker_roles, list): raise TypeError(linker_roles) if linkee_roles and not isinstance(linkee_roles, list): raise TypeError(linkee_roles) self.remove(doc_id, noraise=True) self._links.append([type_name, doc_id, linker_roles or list(), linkee_roles or list()])
def delete_document(self, doc): if IDocument.providedBy(doc): body = { "_id": doc.doc_id, "_rev": doc.rev, "_deleted": True, ".type": unicode(doc.type_name)} for field in type(doc)._fields: if field.meta('keep_deleted'): body[field.serialize_as] = getattr(doc, field.name) elif isinstance(doc, dict): body = { "_id": doc["_id"], "_rev": doc["_rev"], "_deleted": True} else: raise ValueError(repr(doc)) serialized = self._serializer.convert(body) self._lock_notifications() d = self._database.save_doc(serialized, body["_id"]) d.addCallback(self._update_id_and_rev, doc) d.addBoth(defer.bridge_param, self._unlock_notifications) return d
def __init__(self, reference, message): Response.__init__(self, ResponseTypes.created, message) self.reference = reference if reference is not None else None if IDocument.providedBy(reference): self.id = reference.doc_id
def reload_document(self, doc): assert IDocument.providedBy(doc), \ "Incorrect type: %r, expected IDocument" % (type(doc), ) return self.get_document(doc.doc_id)