def delete_doc(self, doc): """ delete a document or a list of documents @param doc: str or dict, document id or full doc. @return: dict like: .. code-block:: python {"ok":true,"rev":"2839830636"} """ result = { 'ok': False } doc1, schema = _maybe_serialize(doc) if isinstance(doc1, dict): if not '_id' or not '_rev' in doc1: raise KeyError('_id and _rev are required to delete a doc') docid = resource.escape_docid(doc1['_id']) result = self.res.delete(docid, rev=doc1['_rev']).json_body elif isinstance(doc1, basestring): # we get a docid rev = self.get_rev(doc1) docid = resource.escape_docid(doc1) result = self.res.delete(docid, rev=rev).json_body if schema: doc._doc.update({ "_rev": result['rev'], "_deleted": True }) elif isinstance(doc, dict): doc.update({ "_rev": result['rev'], "_deleted": True }) return result
def get(self, docid, rev=None, wrapper=None, _raw_json=False): """Get document from database Args: @param docid: str, document id to retrieve @param rev: if specified, allows you to retrieve a specific revision of document @param wrapper: callable. function that takes dict as a param. Used to wrap an object. @param _raw_json: return raw json instead deserializing it @return: dict, representation of CouchDB document as a dict. """ docid = resource.escape_docid(docid) if rev is not None: doc = maybe_raw(self.res.get(docid, rev=rev), raw=_raw_json) else: doc = maybe_raw(self.res.get(docid), raw=_raw_json) if wrapper is not None: if not callable(wrapper): raise TypeError("wrapper isn't a callable") return wrapper(doc) return doc
def doc_revisions(self, docid, with_doc=True, _raw_json=False): """ retrieve revisions of a doc @param docid: str, id of document @param with_doc: bool, if True return document dict with revisions as member, if false return only revisions @param _raw_json: return raw json instead deserializing it @return: dict: '_rev_infos' member if you have set with_doc to True : { "_revs_info": [ {"rev": "123456", "status": "disk"}, {"rev": "234567", "status": "missing"}, {"rev": "345678", "status": "deleted"}, ] } If False, return current revision of the document, but with an additional field, _revs, the value being a list of the available revision IDs. """ docid = resource.escape_docid(docid) try: if with_doc: doc_with_revs = maybe_raw(self.res.get(docid, revs=True), raw=_raw_json) else: doc_with_revs = maybe_raw(self.res.get(docid, revs_info=True), raw=_raw_json) except resource.ResourceNotFound: return None return doc_with_revs
def open_doc(self, docid, **params): """Get document from database Args: @param docid: str, document id to retrieve @param wrapper: callable. function that takes dict as a param. Used to wrap an object. @param _raw_json: return raw json instead deserializing it @param **params: See doc api for parameters to use: http://wiki.apache.org/couchdb/HTTP_Document_API @return: dict, representation of CouchDB document as a dict. """ wrapper = None raw_json = False if "wrapper" in params: wrapper = params.pop("wrapper") if "_raw_json" in params: raw_json = params.pop("_raw_json") docid = resource.escape_docid(docid) doc = maybe_raw(self.res.get(docid, **params), raw=raw_json) if wrapper is not None: if not callable(wrapper): raise TypeError("wrapper isn't a callable") return wrapper(doc) return doc
def open_doc(self, docid, **params): """Get document from database Args: @param docid: str, document id to retrieve @param wrapper: callable. function that takes dict as a param. Used to wrap an object. @param **params: See doc api for parameters to use: http://wiki.apache.org/couchdb/HTTP_Document_API @return: dict, representation of CouchDB document as a dict. """ wrapper = None if "wrapper" in params: wrapper = params.pop("wrapper") elif "schema" in params: schema = params.pop("schema") if not hasattr(schema, "wrap"): raise TypeError("invalid schema") wrapper = schema.wrap docid = resource.escape_docid(docid) doc = self.res.get(docid, **params).json_body if wrapper is not None: if not callable(wrapper): raise TypeError("wrapper isn't a callable") return wrapper(doc) return doc
def debug_open_doc(self, docid, **params): """Get document from database Args: @param docid: str, document id to retrieve @param wrapper: callable. function that takes dict as a param. Used to wrap an object. @param **params: See doc api for parameters to use: http://wiki.apache.org/couchdb/HTTP_Document_API @return: dict, representation of CouchDB document as a dict. """ start = datetime.utcnow() ############################ #Start Database.open_doc wrapper = None if "wrapper" in params: wrapper = params.pop("wrapper") elif "schema" in params: schema = params.pop("schema") if not hasattr(schema, "wrap"): raise TypeError("invalid schema") wrapper = schema.wrap docid = resource.escape_docid(docid) error = None try: doc = self.res.get(docid, **params).json_body except ResourceNotFound, ex: error = ex doc = {}
def get_rev(self, docid): """ Get last revision from docid (the '_rev' member) @param docid: str, undecoded document id. @return rev: str, the last revision of document. """ response = self.res.head(resource.escape_docid(docid)) return response.headers['etag'].strip('"')
def save_doc(self, doc, encode_attachments=True, force_update=False, _raw_json=False, **params): """ Save a document. It will use the `_id` member of the document or request a new uuid from CouchDB. IDs are attached to documents on the client side because POST has the curious property of being automatically retried by proxies in the event of network segmentation and lost responses. (Idee from `Couchrest <http://github.com/jchris/couchrest/>`) @param doc: dict. doc is updated with doc '_id' and '_rev' properties returned by CouchDB server when you save. @param force_update: boolean, if there is conlict, try to update with latest revision @param _raw_json: return raw json instead deserializing it @param params, list of optionnal params, like batch="ok" with `_raw_json=True` It return raw response. If False it update doc instance with new revision (if batch=False). @return res: result of save. doc is updated in the mean time """ if doc is None: doc = {} if '_attachments' in doc and encode_attachments: doc['_attachments'] = resource.encode_attachments(doc['_attachments']) if '_id' in doc: docid = doc['_id'] docid1 = resource.escape_docid(doc['_id']) try: res = maybe_raw(self.res.put(docid1, payload=doc, **params), raw=_raw_json) except resource.ResourceConflict: if force_update: doc['_rev'] = self.get_rev(docid) res = maybe_raw(self.res.put(docid1, payload=doc, **params), raw=_raw_json) else: raise else: try: doc['_id'] = self.server.next_uuid() res = maybe_raw(self.res.put(doc['_id'], payload=doc, **params), raw=_raw_json) except: res = maybe_raw(self.res.post(payload=doc, **params), raw=_raw_json) if _raw_json: return res if 'batch' in params and 'id' in res: doc.update({ '_id': res['id']}) else: doc.update({'_id': res['id'], '_rev': res['rev']}) return res
def compact(self, dname=None): """ compact database @param dname: string, name of design doc. Usefull to compact a view. """ path = "/_compact" if dname is not None: path = "%s/%s" % (path, resource.escape_docid(dname)) res = self.res.post(path) return res.json_body
def compact(self, dname=None): """ compact database @param dname: string, name of design doc. Usefull to compact a view. """ path = "/_compact" if dname is not None: path = "%s/%s" % (path, resource.escape_docid(dname)) res = self.res.post(path, headers={"Content-Type": "application/json"}) return res.json_body
def doc_exist(self, docid): """Test if document exists in a database @param docid: str, document id @return: boolean, True if document exist """ try: self.res.head(resource.escape_docid(docid)) except resource.ResourceNotFound: return False return True
def delete_doc(self, doc, _raw_json=False): """ delete a document or a list of documents @param doc: str or dict, document id or full doc. @param _raw_json: return raw json instead deserializing it @return: dict like: .. code-block:: python {"ok":true,"rev":"2839830636"} """ result = {"ok": False} if isinstance(doc, dict): if not "_id" or not "_rev" in doc: raise KeyError("_id and _rev are required to delete a doc") docid = resource.escape_docid(doc["_id"]) result = maybe_raw(self.res.delete(docid, rev=doc["_rev"]), raw=_raw_json) elif isinstance(doc, basestring): # we get a docid rev = self.get_rev(doc) docid = resource.escape_docid(doc) result = maybe_raw(self.res.delete(docid, rev=rev), raw=_raw_json) return result
def delete_attachment(self, doc, name): """ delete attachement to the document @param doc: dict, document object in python @param name: name of attachement @return: dict, with member ok set to True if delete was ok. """ docid = resource.escape_docid(doc["_id"]) name = url_quote(name, safe="") res = self.res(docid).delete(name, rev=doc["_rev"]).json_body if res["ok"]: doc.update({"_rev": res["rev"]}) return res["ok"]
def _get(self, docid, **params): try: doc_model = SQLDocModel.objects.get(doc_id=docid) except SQLDocModel.DoesNotExist: docid = resource.escape_docid(docid) return self.res.get(docid, **params).json_body else: doc = doc_model.doc assert doc['doc_type'] == doc_model.doc_type assert doc['_id'] == doc_model.doc_id doc['_rev'] = doc_model.sql_rev doc['_attachments'] = dict( att.format_stub() for att in doc_model.sqldocattachment_set.defer('payload') ) return doc
def delete_attachment(self, doc, name): """ delete attachement to the document @param doc: dict, document object in python @param name: name of attachement @return: dict, with member ok set to True if delete was ok. """ docid = resource.escape_docid(doc['_id']) name = url_quote(name, safe="") res = self.res(docid).delete(name, rev=doc['_rev']).json_body if res['ok']: new_doc = self.get(doc['_id'], rev=res['rev']) doc.update(new_doc) return res['ok']
def open_doc(self, docid, **params): """Get document from database Args: @param docid: str, document id to retrieve @param wrapper: callable. function that takes dict as a param. Used to wrap an object. @param **params: See doc api for parameters to use: http://wiki.apache.org/couchdb/HTTP_Document_API @return: dict, representation of CouchDB document as a dict. """ wrapper = None if 'wrapper' in params: wrapper = params.pop('wrapper') elif 'schema' in params: schema = params.pop('schema') if not hasattr(schema, 'wrap'): raise TypeError("invalid schema") wrapper = schema.wrap docid = resource.escape_docid(docid) doc = self.res.get(docid, **params).json_body # Lookup to see if doc_type is registered in schema try: schema = couchdbkit_handler.get_schema(*doc['doc_type']) except TypeError: pass else: if schema: wrapper = schema.wrap if wrapper is not None: if not callable(wrapper): raise TypeError("wrapper isn't a callable") doc = wrapper(doc) doc._db = self return doc return doc
def fetch_attachment(self, id_or_doc, name, stream=False): """ get attachment in a document @param id_or_doc: str or dict, doc id or document dict @param name: name of attachment default: default result @param stream: boolean, if True return a file object @return: `restkit.httpc.Response` object """ if isinstance(id_or_doc, basestring): docid = id_or_doc else: docid = id_or_doc['_id'] docid = resource.escape_docid(docid) name = url_quote(name, safe="") resp = self.res(docid).get(name) if stream: return resp.body_file return resp.body_string(charset="utf-8")
def debug_open_doc(self, docid, **params): """Get document from database Args: @param docid: str, document id to retrieve @param wrapper: callable. function that takes dict as a param. Used to wrap an object. @param **params: See doc api for parameters to use: http://wiki.apache.org/couchdb/HTTP_Document_API @return: dict, representation of CouchDB document as a dict. """ start = datetime.utcnow() ############################ #Start Database.open_doc wrapper = None if "wrapper" in params: wrapper = params.pop("wrapper") elif "schema" in params: schema = params.pop("schema") if not hasattr(schema, "wrap"): raise TypeError("invalid schema") wrapper = schema.wrap docid = resource.escape_docid(docid) error = None try: doc = self.res.get(docid, **params).json_body except ResourceNotFound as ex: error = ex doc = {} ############################# ############################# #Debug Panel data collection stop = datetime.utcnow() duration = ms_from_timedelta(stop - start) stacktrace = tidy_stacktrace(traceback.extract_stack()) if wrapper is not None: view_path_display = "GET %s" % wrapper.__self__._doc_type else: view_path_display = "Raw GET" q = { 'view_path': view_path_display, 'duration': duration, 'params': params, 'stacktrace': stacktrace, 'start_time': start, 'stop_time': stop, 'is_slow': (duration > SQL_WARNING_THRESHOLD), 'total_rows': 1, 'response': 200 if error is None else 404, 'doc_type': doc.get('doc_type', '[unknown]'), 'doc_id': docid, } self._queries.append(q) #end debug panel data collection ################################ ################################## #Resume original Database.open_doc if error is not None: raise error if wrapper is not None: if not callable(wrapper): raise TypeError("wrapper isn't a callable") return wrapper(doc) return doc
def put_attachment(self, doc, content, name=None, content_type=None, content_length=None): """ Add attachement to a document. All attachments are streamed. @param doc: dict, document object @param content: string or :obj:`File` object. @param name: name or attachment (file name). @param content_type: string, mimetype of attachment. If you don't set it, it will be autodetected. @param content_lenght: int, size of attachment. @return: bool, True if everything was ok. Example: >>> from simplecouchdb import server >>> server = server() >>> db = server.create_db('couchdbkit_test') >>> doc = { 'string': 'test', 'number': 4 } >>> db.save(doc) >>> text_attachment = u'un texte attaché' >>> db.put_attachment(doc, text_attachment, "test", "text/plain") True >>> file = db.fetch_attachment(doc, 'test') >>> result = db.delete_attachment(doc, 'test') >>> result['ok'] True >>> db.fetch_attachment(doc, 'test') >>> del server['couchdbkit_test'] {u'ok': True} """ headers = {} if not content: content = "" content_length = 0 if name is None: if hasattr(content, "name"): name = content.name else: raise InvalidAttachment('You should provide a valid attachment name') name = url_quote(name, safe="") if content_type is None: content_type = ';'.join(filter(None, guess_type(name))) if content_type: headers['Content-Type'] = content_type # add appropriate headers if content_length and content_length is not None: headers['Content-Length'] = content_length if hasattr(doc, 'to_json'): doc1 = doc.to_json() else: doc1 = doc docid = resource.escape_docid(doc1['_id']) res = self.res(docid).put(name, payload=content, headers=headers, rev=doc1['_rev']).json_body if res['ok']: new_doc = self.get(doc1['_id'], rev=res['rev']) doc.update(new_doc) return res['ok']
def debug_open_doc(self, docid, **params): """Get document from database Args: @param docid: str, document id to retrieve @param wrapper: callable. function that takes dict as a param. Used to wrap an object. @param **params: See doc api for parameters to use: http://wiki.apache.org/couchdb/HTTP_Document_API @return: dict, representation of CouchDB document as a dict. """ # debug panel start = datetime.now() newparams = params.copy() # end debug panel ############################ # Start Database.open_doc wrapper = None if "wrapper" in params: wrapper = params.pop("wrapper") elif "schema" in params: schema = params.pop("schema") if not hasattr(schema, "wrap"): raise TypeError("invalid schema") wrapper = schema.wrap docid = resource.escape_docid(docid) doc = self.res.get(docid, **params).json_body # End Database.open_doc ############################# ############################# # Debug Panel data collection stop = datetime.now() duration = ms_from_timedelta(stop - start) stacktrace = tidy_stacktrace(traceback.extract_stack()) if wrapper is not None: view_path_display = "GET %s" % wrapper.im_self._doc_type else: view_path_display = "Raw GET" self._queries.append( { "view_path": "get", "view_path_safe": "get", "view_path_display": view_path_display, "duration": duration, "params": {"docid": docid}, "hash": sha1(settings.SECRET_KEY + str(newparams) + docid).hexdigest(), "stacktrace": stacktrace, "start_time": start, "stop_time": stop, "is_slow": (duration > SQL_WARNING_THRESHOLD), "total_rows": 1, #'is_cached': is_cached, #'is_reduce': sql.lower().strip().startswith('select'), #'template_info': template_info, } ) # end debug panel data collection ################################ ################################## # Resume original Database.open_doc if wrapper is not None: if not callable(wrapper): raise TypeError("wrapper isn't a callable") return wrapper(doc) return doc
def debug_open_doc(self, docid, **params): """Get document from database Args: @param docid: str, document id to retrieve @param wrapper: callable. function that takes dict as a param. Used to wrap an object. @param **params: See doc api for parameters to use: http://wiki.apache.org/couchdb/HTTP_Document_API @return: dict, representation of CouchDB document as a dict. """ #debug panel start = datetime.now() newparams = params.copy() #end debug panel ############################ #Start Database.open_doc wrapper = None if "wrapper" in params: wrapper = params.pop("wrapper") elif "schema" in params: schema = params.pop("schema") if not hasattr(schema, "wrap"): raise TypeError("invalid schema") wrapper = schema.wrap docid = resource.escape_docid(docid) doc = self.res.get(docid, **params).json_body #End Database.open_doc ############################# ############################# #Debug Panel data collection stop = datetime.now() duration = ms_from_timedelta(stop - start) stacktrace = tidy_stacktrace(traceback.extract_stack()) if wrapper is not None: view_path_display = "GET %s" % wrapper.im_self._doc_type else: view_path_display = "Raw GET" self._queries.append({ 'view_path': 'get', 'view_path_safe': 'get', 'view_path_display': view_path_display, 'duration': duration, 'params': { 'docid': docid }, 'hash': sha1(settings.SECRET_KEY + str(newparams) + docid).hexdigest(), 'stacktrace': stacktrace, 'start_time': start, 'stop_time': stop, 'is_slow': (duration > SQL_WARNING_THRESHOLD), 'total_rows': 1, #'is_cached': is_cached, #'is_reduce': sql.lower().strip().startswith('select'), #'template_info': template_info, }) #end debug panel data collection ################################ ################################## #Resume original Database.open_doc if wrapper is not None: if not callable(wrapper): raise TypeError("wrapper isn't a callable") return wrapper(doc) return doc