{"id":13686253,"url":"https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet","last_synced_at":"2025-05-01T09:30:47.481Z","repository":{"id":37248920,"uuid":"340161714","full_name":"tomasfabian/ksqlDB.RestApi.Client-DotNet","owner":"tomasfabian","description":"ksqlDb.RestApi.Client is a C# LINQ-enabled client API for issuing and consuming ksqlDB push and pull queries and executing statements.","archived":false,"fork":false,"pushed_at":"2025-04-28T05:39:29.000Z","size":11728,"stargazers_count":99,"open_issues_count":2,"forks_count":25,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-28T06:31:26.158Z","etag":null,"topics":["csharp","dotnet","kafka","ksql","ksqldb","linq","reactive-streams"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tomasfabian.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-02-18T19:54:22.000Z","updated_at":"2025-04-28T05:39:33.000Z","dependencies_parsed_at":"2023-10-25T16:53:45.922Z","dependency_job_id":"97fb3ff0-c9ba-4ee9-89d5-87fb1d5c920c","html_url":"https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet","commit_stats":null,"previous_names":["tomasfabian/kafka.dotnet.ksqldb"],"tags_count":67,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomasfabian%2FksqlDB.RestApi.Client-DotNet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomasfabian%2FksqlDB.RestApi.Client-DotNet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomasfabian%2FksqlDB.RestApi.Client-DotNet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomasfabian%2FksqlDB.RestApi.Client-DotNet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tomasfabian","download_url":"https://codeload.github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251852623,"owners_count":21654439,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","dotnet","kafka","ksql","ksqldb","linq","reactive-streams"],"created_at":"2024-08-02T15:00:25.896Z","updated_at":"2025-05-01T09:30:47.468Z","avatar_url":"https://github.com/tomasfabian.png","language":"C#","funding_links":[],"categories":["Libraries"],"sub_categories":[],"readme":"This package enables seamless integration of **KSQL** push and pull queries with LINQ queries in your .NET C# applications.\nIt allows you to perform server-side operations such as filtering, projection, limiting, and more directly on push notifications using [ksqlDB push queries](https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-rest-api/streaming-endpoint/).\nThis facilitates continuous processing of computations over unbounded, potentially never-ending, streams of data.\n\nIn addition, the package supports executing SQL [statements](https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-reference/) via the REST API. You can use it to insert records into streams, create tables and types, and perform administrative tasks such as listing available streams.\n\n[ksqlDB.RestApi.Client](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet) is a contribution to [Confluent ksqldb-clients](https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-clients/)\n\n[![main](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/actions/workflows/dotnet.yml/badge.svg?branch=main\u0026event=push)](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/actions/workflows/dotnet.yml/)\n\nInstall with **NuGet** package manager:\n```\nInstall-Package ksqlDb.RestApi.Client\n```\nor with .NET CLI\n```\ndotnet add package ksqlDb.RestApi.Client\n```\nThis adds a `\u003cPackageReference\u003e` to your csproj file, similar to the following:\n```XML\n\u003cPackageReference Include=\"ksqlDb.RestApi.Client\" Version=\"7.0.0\" /\u003e\n```\n\nAlternative option is to use [Protobuf content type](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/protobuf.md):\n```\ndotnet add package ksqlDb.RestApi.Client.ProtoBuf\n```\n\nFeel free to experiment with the following example in a [.NET interactive Notebook](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/tree/main/Samples/Notebooks):\n\n```C#\nusing ksqlDB.RestApi.Client.KSql.Linq;\nusing ksqlDB.RestApi.Client.KSql.Query;\nusing ksqlDB.RestApi.Client.KSql.Query.Context;\nusing ksqlDB.RestApi.Client.KSql.Query.Options;\n\nvar ksqlDbUrl = @\"http://localhost:8088\";\n\nvar contextOptions = new KSqlDBContextOptions(ksqlDbUrl)\n{\n  ShouldPluralizeFromItemName = true\n};\n\nawait using var context = new KSqlDBContext(contextOptions);\n\nusing var subscription = context.CreatePushQuery\u003cTweet\u003e()\n  .WithOffsetResetPolicy(AutoOffsetReset.Latest)\n  .Where(p =\u003e p.Message != \"Hello world\" || p.Id == 1)\n  .Select(l =\u003e new { l.Message, l.Id })\n  .Take(2)\n  .Subscribe(tweetMessage =\u003e\n  {\n    Console.WriteLine($\"{nameof(Tweet)}: {tweetMessage.Id} - {tweetMessage.Message}\");\n  }, error =\u003e { Console.WriteLine($\"Exception: {error.Message}\"); }, () =\u003e Console.WriteLine(\"Completed\"));\n\nConsole.WriteLine(\"Press any key to stop the subscription\");\n\nConsole.ReadKey();\n```\n\n```C#\npublic class Tweet : Record\n{\n  public int Id { get; set; }\n\n  public string Message { get; set; }\n}\n```\n\nAn entity class in **ksqlDB.RestApi.Client** represents the structure of a table or stream.\nAn instance of the class represents a record in that stream or table while properties are mapped to columns respectively.\n\nLINQ code written in C# from the sample is equivalent to this KSQL query:\n```SQL\nSELECT Message, Id\n  FROM Tweets\n WHERE Message != 'Hello world' OR Id = 1\n  EMIT CHANGES\n LIMIT 2;\n```\n\nIn the provided C# code snippet, most of the code executes on the server side except for the `IQbservable\u003cTEntity\u003e.Subscribe` extension method. This method is responsible for subscribing to your `ksqlDB` stream, which is created using the following approach:\n\n```C#\nusing ksqlDB.RestApi.Client.KSql.RestApi.Http;\nusing ksqlDB.RestApi.Client.KSql.RestApi.Statements;\nusing ksqlDB.RestApi.Client.KSql.RestApi;\nusing ksqlDB.Api.Client.Samples.Models;\n\nEntityCreationMetadata metadata = new(kafkaTopic: nameof(Tweet))\n{\n  Partitions = 3,\n  Replicas = 3\n};\n\nvar httpClient = new HttpClient()\n{\n  BaseAddress = new Uri(@\"http://localhost:8088\")\n};\n\nvar httpClientFactory = new HttpClientFactory(httpClient);\nvar restApiClient = new KSqlDbRestApiClient(httpClientFactory);\n\nvar httpResponseMessage = await restApiClient.CreateOrReplaceStreamAsync\u003cTweet\u003e(metadata);\n```\n\n`CreateOrReplaceStreamAsync` executes the following statement:\n```SQL\nCREATE OR REPLACE STREAM Tweets (\n  Id INT,\n  Message VARCHAR\n) WITH ( KAFKA_TOPIC='Tweet', VALUE_FORMAT='Json', PARTITIONS='3', REPLICAS='3' );\n```\n\nExecute the following insert statements to **publish messages** using your `ksqldb-cli`\n```\ndocker exec -it $(docker ps -q -f name=ksqldb-cli) ksql http://ksqldb-server:8088\n```\n```SQL\nINSERT INTO tweets (id, message) VALUES (1, 'Hello world');\nINSERT INTO tweets (id, message) VALUES (2, 'ksqlDB rulez!');\n```\n\nor insert a record from C#:\n```C#\nvar responseMessage = await new KSqlDbRestApiClient(httpClientFactory)\n  .InsertIntoAsync(new Tweet { Id = 2, Message = \"ksqlDB rulez!\" });\n```\n\nor with KSqlDbContext:\n\n```C#\nawait using var context = new KSqlDBContext(ksqlDbUrl);\n\ncontext.Add(new Tweet { Id = 1, Message = \"Hello world\" });\ncontext.Add(new Tweet { Id = 2, Message = \"ksqlDB rulez!\" });\n\nvar saveChangesResponse = await context.SaveChangesAsync();\n```\n\nSample projects can be found under [Samples](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/tree/main/Samples/ksqlDB.RestApi.Client.Sample) solution folder in ksqlDB.RestApi.Client.sln\n\n\n**External dependencies:**\n- [kafka broker](https://kafka.apache.org/intro) and [ksqlDB-server](https://ksqldb.io/overview.html) 0.14.0\n- the solution requires [Docker desktop](https://www.docker.com/products/docker-desktop) and Visual Studio 2019\n- [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)\n\nClone the repository\n```\ngit clone https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet.git\n```\n\nCD to [Samples](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/tree/main/Samples/ksqlDB.RestApi.Client.Sample)\n```\nCD Samples\\ksqlDB.RestApi.Client.Sample\\\n```\n\nrun in command line:\n\n```docker compose up -d```\n\n**AspNet Blazor server side sample:**\n\nIn [Blazor](https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor), the application logic and UI rendering occur on the server. The client's web browser receives updates and UI changes through a **SignalR** connection.\nThis ensures smooth integration with the `ksqlDB.RestApi.Client` library, allowing the **Apache Kafka broker** and **ksqlDB** to remain hidden from direct exposure to clients.\nThe **server-side Blazor** application communicates with `ksqlDB` using the `ksqlDB.RestApi.Client`.\nWhenever an event in `ksqlDB` occurs, the server-side Blazor app responds and signals the UI in the client's browser to update. This setup allows a smooth and continuous update flow, creating a real-time, reactive user interface.\n\n- set `docker-compose.csproj` as startup project in [InsideOut.sln](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/tree/main/Samples/InsideOut) for embedded Kafka connect integration and stream processing examples.\n\n# ```IQbservable\u003cT\u003e``` extension methods\nAs depicted below `IObservable\u003cT\u003e` is the dual of `IEnumerable\u003cT\u003e` and `IQbservable\u003cT\u003e` is the dual of `IQueryable\u003cT\u003e`. In all four cases LINQ providers are using deferred execution.\nWhile the first two are executed locally the latter two are executed server side. The server side execution is possible thanks to traversing **AST**s (Abstract Syntax Trees) with visitors. The `KSqlDbProvider` will create the **KSQL syntax** for you from **expression trees** and pass it along to ksqlDB.\n\nBoth `IObservable\u003cT\u003e` and `IQbservable\u003cT\u003e` represent **push-based** sequences of asynchronous and potentially infinite events, while `IEnumerable\u003cT\u003e` and `IQueryable\u003cT\u003e` represent collections or **pull-based** sequences of items that can be iterated or queried, respectively.\n\n\u003cimg src=\"https://www.codeproject.com/KB/cs/646361/WhatHowWhere.jpg\" /\u003e\n\nList of supported [push query](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md) extension methods:\n- [Select](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#select)\n- [Where](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#where)\n- [Take (LIMIT)](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#take-limit)\n- [Subscribe](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#subscribe)\n- [ToObservable](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#toobservable)\n- [ToAsyncEnumerable](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#toasyncenumerable)\n- [ToQueryString](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#getting-the-generated-ksql)\n- [ExplainAsync](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#explainasync)\n- [SubscribeAsync](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#subscribeasync)\n- [SubscribeOn](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#subscribeon)\n- [ObserveOn](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#observeon)\n- [ToStatementString](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#tostatementstring)\n- [WithOffsetResetPolicy](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#withoffsetresetpolicy---push-queries-extension-method)\n- [Window bounds](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#window-bounds)\n- [Raw string KSQL query execution](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#raw-string-ksql-query-execution)\n\n- [IKSqlGrouping.Source](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/push_queries.md#iksqlgroupingsource)\n\n# Register the KSqlDbContext\n`IKSqlDBContext` and `IKSqlDbRestApiClient` can be provided with **dependency injection**. These services can be registered during app startup and components that require these services, are provided with these services via constructor parameters.\n\nTo register `KSqlDbContext` as a service, open `Program.cs`, and add the lines to the `ConfigureServices` method shown below or see some more details in [the workshop](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/wiki/ksqlDB.RestApi.Client-workshop):\n\n```\nusing ksqlDB.RestApi.Client.Sensors;\nusing ksqlDB.RestApi.Client.KSql.Query.Options;\nusing ksqlDb.RestApi.Client.DependencyInjection;\nusing ksqlDB.RestApi.Client.Sensors.KSqlDb;\n\nIHost host = Host.CreateDefaultBuilder(args)\n    .ConfigureServices(services =\u003e\n    {\n      var ksqlDbUrl = @\"http://localhost:8088\";\n\n      services.AddDbContext\u003cISensorsKSqlDbContext, SensorsKSqlDbContext\u003e(\n        options =\u003e\n        {\n          var setupParameters = options.UseKSqlDb(ksqlDbUrl);\n\n          setupParameters.Options.ShouldPluralizeFromItemName = false;\n          setupParameters.SetAutoOffsetReset(AutoOffsetReset.Earliest);\n\n        }, ServiceLifetime.Transient, restApiLifetime: ServiceLifetime.Transient);\n    })\n    .Build();\n\nawait host.RunAsync();\n```\n\n# KSqlDbContextOptions builder\nTo modify parameters or introduce new ones, utilize the following approach:\n\n```C#\nvar contextOptions = new KSqlDbContextOptionsBuilder()\n  .UseKSqlDb(\"http://localhost:8088)\n  .SetBasicAuthCredentials(\"fred\", \"flinstone\")\n  .SetJsonSerializerOptions(jsonOptions =\u003e\n  {\n    jsonOptions.IgnoreReadOnlyFields = true;\n  })\n  .SetAutoOffsetReset(AutoOffsetReset.Latest)\n  .SetProcessingGuarantee(ProcessingGuarantee.ExactlyOnce)\n  .SetIdentifierEscaping(IdentifierEscaping.Keywords)\n  .SetupPushQuery(options =\u003e\n  {\n    options.Properties[\"ksql.query.push.v2.enabled\"] = \"true\";\n  })\n  .Options;\n```\n\nThis code initializes a `KSqlDbContextOptionsBuilder` to configure settings for a `ksqlDB` context. Here's a breakdown of the configurations:\n\n- `UseKSqlDb(\"http://localhost:8088\")`: Specifies the **URL** of the `ksqlDB` server.\n- `SetBasicAuthCredentials(\"fred\", \"flinstone\")`: Sets the basic authentication credentials (username and password) for accessing the `ksqlDB` server.\n- `SetJsonSerializerOptions(jsonOptions =\u003e { ... })`: Configures JSON serialization options, such as ignoring read-only fields.\n- `SetAutoOffsetReset(AutoOffsetReset.Latest)`: Sets the offset reset behavior to start consuming messages from the **latest** available when no committed offset is found. By default, 'auto.offset.reset' is configured to 'earliest'.\n- `SetProcessingGuarantee(ProcessingGuarantee.ExactlyOnce)`: Specifies the processing guarantee as **exactly-once** semantics.\n- `SetIdentifierEscaping(IdentifierEscaping.Keywords)`: Escapes identifiers such as table and column names that are SQL keywords.\n- `SetupPushQuery(options =\u003e { ... })`: Configures push query options, specifically enabling KSQL query push version 2.\n\nFinally, `.Options` returns the configured options for the `ksqlDB` context.\n\n### Overriding stream names\nStream names are generated based on the generic record types. They are pluralized with Pluralize.NET package.\n\n**By default the generated from item names such as stream and table names are pluralized**. This behavior could be switched off with the following `ShouldPluralizeStreamName` configuration.\n\n```C#\ncontext.CreatePushQuery\u003cPerson\u003e();\n```\n```SQL\nFROM People\n```\nThis can be disabled:\n```C#\nvar contextOptions = new KSqlDBContextOptions(@\"http://localhost:8088\")\n{\n  ShouldPluralizeFromItemName = false\n};\n\nnew KSqlDBContext(contextOptions).CreatePushQuery\u003cPerson\u003e();\n```\n```SQL\nFROM Person\n```\n\nSetting an arbitrary stream name (from_item name):\n```C#\ncontext.CreatePushQuery\u003cTweet\u003e(\"custom_topic_name\");\n```\n```SQL\nFROM custom_topic_name\n```\n\n# KSqlDbRestApiClient\nThe `KSqlDbRestApiClient` supports various operations such as executing KSQL statements, inserting data into streams asynchronously, creating, listing or dropping entities, and managing KSQL connectors.\n\n```C#\nusing ksqlDB.RestApi.Client.KSql.RestApi;\nusing ksqlDB.RestApi.Client.KSql.RestApi.Enums;\nusing ksqlDB.RestApi.Client.KSql.RestApi.Extensions;\nusing ksqlDB.RestApi.Client.KSql.RestApi.Http;\nusing ksqlDB.RestApi.Client.KSql.RestApi.Serialization;\nusing ksqlDB.RestApi.Client.KSql.RestApi.Statements;\nusing ksqlDB.RestApi.Client.KSql.RestApi.Statements.Properties;\nusing ksqlDB.RestApi.Client.Samples.Models.Movies;\n\npublic static async Task ExecuteAsync(CancellationToken cancellationToken = default)\n{\n  var httpClient = new HttpClient()\n  {\n    BaseAddress = new Uri(\"http://localhost:8088\")\n  };\n  var httpClientFactory = new HttpClientFactory(httpClient);\n  var kSqlDbRestApiClient = new KSqlDbRestApiClient(httpClientFactory);\n\n  EntityCreationMetadata entityCreationMetadata = new(kafkaTopic: \"companyname.movies\")\n  {\n    Partitions = 3,\n    Replicas = 3,\n    ValueFormat = SerializationFormats.Json,\n    IdentifierEscaping = IdentifierEscaping.Keywords\n  };\n\n  var httpResponseMessage = await kSqlDbRestApiClient.CreateOrReplaceTableAsync\u003cMovie\u003e(entityCreationMetadata, cancellationToken);\n  var responses = await httpResponseMessage.ToStatementResponsesAsync();\n  Console.WriteLine($\"Create or replace table response: {responses[0].CommandStatus!.Message}\");\n\n  Console.WriteLine($\"{Environment.NewLine}Available tables:\");\n  var tablesResponses = await kSqlDbRestApiClient.GetTablesAsync(cancellationToken);\n  Console.WriteLine(string.Join(', ', tablesResponses[0].Tables!.Select(c =\u003e c.Name)));\n\n  var dropProperties = new DropFromItemProperties\n  {\n    UseIfExistsClause = true,\n    DeleteTopic = true,\n    IdentifierEscaping = IdentifierEscaping.Keywords\n  };\n  httpResponseMessage = await kSqlDbRestApiClient.DropTableAsync\u003cMovie\u003e(dropProperties, cancellationToken: cancellationToken);\n  tablesResponses = await kSqlDbRestApiClient.GetTablesAsync(cancellationToken);\n}\n```\n\n```C#\nusing ksqlDB.RestApi.Client.KSql.Query;\nusing ksqlDB.RestApi.Client.KSql.RestApi.Statements.Annotations;\n\npublic class Movie : Record\n{\n  [Key]\n  public int Id { get; set; }\n  public string Title { get; set; } = null!;\n}\n```\n\n# Model builder\nBy leveraging the `ksqlDb.RestApi.Client` fluent API model builder, you can streamline the configuration process, improve code readability, and mitigate issues related to code regeneration by keeping configuration logic separate from generated POCOs.\n\n```C#\nusing ksqlDb.RestApi.Client.FluentAPI.Builders;\nusing ksqlDb.RestApi.Client.FluentAPI.Builders.Configuration;\n\nModelBuilder modelBuilder = new();\n\nvar decimalTypeConvention = new DecimalTypeConvention(14, 14);\n\nmodelBuilder.AddConvention(decimalTypeConvention);\n\nmodelBuilder.Entity\u003cPayment\u003e()\n  .Property(b =\u003e b.Amount)\n  .Decimal(precision: 10, scale: 2);\n\nmodelBuilder.Entity\u003cPayment\u003e()\n  .Property(b =\u003e b.Description)\n  .HasColumnName(\"Desc\");\n\nmodelBuilder.Entity\u003cAccount\u003e()\n  .HasKey(c =\u003e c.Id);\n\nmodelBuilder.Entity\u003cAccount\u003e()\n  .Property(b =\u003e b.Secret)\n  .Ignore();\n```\n\nC# entity definitions:\n\n```C#\nrecord Payment\n{\n  public string Id { get; set; } = null!;\n  public decimal Amount { get; set; }\n  public string Description { get; set; } = null!;\n}\n\nrecord Account\n{\n  public string Id { get; set; } = null!;\n  public decimal Balance { get; set; }\n  public string Secret { get; set; }\n}\n```\n\nUsage with ksqlDB REST API Client:\n\n```C#\nvar kSqlDbRestApiClient = new KSqlDbRestApiClient(httpClientFactory, modelBuilder);\nawait kSqlDbRestApiClient.CreateTypeAsync\u003cPayment\u003e(cancellationToken);\n\nvar entityCreationMetadata = new EntityCreationMetadata(kafkaTopic: nameof(Account), partitions: 3)\n{\n  Replicas = 3\n};\nresponseMessage = await restApiProvider.CreateTableAsync\u003cAccount\u003e(entityCreationMetadata, true, cancellationToken);\n```\n\nGenerated KSQL:\n\n```SQL\nCREATE TYPE Payment AS STRUCT\u003cId VARCHAR, Amount DECIMAL(10,2), Desc VARCHAR\u003e;\n\nCREATE TABLE IF NOT EXISTS Accounts (\n\tId VARCHAR PRIMARY KEY,\n\tBalance DECIMAL(14,14)\n) WITH ( KAFKA_TOPIC='Account', VALUE_FORMAT='Json', PARTITIONS='3', REPLICAS='3' );\n```\n\nThe `Description` property within the `Payment` type has been customized to override the resulting column name as \"Desc\".\nAdditionally, the `Id` property within the `Account` table has been designated as the **primary key**, while the `Secret` property is disregarded during code generation.\n\n### Aggregation functions\nList of supported ksqldb [aggregation functions](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md):\n- [GROUP BY](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#groupby)\n- [MIN, MAX](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#min-and-max)\n- [AVG](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#avg)\n- [COUNT](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#count)\n- [COLLECT_LIST, COLLECT_SET](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#collect_list-collect_set)\n- [EARLIEST_BY_OFFSET, LATEST_BY_OFFSET](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#earliestbyoffset-latestbyoffset-earliestbyoffsetallownulls-latestbyoffsetallownull)\n- [SUM](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#sum)\n- [TOPK,TOPKDISTINCT](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#topk-topkdistinct-longcount-countcolumn)\n- [COUNT_DISTINCT](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#countdistinct)\n- [HAVING](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#having)\n\n- [TimeWindows - EMIT FINAL](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#timewindows---emit-final)\n- [WindowedBy](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#windowedby)\n  - [Session Window](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#session-window)\n  - [Tumbling Window](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#tumbling-window)\n  - [Hopping Window](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/aggregations.md#hopping-window)\n\n[Rest API reference](https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-reference/aggregate-functions/)\n\n**List of supported data types:**\n- [Supported data types mapping](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/data_types.md#supported-data-types-mapping)\n- [Structs](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/data_types.md#structs)\n- [Maps](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/data_types.md#maps)\n- [Time types DATE, TIME AND TIMESTAMP](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/data_types.md#time-types-date-time-and-timestamp)\n- [System.GUID as ksqldb VARCHAR type](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/data_types.md#systemguid-as-ksqldb-varchar-type-v240)\n\n**List of supported Joins:**\n- [RightJoin](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/joins.md#rightjoin)\n- [Full Outer Join](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/joins.md#full-outer-join)\n- [Left Join](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/joins.md#leftjoin---left-outer)\n- [Inner Joins](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/joins.md#inner-joins)\n- [Multiple joins with query comprehension syntax (GroupJoin, SelectMany, DefaultIfEmpty)](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/joins.md#multiple-joins-with-query-comprehension-syntax-groupjoin-selectmany-defaultifempty)\n\nList of supported [pull query](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/pull_queries.md) extension methods:\n- [Take (LIMIT)](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/pull_queries.md#pull-query-take-extension-method-limit)\n- [FirstOrDefaultAsync](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/pull_queries.md#ipullabletfirstordefaultasync-v100)\n- [GetManyAsync](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/pull_queries.md#getmanyasync)\n- [CreatePullQuery](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/pull_queries.md#createpullquerytentity-v100)\n- [ExecutePullQuery](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/pull_queries.md#pull-queries---executepullquery)\n\n**List of supported ksqlDB SQL statements:**\n- [Pause and resume persistent qeries](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#pause-and-resume-persistent-queries)\n- [Added support for extracting field names and values (for insert and select statements)](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#added-support-for-extracting-field-names-and-values-for-insert-and-select-statements)\n- [Assert topics](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#assert-topics)\n- [Assert schemas](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#assert-schemas)\n- [Rename stream or table column names with the `JsonPropertyNameAttribute`](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#rename-stream-or-table-column-names-with-the-jsonpropertynameattribute)\n- [Create source streams and tables](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#createsourcestreamasync-and-createsourcetableasync)\n- [InsertIntoAsync](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#insertintoasync)\n- [Connectors](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#connectors)\n- [Drop a stream](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#drop-a-stream)\n- [Drop type](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#droping-types)\n- [Creating types](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#create-types)\n- [Execute statement async](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#executestatementasync-extension-method)\n- [PartitionBy](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#partitionby)\n- [Terminate push queries](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#terminate-push-queries)\n- [Drop a table](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#drop-a-table)\n- [Creating connectors](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#creating-connectors)\n- [Get topics](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#get-topics)\n- [Getting queries and termination of persistent queries](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#getting-queries-and-termination-of-persistent-queries)\n- [Execute statements](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#executestatementasync)\n- [Create or replace table statements](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#create-or-replace-table-statements)\n- [Creating streams and tables](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#creating-streams-and-tables)\n- [Get streams](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#get-streams)\n- [Get tables](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbrestapiclient.md#get-tables)\n\n**KSqlDbContext**\n- [Dependency injection with ServicesCollection](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/4e6487dbf201f4318da88707d62e1a75c6cef402/docs/ksqldbcontext.md#logging-info-and-configureksqldb)\n- [Creating query streams](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbcontext.md#creating-query-streams)\n- [Creating queries](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbcontext.md#creating-queries)\n- [AddDbContext and AddDbContextFactory](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbcontext.md#ksqldbservicecollectionextensions---adddbcontext-and-adddbcontextfactory)\n- [Logging info and ConfigureKSqlDb](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbcontext.md#logging-info-and-configureksqldb)\n- [Basic auth](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbcontext.md#basic-auth)\n- [Add and SaveChangesAsync](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbcontext.md#add-and-savechangesasync)\n- [KSqlDbContextOptionsBuilder](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/ksqldbcontext.md#ksqldbcontextoptionsbuilder)\n\n**Config**\n- [Fluent API - Model builder](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/modelbuilder.md)\n- [Bearer token authentication](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/config.md#bearer-token-authentication)\n- [Replacing HttpClient](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/config.md#ksqldbcontextoptionsbuilderreplacehttpclient)\n- [Processing guarantees](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/config.md#processingguarantee-enum)\n\n**Operators**\n- [Operator LIKE](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/operators.md#operator-like---stringstartswith-stringendswith-stringcontains)\n- [Operator IN](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/operators.md#operator-in---ienumerablet-and-ilistt-contains)\n- [Operator BETWEEN](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/operators.md#operator-not-between)\n- [Operator CASE](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/operators.md#case)\n- [Arithmetic operations on columns](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/operators.md#arithmetic-operations-on-columns)\n- [Lexical precedence](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/operators.md#lexical-precedence)\n- [WHERE IS NULL, IS NOT NULL](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/operators.md#where-is-null-is-not-null)\n\n**Data definitions**\n- [Headers](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/data_definitions.md#access-record-header-data-v160)\n\n**Miscelenaous**\n- [Change data capture](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/cdc.md)\n- [List of breaking changes](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/breaking_changes.md)\n- [Operators](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/operators.md)\n- [Invocation functions](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/functions.md#improved-invocation-function-extensions)\n- [Setting JsonSerializerOptions](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/config.md#setjsonserializeroptions)\n- [Kafka stream processing example](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/stream_processing.md)\n- [ksqlDB streams and tables](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/streams_and_tables.md)\n\n**Functions**\n- [String functions](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/functions.md#string-functions)\n- [Numeric functions](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/functions.md#numeric-functions)\n- [Date and time functions](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/functions.md#date-and-time-functions)\n- [Lambda functions (Invocation functions) - Maps](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/functions.md#lambda-functions-invocation-functions---maps)\n  - [Transform maps](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/functions.md#transform-maps)\n  - [Filter maps](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/functions.md#filter-maps)\n  - [Reduce maps](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/blob/main/docs/functions.md#reduce-maps)\n\n# LinqPad samples\n[Push Query](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/tree/main/Samples/ksqlDB.RestApi.Client.LinqPad/ksqlDB.RestApi.Client.linq)\n\n[Pull Query](https://github.com/tomasfabian/ksqlDB.RestApi.Client-DotNet/tree/main/Samples/ksqlDB.RestApi.Client.LinqPad/ksqlDB.RestApi.Client.pull-query.linq)\n\n# Nuget\nhttps://www.nuget.org/packages/ksqlDB.RestApi.Client/\n\n# ksqldb links\n[Scalar functions](https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-reference/scalar-functions/#as_value)\n\n[Aggregation functions](https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-reference/aggregate-functions/)\n\n[Push query](https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-reference/select-push-query/)\n\n# Acknowledgements:\n- [ksql](https://github.com/confluentinc/ksql)\n\n- [Microsoft.Extensions.DependencyInjection](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/)\n- [Pluralize.NET](https://www.nuget.org/packages/Pluralize.NET/)\n- [System.Interactive.Async](https://www.nuget.org/packages/System.Interactive.Async/)\n- [System.Reactive](https://www.nuget.org/packages/System.Reactive/)\n- [System.Text.Json](https://www.nuget.org/packages/System.Text.Json/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomasfabian%2FksqlDB.RestApi.Client-DotNet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomasfabian%2FksqlDB.RestApi.Client-DotNet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomasfabian%2FksqlDB.RestApi.Client-DotNet/lists"}