/// <summary> /// Automatically reconcile the database copy with the target instance. This method /// uses reflection to perform the reconcilliation, and as such won't perform as well /// as other version, but is available for low-occurance scenarios /// </summary> /// <param name="databaseCopy">The database copy.</param> protected void AutoReconcile(IBigDbDocument databaseCopy) { var properties = GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); var fields = GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); foreach (var field in fields) { // if we haven't changed the field, if (EqualFields(field.GetValue(_sourceData), field.GetValue(this))) { field.SetValue(this, field.GetValue(databaseCopy)); } } foreach (var prop in properties) { if (!prop.CanWrite || prop.GetIndexParameters().Length > 0) { continue; } else if (EqualFields(prop.GetValue(_sourceData, null), prop.GetValue(this, null))) { prop.SetValue(this, prop.GetValue(databaseCopy, null), null); } } // this is non-negotiable Rev = databaseCopy.Rev; }
/// <summary> /// First use HEAD to see if it has indeed changed. /// </summary> /// <param name="document">Document to fill.</param> public void FetchDocumentIfChanged(IBigDbDocument document) { if (HasDocumentChanged(document)) { ReadDocument(document); } }
/// <summary> /// Deletes the attachment. /// </summary> /// <param name="document">The document.</param> /// <param name="attachmentName">Name of the attachment.</param> /// <returns>ICouchDocument.</returns> public IBigDbDocument DeleteAttachment(IBigDbDocument document, string attachmentName) { JObject result = Request(document.Id + "/" + attachmentName).Query("?rev=" + document.Rev).Delete().Check("Failed to delete attachment").Result(); document.Id = result["id"].Value <string>(); // Not really neeed document.Rev = result["rev"].Value <string>(); return(document); }
/// <summary> /// Read a CouchDocument or ICouchDocument, this relies on the document to obviously have an id. /// We also check the revision so that we can avoid parsing JSON if the document is unchanged. /// </summary> /// <param name="document">Document to fill.</param> public void ReadDocumentIfChanged(IBigDbDocument document) { var result = Request(document.Id).Etag(document.Rev).Parse(); if (result == null) { return; } document.ReadJson(result); }
/// <summary> /// Called by the runtime when a conflict is detected during save. The supplied parameter /// is the database copy of the document being saved. /// </summary> /// <param name="databaseCopy">The database copy.</param> public virtual void Reconcile(IBigDbDocument databaseCopy) { if (ReconcileBy == ReconcileStrategy.AutoMergeFields) { AutoReconcile(databaseCopy); return; } Rev = databaseCopy.Rev; }
/// <summary> /// Writes the identifier and rev. /// </summary> /// <param name="doc">The document.</param> /// <param name="writer">The writer.</param> public static void WriteIdAndRev(IBigDbDocument doc, JsonWriter writer) { if (doc.Id != null) { writer.WritePropertyName("_id"); writer.WriteValue(doc.Id); } if (doc.Rev != null) { writer.WritePropertyName("_rev"); writer.WriteValue(doc.Rev); } }
/// <summary> /// Reads the identifier and rev. /// </summary> /// <param name="doc">The document.</param> /// <param name="reader">The reader.</param> public static void ReadIdAndRev(IBigDbDocument doc, JsonReader reader) { reader.Read(); if (reader.TokenType == JsonToken.PropertyName && (reader.Value as string == "_id")) { reader.Read(); doc.Id = reader.Value as string; } reader.Read(); if (reader.TokenType == JsonToken.PropertyName && (reader.Value as string == "_rev")) { reader.Read(); doc.Rev = reader.Value as string; } }
/// <summary> /// Writes the attachment. /// </summary> /// <param name="document">The document.</param> /// <param name="attachmentName">Name of the attachment.</param> /// <param name="attachmentData">The attachment data.</param> /// <param name="mimeType">Type of the MIME.</param> /// <returns>The document.</returns> /// <remarks>This relies on the document to already have an id.</remarks> public IBigDbDocument WriteAttachment(IBigDbDocument document, string attachmentName, Stream attachmentData, string mimeType) { if (document.Id == null) { throw BigDException.Create( "Failed to add attachment to document using PUT because it lacks an id"); } JObject result = Request(document.Id + "/" + attachmentName).Query("?rev=" + document.Rev).Data(attachmentData).MimeType(mimeType).Put().Check("Failed to write attachment") .Result(); document.Id = result["id"].Value <string>(); // Not really neeed document.Rev = result["rev"].Value <string>(); return(document); }
/// <summary> /// Create a given ICouchDocument in CouchDB. Uses POST and CouchDB will allocate a new id and overwrite any existing id. /// </summary> /// <param name="document">Document to store.</param> /// <returns>Document with Id and Rev set.</returns> /// <remarks>POST which may be problematic in some environments.</remarks> public IBigDbDocument CreateDocument(IBigDbDocument document) { try { // Wulka mods var json = BigDDocument.WriteJson(document, false); // end Wulka mods JObject result = Request().Data(json).PostJson().Check("Failed to create document").Result(); document.Id = result["id"].Value <string>(); document.Rev = result["rev"].Value <string>(); return(document); } catch (WebException e) { throw BigDException.Create("Failed to create document", e); } }
/// <summary> /// This is a convenience method that creates or writes a ICouchDocument depending on if /// it has an id or not. If it does not have an id we create the document and let CouchDB allocate /// an id. If it has an id we use WriteDocument which will overwrite the existing document in CouchDB. /// </summary> /// <param name="document">ICouchDocument</param> /// <returns>ICouchDocument with new Rev set.</returns> public IBigDbDocument SaveDocument(IBigDbDocument document) { var reconcilingDoc = document as IReconcilingDocument; IBigDbDocument savedDoc; try { savedDoc = document.Id == null? CreateDocument(document) : WriteDocument(document); } catch (BigDConflictException) { if (reconcilingDoc == null) { throw; } // can't handle a brand-new document if (String.IsNullOrEmpty(reconcilingDoc.Rev)) { throw; } switch (reconcilingDoc.ReconcileBy) { case ReconcileStrategy.None: throw; default: reconcilingDoc.Reconcile(reconcilingDoc.GetDatabaseCopy(this)); SaveDocument(reconcilingDoc); break; } savedDoc = reconcilingDoc; } if (reconcilingDoc != null) { reconcilingDoc.SaveCommited(); } // SynchDesignDocuments(); return(savedDoc); }
/// <summary> /// Write a CouchDocument or ICouchDocument, it may already exist in db and will then be overwritten. /// </summary> /// <param name="document">Couch document</param> /// <param name="batch">True if we don't want to wait for flush (commit).</param> /// <returns>Couch Document with new Rev set.</returns> /// <remarks>This relies on the document to already have an id.</remarks> public IBigDbDocument WriteDocument(IBigDbDocument document, bool batch) { if (document.Id == null) { throw BigDException.Create( "Failed to write document using PUT because it lacks an id, use CreateDocument instead to let CouchDB generate an id"); } // Wulka additions var json = BigDDocument.WriteJson(document, false); // End Wulka additions JObject result = Request(document.Id).Query(batch ? "?batch=ok" : null).Data(json).Put().Check("Failed to write document").Result(); document.Id = result["id"].Value <string>(); // Not really needed document.Rev = result["rev"].Value <string>(); return(document); }
/// <summary> /// Read a ICouchDocument with an id even if it has not changed revision. /// </summary> /// <param name="document">Document to fill.</param> public void ReadDocument(IBigDbDocument document) { document.ReadJson(ReadDocumentJObject(document.Id)); }
/// <summary> /// Determines whether [has document changed] [the specified document]. /// </summary> /// <param name="document">The document.</param> /// <returns><c>true</c> if [has document changed] [the specified document]; otherwise, <c>false</c>.</returns> public bool HasDocumentChanged(IBigDbDocument document) { return(HasDocumentChanged(document.Id, document.Rev)); }
/// <summary> /// Copies the specified source document to the destination document, replacing it. /// </summary> /// <param name="sourceDocument">The source document.</param> /// <param name="destinationDocument">The destination document.</param> /// <remarks>This method does not update the destinationDocument object.</remarks> public void Copy(IBigDbDocument sourceDocument, IBigDbDocument destinationDocument) { Copy(sourceDocument.Id, destinationDocument.Id, destinationDocument.Rev); }
WriteDocument(IBigDbDocument document) { return(WriteDocument(document, false)); }
/// <summary> /// Deletes the document. /// </summary> /// <param name="document">The document.</param> public void DeleteDocument(IBigDbDocument document) { DeleteDocument(document.Id, document.Rev); }
/// <summary> /// Determines whether the specified document has attachment. /// </summary> /// <param name="document">The document.</param> /// <param name="attachmentName">Name of the attachment.</param> /// <returns><c>true</c> if the specified document has attachment; otherwise, <c>false</c>.</returns> public bool HasAttachment(IBigDbDocument document, string attachmentName) { return(HasAttachment(document.Id, attachmentName)); }
/// <summary> /// Reads the identifier and rev. /// </summary> /// <param name="doc">The document.</param> /// <param name="obj">The object.</param> public static void ReadIdAndRev(IBigDbDocument doc, JObject obj) { doc.Id = obj["_id"].Value <string>(); doc.Rev = obj["_rev"].Value <string>(); }
/// <summary> /// Add an attachment to an existing ICouchDocument, it may already exist in db and will then be overwritten. /// </summary> /// <param name="document">Couch document</param> /// <param name="attachmentName">Name of the attachment.</param> /// <param name="attachmentData">The attachment data.</param> /// <param name="mimeType">The MIME type for the attachment.</param> /// <returns>The document.</returns> /// <remarks>This relies on the document to already have an id.</remarks> public IBigDbDocument WriteAttachment(IBigDbDocument document, string attachmentName, string attachmentData, string mimeType) { var byteData = Encoding.UTF8.GetBytes(attachmentData); return(WriteAttachment(document, attachmentName, byteData, mimeType)); }
/// <summary> /// Read the attachment for an ICouchDocument. /// </summary> /// <param name="document">Document to read.</param> /// <param name="attachmentName">Name of the attachment.</param> /// <returns>WebResponse.</returns> public WebResponse ReadAttachment(IBigDbDocument document, string attachmentName) { return(ReadAttachment(document.Id, attachmentName)); }
/// <summary> /// Determines whether the specified document has document. /// </summary> /// <param name="document">The document.</param> /// <returns><c>true</c> if the specified document has document; otherwise, <c>false</c>.</returns> public bool HasDocument(IBigDbDocument document) { return(HasDocument(document.Id)); }