Skip to content

Commit 40b8608

Browse files
author
Jeff Treuting
committed
Moved CouchDb into master and upgraded RavenDb.Client
Moved the CouchDbRepository project on to the master branch since it passes all the integration tests. It's not yet ready for prime time so we won't make a NuGet package yet, but it's working well it seems. I'm sure the LINQ provider will need to be expanded to cover other things as we move forward with it, but the basics seem to be covered. Upgraded the RavenDB Client to the latest.
1 parent 34bfc47 commit 40b8608

154 files changed

Lines changed: 134147 additions & 126552 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
// Inspired by SharpCouch and tweaked for our specific needs
2+
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using Newtonsoft.Json;
7+
using Newtonsoft.Json.Linq;
8+
9+
namespace SharpRepository.CouchDbRepository
10+
{
11+
12+
/// <summary>
13+
/// Used to return metadata about a document.
14+
/// </summary>
15+
public class DocInfo
16+
{
17+
public string Id;
18+
public string Revision;
19+
}
20+
21+
/// <summary>
22+
/// A simple wrapper class for the CouchDB HTTP API. No
23+
/// initialisation is necessary, just create an instance and
24+
/// call the appropriate methods to interact with CouchDB.
25+
/// All methods throw exceptions when things go wrong.
26+
/// </summary>
27+
public class CouchDbClient<T> where T : class, new()
28+
{
29+
private readonly string _server;
30+
private readonly string _database;
31+
32+
public CouchDbClient()
33+
{
34+
}
35+
36+
public CouchDbClient(string server, string database)
37+
{
38+
_server = server;
39+
_database = database;
40+
}
41+
42+
public string Server
43+
{
44+
get { return _server; }
45+
}
46+
47+
public string Database
48+
{
49+
get { return _database; }
50+
}
51+
52+
public string DatabaseUrl
53+
{
54+
get { return _server + "/" + _database; }
55+
}
56+
57+
/// <summary>
58+
/// Get the document count for the given database.
59+
/// </summary>
60+
/// <returns>The number of documents in the database</returns>
61+
public int CountDocuments()
62+
{
63+
// Get information about the database...
64+
var result = CouchDbRequest.Execute(_server + "/" + _database, "GET");
65+
66+
var dictionary = JsonConvert.DeserializeObject<IDictionary<string, string>>(result);
67+
68+
// The document count is a field within...
69+
return Int32.Parse(dictionary["doc_count"]);
70+
}
71+
72+
/// <summary>
73+
/// Get information on all the documents in the given database.
74+
/// </summary>
75+
/// <returns>An array of entitiy instances</returns>
76+
public IList<T> GetAllDocuments()
77+
{
78+
var json = ExecTempView(_server + "/" + _database + "/_temp_view", "function (doc) {emit(doc._id, doc);}", null);
79+
80+
var res = JObject.Parse(json);
81+
var rows = res["rows"];
82+
83+
return rows.Select(row => row["value"].ToObject<T>()).ToList();
84+
}
85+
86+
public string ExecTempView(string url, string map, string reduce)
87+
{
88+
var viewdef = "{ \"map\":\"" + map + "\"";
89+
if (reduce != null)
90+
viewdef += ",\"reduce\":\"" + reduce + "\"";
91+
viewdef += "}";
92+
93+
return CouchDbRequest.Execute(url, "POST", viewdef, "application/json");
94+
}
95+
96+
/// <summary>
97+
/// Execute a temporary view and return the results.
98+
/// </summary>
99+
/// <param name="map">The javascript map function</param>
100+
/// <param name="reduce">The javascript reduce function or
101+
/// null if not required</param>
102+
/// <param name="startkey">The startkey or null not to use</param>
103+
/// <param name="endkey">The endkey or null not to use</param>
104+
/// <returns>The result (JSON format)</returns>
105+
public string ExecTempView(string map, string reduce ,string startkey,string endkey)
106+
{
107+
// Generate the JSON view definition from the supplied
108+
// map and optional reduce functions...
109+
var viewdef = "{ \"map\":\"" + map + "\"";
110+
if (reduce != null)
111+
viewdef += ",\"reduce\":\"" + reduce + "\"";
112+
viewdef += "}";
113+
114+
var url = _server + "/" + _database + "/_temp_view";
115+
if(startkey!=null)
116+
{
117+
url+="?startkey=" + Uri.EscapeDataString(startkey);
118+
}
119+
if(endkey!=null)
120+
{
121+
if(startkey==null) url+="?"; else url+="&";
122+
url+="endkey=" + Uri.EscapeDataString(endkey);
123+
}
124+
125+
return CouchDbRequest.Execute(url, "POST", viewdef, "application/json");
126+
}
127+
128+
/// <summary>
129+
/// Create a new document. If the document has no ID field,
130+
/// it will be assigned one by the server.
131+
/// </summary>
132+
/// <param name="entity">The item to store in the database.</param>
133+
public void CreateDocument(T entity, string id)
134+
{
135+
var item = JsonConvert.SerializeObject(entity);
136+
137+
// add the _id so that it is the same as the PK of the entity
138+
// this is a crappy way of doing it I think, but just trying to get it to work for now
139+
if (!String.IsNullOrEmpty(id))
140+
{
141+
item = "{\"_id\":\"" + id + "\"," + item.Substring(1);
142+
}
143+
144+
CouchDbRequest.Execute(_server + "/" + _database, "POST", item, "application/json");
145+
}
146+
147+
public string GetLatestRevision(string id)
148+
{
149+
var json = Get(id);
150+
151+
var obj = JObject.Parse(json);
152+
153+
return obj.Value<string>("_rev");
154+
}
155+
156+
/// <summary>
157+
/// Updates a document.
158+
/// </summary>
159+
/// <param name="entity">The item to store in the database.</param>
160+
/// <param name="id">The document ID.</param>
161+
public void UpdateDocument(T entity, string id)
162+
{
163+
var item = JsonConvert.SerializeObject(entity);
164+
165+
//needs the revision for updates and deletes, this isn't a great way because it's an extra API call, but it is what it is for now, just want to get it working then refactor
166+
var rev = GetLatestRevision(id);
167+
168+
// add the _id so that it is the same as the PK of the entity
169+
// this is a crappy way of doing it I think, but just trying to get it to work for now
170+
item = "{\"_id\":\"" + id + "\",\"_rev\":\"" + rev + "\"," + item.Substring(1);
171+
172+
CouchDbRequest.Execute(_server + "/" + _database + "/" + id, "PUT", item, "application/json");
173+
}
174+
175+
/// <summary>
176+
/// Get a document.
177+
/// </summary>
178+
/// <param name="id">The document ID.</param>
179+
/// <returns>The document contents (JSON)</returns>
180+
public T GetDocument(string id)
181+
{
182+
var json = Get(id);
183+
if (String.IsNullOrEmpty(json))
184+
return null;
185+
186+
return JsonConvert.DeserializeObject<T>(json);
187+
}
188+
189+
private string Get(string id)
190+
{
191+
var url = _server + "/" + _database + "/" + id;
192+
return CouchDbRequest.Execute(url, "GET");
193+
}
194+
195+
/// <summary>
196+
/// Delete a document.
197+
/// </summary>
198+
/// <param name="id">The document ID.</param>
199+
public void DeleteDocument(string id)
200+
{
201+
//needs the revision for updates and deletes, this isn't a great way because it's an extra API call, but it is what it is for now, just want to get it working then refactor
202+
var rev = GetLatestRevision(id);
203+
204+
CouchDbRequest.Execute(_server + "/" + _database + "/" + id + "?rev=" + rev, "DELETE");
205+
}
206+
}
207+
}
208+
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Newtonsoft.Json;
4+
5+
namespace SharpRepository.CouchDbRepository
6+
{
7+
public static class CouchDbManager
8+
{
9+
/// <summary>
10+
/// Get a list of database on the server.
11+
/// </summary>
12+
/// <param name="server">The server URL</param>
13+
/// <returns>A string array containing the database names
14+
/// </returns>
15+
public static IList<string> GetDatabases(string server)
16+
{
17+
return JsonConvert.DeserializeObject<IList<string>>(
18+
CouchDbRequest.Execute(server + "/_all_dbs", "GET")
19+
);
20+
}
21+
22+
/// <summary>
23+
/// Checks if the database exists already
24+
/// </summary>
25+
public static bool HasDatabase(string server, string db)
26+
{
27+
return GetDatabases(server).Contains(db);
28+
}
29+
30+
/// <summary>
31+
/// Create a new database.
32+
/// </summary>
33+
public static void CreateDatabase(string server, string db)
34+
{
35+
var result = CouchDbRequest.Execute(server + "/" + db, "PUT");
36+
if (result.Trim() != "{\"ok\":true}")
37+
throw new ApplicationException("Failed to create database: " + result);
38+
}
39+
40+
/// <summary>
41+
/// Delete a database
42+
/// </summary>
43+
public static void DeleteDatabase(string server, string db)
44+
{
45+
var result = CouchDbRequest.Execute(server + "/" + db, "DELETE");
46+
if (result.Trim() != "{\"ok\":true}")
47+
throw new ApplicationException("Failed to delete database: " + result);
48+
}
49+
}
50+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+

2+
namespace SharpRepository.CouchDbRepository
3+
{
4+
public class CouchDbRepository<T> : CouchDbRepositoryBase<T> where T : class, new()
5+
{
6+
public CouchDbRepository()
7+
{
8+
}
9+
10+
public CouchDbRepository(string host) : base(host)
11+
{
12+
}
13+
14+
public CouchDbRepository(string host, int port, string database = null, string username = null, string password = null)
15+
: base(host, port, database, username, password)
16+
{
17+
}
18+
}
19+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using System;
2+
using System.Linq;
3+
using SharpRepository.CouchDbRepository.Linq;
4+
using SharpRepository.Repository;
5+
using SharpRepository.Repository.FetchStrategies;
6+
7+
namespace SharpRepository.CouchDbRepository
8+
{
9+
public class CouchDbRepositoryBase<T> : LinqRepositoryBase<T, string> where T : class, new()
10+
{
11+
protected CouchDbClient<T> Client;
12+
private readonly string _serverUrl;
13+
private readonly string _database;
14+
15+
//private readonly CouchDbQueryProvider _provider;
16+
private readonly IQueryable<T> _baseQuery;
17+
18+
internal CouchDbRepositoryBase()
19+
: this("127.0.0.1", 5984)
20+
{
21+
}
22+
23+
internal CouchDbRepositoryBase(string host)
24+
: this(host, 5984)
25+
{
26+
}
27+
28+
internal CouchDbRepositoryBase(string host, int port, string database = null, string username = null, string password = null)
29+
{
30+
if (String.IsNullOrEmpty(database))
31+
{
32+
database = typeof (T).Name;
33+
}
34+
_database = database.ToLower(); // CouchDb requires lowercase database names
35+
36+
_serverUrl = String.Format("http://{0}:{1}", host, port);
37+
38+
Client = new CouchDbClient<T>(_serverUrl, _database);
39+
40+
if (!CouchDbManager.HasDatabase(_serverUrl, _database))
41+
{
42+
CouchDbManager.CreateDatabase(_serverUrl, _database);
43+
}
44+
}
45+
46+
protected override IQueryable<T> BaseQuery(IFetchStrategy<T> fetchStrategy = null)
47+
{
48+
return CouchDbQueryFactory.Queryable<T>(_serverUrl, _database);
49+
//return Client.GetAllDocuments().AsQueryable();
50+
}
51+
52+
// we override the implementation fro LinqBaseRepository becausee this is built in
53+
protected override T GetQuery(string key)
54+
{
55+
var item = Client.GetDocument(key);
56+
57+
if (item == null)
58+
return null;
59+
60+
// this always returns an object, so check to see if the PK is null, if so then return null
61+
string id;
62+
GetPrimaryKey(item, out id);
63+
64+
return id == null ? null : item;
65+
}
66+
67+
protected override void AddItem(T entity)
68+
{
69+
string id;
70+
if (GetPrimaryKey(entity, out id) && Equals(id, default(string)))
71+
{
72+
id = GeneratePrimaryKey();
73+
SetPrimaryKey(entity, id);
74+
}
75+
76+
Client.CreateDocument(entity, id);
77+
}
78+
79+
protected override void DeleteItem(T entity)
80+
{
81+
string id;
82+
if (!GetPrimaryKey(entity, out id))
83+
return;
84+
85+
Client.DeleteDocument(id);
86+
}
87+
88+
protected override void UpdateItem(T entity)
89+
{
90+
string id;
91+
GetPrimaryKey(entity, out id);
92+
93+
Client.UpdateDocument(entity, id);
94+
}
95+
96+
protected override void SaveChanges()
97+
{
98+
99+
}
100+
101+
public override void Dispose()
102+
{
103+
104+
}
105+
106+
private static string GeneratePrimaryKey()
107+
{
108+
return (string) Convert.ChangeType(Guid.NewGuid().ToString("N"), typeof (string));
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)