Last active
May 16, 2018 08:03
-
-
Save petevb/f0b47873ef36eeb4e50a29a9c3871071 to your computer and use it in GitHub Desktop.
[LINQPad to CosmosDB (local emulator)] https://gist.github.com/stuarthallows/999db511fc80c4d9891265088ac3e271 #CosmosDB #LINQPad
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Write code to test your extensions here. Press F5 to compile and run. | |
void Main() | |
{ | |
Fetch(); | |
Create(); | |
} | |
void Fetch() | |
{ | |
var src = new TtcDBRepository(BaseRepository.LocalEmulator); | |
var todos = src.GetItemsAsync<TodoItem>(item => true); | |
todos.Result.Dump(); | |
} | |
void Create() | |
{ | |
var source = new DocumentDBRepository(BaseRepository.LocalEmulator /*, null, "ToDoList", "Items"*/); | |
var all = source.GetItemsAsync<TodoItem>(item => true).Result; | |
all.Dump(); | |
var dest = new DocumentDBRepository(BaseRepository.LocalEmulator, null, "Backups", "TodoList-Items"); | |
foreach (var doc in all) | |
{ | |
doc.PartitionKey = doc.PartitionKey; | |
var newItem = dest.CreateItemAsync(doc).Result; | |
newItem.Dump(); | |
} | |
var backup = dest.GetItemsAsync<TodoItem>(item => true).Result; | |
backup.Dump(); | |
} | |
public static class MyExtensions | |
{ | |
// Write custom extension methods here. They will be available to all queries. | |
} | |
public class TodoItem : Document | |
{ | |
[JsonProperty(PropertyName = "name")] | |
public string Name { get; set; } | |
[JsonProperty(PropertyName = "description")] | |
public string Description { get; set; } | |
[JsonProperty(PropertyName = "isComplete")] | |
public bool Completed { get; set; } | |
} | |
public class Document : Microsoft.Azure.Documents.Document, IPartitionKey | |
{ | |
[JsonProperty(PropertyName = "partitionKey")] | |
public string PartitionKey { get; set; } | |
[JsonProperty(PropertyName = "dateModified")] | |
public DateTime? DateModified | |
{ | |
get | |
{ | |
return this.Timestamp; | |
} | |
} | |
} | |
// You can also define non-static classes, enums, etc. | |
public class CosmosDBDocument : IDocument, IPartitionKey | |
{ | |
[JsonProperty(PropertyName = "id")] | |
public string Id { get; set; } | |
[JsonProperty(PropertyName = "partitionKey")] | |
public string PartitionKey { get; set; } | |
[JsonProperty(PropertyName = "dateCreated")] | |
public DateTime DateCreated { get; set; } | |
[JsonProperty(PropertyName = "dateModified")] | |
public DateTime? DateModified { get; set; } | |
[JsonProperty(PropertyName = "_etag")] | |
public string ETag { get; set; } | |
[JsonProperty(PropertyName = "_self")] | |
public string SelfIdentifier { get; set; } | |
} | |
public interface IDocument : IPartitionKey | |
{ | |
// [JsonProperty(PropertyName = "id")] | |
// string Id { get; set; } | |
// [JsonProperty(PropertyName = "partitionKey")] | |
// new string PartitionKey { get; set; } | |
DateTime DateCreated { get; set; } | |
new DateTime? DateModified { get; set; } | |
[JsonProperty(PropertyName = "_etag")] | |
new string ETag { get; set; } | |
[JsonProperty(PropertyName = "_self")] | |
string SelfIdentifier { get; set; } | |
} | |
public interface IPartitionKey | |
{ | |
[JsonProperty(PropertyName = "id")] | |
string Id { get; set; } | |
[JsonProperty(PropertyName = "partitionKey")] | |
string PartitionKey { get; } | |
[JsonProperty(PropertyName = "_etag")] | |
string ETag { get; } | |
DateTime? DateModified { get; } | |
} | |
public class DocumentDBRepository : BaseRepository | |
{ | |
public DocumentDBRepository(string endpoint = null, string token = null, string databaseId = "ToDoList", string collectionId = "Items") | |
: base(endpoint, token, databaseId, collectionId) | |
{ | |
} | |
public new async Task<T> CreateItemAsync<T>(T item) where T : Document | |
{ | |
return await base.CreateItemAsync<T>(item); | |
} | |
public async Task<Document> GetItemAsync(string id) | |
{ | |
return await base.GetItemAsync<Document>(id); | |
} | |
public async Task<IEnumerable<Document>> GetItemsAsync(Expression<Func<Document, bool>> predicate) | |
{ | |
return await base.GetItemsAsync<Document>(predicate); | |
} | |
} | |
public class TtcDBRepository : BaseRepository | |
{ | |
public TtcDBRepository(string endpoint = null, string token = null, string databaseId = "ToDoList", string collectionId = "Items") | |
: base(endpoint, token, databaseId, collectionId) | |
{ | |
} | |
public async new Task<T> CreateItemAsync<T>(T item) where T : class, IDocument | |
{ | |
if (item == null) | |
{ | |
throw new ArgumentNullException(nameof(item)); | |
} | |
if (string.IsNullOrWhiteSpace(item.Id)) | |
{ | |
throw new ArgumentException("Cannot add to repository; item has a blank Id", nameof(item)); | |
} | |
if (string.IsNullOrWhiteSpace(item.PartitionKey)) | |
{ | |
throw new ArgumentException("Cannot add to repository; item has a blank PartitionKey", nameof(item)); | |
} | |
if (item.DateCreated != DateTime.MinValue) | |
{ | |
// item.DateCreated = item.DateCreated; | |
item.DateModified = DateTime.UtcNow; | |
} | |
else | |
{ | |
item.DateCreated = DateTime.UtcNow; | |
// item.DateModified = null; | |
} | |
var collectionUri = UriFactory.CreateDocumentCollectionUri(this.databaseId, this.collectionId); | |
var response = await this.client.CreateDocumentAsync(collectionUri, item); | |
item.ETag = response.Resource.ETag; | |
item.SelfIdentifier = response.Resource.SelfLink; | |
return item; | |
} | |
} | |
public class BaseRepository | |
{ | |
public const string LocalEmulator = "https://localhost:8081/"; | |
// local emulator key is publicly available (https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator). | |
private const string LocalKey = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="; | |
protected string databaseId = "ToDoList"; | |
protected string collectionId = "Items"; | |
protected DocumentClient client; | |
protected BaseRepository(string endpoint = null, string token = null, string databaseId = "ToDoList", string collectionId = "Items") | |
{ | |
endpoint = getEndpoint(endpoint); | |
token = getAuthKey(token); | |
client = new DocumentClient(new Uri(endpoint), token); | |
this.databaseId = databaseId; | |
this.collectionId = collectionId; | |
CreateDatabaseIfNotExistsAsync().Wait(); | |
CreateCollectionIfNotExistsAsync().Wait(); | |
} | |
public async Task<T> GetItemAsync<T>(string id) where T : class, IPartitionKey | |
{ | |
try | |
{ | |
var documentUri = UriFactory.CreateDocumentUri(this.databaseId, this.collectionId, id); | |
Microsoft.Azure.Documents.Document document = await client.ReadDocumentAsync(documentUri); | |
return (T)(dynamic)document; | |
} | |
catch (DocumentClientException e) when (e.StatusCode == System.Net.HttpStatusCode.NotFound) | |
{ | |
return null; | |
} | |
} | |
public async Task<IEnumerable<T>> GetItemsAsync<T>(Expression<Func<T, bool>> predicate) where T : class, IPartitionKey | |
{ | |
var collectionUri = UriFactory.CreateDocumentCollectionUri(this.databaseId, this.collectionId); | |
IDocumentQuery<T> query = client.CreateDocumentQuery<T>( | |
collectionUri, | |
new FeedOptions | |
{ | |
MaxItemCount = -1, | |
EnableCrossPartitionQuery = true | |
}) | |
.Where(predicate) | |
.AsDocumentQuery(); | |
List<T> results = new List<T>(); | |
while (query.HasMoreResults) | |
{ | |
results.AddRange(await query.ExecuteNextAsync<T>()); | |
} | |
return results; | |
} | |
protected virtual async Task<T> CreateItemAsync<T>(T item) where T : class, IPartitionKey | |
{ | |
if (item == null) | |
{ | |
throw new ArgumentNullException(nameof(item)); | |
} | |
var collectionUri = UriFactory.CreateDocumentCollectionUri(this.databaseId, this.collectionId); | |
var requestOptions = item.PartitionKey == null ? null : new RequestOptions { PartitionKey = new PartitionKey(item.PartitionKey) }; | |
Microsoft.Azure.Documents.Document document = await client.CreateDocumentAsync(collectionUri, item, requestOptions); | |
item.Id = document.Id; | |
return item; | |
} | |
public async Task<T> UpdateItemAsync<T>(string id, T item) where T : class, IPartitionKey | |
{ | |
var documentUri = UriFactory.CreateDocumentUri(this.databaseId, this.collectionId, id); | |
var document = await this.client.ReplaceDocumentAsync(documentUri, item); | |
return (T)(dynamic)document.Resource; | |
} | |
public async Task DeleteItemAsync(string id) | |
{ | |
var documentUri = UriFactory.CreateDocumentUri(this.databaseId, this.collectionId, id); | |
await this.client.DeleteDocumentAsync(documentUri); | |
} | |
private async Task CreateDatabaseIfNotExistsAsync() | |
{ | |
try | |
{ | |
var databaseUri = UriFactory.CreateDatabaseUri(this.databaseId); | |
await client.ReadDatabaseAsync(databaseUri); | |
} | |
catch (DocumentClientException e) when (e.StatusCode == System.Net.HttpStatusCode.NotFound) | |
{ | |
await client.CreateDatabaseAsync(new Database { Id = this.databaseId }); | |
} | |
} | |
private async Task CreateCollectionIfNotExistsAsync() | |
{ | |
try | |
{ | |
var collectionUri = UriFactory.CreateDocumentCollectionUri(this.databaseId, this.collectionId); | |
await client.ReadDocumentCollectionAsync(collectionUri); | |
} | |
catch (DocumentClientException e) when (e.StatusCode == System.Net.HttpStatusCode.NotFound) | |
{ | |
var databaseUri = UriFactory.CreateDatabaseUri(this.databaseId); | |
await client.CreateDocumentCollectionAsync( | |
databaseUri, | |
new DocumentCollection { Id = this.collectionId }, | |
new RequestOptions { OfferThroughput = 400 }); | |
} | |
} | |
private string getEndpoint(string endpoint = null) | |
{ | |
if (string.IsNullOrWhiteSpace(endpoint)) | |
{ | |
endpoint = Util.ReadLine("endpoint (or blank for local emulator)"); | |
endpoint = string.IsNullOrWhiteSpace(endpoint) ? LocalEmulator : endpoint; | |
} | |
return endpoint; | |
} | |
private string getAuthKey(string authKey = null) | |
{ | |
if (string.IsNullOrWhiteSpace(authKey)) | |
{ | |
authKey = Util.GetPassword("auth key"); | |
authKey = string.IsNullOrWhiteSpace(authKey) ? BaseRepository.LocalKey : authKey; | |
} | |
return authKey; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment