Click here to Skip to main content
15,881,844 members
Articles / Database Development / NoSQL

RavenDB - An Introduction

,
Rate me:
Please Sign up or sign in to vote.
4.87/5 (38 votes)
28 Apr 2010CPOL7 min read 261.5K   2.7K   112  
An introduction to RavenDB - a new open source .NET document database using .NET 4.0 and VS 2010
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Transactions;
using System.Web;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Raven.Database;
using Raven.Database.Data;
using Raven.Database.Exceptions;
using Raven.Database.Indexing;
using Raven.Database.Json;

namespace Raven.Client.Client
{
	public class ServerClient : IDatabaseCommands
	{
		private readonly string url;

		public ServerClient(string server, int port)
		{
			url = String.Format("http://{0}:{1}", server, port);
		}

		#region IDatabaseCommands Members

		public JsonDocument Get(string key)
		{
			EnsureIsNotNullOrEmpty(key, "key");

		    var metadata = new JObject();
		    AddTransactionInformation(metadata);
			var request = new HttpJsonRequest(url + "/docs/" + key, "GET", metadata);
			try
			{
				return new JsonDocument
				{
					Data = Encoding.UTF8.GetBytes(request.ReadResponseString()),
					Key = key,
					Etag = new Guid(request.ResponseHeaders["ETag"]),
					Metadata = request.ResponseHeaders.FilterHeaders()
				};
			}
			catch (WebException e)
			{
				var httpWebResponse = e.Response as HttpWebResponse;
				if (httpWebResponse == null ||
					httpWebResponse.StatusCode != HttpStatusCode.NotFound)
					throw;
				return null;
			}
		}

		private static void EnsureIsNotNullOrEmpty(string key, string argName)
		{
			if(string.IsNullOrEmpty(key))
				throw new ArgumentException("Key cannot be null or empty", argName);
		}

		public PutResult Put(string key, Guid? etag, JObject document, JObject metadata)
		{
            if (metadata == null)
                metadata = new JObject();
			var method = String.IsNullOrEmpty(key) ? "POST" : "PUT";
            AddTransactionInformation(metadata);
            if (etag != null)
                metadata["ETag"] = new JValue(etag.Value.ToString());
		    var request = new HttpJsonRequest(url + "/docs/" + key, method, metadata);
			request.Write(document.ToString());

		    string readResponseString;
		    try
		    {
		        readResponseString = request.ReadResponseString();
		    }
		    catch (WebException e)
		    {
                var httpWebResponse = e.Response as HttpWebResponse;
                if (httpWebResponse == null ||
                    httpWebResponse.StatusCode != HttpStatusCode.Conflict)
                    throw;
                throw ThrowConcurrencyException(e);
		    }
			return JsonConvert.DeserializeObject<PutResult>(readResponseString, new JsonEnumConverter());
		}

	    private static void AddTransactionInformation(JObject metadata)
	    {
	        if (Transaction.Current == null) 
                return;

	        string txInfo = Transaction.Current.TransactionInformation.DistributedIdentifier + ", " +
	                        TransactionManager.DefaultTimeout.ToString("c");
	        metadata["Raven-Transaction-Information"] = new JValue(txInfo);
	    }

	    public void Delete(string key, Guid? etag)
		{
			EnsureIsNotNullOrEmpty(key, "key");
	        var metadata = new JObject();
            if (etag != null)
                metadata.Add("ETag", new JValue(etag.Value.ToString()));
	        AddTransactionInformation(metadata);
	        var httpJsonRequest = new HttpJsonRequest(url + "/docs/" + key, "DELETE", metadata);
	        try
	        {
	            httpJsonRequest.ReadResponseString();
	        }
	        catch (WebException e)
	        {
	            var httpWebResponse = e.Response as HttpWebResponse;
                if (httpWebResponse == null ||
                    httpWebResponse.StatusCode != HttpStatusCode.Conflict)
                    throw;
                 throw ThrowConcurrencyException(e);
	        }
		}

	    private static Exception ThrowConcurrencyException(WebException e)
	    {
	        using (var sr = new StreamReader(e.Response.GetResponseStream()))
	        {
	            var text = sr.ReadToEnd();
	            var errorResults = JsonConvert.DeserializeAnonymousType(text, new
	            {
	                url = (string) null,
	                actualETag = Guid.Empty,
	                expectedETag = Guid.Empty,
	                error = (string) null
	            });
	            return new ConcurrencyException(errorResults.error)
	            {
	                ActualETag = errorResults.actualETag,
	                ExpectedETag = errorResults.expectedETag
	            };
	        }
	    }

	    public string PutIndex(string name, IndexDefinition definition)
		{
			EnsureIsNotNullOrEmpty(name, "name");
			var request = new HttpJsonRequest(url + "/indexes/" + name, "PUT");
			request.Write(JsonConvert.SerializeObject(definition, new JsonEnumConverter()));

			var obj = new {index = ""};
			obj = JsonConvert.DeserializeAnonymousType(request.ReadResponseString(), obj);
			return obj.index;
		}

		public QueryResult Query(string index, IndexQuery query)
		{
            EnsureIsNotNullOrEmpty(index, "index");
            var path = string.Format("{0}/indexes/{1}?query={2}&start={3}&pageSize={4}", url, index, query.Query, query.Start, query.PageSize);
            if (query.FieldsToFetch != null && query.FieldsToFetch.Length > 0)
            {
                path = query.FieldsToFetch.Aggregate(
                        new StringBuilder(path),
                        (sb, field) => sb.Append("&fetch=").Append(field)
                    ).ToString();
            }
            if(query.SortedFields!=null && query.SortedFields.Length>0)
            {
                path = query.SortedFields.Aggregate(
                        new StringBuilder(path),
						(sb, field) => sb.Append("&sort=").Append(HttpUtility.UrlEncode(field.Descending ? "-" : "+")).Append(field.Field)
                    ).ToString();
            }
            var request = new HttpJsonRequest(path, "GET");
            var serializer = new JsonSerializer();
            JToken json;
            using (var reader = new JsonTextReader(new StringReader(request.ReadResponseString())))
                json = (JToken)serializer.Deserialize(reader);

            return new QueryResult
            {
                IsStale = Convert.ToBoolean(json["IsStale"].ToString()),
                Results = json["Results"].Children().Cast<JObject>().ToArray(),
            }; 
	    }

	    public void DeleteIndex(string name)
		{
			EnsureIsNotNullOrEmpty(name, "name");
            var request = new HttpJsonRequest(url + "/indexes/" + name, "DELETE");
		    request.ReadResponseString();
		}

	    public JsonDocument[] Get(string[] ids)
	    {
            var request = new HttpJsonRequest(url + "/queries/", "POST");
            request.Write(new JArray(ids).ToString(Formatting.None));
            var responses = JArray.Parse(request.ReadResponseString());

	        return (from doc in responses.Cast<JObject>()
	                let metadata = (JObject) doc["@metadata"]
	                let _ = doc.Remove("@metadata")
	                select new JsonDocument
	                {
	                    Key = metadata["@id"].Value<string>(),
	                    Etag = new Guid(metadata["@etag"].Value<string>()),
	                    Metadata = metadata,
	                    Data = Encoding.UTF8.GetBytes(doc.ToString(Formatting.None)),
	                })
	            .ToArray();
	    }

		public BatchResult[] Batch(ICommandData[] commandDatas)
		{
			var metadata = new JObject();
			AddTransactionInformation(metadata);
			var req = new HttpJsonRequest(url + "/bulk_docs", "POST",metadata);
			var jArray = new JArray(commandDatas.Select(x => x.ToJson()));
			req.Write(jArray.ToString(Formatting.None));

			string response;
			try
			{
				response = req.ReadResponseString();
			}
			catch (WebException e)
			{
				var httpWebResponse = e.Response as HttpWebResponse;
				if (httpWebResponse == null ||
					httpWebResponse.StatusCode != HttpStatusCode.Conflict)
					throw;
				throw ThrowConcurrencyException(e);
			}
			return JsonConvert.DeserializeObject<BatchResult[]>(response);
		}

		public void Commit(Guid txId)
	    {
	        var httpJsonRequest = new HttpJsonRequest("/transaction/commit?tx=" + txId, "POST");
	        httpJsonRequest.ReadResponseString();
	    }

	    public void Rollback(Guid txId)
	    {
            var httpJsonRequest = new HttpJsonRequest("/transaction/rollback?tx=" + txId, "POST");
            httpJsonRequest.ReadResponseString();
	    }

	    #endregion

        #region IDisposable Members

        public void Dispose()
        {
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
I've been a software developer since 1996 and have enjoyed C# since 2003. I have a Bachelor's degree in Computer Science and for some reason, a Master's degree in Business Administration. I currently do software development contracting/consulting.

Written By
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions