Skip to content

Commit

Permalink
[ksqlDb.RestApi.Client]: PaymentModelBuilder example
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasfabian committed Apr 6, 2024
1 parent 3c33d18 commit 35eef5a
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
using ksqlDb.RestApi.Client.DependencyInjection;
using ksqlDb.RestApi.Client.FluentAPI.Builders;
using ksqlDB.RestApi.Client.KSql.Query.Context;
using ksqlDB.RestApi.Client.KSql.RestApi;
using ksqlDB.RestApi.Client.KSql.RestApi.Http;
using ksqlDB.RestApi.Client.KSql.RestApi.Statements;
using Microsoft.Extensions.DependencyInjection;

namespace ksqlDB.RestApi.Client.Samples.Model;
namespace ksqlDB.RestApi.Client.Samples.ModelBuilders;

public class PaymentModelBuilder
{
public static async Task InitModelAndCreateStreamAsync(CancellationToken cancellationToken = default)
private readonly string ksqlDbUrl = "http://localhost:8088";

public async Task InitModelAndCreateStreamAsync(CancellationToken cancellationToken = default)
{
ModelBuilder builder = new();

Expand All @@ -22,16 +27,36 @@ public static async Task InitModelAndCreateStreamAsync(CancellationToken cancell

var httpClient = new HttpClient
{
BaseAddress = new Uri("http://localhost:8088")
BaseAddress = new Uri(ksqlDbUrl)
};
var httpClientFactory = new HttpClientFactory(httpClient);
var restApiProvider = new KSqlDbRestApiClient(httpClientFactory, builder);
IKSqlDbRestApiClient restApiProvider = new KSqlDbRestApiClient(httpClientFactory, builder);
restApiProvider = ConfigureRestApiClientWithServicesCollection(new ServiceCollection(), builder);

var entityCreationMetadata = new EntityCreationMetadata(kafkaTopic: nameof(Payment), partitions: 1);

var responseMessage = await restApiProvider.CreateTableAsync<Payment>(entityCreationMetadata, true, cancellationToken);
var content = await responseMessage.Content.ReadAsStringAsync(cancellationToken);
}

private IKSqlDbRestApiClient ConfigureRestApiClientWithServicesCollection(ServiceCollection serviceCollection, ModelBuilder builder)
{
serviceCollection
.AddDbContext<IKSqlDBContext, KSqlDBContext>(c =>
{
c.UseKSqlDb(ksqlDbUrl);
c.ReplaceHttpClient<ksqlDB.RestApi.Client.KSql.RestApi.Http.IHttpClientFactory, ksqlDB.RestApi.Client.KSql.RestApi.Http.HttpClientFactory>(_ => { })
.AddHttpMessageHandler(_ => new Program.DebugHandler());
})
.AddSingleton(builder);

var provider = serviceCollection.BuildServiceProvider();

var restApiClient = provider.GetRequiredService<IKSqlDbRestApiClient>();

return restApiClient;
}
}

record Payment
Expand Down
115 changes: 115 additions & 0 deletions docs/modelbuilder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Model builder

Using the **fluent API** with **POCO**s for generated classes that cannot be changed due to code regeneration offers a structured and maintainable approach to configuring your domain model, while keeping your codebase clean and flexible.

The `ModelBuilder` class provides functionalities to define mappings for entities.
The configurations made using the fluent API will override any attributes defined on the entity or its properties.
Use the `Entity<T>()` method of `ModelBuilder` to configure entities and define their properties.

```C#
using ksqlDb.RestApi.Client.FluentAPI.Builders;
using ksqlDB.RestApi.Client.KSql.RestApi;
using ksqlDB.RestApi.Client.KSql.RestApi.Http;

namespace ksqlDB.RestApi.Client.Samples.Model
{
public class PaymentModelBuilder
{
public static async Task InitModelAndCreateStreamAsync(CancellationToken cancellationToken = default)
{
ModelBuilder builder = new();

builder.Entity<Account>()
.HasKey(c => c.Id)
.Property(b => b.Balance);

builder.Entity<Payment>()
.HasKey(c => c.Id)
.Property(b => b.Amount)
.Decimal(precision: 10, scale: 2);

var httpClient = new HttpClient
{
BaseAddress = new Uri("http://localhost:8088")
};
var httpClientFactory = new HttpClientFactory(httpClient);
var restApiProvider = new KSqlDbRestApiClient(httpClientFactory, builder);

var entityCreationMetadata = new EntityCreationMetadata(kafkaTopic: nameof(Payment), partitions: 1);

var responseMessage = await restApiProvider.CreateTableAsync<Payment>(entityCreationMetadata, true, cancellationToken);
var content = await responseMessage.Content.ReadAsStringAsync(cancellationToken);
}
}
}
```

```C#
private record Payment
{
public string Id { get; set; } = null!;
public decimal Amount { get; set; }
public string Description { get; set; } = null!;
}

private record Account
{
public string Id { get; set; } = null!;
public decimal Balance { get; set; }
}
```

`builder`: An instance of `ModelBuilder` used to configure the model.

`Entity<T>`: A method that configures an entity of type T.

`HasKey(expression)`: A method used to specify the **primary key** for the entity. It takes a lambda expression that specifies the property that make up the primary key.

`Property(expression)`: A method used to specify a property of the entity. It takes a lambda expression that specifies the property.

`Decimal(precision, scale)`: A method used to specify **precision** and **scale** for a **decimal** property. Precision specifies the maximum number of digits, and scale specifies the number of digits to the right of the decimal point.

## IFromItemTypeConfiguration

To apply configurations using the provided `ModelBuilder`, follow these steps:

- Define Configuration Class: Create a class that implements the appropriate configuration interface. In this case, `PaymentConfiguration` implements `IFromItemTypeConfiguration<Payment>`.
This class contains configuration logic for the `Payment` entity.

- Configure Properties: Within the `Configure` method of your configuration class, use the provided `IEntityTypeBuilder` to configure the properties of the entity. For instance, the code snippet provided configures the `Amount` property of the `Payment` entity to have a precision of 14 digits and a scale of 14.

- Apply Configuration: Instantiate a `ModelBuilder` object. Then, use the `Apply` method to apply the configuration defined in the `PaymentConfiguration` class to the `ModelBuilder`.

Here's the code snippet demonstrating the application of configurations:

```C#
using ksqlDb.RestApi.Client.FluentAPI.Builders.Configuration;

public class PaymentConfiguration : IFromItemTypeConfiguration<Payment>
{
public void Configure(IEntityTypeBuilder<Payment> builder)
{
builder.Property(b => b.Amount)
.Decimal(precision: 14, scale: 14);
}
}
```

```C#
using ksqlDb.RestApi.Client.FluentAPI.Builders;

ModelBuilder builder = new();
builder.Apply(new PaymentConfiguration());
```

## ModelBuilder conventions
You can add a global convention to the model builder for the **decimal** type in the following way.

```C#
using ksqlDb.RestApi.Client.FluentAPI.Builders;
using ksqlDb.RestApi.Client.FluentAPI.Builders.Configuration;

var modelBuilder = new ModelBuilder();
var decimalTypeConvention = new DecimalTypeConvention(14, 14);
modelBuilder.AddConvention(decimalTypeConvention);
```
2 changes: 1 addition & 1 deletion ksqlDb.RestApi.Client.sln
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{0ABA2B0A-0
docs\functions.md = docs\functions.md
docs\joins.md = docs\joins.md
docs\ksqldbcontext.md = docs\ksqldbcontext.md
modelbuilder.md = modelbuilder.md
docs\modelbuilder.md = docs\modelbuilder.md
docs\operators.md = docs\operators.md
docs\protobuf.md = docs\protobuf.md
docs\pull_queries.md = docs\pull_queries.md
Expand Down
2 changes: 1 addition & 1 deletion ksqlDb.RestApi.Client/ksqlDb.RestApi.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
Documentation for the library can be found at https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/README.md.
</Description>
<PackageTags>ksql ksqlDB LINQ .NET csharp push query</PackageTags>
<Version>5.0.0-rc.1</Version>
<Version>5.0.0-rc.2</Version>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<LangVersion>12.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down

0 comments on commit 35eef5a

Please sign in to comment.