Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions DataLayer/DataLayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Microsoft.Azure.Cosmos;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace DataLayer
{
/// <summary>
/// This is a Generic Data Access Layer (DAL) object.
/// </summary>
public class DataLayer<T> : IDataLayer<T> where T : Model
{
private readonly Container _container;
private string ContainerId { get; set; }

public DataLayer(CosmosClient client, string databaseId, string containerId)
{
ContainerId = containerId;
_container = client.GetContainer(databaseId, containerId);
}

/// <summary>
/// Gets all items.
/// </summary>
/// <returns><see cref="IEnumerable{T}"/></returns>
public async Task<IEnumerable<T>> GetAll()
{
// Define a Query
var query = new QueryDefinition($"SELECT * FROM {ContainerId}");

// Get an Iterator
var iterator = _container.GetItemQueryIterator<T>(query);

// Get the first page of results
var response = await iterator.ReadNextAsync();

//TODO: Paging

return response.Resource;
}

public async Task Remove(T item)
=> await _container.DeleteItemAsync<T>(
item.Id,
new PartitionKey(item.Id),
new ItemRequestOptions { IfMatchEtag = item.ETag });

public async Task<T> Create(T item)
{
var response = await _container.CreateItemAsync(item);
return response.Resource;
}

public async Task<T> Get(string id)
{
var response = await _container.ReadItemAsync<T>(id, new PartitionKey(id));
return response.Resource;
}

public async Task<T> Update(T item)
{
var response = await _container.ReplaceItemAsync(item,
item.Id,
new PartitionKey(item.Id),
new ItemRequestOptions { IfMatchEtag = item.ETag });
return response.Resource;
}

}
}
14 changes: 14 additions & 0 deletions DataLayer/DataLayer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,18 @@
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.19.0" />
</ItemGroup>

<PropertyGroup>
<PackageId>CodeCamp.DataLayer</PackageId>
<Title>Generic Data Layer for Codecamp</Title>
<Description></Description>
<Version>1.0.0</Version>
<Authors>Noah Costar and contributors</Authors>
<Company>Code Camp</Company>
<Copyright>Copyright 2021 Noah Costar and contributors</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/DanielLarsenNZ/CodeCamp.DataLayer</PackageProjectUrl>
<RepositoryUrl>https://github.com/DanielLarsenNZ/CodeCamp.DataLayer</RepositoryUrl>
<PackageTags>csharp;cosmos;azure;data</PackageTags>
</PropertyGroup>

</Project>
14 changes: 14 additions & 0 deletions DataLayer/IDataLayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;

namespace DataLayer
{
public interface IDataLayer<T> where T : Model
{
Task<T> Create(T item);
Task<T> Get(string id);
Task<IEnumerable<T>> GetAll();
Task Remove(T item);
Task<T> Update(T item);
}
}
18 changes: 18 additions & 0 deletions DataLayer/Model.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataLayer
{
public abstract class Model
{
[JsonProperty("id")]
public string Id { get; set; }

[JsonProperty("_eTag")]
public string ETag { get; set; }
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add

[JsonProperty("_etag")]

and this should serialise / de-serialise from Cosmos without the need for an ItemWithETag helper

}
}
42 changes: 0 additions & 42 deletions DataLayer/PeopleData.cs

This file was deleted.

116 changes: 114 additions & 2 deletions DataLayerTests/PeopleDataTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using DataLayer;
using Microsoft.Azure.Cosmos;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using System.Threading.Tasks;

Expand All @@ -18,15 +19,126 @@ public async Task GetAll()

// Create a CosmosClient
var client = new CosmosClient(_config["Cosmos_ConnectionString"]);

// Inject into PeopleData. IRL we would do this with IoC
var data = new PeopleData(client, _config["Cosmos_DatabaseId"]);
var data = new DataLayer<Person>(client, _config["Cosmos_DatabaseId"], "People");

// act
var people = await data.GetAll();

// assert
Assert.IsTrue(people.Any());
}

[TestMethod]
[TestCategory("Integration")]
public async Task AllPeopleHaveName()
{
// arrange
var client = new CosmosClient(_config["Cosmos_ConnectionString"]);

// Inject into PeopleData. IRL we would do this with IoC
var data = new DataLayer<Person>(client, _config["Cosmos_DatabaseId"], "People");

// act
var people = await data.GetAll();

// assert
Assert.IsFalse(people.Any(p => string.IsNullOrEmpty(p.FirstName)));
}

[TestMethod]
[TestCategory("Integration")]
public async Task CreatePerson()
{
//setup
// arrange
var client = new CosmosClient(_config["Cosmos_ConnectionString"]);
var person = new Person { FirstName = "Alice", Id = "A104", LastName = "Bob", HoursWorked = 5.5, Phone = "+642123456" };

// Inject into PeopleData. IRL we would do this with IoC
var data = new DataLayer<Person>(client, _config["Cosmos_DatabaseId"], "People");


// act
var newPerson = await data.Create(person);
try
{
var people = await data.GetAll();

// assert
Assert.IsTrue(people.Any(p => p.Id == newPerson.Id));
}
finally
{
// teardown
await data.Remove(newPerson);
}
}

[TestMethod]
[TestCategory("Integration")]
public async Task RemovePerson()
{
//setup
var client = new CosmosClient(_config["Cosmos_ConnectionString"]);
var person = new Person { FirstName = "Alice", Id = "A105", LastName = "Bob", HoursWorked = 5.5, Phone = "+642123456" };

var data = new DataLayer<Person>(client, _config["Cosmos_DatabaseId"], "People");
var newPerson = await data.Create(person);

//act
await data.Remove(newPerson);
var people = await data.GetAll();

//assert
Assert.IsFalse(people.Any(p => p.Id == newPerson.Id)); // check other attributes?

}

[TestMethod]
[TestCategory("Integration")]
public async Task Get_WithId_ReturnsPersonWithSameId()
{
//setup
var client = new CosmosClient(_config["Cosmos_ConnectionString"]);
var data = new DataLayer<Person>(client, _config["Cosmos_DatabaseId"], "People");


// act
var person = await data.Get("A101");

Assert.IsTrue(person.Id == "A101");

}

[TestMethod]
[TestCategory("Integration")]
[ExpectedException(typeof(CosmosException))]
public async Task CorrectUpdate()
{
// arrange
var client = new CosmosClient(_config["Cosmos_ConnectionString"]);
var person = new Person { FirstName = "Alice", Id = "A104", LastName = "Bob", HoursWorked = 5.5, Phone = "+642123456" };

var data = new DataLayer<Person>(client, _config["Cosmos_DatabaseId"], "People");
var newPerson = await data.Create(person);

// act
newPerson.FirstName = "Alice2";
var updatePerson = await data.Update(newPerson);

// remove older version of item.
try
{
newPerson.FirstName = "Alice3";
var outdatedPerson = await data.Update(newPerson);
}
finally
{
// teardown
await data.Remove(updatePerson);
}
}
}
}
12 changes: 10 additions & 2 deletions DataLayer/Person.cs → DataLayerTests/Person.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Person.cs should be moved to the Test project and deleted from this project as per #2

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand All @@ -10,8 +11,15 @@ namespace DataLayer
/// A Person Model
/// </summary>
/// <remarks>AKA DTO (data transfer object), POCO (plain old c# object)</remarks>
public class Person
public class Person : Model
{
//TODO: Properties
public string FirstName { get; set; }

public string LastName { get; set; }

public double HoursWorked { get; set; }

public string Phone { get; set; }
}
}
14 changes: 14 additions & 0 deletions DataLayerTests/Pet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataLayer
{
public class Pet : Model
{
public string Name { get; set; }

}
}