Skip to content

Commit

Permalink
task: updated examples and added initial README.md content
Browse files Browse the repository at this point in the history
  • Loading branch information
dtanglr committed Feb 6, 2024
1 parent 53a4071 commit 0b673d4
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 78 deletions.
5 changes: 5 additions & 0 deletions Primitively.sln
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Primitively.MongoDB.Bson",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.TestLib", "test\Acme.TestLib\Acme.TestLib.csproj", "{F159F852-EC63-4AB9-A68F-C1F10E2B6CD9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{53DB2221-007B-44EC-8CA5-06E340E20DFA}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,28 @@
[![CI](https://github.com/dtanglr/Primitively/actions/workflows/dotnet.yml/badge.svg?branch=main)](https://github.com/dtanglr/Primitively/actions/workflows/dotnet.yml)
[![NuGet version](https://badge.fury.io/nu/Primitively.svg)](https://badge.fury.io/nu/Primitively)
# Primitively

[![CI](https://github.com/dtanglr/Primitively/actions/workflows/dotnet.yml/badge.svg?branch=main)](https://github.com/dtanglr/Primitively/actions/workflows/dotnet.yml)
[![NuGet version](https://badge.fury.io/nu/Primitively.svg)](https://badge.fury.io/nu/Primitively)

**Primitively** is Rosyln-powered C# source code generator of strongly-typed IDs and DDD-style value objects that encapsulate a single GUID, integer, date or string .NET **primitively** typed value.

```csharp
// Before
namespace Acme.Abstractions;

public record Product(Guid Id, Guid Sku);
```

```csharp
// After
using Primitively;

namespace Acme.Abstractions;

public record Product(ProductId Id, Sku Sku);

[Guid]
public partial record struct ProductId;

[Guid]
public partial record struct Sku;
```
Original file line number Diff line number Diff line change
Expand Up @@ -18,88 +18,56 @@ public CatalogController(IProductRepository repository, ILogger<CatalogControlle
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

[HttpGet]
[HttpGet("products", Name = $"{nameof(GetProducts)}")]
[ProducesResponseType(typeof(IEnumerable<Product>), (int)HttpStatusCode.OK)]
public async Task<ActionResult<IEnumerable<Product>>> GetProducts()
{
var products = await _repository.GetProducts();
return Ok(products);
}

[HttpGet("id/{id}", Name = "GetProductById")]
[HttpGet("products/{productId}", Name = $"{nameof(GetProductById)}")]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)]
public async Task<ActionResult<Product>> GetProductById(ProductId id)
public async Task<ActionResult<Product>> GetProductById(ProductId productId)
{
var product = await _repository.GetProductById(id);
var product = await _repository.GetProduct(productId);

if (product == null)
{
_logger.LogError("Product with id: {id}, not found.", id);
_logger.LogError("Product with ProductId: {ProductId}, not found.", productId);
return NotFound();
}

return Ok(product);
}

[HttpGet("guid/{guid}", Name = "GetProductByGuid")]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)]
public async Task<ActionResult<Product>> GetProductByGuid(Guid guid)
{
var product = await _repository.GetProductByGuid(guid);

if (product == null)
{
_logger.LogError("Product with Guid: {guid}, not found.", guid);
return NotFound();
}

return Ok(product);
}

[HttpGet("sku/{sku}", Name = "GetProductBySku")]
[HttpGet("products/sku/{sku}", Name = $"{nameof(GetProductBySku)}")]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)]
public async Task<ActionResult<Product>> GetProductBySku(Sku sku)
{
var product = await _repository.GetProductBySku(sku);
var product = await _repository.GetProduct(sku);

if (product == null)
{
_logger.LogError("Product with Sku: {sku}, not found.", sku);
_logger.LogError("Product with Sku: {Sku}, not found.", sku);
return NotFound();
}

return Ok(product);
}

[HttpGet("productId/{productId}", Name = "GetProductByProductId")]
[HttpGet("products/category/{categoryId}", Name = $"{nameof(GetProductsByCategoryId)}")]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)]
public async Task<ActionResult<Product>> GetProductByProductId(ProductId productId)
{
var product = await _repository.GetProductByProductId(productId);

if (product == null)
{
_logger.LogError("Product with ProductId: {productId}, not found.", productId);
return NotFound();
}

return Ok(product);
}

[HttpGet("category/{categoryId}", Name = "GetProductByCategoryId")]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(List<Product>), (int)HttpStatusCode.OK)]
public async Task<ActionResult<List<Product>>> GetProductByCategoryId(CategoryId categoryId)
[ProducesResponseType(typeof(IEnumerable<Product>), (int)HttpStatusCode.OK)]
public async Task<ActionResult<IEnumerable<Product>>> GetProductsByCategoryId(CategoryId categoryId)
{
var products = await _repository.GetProducts(categoryId);

if (products == null)
{
_logger.LogError("Products with CategoryId: {categoryId}, not found.", categoryId);
_logger.LogError("Products with CategoryId: {CategoryId}, not found.", categoryId);
return NotFound();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ private static IEnumerable<Product> GetPreconfiguredProducts()
yield return new()
{
Id = (ProductId)ProductId.Example,
Guid = Guid.Parse("2c48c152-7cb7-4f51-8f01-704454f36e60"),
ProductId = (ProductId)ProductId.Example,
Sku = (Sku)Sku.Example,
Guid = Guid.Parse("2c48c152-7cb7-4f51-8f01-704454f36e60"),
Name = "IPhone X",
Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.",
Description = "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@ namespace Acme.Catalog.Api.Entities;
public class Product
{
[BsonId]
// Primitively IGuid: Will use the default GuidRepresentation of CSharpLegacy unless configured differently in the DI
public ProductId Id { get; set; } = ProductId.New();

// .net Guid: Requires configuration of either GuidSerializer (via DI), BsonType or GuidRepresentation (via attribute) or property map to work correctly
[BsonGuidRepresentation(GuidRepresentation.CSharpLegacy)]
public Guid Guid { get; set; } = Guid.NewGuid();

// Primitively IGuid: Will use the default GuidRepresentation of CSharpLegacy unless configured differently in the DI
public Sku Sku { get; set; } = Sku.New();

// Primitively IGuid: Will use Standard (UUID) format
[BsonIGuidRepresentation(GuidRepresentation.Standard)]
public ProductId ProductId { get; set; } = ProductId.New();

// .NET Guid: Requires configuration of either GuidSerializer (via DI), BsonType or GuidRepresentation (via attribute) or property map to work correctly
[BsonGuidRepresentation(GuidRepresentation.CSharpLegacy)]
public Guid Guid { get; set; } = Guid.NewGuid();

public string? Name { get; set; }

public Category Category { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ namespace Acme.Catalog.Api.Repositories;

public interface IProductRepository
{
Task<Product> GetProduct(ProductId id);
Task<Product> GetProduct(Sku sku);
Task<IEnumerable<Product>> GetProducts();
Task<Product> GetProductById(ProductId id);
Task<Product> GetProductByGuid(Guid guid);
Task<Product> GetProductBySku(Sku sku);
Task<Product> GetProductByProductId(ProductId productId);
Task<List<Product>> GetProducts(CategoryId categoryId);
Task<IEnumerable<Product>> GetProducts(CategoryId categoryId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,31 @@ public ProductRepository(ICatalogContext context)
_context = context ?? throw new ArgumentNullException(nameof(context));
}

public async Task<IEnumerable<Product>> GetProducts()
{
return await _context
.Products
.Find(Builders<Product>.Filter.Empty)
.ToListAsync();
}

public async Task<Product> GetProductById(ProductId id)
public async Task<Product> GetProduct(ProductId id)
{
return await _context
.Products
.Find(p => p.Id == id)
.SingleOrDefaultAsync();
}

public async Task<Product> GetProductByGuid(Guid guid)
{
return await _context
.Products
.Find(p => p.Guid == guid)
.SingleOrDefaultAsync();
}

public async Task<Product> GetProductBySku(Sku sku)
public async Task<Product> GetProduct(Sku sku)
{
return await _context
.Products
.Find(Builders<Product>.Filter.Eq(p => p.Sku, sku))
.SingleOrDefaultAsync();
}

public async Task<Product> GetProductByProductId(ProductId productId)
public async Task<IEnumerable<Product>> GetProducts()
{
return await _context
.Products
.Find(p => p.ProductId == productId)
.SingleOrDefaultAsync();
.Find(Builders<Product>.Filter.Empty)
.ToListAsync();
}

public async Task<List<Product>> GetProducts(CategoryId categoryId)
public async Task<IEnumerable<Product>> GetProducts(CategoryId categoryId)
{
return await _context
.Products
Expand Down

0 comments on commit 0b673d4

Please sign in to comment.