Skip to content

Commit de77455

Browse files
committed
[ksqlDb.RestApi.Client]: added KSqlDBRestApiClientOptions ctor argument for KSqlDbRestApiClient
1 parent 3e9c753 commit de77455

File tree

9 files changed

+121
-12
lines changed

9 files changed

+121
-12
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace ksqlDB.RestApi.Client.KSql.Query.Context
2+
{
3+
/// <summary>
4+
/// Options class for ksqlDB REST API client configuration.
5+
/// </summary>
6+
public sealed class KSqlDBRestApiClientOptions
7+
{
8+
/// <summary>
9+
/// Gets or sets a value indicating whether table or stream name should be pluralized from the item name (by default: true).
10+
/// </summary>
11+
public bool ShouldPluralizeFromItemName { get; set; } = true;
12+
}
13+
}

ksqlDb.RestApi.Client/KSql/RestApi/Generators/StatementGenerator.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ public string CreateOrReplaceTable<T>(EntityCreationMetadata creationMetadata)
105105
/// <returns>A string representing a KSQL statement for creating or replacing a stream or table.</returns>
106106
private string CreateOrReplace<T>(StatementContext statementContext, EntityCreationMetadata creationMetadata, bool? ifNotExists)
107107
{
108+
if (creationMetadata.ShouldPluralizeEntityName == null)
109+
creationMetadata = creationMetadata with { ShouldPluralizeEntityName = true };
110+
108111
string ksql = new CreateEntity(modelBuilder).Print<T>(statementContext, creationMetadata, ifNotExists);
109112

110113
return ksql;

ksqlDb.RestApi.Client/KSql/RestApi/IKSqlDbRestApiClient.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
namespace ksqlDB.RestApi.Client.KSql.RestApi;
1212

13+
/// <summary>
14+
/// Represents a client for interacting with the KSQL REST API.
15+
/// </summary>
1316
public interface IKSqlDbRestApiClient : IKSqlDbCreateRestApiClient, IKSqlDbAssertionsRestApiClient, IKSqlDbDropRestApiClient
1417
{
1518
/// <summary>

ksqlDb.RestApi.Client/KSql/RestApi/KSqlDbRestApiClient.cs

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,69 @@
2222
using Microsoft.Extensions.Logging;
2323
using IHttpClientFactory = ksqlDB.RestApi.Client.KSql.RestApi.Http.IHttpClientFactory;
2424
using ksqlDb.RestApi.Client.KSql.RestApi.Statements.Providers;
25+
using ksqlDB.RestApi.Client.KSql.Query.Context;
2526

2627
namespace ksqlDB.RestApi.Client.KSql.RestApi;
2728

29+
/// <summary>
30+
/// Represents a client for interacting with the KSQL REST API.
31+
/// </summary>
2832
public class KSqlDbRestApiClient : IKSqlDbRestApiClient
2933
{
3034
private readonly EntityProvider entityProvider = new();
3135
private readonly IHttpClientFactory httpClientFactory;
3236
private readonly ModelBuilder modelBuilder;
37+
private readonly KSqlDBRestApiClientOptions clientOptions;
3338
private readonly StatementGenerator statementGenerator;
3439
private readonly ILogger? logger;
3540

41+
/// <summary>
42+
/// Initializes a new instance of the <see cref="KSqlDbRestApiClient"/> class.
43+
/// </summary>
44+
/// <param name="httpClientFactory">The factory to create <see cref="HttpClient"/> instances.</param>
45+
/// <param name="loggerFactory">The factory to create <see cref="ILogger"/> instances. This parameter is optional.</param>
46+
/// <exception cref="ArgumentNullException">Thrown when <paramref name="httpClientFactory"/> is null.</exception>
3647
public KSqlDbRestApiClient(IHttpClientFactory httpClientFactory, ILoggerFactory? loggerFactory = null)
3748
: this(httpClientFactory, new ModelBuilder(), loggerFactory)
3849
{
3950
}
4051

52+
/// <summary>
53+
/// Initializes a new instance of the <see cref="KSqlDbRestApiClient"/> class.
54+
/// </summary>
55+
/// <param name="httpClientFactory">The factory to create <see cref="HttpClient"/> instances.</param>
56+
/// <param name="loggerFactory">The factory to create <see cref="ILogger"/> instances. This parameter is optional.</param>
57+
/// <param name="clientOptions">The options for configuring the KSqlDB REST API client.</param>
58+
/// <exception cref="ArgumentNullException">Thrown when <paramref name="httpClientFactory"/> is null.</exception>
59+
public KSqlDbRestApiClient(IHttpClientFactory httpClientFactory, KSqlDBRestApiClientOptions clientOptions, ILoggerFactory? loggerFactory = null)
60+
: this(httpClientFactory, new ModelBuilder(), clientOptions, loggerFactory)
61+
{
62+
}
63+
64+
/// <summary>
65+
/// Initializes a new instance of the <see cref="KSqlDbRestApiClient"/> class.
66+
/// </summary>
67+
/// <param name="httpClientFactory">The factory to create <see cref="HttpClient"/> instances.</param>
68+
/// <param name="modelBuilder">The model builder used to construct the models.</param>
69+
/// <param name="loggerFactory">The factory to create <see cref="ILogger"/> instances. This parameter is optional.</param>
4170
public KSqlDbRestApiClient(IHttpClientFactory httpClientFactory, ModelBuilder modelBuilder, ILoggerFactory? loggerFactory = null)
71+
: this(httpClientFactory, modelBuilder, new KSqlDBRestApiClientOptions(), loggerFactory)
72+
{
73+
}
74+
75+
/// <summary>
76+
/// Initializes a new instance of the <see cref="KSqlDbRestApiClient"/> class.
77+
/// </summary>
78+
/// <param name="httpClientFactory">The factory to create <see cref="HttpClient"/> instances.</param>
79+
/// <param name="modelBuilder">The model builder used to construct the models.</param>
80+
/// <param name="loggerFactory">The factory to create <see cref="ILogger"/> instances. This parameter is optional.</param>
81+
/// <param name="clientOptions">The options for configuring the KSqlDB REST API client.</param>
82+
/// <exception cref="ArgumentNullException">Thrown when <paramref name="httpClientFactory"/> is null.</exception>
83+
public KSqlDbRestApiClient(IHttpClientFactory httpClientFactory, ModelBuilder modelBuilder, KSqlDBRestApiClientOptions clientOptions, ILoggerFactory? loggerFactory = null)
4284
{
4385
this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
4486
this.modelBuilder = modelBuilder;
87+
this.clientOptions = clientOptions;
4588

4689
if (loggerFactory != null)
4790
logger = loggerFactory.CreateLogger(LoggingCategory.Name);
@@ -191,6 +234,9 @@ public Task<HttpResponseMessage> CreateStreamAsync<T>(EntityCreationMetadata cre
191234
ArgumentNullException.ThrowIfNull(creationMetadata);
192235
#endif
193236

237+
if (creationMetadata.ShouldPluralizeEntityName == null)
238+
creationMetadata = creationMetadata with {ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName};
239+
194240
var ksql = statementGenerator.CreateStream<T>(creationMetadata, ifNotExists);
195241

196242
return ExecuteAsync(ksql, cancellationToken);
@@ -211,6 +257,9 @@ public Task<HttpResponseMessage> CreateOrReplaceStreamAsync<T>(EntityCreationMet
211257
ArgumentNullException.ThrowIfNull(creationMetadata);
212258
#endif
213259

260+
if (creationMetadata.ShouldPluralizeEntityName == null)
261+
creationMetadata = creationMetadata with { ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName };
262+
214263
var ksql = statementGenerator.CreateOrReplaceStream<T>(creationMetadata);
215264

216265
return ExecuteAsync(ksql, cancellationToken);
@@ -232,7 +281,12 @@ public Task<HttpResponseMessage> CreateSourceStreamAsync<T>(EntityCreationMetada
232281
ArgumentNullException.ThrowIfNull(creationMetadata);
233282
#endif
234283

235-
creationMetadata.IsReadOnly = true;
284+
if (creationMetadata.ShouldPluralizeEntityName == null)
285+
creationMetadata = creationMetadata with
286+
{
287+
ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName,
288+
IsReadOnly = true
289+
};
236290

237291
var ksql = statementGenerator.CreateStream<T>(creationMetadata, ifNotExists);
238292

@@ -255,6 +309,9 @@ public Task<HttpResponseMessage> CreateTableAsync<T>(EntityCreationMetadata crea
255309
ArgumentNullException.ThrowIfNull(creationMetadata);
256310
#endif
257311

312+
if (creationMetadata.ShouldPluralizeEntityName == null)
313+
creationMetadata = creationMetadata with { ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName };
314+
258315
var ksql = statementGenerator.CreateTable<T>(creationMetadata, ifNotExists);
259316

260317
return ExecuteAsync(ksql, cancellationToken);
@@ -276,7 +333,12 @@ public Task<HttpResponseMessage> CreateSourceTableAsync<T>(EntityCreationMetadat
276333
ArgumentNullException.ThrowIfNull(creationMetadata);
277334
#endif
278335

279-
creationMetadata.IsReadOnly = true;
336+
if (creationMetadata.ShouldPluralizeEntityName == null)
337+
creationMetadata = creationMetadata with
338+
{
339+
ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName,
340+
IsReadOnly = true
341+
};
280342

281343
var ksql = statementGenerator.CreateTable<T>(creationMetadata, ifNotExists);
282344

@@ -298,6 +360,9 @@ public Task<HttpResponseMessage> CreateOrReplaceTableAsync<T>(EntityCreationMeta
298360
ArgumentNullException.ThrowIfNull(creationMetadata);
299361
#endif
300362

363+
if (creationMetadata.ShouldPluralizeEntityName == null)
364+
creationMetadata = creationMetadata with { ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName };
365+
301366
var ksql = statementGenerator.CreateOrReplaceTable<T>(creationMetadata);
302367

303368
return ExecuteAsync(ksql, cancellationToken);
@@ -321,6 +386,7 @@ private Task<HttpResponseMessage> ExecuteAsync(string ksql, CancellationToken ca
321386
public Task<HttpResponseMessage> CreateTypeAsync<T>(CancellationToken cancellationToken = default)
322387
{
323388
var properties = new TypeProperties();
389+
324390
return CreateTypeAsync<T>(properties, cancellationToken);
325391
}
326392

@@ -335,7 +401,11 @@ public Task<HttpResponseMessage> CreateTypeAsync<T>(CancellationToken cancellati
335401
/// <returns>Http response object.</returns>
336402
public Task<HttpResponseMessage> CreateTypeAsync<T>(string typeName, CancellationToken cancellationToken = default)
337403
{
338-
var properties = new TypeProperties { EntityName = typeName };
404+
var properties = new TypeProperties
405+
{
406+
EntityName = typeName
407+
};
408+
339409
return CreateTypeAsync<T>(properties, cancellationToken);
340410
}
341411

@@ -350,6 +420,9 @@ public Task<HttpResponseMessage> CreateTypeAsync<T>(string typeName, Cancellatio
350420
/// <returns>Http response object.</returns>
351421
public Task<HttpResponseMessage> CreateTypeAsync<T>(TypeProperties properties, CancellationToken cancellationToken = default)
352422
{
423+
if (properties.ShouldPluralizeEntityName == null)
424+
properties = properties with { ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName };
425+
353426
var ksql = new TypeGenerator(modelBuilder).Print<T>(properties);
354427

355428
return ExecuteAsync(ksql, cancellationToken);
@@ -363,6 +436,9 @@ public Task<HttpResponseMessage> CreateTypeAsync<T>(TypeProperties properties, C
363436
/// <returns>Http response object.</returns>
364437
public Task<HttpResponseMessage> DropTypeAsync<T>(DropTypeProperties dropTypeProperties, CancellationToken cancellationToken = default)
365438
{
439+
if (dropTypeProperties.ShouldPluralizeEntityName == null)
440+
dropTypeProperties = dropTypeProperties with { ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName };
441+
366442
var typeName = entityProvider.GetFormattedName<T>(dropTypeProperties);
367443
string dropStatement = StatementTemplates.DropType(typeName);
368444

@@ -413,6 +489,10 @@ public Task<HttpResponseMessage> DropTypeIfExistsAsync(string typeName, Cancella
413489
/// <returns>Http response object.</returns>
414490
public Task<HttpResponseMessage> InsertIntoAsync<T>(T entity, InsertProperties? insertProperties = null, CancellationToken cancellationToken = default)
415491
{
492+
insertProperties ??= new InsertProperties();
493+
if (insertProperties.ShouldPluralizeEntityName == null)
494+
insertProperties = insertProperties with { ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName };
495+
416496
var insertStatement = ToInsertStatement(entity, insertProperties);
417497

418498
var httpResponseMessage = ExecuteStatementAsync(insertStatement, cancellationToken);
@@ -429,6 +509,10 @@ public Task<HttpResponseMessage> InsertIntoAsync<T>(T entity, InsertProperties?
429509
/// <returns>A <see cref="KSqlDbStatement"/></returns>
430510
public KSqlDbStatement ToInsertStatement<T>(InsertValues<T> insertValues, InsertProperties? insertProperties = null)
431511
{
512+
insertProperties ??= new InsertProperties();
513+
if (insertProperties.ShouldPluralizeEntityName == null)
514+
insertProperties = insertProperties with { ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName };
515+
432516
var insertStatement = new CreateInsert(modelBuilder).Generate(insertValues, insertProperties);
433517

434518
return new KSqlDbStatement(insertStatement);
@@ -443,6 +527,10 @@ public KSqlDbStatement ToInsertStatement<T>(InsertValues<T> insertValues, Insert
443527
/// <returns>A <see cref="KSqlDbStatement"/></returns>
444528
public KSqlDbStatement ToInsertStatement<T>(T entity, InsertProperties? insertProperties = null)
445529
{
530+
insertProperties ??= new InsertProperties();
531+
if (insertProperties.ShouldPluralizeEntityName == null)
532+
insertProperties = insertProperties with { ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName };
533+
446534
var insertStatement = new CreateInsert(modelBuilder).Generate(entity, insertProperties);
447535

448536
return new KSqlDbStatement(insertStatement);
@@ -746,6 +834,9 @@ public Task<HttpResponseMessage> DropStreamAsync(string streamName, Cancellation
746834
/// <returns></returns>
747835
public Task<HttpResponseMessage> DropTableAsync<T>(DropFromItemProperties dropFromItemProperties, CancellationToken cancellationToken = default)
748836
{
837+
if (dropFromItemProperties.ShouldPluralizeEntityName == null)
838+
dropFromItemProperties = dropFromItemProperties with { ShouldPluralizeEntityName = clientOptions.ShouldPluralizeFromItemName };
839+
749840
var tableName = entityProvider.GetFormattedName<T>(dropFromItemProperties);
750841
string dropStatement = StatementTemplates.DropTable(tableName, dropFromItemProperties.UseIfExistsClause, dropFromItemProperties.DeleteTopic);
751842

ksqlDb.RestApi.Client/KSql/RestApi/Statements/CreateEntity.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ internal string Print<T>(StatementContext statementContext, EntityCreationMetada
4242
private void PrintProperties<T>(StatementContext statementContext, EntityCreationMetadata metadata)
4343
{
4444
var ksqlProperties = new List<string>();
45-
metadata ??= new EntityCreationMetadata();
45+
4646
foreach (var memberInfo in Members<T>(metadata.IncludeReadOnlyProperties))
4747
{
4848
var type = GetMemberType(memberInfo);

ksqlDb.RestApi.Client/KSql/RestApi/Statements/CreateInsert.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,15 @@ public CreateInsert(ModelBuilder modelBuilder)
1818
this.modelBuilder = modelBuilder;
1919
}
2020

21-
internal string Generate<T>(T entity, InsertProperties? insertProperties = null)
21+
internal string Generate<T>(T entity, InsertProperties insertProperties)
2222
{
2323
return Generate(new InsertValues<T>(entity), insertProperties);
2424
}
2525

26-
internal string Generate<T>(InsertValues<T> insertValues, InsertProperties? insertProperties = null)
26+
internal string Generate<T>(InsertValues<T> insertValues, InsertProperties insertProperties)
2727
{
28-
if (insertValues == null) throw new ArgumentNullException(nameof(insertValues));
29-
30-
insertProperties ??= new InsertProperties();
28+
if (insertProperties.ShouldPluralizeEntityName == null)
29+
insertProperties = insertProperties with { ShouldPluralizeEntityName = true };
3130

3231
var entityName = EntityProvider.GetFormattedName<T>(insertProperties);
3332

ksqlDb.RestApi.Client/KSql/RestApi/Statements/EntityCreationMetadata.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ internal EntityCreationMetadata()
3939
/// <summary>
4040
/// By setting the value of this field to "true" the entity name will be automatically pluralized during code generation.
4141
/// </summary>
42-
public bool ShouldPluralizeEntityName { get; set; } = true;
42+
public bool? ShouldPluralizeEntityName { get; set; }
4343

4444
/// <summary>
4545
/// By default, the topic is assumed to contain non-windowed data. If the data is windowed, i.e., was created using ksqlDB using a query that contains a WINDOW clause, then the WINDOW_TYPE property can be used to provide the window type. Valid values are SESSION, HOPPING, and TUMBLING.

ksqlDb.RestApi.Client/KSql/RestApi/Statements/Properties/EntityProperties.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public record EntityProperties : IEntityProperties
1515
/// <summary>
1616
/// Gets or sets a value indicating whether the entity name should be pluralized.
1717
/// </summary>
18-
public bool ShouldPluralizeEntityName { get; init; } = true;
18+
public bool? ShouldPluralizeEntityName { get; init; }
1919

2020
/// <summary>
2121
/// Gets or sets the identifier escaping type.

ksqlDb.RestApi.Client/KSql/RestApi/Statements/Properties/IEntityProperties.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public interface IEntityProperties
1212
/// <summary>
1313
/// Gets a value indicating whether the entity name should be pluralized.
1414
/// </summary>
15-
public bool ShouldPluralizeEntityName { get; }
15+
public bool? ShouldPluralizeEntityName { get; }
1616

1717
/// <summary>
1818
/// Gets the identifier escaping type.

0 commit comments

Comments
 (0)