├── .github └── dependabot.yml ├── .gitignore ├── .gitmodules ├── LICENSE.md ├── README.md ├── YdbDriver.sln ├── examples └── ShortenLinks │ ├── .dockerignore │ ├── Controllers │ └── TaskController.cs │ ├── Dockerfile │ ├── ITaskRepository.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── QueryResult.cs │ ├── ShortenLinks.csproj │ ├── TaskWorker.cs │ ├── YdbTaskRepository.cs │ ├── appsettings.Development.json │ └── appsettings.json ├── src ├── Yandex.Ydb.DependencyInjection │ └── Yandex.Ydb.DependencyInjection │ │ ├── Yandex.Ydb.DependencyInjection.csproj │ │ └── YdbServiceCollectionExtensions.cs ├── Yandex.Ydb.Driver.Proto │ ├── OperationService.cs │ ├── SchemeService.cs │ ├── TableService.cs │ ├── TopicService.cs │ ├── Yandex.Ydb.Driver.Proto.csproj │ └── protos │ │ ├── annotations │ │ └── validation.proto │ │ ├── ydb_auth.proto │ │ ├── ydb_auth_v1.proto │ │ ├── ydb_cms.proto │ │ ├── ydb_cms_v1.proto │ │ ├── ydb_common.proto │ │ ├── ydb_coordination.proto │ │ ├── ydb_coordination_v1.proto │ │ ├── ydb_discovery.proto │ │ ├── ydb_discovery_v1.proto │ │ ├── ydb_export.proto │ │ ├── ydb_export_v1.proto │ │ ├── ydb_formats.proto │ │ ├── ydb_import.proto │ │ ├── ydb_import_v1.proto │ │ ├── ydb_issue_message.proto │ │ ├── ydb_monitoring.proto │ │ ├── ydb_monitoring_v1.proto │ │ ├── ydb_operation.proto │ │ ├── ydb_operation_v1.proto │ │ ├── ydb_query_stats.proto │ │ ├── ydb_rate_limiter.proto │ │ ├── ydb_rate_limiter_v1.proto │ │ ├── ydb_scheme.proto │ │ ├── ydb_scheme_v1.proto │ │ ├── ydb_scripting.proto │ │ ├── ydb_scripting_v1.proto │ │ ├── ydb_status_codes.proto │ │ ├── ydb_table.proto │ │ ├── ydb_table_v1.proto │ │ ├── ydb_topic.proto │ │ ├── ydb_topic_v1.proto │ │ └── ydb_value.proto └── Yandex.Ydb.Driver │ └── Yandex.Ydb.Driver │ ├── Common.cs │ ├── Credentials │ ├── DefaultCredentialsProvider.cs │ └── ServiceAccountTokenProvider.cs │ ├── Helpers │ ├── TaskHelper.cs │ ├── ThrowHelper.cs │ └── YdbValueExt.cs │ ├── ISessionPool.cs │ ├── IYdbConnection.cs │ ├── IYdbConnector.cs │ ├── IYdbDataSourceBuilder.cs │ ├── Internal │ ├── TypeHandlers │ │ ├── IYdbSimpleTypeHandler.cs │ │ ├── Primitives │ │ │ ├── BoolHandler.cs │ │ │ ├── ContainerHandlerBase.cs │ │ │ ├── DateOnlyHandler.cs │ │ │ ├── DateTimeHandler.cs │ │ │ ├── DecimalHandler.cs │ │ │ ├── DictionaryHandler.cs │ │ │ ├── DoubleHandler.cs │ │ │ ├── FloatHandler.cs │ │ │ ├── GuidHandler.cs │ │ │ ├── IContainerHandler.cs │ │ │ ├── Int16Handler.cs │ │ │ ├── Int32Handler.cs │ │ │ ├── Int64Handler.cs │ │ │ ├── Int8Handler.cs │ │ │ ├── JsonHandler.cs │ │ │ ├── ListHandler.cs │ │ │ ├── StructHandler.cs │ │ │ ├── TextTypeHandler.cs │ │ │ ├── TimeStampHandler.cs │ │ │ ├── TupleHandler.cs │ │ │ ├── UInt16Handler.cs │ │ │ ├── UInt32Handler.cs │ │ │ ├── UInt64Handler.cs │ │ │ ├── UInt8Handler.cs │ │ │ ├── Utf8Handler.cs │ │ │ ├── YdbPrimitiveTypeHandler.cs │ │ │ └── YsonHandler.cs │ │ └── YdbTypeHandler.cs │ ├── TypeHandling │ │ ├── BuiltInTypeHandlerResolver.cs │ │ ├── BuiltInTypeHandlerResolverFactory.cs │ │ ├── IYdbTypeHandler.cs │ │ ├── OperationExtensions.cs │ │ └── UserDefinedTypeHandlerResolver.cs │ └── TypeMapping │ │ ├── GlobalTypeMapper.cs │ │ ├── IUserTypeMapping.cs │ │ ├── IYdbTypeMapper.cs │ │ ├── TypeHandlerResolver.cs │ │ ├── TypeHandlerResolverFactory.cs │ │ └── TypeMapper.cs │ ├── LogMessages.cs │ ├── PooledDataSource.cs │ ├── Session.cs │ ├── SessionPool.cs │ ├── Types │ └── Primitives │ │ └── Utf8String.cs │ ├── UnpooledYdbDataSource.cs │ ├── YDbConnectionStringBuilder.cs │ ├── Yandex.Ydb.Driver.csproj │ ├── YdbBatchTransaction.cs │ ├── YdbCommand.cs │ ├── YdbConnection.cs │ ├── YdbConnectionSettings.cs │ ├── YdbConnectionState.cs │ ├── YdbConnector.cs │ ├── YdbDataSource.cs │ ├── YdbDataSourceBuilder.cs │ ├── YdbDataSourceCommand.cs │ ├── YdbDataSourceConfiguration.cs │ ├── YdbDbDataReader.cs │ ├── YdbDriverException.cs │ ├── YdbLoggingConfiguration.cs │ ├── YdbMetadata.cs │ ├── YdbParameter.cs │ ├── YdbParameterCollection.cs │ └── YdbTransaction.cs └── tests └── Yandex.Ydb.Driver.Tests └── Yandex.Ydb.Driver.Tests ├── DapperTests.cs ├── DataSourceTests.cs ├── TestHelper.cs ├── TypeMapperTests.cs ├── Usings.cs ├── Yandex.Ydb.Driver.Tests.csproj ├── YdbCommandTests.cs ├── YdbConnectionTests.cs ├── YdbTransactionTests.cs └── certs ├── cert.pem └── key.pem /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/src" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "dependencies/ydb-api-protos"] 2 | path = dependencies/ydb-api-protos 3 | url = https://github.com/ydb-platform/ydb-api-protos.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YDB.ADO 2 | YDB C# Driver for [YDB (Yandex Database)](https://github.com/ydb-platform/ydb). This driver implements YDB protobuf protocol and supports ADO.NET rules. 3 | 4 | ## Installation 5 | [Get it on Nuget][https://www.nuget.org/packages/Yandex.Ydb.ADO/] 6 | ```bash 7 | PM> Install-Package Yandex.Ydb.Ado 8 | ``` 9 | To get hosting extensions 10 | ```bash 11 | PM> Install-Package Yandex.Ydb.DependencyInjection 12 | ``` 13 | 14 | 15 | ## Features 16 | 17 | - [x] Sync and Async API 18 | - [x] Pooling sessions 19 | - [x] Simple statements 20 | - [x] Dependency Injection integration 21 | - [x] Primitives mapping (Int32, Bool, DateTime, Guid etc.) 22 | - [x] Json type mapping 23 | 24 | 25 | ## Basic usage 26 | 27 | ```csharp 28 | // injecting YdbDataSource with connection string 29 | builder.Services.AddYdbDataSource("Host=localhost;Port=2136;Pooling=true;MaxSessions=100;"); 30 | ``` 31 | 32 | In controller class or services usage: 33 | 34 | ```csharp 35 | public YdbTaskRepository(YdbDataSource dataSource) 36 | { 37 | _source = dataSource; 38 | } 39 | ... 40 | 41 | public async Task AddTask(TaskToWork entity) 42 | { 43 | // Getting connection (it will not open physical connection and will get session from pool by default) 44 | await using var connection = await _source.OpenConnectionAsync(); 45 | 46 | // Creating command 47 | var ydbCommand = connection.CreateYdbCommand(); 48 | ydbCommand.AddParameter("$id", Guid.NewGuid().ToString()); 49 | ydbCommand.AddParameter("$task", JsonSerializer.Serialize(entity)); 50 | ydbCommand.AddParameter("$created_at", (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); 51 | 52 | ydbCommand.CommandText = @" 53 | DECLARE $task as String; 54 | DECLARE $id as String; 55 | DECLARE $created_at as Uint64; 56 | 57 | UPSERT INTO tasks (`task_id`, `task`, `created_at`) VALUES ($id, $task, $created_at)"; 58 | 59 | // Executing command 60 | await ydbCommand.ExecuteNonQueryAsync(); 61 | } 62 | 63 | 64 | public async Task GetNextTask() 65 | { 66 | await using var connection = await _source.OpenConnectionAsync(); 67 | var ydbCommand = connection.CreateYdbCommand(); 68 | ydbCommand.CommandText = 69 | "SELECT task_id, task, created_at, is_processed FROM tasks WHERE processing_at IS NULL ORDER BY created_at LIMIT 1;"; 70 | 71 | var reader = await ydbCommand.ExecuteReaderAsync(); 72 | var resultAsync = await reader.NextResultAsync(); 73 | if (!resultAsync) 74 | return null; 75 | 76 | var first = new QueryResult() 77 | { 78 | TaskId = reader.GetString(0), 79 | Task = reader.GetString(1), 80 | CreatedAt = reader.GetFieldValue(2), 81 | IsProcessed = reader.GetFieldValue(3), 82 | }; 83 | 84 | return first ?? null; 85 | } 86 | 87 | ``` 88 | 89 | 90 | 91 | ## Planned 92 | 93 | - [ ] Prepared statements 94 | - [ ] Batch statements 95 | - [ ] Custom user defined mappers 96 | - [ ] Streaming 97 | - [ ] Flexible retry backoff policies 98 | 99 | -------------------------------------------------------------------------------- /YdbDriver.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6F9F549C-4070-4107-B5B6-45DE37083E0E}" 4 | EndProject 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{5DB15F65-DE78-4C0E-A3A7-28CEA0271518}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yandex.Ydb.Driver.Tests", "tests\Yandex.Ydb.Driver.Tests\Yandex.Ydb.Driver.Tests\Yandex.Ydb.Driver.Tests.csproj", "{BB75DF79-4037-4FF0-8C3A-8D3331184794}" 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yandex.Ydb.Driver.Proto", "src\Yandex.Ydb.Driver.Proto\Yandex.Ydb.Driver.Proto.csproj", "{2F5EF227-4643-410B-B8F1-E1E29EC26161}" 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yandex.Ydb.Driver", "src\Yandex.Ydb.Driver\Yandex.Ydb.Driver\Yandex.Ydb.Driver.csproj", "{D10FAF70-9B5C-4311-B4D5-1AB29C6925CB}" 12 | EndProject 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{FA3E94C9-1D60-4539-B71F-43CD205176B0}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShortenLinks", "examples\ShortenLinks\ShortenLinks.csproj", "{477886DF-D283-49E2-A222-0A8B5FE792F9}" 16 | EndProject 17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yandex.Ydb.DependencyInjection", "src\Yandex.Ydb.DependencyInjection\Yandex.Ydb.DependencyInjection\Yandex.Ydb.DependencyInjection.csproj", "{45B51D0D-643D-42C3-8F41-224DB7973D6B}" 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Release|Any CPU = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {BB75DF79-4037-4FF0-8C3A-8D3331184794}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {BB75DF79-4037-4FF0-8C3A-8D3331184794}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {BB75DF79-4037-4FF0-8C3A-8D3331184794}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {BB75DF79-4037-4FF0-8C3A-8D3331184794}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {2F5EF227-4643-410B-B8F1-E1E29EC26161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {2F5EF227-4643-410B-B8F1-E1E29EC26161}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {2F5EF227-4643-410B-B8F1-E1E29EC26161}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {2F5EF227-4643-410B-B8F1-E1E29EC26161}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {D10FAF70-9B5C-4311-B4D5-1AB29C6925CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {D10FAF70-9B5C-4311-B4D5-1AB29C6925CB}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {D10FAF70-9B5C-4311-B4D5-1AB29C6925CB}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {D10FAF70-9B5C-4311-B4D5-1AB29C6925CB}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {477886DF-D283-49E2-A222-0A8B5FE792F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {477886DF-D283-49E2-A222-0A8B5FE792F9}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {477886DF-D283-49E2-A222-0A8B5FE792F9}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {477886DF-D283-49E2-A222-0A8B5FE792F9}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {45B51D0D-643D-42C3-8F41-224DB7973D6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {45B51D0D-643D-42C3-8F41-224DB7973D6B}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {45B51D0D-643D-42C3-8F41-224DB7973D6B}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {45B51D0D-643D-42C3-8F41-224DB7973D6B}.Release|Any CPU.Build.0 = Release|Any CPU 45 | EndGlobalSection 46 | GlobalSection(NestedProjects) = preSolution 47 | {BB75DF79-4037-4FF0-8C3A-8D3331184794} = {5DB15F65-DE78-4C0E-A3A7-28CEA0271518} 48 | {2F5EF227-4643-410B-B8F1-E1E29EC26161} = {6F9F549C-4070-4107-B5B6-45DE37083E0E} 49 | {D10FAF70-9B5C-4311-B4D5-1AB29C6925CB} = {6F9F549C-4070-4107-B5B6-45DE37083E0E} 50 | {477886DF-D283-49E2-A222-0A8B5FE792F9} = {FA3E94C9-1D60-4539-B71F-43CD205176B0} 51 | {45B51D0D-643D-42C3-8F41-224DB7973D6B} = {6F9F549C-4070-4107-B5B6-45DE37083E0E} 52 | EndGlobalSection 53 | EndGlobal 54 | -------------------------------------------------------------------------------- /examples/ShortenLinks/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.dockerignore 2 | **/.env 3 | **/.git 4 | **/.gitignore 5 | **/.project 6 | **/.settings 7 | **/.toolstarget 8 | **/.vs 9 | **/.vscode 10 | **/.idea 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /examples/ShortenLinks/Controllers/TaskController.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text.Json; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Yandex.Ydb.Driver; 5 | 6 | namespace ShortenLinks.Controllers; 7 | 8 | public record TaskToWork(string MethodName, string[] Arguments); 9 | 10 | [Route("api/[controller]")] 11 | [ApiController] 12 | public class TaskController : ControllerBase 13 | { 14 | private readonly ITaskRepository _repository; 15 | private readonly ILogger _log; 16 | 17 | public TaskController(ITaskRepository repository, ILogger log) 18 | { 19 | _repository = repository; 20 | _log = log; 21 | } 22 | 23 | [HttpPost("create")] 24 | public async Task Create() 25 | { 26 | try 27 | { 28 | var start = Stopwatch.GetTimestamp(); 29 | await _repository.AddTask(new TaskToWork("Console.WriteLine", new[] { Guid.NewGuid().ToString() })); 30 | return Ok(new { elapsed = Stopwatch.GetElapsedTime(start) }); 31 | } 32 | catch (Exception e) 33 | { 34 | _log.LogError(e, "Failed to process creating task"); 35 | return Problem(e.ToString()); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /examples/ShortenLinks/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base 2 | WORKDIR /app 3 | EXPOSE 80 4 | EXPOSE 443 5 | 6 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 7 | WORKDIR /src 8 | COPY ["examples/ShortenLinks/ShortenLinks.csproj", "ShortenLinks/"] 9 | RUN dotnet restore "examples/ShortenLinks/ShortenLinks.csproj" 10 | COPY . . 11 | WORKDIR "/src/ShortenLinks" 12 | RUN dotnet build "ShortenLinks.csproj" -c Release -o /app/build 13 | 14 | FROM build AS publish 15 | RUN dotnet publish "ShortenLinks.csproj" -c Release -o /app/publish 16 | 17 | FROM base AS final 18 | WORKDIR /app 19 | COPY --from=publish /app/publish . 20 | ENTRYPOINT ["dotnet", "ShortenLinks.dll"] 21 | -------------------------------------------------------------------------------- /examples/ShortenLinks/ITaskRepository.cs: -------------------------------------------------------------------------------- 1 | using ShortenLinks.Controllers; 2 | 3 | public interface ITaskRepository 4 | { 5 | Task AddTask(TaskToWork entity); 6 | 7 | Task GetNextTask(); 8 | 9 | Task SetAsProcessing(string taskId); 10 | } -------------------------------------------------------------------------------- /examples/ShortenLinks/Program.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver; 2 | 3 | var builder = WebApplication.CreateBuilder(args); 4 | 5 | // Add services to the container. 6 | 7 | builder.Services.AddSingleton(); 8 | builder.Services.AddYdbDataSource("Host=localhost;Port=2136;Pooling=true;MaxSessions=100;"); 9 | 10 | builder.Services.AddControllers(); 11 | builder.Services.AddHostedService(); 12 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 13 | builder.Services.AddEndpointsApiExplorer(); 14 | builder.Services.AddSwaggerGen(); 15 | 16 | var app = builder.Build(); 17 | 18 | // Configure the HTTP request pipeline. 19 | app.UseSwagger(); 20 | app.UseSwaggerUI(); 21 | 22 | app.UseAuthorization(); 23 | 24 | app.MapControllers(); 25 | 26 | app.MapPost("/createSchema", async context => 27 | { 28 | await using var connection = context.RequestServices.GetRequiredService(); 29 | var ydbCommand = connection.CreateYdbCommand(); 30 | ydbCommand.CommandText = @" 31 | CREATE TABLE tasks 32 | ( 33 | task_id String, 34 | created_at Uint64, 35 | task String, 36 | processing_at Uint64, 37 | is_processed bool, 38 | 39 | PRIMARY KEY (task_id) 40 | ) 41 | 42 | "; 43 | 44 | await ydbCommand.ExecuteNonQueryAsync(); 45 | }); 46 | 47 | app.Run(); -------------------------------------------------------------------------------- /examples/ShortenLinks/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:47125", 8 | "sslPort": 44307 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "http://localhost:5078", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "https": { 23 | "commandName": "Project", 24 | "dotnetRunMessages": true, 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "applicationUrl": "https://localhost:7061;http://localhost:5078", 28 | "environmentVariables": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | } 31 | }, 32 | "IIS Express": { 33 | "commandName": "IISExpress", 34 | "launchBrowser": true, 35 | "launchUrl": "swagger", 36 | "environmentVariables": { 37 | "ASPNETCORE_ENVIRONMENT": "Development" 38 | } 39 | }, 40 | "http prod": { 41 | "commandName": "Project", 42 | "dotnetRunMessages": true, 43 | "launchBrowser": true, 44 | "launchUrl": "swagger", 45 | "applicationUrl": "https://localhost:7061;http://localhost:5078", 46 | "environmentVariables": { 47 | "ASPNETCORE_ENVIRONMENT": "Production" 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/ShortenLinks/QueryResult.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Schema; 2 | 3 | public class QueryResult 4 | { 5 | public QueryResult() 6 | { 7 | } 8 | 9 | public QueryResult(string TaskId, ulong CreatedAt, bool? IsProcessed, string Task) 10 | { 11 | this.TaskId = TaskId; 12 | this.CreatedAt = CreatedAt; 13 | this.IsProcessed = IsProcessed; 14 | this.Task = Task; 15 | } 16 | 17 | [Column("task_id")] public string TaskId { get; init; } 18 | [Column("created_at")] public ulong CreatedAt { get; init; } 19 | [Column("is_processed")] public bool? IsProcessed { get; init; } 20 | [Column("task")] public string Task { get; init; } 21 | 22 | public void Deconstruct(out string TaskId, out ulong CreatedAt, out bool? IsProcessed, out string Task) 23 | { 24 | TaskId = this.TaskId; 25 | CreatedAt = this.CreatedAt; 26 | IsProcessed = this.IsProcessed; 27 | Task = this.Task; 28 | } 29 | } -------------------------------------------------------------------------------- /examples/ShortenLinks/ShortenLinks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | Linux 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/ShortenLinks/TaskWorker.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Schema; 2 | using Dapper; 3 | 4 | public class TaskWorker : IHostedService 5 | { 6 | private readonly ILogger _log; 7 | private readonly ITaskRepository _taskRepository; 8 | private Task _task; 9 | private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); 10 | 11 | 12 | public TaskWorker(ILogger log, ITaskRepository taskRepository) 13 | { 14 | _log = log; 15 | _taskRepository = taskRepository; 16 | 17 | Dapper.SqlMapper.SetTypeMap( 18 | typeof(QueryResult), 19 | new CustomPropertyTypeMap( 20 | typeof(QueryResult), 21 | (type, columnName) => 22 | type.GetProperties().FirstOrDefault(prop => 23 | prop.GetCustomAttributes(false) 24 | .OfType() 25 | .Any(attr => attr.Name == columnName)))); 26 | } 27 | 28 | public Task StartAsync(CancellationToken cancellationToken) 29 | { 30 | _task = Task.Factory.StartNew(Processing, cancellationToken); 31 | return Task.CompletedTask; 32 | } 33 | 34 | private async Task Processing() 35 | { 36 | while (!_cancellationTokenSource.Token.IsCancellationRequested) 37 | { 38 | await Task.Delay(1000); 39 | 40 | try 41 | { 42 | var nextTask = await _taskRepository.GetNextTask(); 43 | if (nextTask == null) 44 | continue; 45 | 46 | await _taskRepository.SetAsProcessing(nextTask.TaskId); 47 | } 48 | catch (Exception e) 49 | { 50 | _log.LogError(e, "Failed to process task"); 51 | } 52 | } 53 | } 54 | 55 | public Task StopAsync(CancellationToken cancellationToken) 56 | { 57 | _cancellationTokenSource.Cancel(); 58 | return Task.CompletedTask; 59 | } 60 | } -------------------------------------------------------------------------------- /examples/ShortenLinks/YdbTaskRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using ShortenLinks.Controllers; 3 | using Yandex.Ydb.Driver; 4 | 5 | public class YdbTaskRepository : ITaskRepository 6 | { 7 | private readonly YdbDataSource _source; 8 | 9 | public YdbTaskRepository(YdbDataSource dataSource) 10 | { 11 | _source = dataSource; 12 | } 13 | 14 | public async Task AddTask(TaskToWork entity) 15 | { 16 | await using var connection = await _source.OpenConnectionAsync(); 17 | 18 | var ydbCommand = connection.CreateYdbCommand(); 19 | ydbCommand.AddParameter("$id", Guid.NewGuid().ToString()); 20 | ydbCommand.AddParameter("$task", JsonSerializer.Serialize(entity)); 21 | ydbCommand.AddParameter("$created_at", (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); 22 | 23 | ydbCommand.CommandText = @" 24 | DECLARE $task as String; 25 | DECLARE $id as String; 26 | DECLARE $created_at as Uint64; 27 | 28 | UPSERT INTO tasks (`task_id`, `task`, `created_at`) VALUES ($id, $task, $created_at)"; 29 | 30 | await ydbCommand.ExecuteNonQueryAsync(); 31 | } 32 | 33 | public async Task GetNextTask() 34 | { 35 | return null; 36 | 37 | 38 | await using var connection = await _source.OpenConnectionAsync(); 39 | var ydbCommand = connection.CreateYdbCommand(); 40 | ydbCommand.CommandText = 41 | "SELECT task_id, task, created_at, is_processed FROM tasks WHERE processing_at IS NULL ORDER BY created_at LIMIT 1;"; 42 | 43 | var reader = await ydbCommand.ExecuteReaderAsync(); 44 | var resultAsync = await reader.NextResultAsync(); 45 | if (!resultAsync) 46 | return null; 47 | 48 | var first = new QueryResult() 49 | { 50 | TaskId = reader.GetString(0), 51 | Task = reader.GetString(1), 52 | CreatedAt = reader.GetFieldValue(2), 53 | IsProcessed = reader.GetFieldValue(3), 54 | }; 55 | 56 | // var first = await connection.QueryFirstOrDefaultAsync( 57 | // "SELECT * FROM tasks WHERE processing_at IS NULL ORDER BY created_at LIMIT 1;"); 58 | 59 | return first ?? null; 60 | } 61 | 62 | public async Task SetAsProcessing(string taskId) 63 | { 64 | await using var connection = await _source.OpenConnectionAsync(); 65 | var ydbCommand = connection.CreateYdbCommand(); 66 | ydbCommand.CommandText = @"DECLARE $id as String; UPDATE tasks SET processing_at = 123 WHERE task_id = $id"; 67 | await ydbCommand.ExecuteNonQueryAsync(); 68 | } 69 | } -------------------------------------------------------------------------------- /examples/ShortenLinks/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/ShortenLinks/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "Kestrel": { 10 | "Limits": { 11 | "MaxConcurrentConnections": 1000, 12 | "MaxConcurrentUpgradedConnections": 1000 13 | }, 14 | "DisableStringReuse": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.DependencyInjection/Yandex.Ydb.DependencyInjection/Yandex.Ydb.DependencyInjection.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | latest 8 | Yandex.Ydb.DependencyInjection 9 | Golenok Roman 10 | DI Hosting Extension for YDB.ADO 11 | https://github.com/shersh/YdbDriver 12 | https://github.com/shersh/YdbDriver/blob/master/LICENSE.md 13 | https://github.com/shersh/YdbDriver 14 | git 15 | YDB yandex ADO.NET 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.DependencyInjection/Yandex.Ydb.DependencyInjection/YdbServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | using Microsoft.Extensions.DependencyInjection.Extensions; 3 | using Microsoft.Extensions.Logging; 4 | using Yandex.Ydb.Driver; 5 | 6 | // ReSharper disable once CheckNamespace 7 | namespace Microsoft.Extensions.DependencyInjection; 8 | 9 | public static class YdbServiceCollectionExtensions 10 | { 11 | /// 12 | /// Registers an and an in the . 13 | /// 14 | /// The to add services to. 15 | /// An Ydb connection string. 16 | /// 17 | /// The lifetime with which to register the in the container. 18 | /// Defaults to . 19 | /// 20 | /// 21 | /// The lifetime with which to register the service in the container. 22 | /// Defaults to . 23 | /// 24 | /// The same service collection so that multiple calls can be chained. 25 | public static IServiceCollection AddYdbDataSource( 26 | this IServiceCollection serviceCollection, 27 | string connectionString, 28 | ServiceLifetime connectionLifetime = ServiceLifetime.Transient, 29 | ServiceLifetime dataSourceLifetime = ServiceLifetime.Singleton) 30 | => AddYdbDataSourceCore( 31 | serviceCollection, connectionString, dataSourceBuilderAction: null, connectionLifetime, dataSourceLifetime); 32 | 33 | public static IServiceCollection AddYdbDataSource( 34 | this IServiceCollection serviceCollection, 35 | string connectionString, 36 | Action dataSourceBuilderAction, 37 | ServiceLifetime connectionLifetime = ServiceLifetime.Transient, 38 | ServiceLifetime dataSourceLifetime = ServiceLifetime.Singleton) 39 | => AddYdbDataSourceCore(serviceCollection, connectionString, dataSourceBuilderAction, connectionLifetime, 40 | dataSourceLifetime); 41 | 42 | 43 | /// 44 | /// Registers an and an in the . 45 | /// 46 | /// The to add services to. 47 | /// An Ydb connection string. 48 | /// 49 | /// An action to configure the for further customizations of the . 50 | /// 51 | /// 52 | /// The lifetime with which to register the in the container. 53 | /// Defaults to . 54 | /// 55 | /// 56 | /// The lifetime with which to register the service in the container. 57 | /// Defaults to . 58 | /// 59 | /// The same service collection so that multiple calls can be chained. 60 | private static IServiceCollection AddYdbDataSourceCore(IServiceCollection serviceCollection, 61 | string connectionString, Action dataSourceBuilderAction, 62 | ServiceLifetime connectionLifetime, ServiceLifetime dataSourceLifetime) 63 | { 64 | serviceCollection.TryAdd( 65 | new ServiceDescriptor( 66 | typeof(YdbDataSource), 67 | sp => 68 | { 69 | var dataSourceBuilder = new YdbDataSourceBuilder(connectionString); 70 | dataSourceBuilder.UseLoggerFactory(sp.GetService()); 71 | dataSourceBuilderAction?.Invoke(dataSourceBuilder); 72 | return dataSourceBuilder.Build(); 73 | }, 74 | dataSourceLifetime)); 75 | 76 | AddCommonServices(serviceCollection, connectionLifetime, dataSourceLifetime); 77 | 78 | return serviceCollection; 79 | } 80 | 81 | static void AddCommonServices( 82 | IServiceCollection serviceCollection, 83 | ServiceLifetime connectionLifetime, 84 | ServiceLifetime dataSourceLifetime) 85 | { 86 | serviceCollection.TryAdd( 87 | new ServiceDescriptor( 88 | typeof(YdbConnection), 89 | sp => sp.GetRequiredService().CreateConnection(), 90 | connectionLifetime)); 91 | 92 | serviceCollection.TryAdd( 93 | new ServiceDescriptor( 94 | typeof(DbDataSource), 95 | sp => sp.GetRequiredService(), 96 | dataSourceLifetime)); 97 | 98 | serviceCollection.TryAdd( 99 | new ServiceDescriptor( 100 | typeof(DbConnection), 101 | sp => sp.GetRequiredService(), 102 | connectionLifetime)); 103 | } 104 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/OperationService.cs: -------------------------------------------------------------------------------- 1 | using Ydb.Operations; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace Ydb.Operation.V1; 5 | 6 | public static partial class OperationService 7 | { 8 | public static Grpc.Core.Method GetOperationMethod => 9 | __Method_GetOperation; 10 | 11 | public static Grpc.Core.Method CancelOperationMethod => 12 | __Method_CancelOperation; 13 | 14 | public static Grpc.Core.Method ForgetOperationMethod => 15 | __Method_ForgetOperation; 16 | 17 | public static Grpc.Core.Method ListOperationsMethod => 18 | __Method_ListOperations; 19 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/SchemeService.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | 3 | namespace Ydb.Scheme.V1; 4 | 5 | public static partial class SchemeService 6 | { 7 | public static Grpc.Core.Method MakeDirectoryMethod => __Method_MakeDirectory; 8 | 9 | public static Grpc.Core.Method RemoveDirectoryMethod => __Method_RemoveDirectory; 10 | 11 | public static Grpc.Core.Method ListDirectoryMethod => __Method_ListDirectory; 12 | 13 | public static Grpc.Core.Method DescribePathMethod => __Method_DescribePath; 14 | 15 | public static Grpc.Core.Method ModifyPermissionsMethod => __Method_ModifyPermissions; 16 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/TableService.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | namespace Ydb.Table.V1; 3 | 4 | public static partial class TableService 5 | { 6 | public static Grpc.Core.Method 7 | CreateSessionMethod => __Method_CreateSession; 8 | 9 | public static Grpc.Core.Method DeleteSessionMethod => 10 | __Method_DeleteSession; 11 | 12 | public static Grpc.Core.Method KeepAliveMethod => __Method_KeepAlive; 13 | 14 | public static Grpc.Core.Method CreateTableMethod => __Method_CreateTable; 15 | 16 | public static Grpc.Core.Method DropTableMethod => __Method_DropTable; 17 | 18 | public static Grpc.Core.Method AlterTableMethod => __Method_AlterTable; 19 | 20 | public static Grpc.Core.Method CopyTableMethod => __Method_CopyTable; 21 | 22 | public static Grpc.Core.Method CopyTablesMethod => __Method_CopyTables; 23 | 24 | public static Grpc.Core.Method RenameTablesMethod => 25 | __Method_RenameTables; 26 | 27 | public static Grpc.Core.Method DescribeTableMethod => 28 | __Method_DescribeTable; 29 | 30 | public static Grpc.Core.Method ExplainDataQueryMethod => 31 | __Method_ExplainDataQuery; 32 | 33 | public static Grpc.Core.Method PrepareDataQueryMethod => 34 | __Method_PrepareDataQuery; 35 | 36 | public static Grpc.Core.Method ExecuteDataQueryMethod => 37 | __Method_ExecuteDataQuery; 38 | 39 | public static Grpc.Core.Method ExecuteSchemeQueryMethod => 40 | __Method_ExecuteSchemeQuery; 41 | 42 | public static Grpc.Core.Method BeginTransactionMethod => 43 | __Method_BeginTransaction; 44 | 45 | public static Grpc.Core.Method CommitTransactionMethod => 46 | __Method_CommitTransaction; 47 | 48 | public static Grpc.Core.Method RollbackTransactionMethod => 49 | __Method_RollbackTransaction; 50 | 51 | public static Grpc.Core.Method 52 | DescribeTableOptionsMethod => __Method_DescribeTableOptions; 53 | 54 | public static Grpc.Core.Method StreamReadTableMethod => 55 | __Method_StreamReadTable; 56 | 57 | public static Grpc.Core.Method BulkUpsertMethod => __Method_BulkUpsert; 58 | 59 | public static Grpc.Core.Method 60 | StreamExecuteScanQueryMethod => __Method_StreamExecuteScanQuery; 61 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/TopicService.cs: -------------------------------------------------------------------------------- 1 | using Grpc.Core; 2 | 3 | namespace Ydb.Topic.V1; 4 | 5 | public static partial class TopicService 6 | { 7 | public static Method CreateTopicMethod => __Method_CreateTopic; 8 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/Yandex.Ydb.Driver.Proto.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | enable 6 | enable 7 | latest 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/annotations/validation.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"; 7 | option java_package = "tech.ydb"; 8 | 9 | import "google/protobuf/descriptor.proto"; 10 | 11 | message Limit { 12 | message Range { 13 | uint32 min = 1; 14 | uint32 max = 2; 15 | } 16 | 17 | oneof kind { 18 | Range range = 1; 19 | uint32 lt = 2; 20 | uint32 le = 3; 21 | uint32 eq = 4; 22 | uint32 ge = 5; 23 | uint32 gt = 6; 24 | } 25 | } 26 | 27 | message MapKey { 28 | Limit length = 1; 29 | string value = 2; 30 | } 31 | 32 | extend google.protobuf.FieldOptions { 33 | bool required = 87650; 34 | Limit size = 87651; 35 | Limit length = 87652; 36 | MapKey map_key = 87653; 37 | string value = 87654; 38 | } 39 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_auth.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb.Auth; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Auth"; 7 | option java_package = "tech.ydb.auth"; 8 | 9 | import "protos/ydb_operation.proto"; 10 | 11 | message LoginRequest { 12 | Ydb.Operations.OperationParams operation_params = 1; 13 | string user = 2; 14 | string password = 3; 15 | } 16 | 17 | message LoginResponse { 18 | // After successfull completion must contain LoginResult. 19 | Ydb.Operations.Operation operation = 1; 20 | } 21 | 22 | message LoginResult { 23 | string token = 1; 24 | } 25 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_auth_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Auth.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Auth_V1"; 6 | option java_package = "tech.ydb.auth.v1"; 7 | 8 | import "protos/ydb_auth.proto"; 9 | 10 | service AuthService { 11 | // Perform login using built-in auth system 12 | rpc Login(Auth.LoginRequest) returns (Auth.LoginResponse); 13 | } 14 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_cms_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Cms.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Cms_V1"; 6 | option java_package = "tech.ydb.cms.v1"; 7 | 8 | import "protos/ydb_cms.proto"; 9 | 10 | // CMS stands for Cluster Management System. CmsService provides some 11 | // functionality for managing cluster, i.e. managing YDB Database 12 | // instances for example. 13 | 14 | service CmsService { 15 | // Create a new database. 16 | rpc CreateDatabase(Cms.CreateDatabaseRequest) returns (Cms.CreateDatabaseResponse); 17 | 18 | // Get current database's status. 19 | rpc GetDatabaseStatus(Cms.GetDatabaseStatusRequest) returns (Cms.GetDatabaseStatusResponse); 20 | 21 | // Alter database resources. 22 | rpc AlterDatabase(Cms.AlterDatabaseRequest) returns (Cms.AlterDatabaseResponse); 23 | 24 | // List all databases. 25 | rpc ListDatabases(Cms.ListDatabasesRequest) returns (Cms.ListDatabasesResponse); 26 | 27 | // Remove database. 28 | rpc RemoveDatabase(Cms.RemoveDatabaseRequest) returns (Cms.RemoveDatabaseResponse); 29 | 30 | // Describe supported database options. 31 | rpc DescribeDatabaseOptions(Cms.DescribeDatabaseOptionsRequest) returns (Cms.DescribeDatabaseOptionsResponse); 32 | } 33 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"; 7 | option java_package = "tech.ydb.common"; 8 | option java_outer_classname = "CommonProtos"; 9 | 10 | message FeatureFlag { 11 | enum Status { 12 | STATUS_UNSPECIFIED = 0; 13 | ENABLED = 1; 14 | DISABLED = 2; 15 | } 16 | } 17 | 18 | message CostInfo { 19 | // Total amount of request units (RU), consumed by the operation. 20 | double consumed_units = 1; 21 | } 22 | 23 | message QuotaExceeded { 24 | bool disk = 1; 25 | } 26 | 27 | // Specifies a point in database time 28 | message VirtualTimestamp { 29 | uint64 plan_step = 1; 30 | uint64 tx_id = 2; 31 | } 32 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_coordination_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Coordination.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Coordination_V1"; 6 | option java_package = "tech.ydb.coordination.v1"; 7 | option java_outer_classname = "CoordinationGrpc"; 8 | option java_multiple_files = true; 9 | 10 | import "protos/ydb_coordination.proto"; 11 | 12 | service CoordinationService { 13 | /** 14 | * Bidirectional stream used to establish a session with a coordination node 15 | * 16 | * Relevant APIs for managing semaphores, distributed locking, creating or 17 | * restoring a previously established session are described using nested 18 | * messages in SessionRequest and SessionResponse. Session is established 19 | * with a specific coordination node (previously created using CreateNode 20 | * below) and semaphores are local to that coordination node. 21 | */ 22 | rpc Session(stream Coordination.SessionRequest) returns (stream Coordination.SessionResponse); 23 | 24 | // Creates a new coordination node 25 | rpc CreateNode(Coordination.CreateNodeRequest) returns (Coordination.CreateNodeResponse); 26 | 27 | // Modifies settings of a coordination node 28 | rpc AlterNode(Coordination.AlterNodeRequest) returns (Coordination.AlterNodeResponse); 29 | 30 | // Drops a coordination node 31 | rpc DropNode(Coordination.DropNodeRequest) returns (Coordination.DropNodeResponse); 32 | 33 | // Describes a coordination node 34 | rpc DescribeNode(Coordination.DescribeNodeRequest) returns (Coordination.DescribeNodeResponse); 35 | } 36 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_discovery.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb.Discovery; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Discovery"; 7 | option java_package = "tech.ydb.discovery"; 8 | option java_outer_classname = "DiscoveryProtos"; 9 | 10 | import "protos/ydb_operation.proto"; 11 | 12 | message ListEndpointsRequest { 13 | string database = 1; 14 | repeated string service = 2; 15 | 16 | // todo: feature flags 17 | } 18 | 19 | message EndpointInfo { 20 | // This is an address (usually fqdn) and port of this node's grpc endpoint 21 | string address = 1; 22 | uint32 port = 2; 23 | float load_factor = 3; 24 | bool ssl = 4; 25 | repeated string service = 5; 26 | string location = 6; 27 | uint32 node_id = 7; 28 | 29 | // Optional ipv4 and/or ipv6 addresses of the endpoint, which clients may 30 | // use instead of a dns name in the address field. 31 | repeated string ip_v4 = 8; 32 | repeated string ip_v6 = 9; 33 | 34 | // Optional value for grpc.ssl_target_name_override option that must be 35 | // used when connecting to this endpoint. This may be specified when an ssl 36 | // endpoint is using certificate chain valid for a balancer hostname, and 37 | // not this specific node hostname. 38 | string ssl_target_name_override = 10; 39 | } 40 | 41 | message ListEndpointsResult { 42 | repeated EndpointInfo endpoints = 1; 43 | string self_location = 2; 44 | } 45 | 46 | message ListEndpointsResponse { 47 | Ydb.Operations.Operation operation = 1; 48 | } 49 | 50 | message WhoAmIRequest { 51 | // Include user groups in response 52 | bool include_groups = 1; 53 | } 54 | 55 | message WhoAmIResult { 56 | // User SID (Security ID) 57 | string user = 1; 58 | // List of group SIDs (Security IDs) for the user 59 | repeated string groups = 2; 60 | } 61 | 62 | message WhoAmIResponse { 63 | Ydb.Operations.Operation operation = 1; 64 | } 65 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_discovery_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Discovery.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Discovery_V1"; 6 | option java_package = "tech.ydb.discovery.v1"; 7 | 8 | import "protos/ydb_discovery.proto"; 9 | 10 | service DiscoveryService { 11 | rpc ListEndpoints(Ydb.Discovery.ListEndpointsRequest) returns (Ydb.Discovery.ListEndpointsResponse); 12 | rpc WhoAmI(Ydb.Discovery.WhoAmIRequest) returns (Ydb.Discovery.WhoAmIResponse); 13 | } 14 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_export.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | import "protos/annotations/validation.proto"; 5 | import "protos/ydb_operation.proto"; 6 | 7 | import "google/protobuf/timestamp.proto"; 8 | 9 | package Ydb.Export; 10 | 11 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Export"; 12 | option java_package = "tech.ydb.export"; 13 | 14 | /// Common 15 | message ExportProgress { 16 | enum Progress { 17 | PROGRESS_UNSPECIFIED = 0; 18 | PROGRESS_PREPARING = 1; 19 | PROGRESS_TRANSFER_DATA = 2; 20 | PROGRESS_DONE = 3; 21 | PROGRESS_CANCELLATION = 4; 22 | PROGRESS_CANCELLED = 5; 23 | } 24 | } 25 | 26 | message ExportItemProgress { 27 | uint32 parts_total = 1; 28 | uint32 parts_completed = 2; 29 | google.protobuf.Timestamp start_time = 3; 30 | google.protobuf.Timestamp end_time = 4; 31 | } 32 | 33 | /// YT 34 | message ExportToYtSettings { 35 | message Item { 36 | // Database path to a table to be exported 37 | string source_path = 1 [(required) = true]; 38 | string destination_path = 2 [(required) = true]; 39 | } 40 | 41 | string host = 1 [(required) = true]; 42 | uint32 port = 2; 43 | string token = 3 [(required) = true]; 44 | repeated Item items = 4 [(size).ge = 1]; 45 | string description = 5 [(length).le = 128]; 46 | uint32 number_of_retries = 6; 47 | bool use_type_v3 = 7; 48 | } 49 | 50 | message ExportToYtResult { 51 | } 52 | 53 | message ExportToYtMetadata { 54 | ExportToYtSettings settings = 1; 55 | ExportProgress.Progress progress = 2; 56 | repeated ExportItemProgress items_progress = 3; 57 | } 58 | 59 | message ExportToYtRequest { 60 | Ydb.Operations.OperationParams operation_params = 1; 61 | ExportToYtSettings settings = 2 [(required) = true]; 62 | } 63 | 64 | message ExportToYtResponse { 65 | // operation.result = ExportToYtResult 66 | // operation.metadata = ExportToYtMetadata 67 | Ydb.Operations.Operation operation = 1; 68 | } 69 | 70 | /// S3 71 | message ExportToS3Settings { 72 | enum Scheme { 73 | UNSPECIFIED = 0; 74 | HTTP = 1; 75 | HTTPS = 2; 76 | } 77 | 78 | enum StorageClass { 79 | STORAGE_CLASS_UNSPECIFIED = 0; 80 | STANDARD = 1; 81 | REDUCED_REDUNDANCY = 2; 82 | STANDARD_IA = 3; 83 | ONEZONE_IA = 4; 84 | INTELLIGENT_TIERING = 5; 85 | GLACIER = 6; 86 | DEEP_ARCHIVE = 7; 87 | OUTPOSTS = 8; 88 | }; 89 | 90 | message Item { 91 | // Database path to a table to be exported 92 | string source_path = 1 [(required) = true]; 93 | 94 | /* Tables are exported to one or more S3 objects. 95 | The object name begins with 'destination_prefix'. 96 | This prefix will be followed by '/data_PartNumber', where 'PartNumber' 97 | represents the index of the part, starting at zero. 98 | */ 99 | string destination_prefix = 2 [(required) = true]; 100 | } 101 | 102 | string endpoint = 1 [(required) = true]; 103 | Scheme scheme = 2; // HTTPS if not specified 104 | string bucket = 3 [(required) = true]; 105 | string access_key = 4 [(required) = true]; 106 | string secret_key = 5 [(required) = true]; 107 | repeated Item items = 6 [(size).ge = 1]; 108 | string description = 7 [(length).le = 128]; 109 | uint32 number_of_retries = 8; 110 | StorageClass storage_class = 9; 111 | 112 | // Codec used to compress data. Codecs are available: 113 | // - zstd. 114 | // - zstd-N, where N is compression level, e.g. zstd-3. 115 | string compression = 10; 116 | 117 | // Region to use in requests 118 | string region = 11; 119 | } 120 | 121 | message ExportToS3Result { 122 | } 123 | 124 | message ExportToS3Metadata { 125 | ExportToS3Settings settings = 1; 126 | ExportProgress.Progress progress = 2; 127 | repeated ExportItemProgress items_progress = 3; 128 | } 129 | 130 | message ExportToS3Request { 131 | Ydb.Operations.OperationParams operation_params = 1; 132 | ExportToS3Settings settings = 2 [(required) = true]; 133 | } 134 | 135 | message ExportToS3Response { 136 | // operation.result = ExportToS3Result 137 | // operation.metadata = ExportToS3Metadata 138 | Ydb.Operations.Operation operation = 1; 139 | } 140 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_export_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Export.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Export_V1"; 6 | option java_package = "tech.ydb.export.v1"; 7 | 8 | import "protos/ydb_export.proto"; 9 | 10 | service ExportService { 11 | 12 | // Exports data to YT. 13 | // Method starts an asynchronous operation that can be cancelled while it is in progress. 14 | rpc ExportToYt(Export.ExportToYtRequest) returns (Export.ExportToYtResponse); 15 | 16 | // Exports data to S3. 17 | // Method starts an asynchronous operation that can be cancelled while it is in progress. 18 | rpc ExportToS3(Export.ExportToS3Request) returns (Export.ExportToS3Response); 19 | } 20 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_formats.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb.Formats; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Formats"; 7 | option java_package = "tech.ydb.formats"; 8 | 9 | message ArrowBatchSettings { 10 | bytes schema = 1; 11 | } 12 | 13 | message CsvSettings { 14 | // Number of rows to skip before CSV data. It should be present only in the first upsert of CSV file. 15 | uint32 skip_rows = 1; 16 | // Fields delimiter in CSV file. It's "," if not set. 17 | bytes delimiter = 2; 18 | // String value that would be interpreted as NULL. 19 | bytes null_value = 3; 20 | // First not skipped line is a CSV header (list of column names). 21 | bool header = 4; 22 | } 23 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_import.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | import "protos/annotations/validation.proto"; 5 | import "protos/ydb_operation.proto"; 6 | 7 | import "google/protobuf/timestamp.proto"; 8 | 9 | package Ydb.Import; 10 | 11 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Import"; 12 | option java_package = "tech.ydb.import_"; 13 | 14 | /// Common 15 | message ImportProgress { 16 | enum Progress { 17 | PROGRESS_UNSPECIFIED = 0; 18 | PROGRESS_PREPARING = 1; 19 | PROGRESS_TRANSFER_DATA = 2; 20 | PROGRESS_BUILD_INDEXES = 3; 21 | PROGRESS_DONE = 4; 22 | PROGRESS_CANCELLATION = 5; 23 | PROGRESS_CANCELLED = 6; 24 | } 25 | } 26 | 27 | message ImportItemProgress { 28 | uint32 parts_total = 1; 29 | uint32 parts_completed = 2; 30 | google.protobuf.Timestamp start_time = 3; 31 | google.protobuf.Timestamp end_time = 4; 32 | } 33 | 34 | /// S3 35 | message ImportFromS3Settings { 36 | enum Scheme { 37 | UNSPECIFIED = 0; 38 | HTTP = 1; 39 | HTTPS = 2; 40 | } 41 | 42 | message Item { 43 | /* YDB tables in S3 are stored in one or more objects (see ydb_export.proto). 44 | The object name begins with 'source_prefix'. 45 | This prefix is followed by: 46 | * '/data_PartNumber', where 'PartNumber' represents the index of the part, starting at zero; 47 | * '/scheme.pb' - object with information about scheme, indexes, etc. 48 | */ 49 | string source_prefix = 1 [(required) = true]; 50 | 51 | // Database path to a table to import to. 52 | string destination_path = 2 [(required) = true]; 53 | } 54 | 55 | string endpoint = 1 [(required) = true]; 56 | Scheme scheme = 2; // HTTPS if not specified 57 | string bucket = 3 [(required) = true]; 58 | string access_key = 4 [(required) = true]; 59 | string secret_key = 5 [(required) = true]; 60 | repeated Item items = 6 [(size).ge = 1]; 61 | string description = 7 [(length).le = 128]; 62 | uint32 number_of_retries = 8; 63 | } 64 | 65 | message ImportFromS3Result { 66 | } 67 | 68 | message ImportFromS3Metadata { 69 | ImportFromS3Settings settings = 1; 70 | ImportProgress.Progress progress = 2; 71 | repeated ImportItemProgress items_progress = 3; 72 | } 73 | 74 | message ImportFromS3Request { 75 | Ydb.Operations.OperationParams operation_params = 1; 76 | ImportFromS3Settings settings = 2 [(required) = true]; 77 | } 78 | 79 | message ImportFromS3Response { 80 | // operation.result = ImportFromS3Result 81 | // operation.metadata = ImportFromS3Metadata 82 | Ydb.Operations.Operation operation = 1; 83 | } 84 | 85 | /// Data 86 | message YdbDumpFormat { 87 | repeated string columns = 1; 88 | } 89 | 90 | message ImportDataResult { 91 | } 92 | 93 | message ImportDataRequest { 94 | Ydb.Operations.OperationParams operation_params = 1; 95 | // Full path to table 96 | string path = 2; 97 | // Data serialized in the selected format. Restrictions: 98 | // - sorted by primary key; 99 | // - all keys must be from the same partition; 100 | // - table has no global secondary indexes; 101 | // - size of serialized data is limited to 8 MB. 102 | bytes data = 3 [(length).le = 8388608]; 103 | oneof format { 104 | // Result of `ydb tools dump` 105 | YdbDumpFormat ydb_dump = 4; 106 | } 107 | } 108 | 109 | message ImportDataResponse { 110 | // operation.result = ImportDataResult 111 | Ydb.Operations.Operation operation = 1; 112 | } 113 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_import_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Import.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Import_V1"; 6 | option java_package = "tech.ydb.import_.v1"; 7 | 8 | import "protos/ydb_import.proto"; 9 | 10 | service ImportService { 11 | 12 | // Imports data from S3. 13 | // Method starts an asynchronous operation that can be cancelled while it is in progress. 14 | rpc ImportFromS3(Import.ImportFromS3Request) returns (Import.ImportFromS3Response); 15 | 16 | // Writes data to a table. 17 | // Method accepts serialized data in the selected format and writes it non-transactionally. 18 | rpc ImportData(Import.ImportDataRequest) returns (Import.ImportDataResponse); 19 | } 20 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_issue_message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb.Issue; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Issue"; 7 | option java_package = "tech.ydb"; 8 | 9 | // IssueMessage is a transport format for ydb/library/yql/public/issue library 10 | message IssueMessage { 11 | message Position { 12 | uint32 row = 1; 13 | uint32 column = 2; 14 | string file = 3; 15 | } 16 | 17 | Position position = 1; 18 | string message = 2; 19 | Position end_position = 3; 20 | uint32 issue_code = 4; 21 | // Severity values from ydb/library/yql/public/issue/protos/issue_severity.proto 22 | // FATAL = 0; 23 | // ERROR = 1; 24 | // WARNING = 2; 25 | // INFO = 3; 26 | uint32 severity = 5; 27 | repeated IssueMessage issues = 6; 28 | } 29 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_monitoring.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb.Monitoring; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Monitoring"; 7 | option java_package = "tech.ydb.monitoring"; 8 | option java_outer_classname = "MonitoringProtos"; 9 | 10 | import "protos/ydb_operation.proto"; 11 | 12 | message StatusFlag { 13 | // Describes the general state of a component. 14 | // From GREEN to RED, where GREEN is good, and RED is bad. 15 | // GREY means that the corresponding status is unknown. 16 | enum Status { 17 | UNSPECIFIED = 0; 18 | GREY = 1; 19 | GREEN = 2; 20 | BLUE = 3; 21 | YELLOW = 4; 22 | ORANGE = 5; 23 | RED = 6; 24 | } 25 | } 26 | 27 | message SelfCheckRequest { 28 | Ydb.Operations.OperationParams operation_params = 1; // basic operation params, including timeout 29 | bool return_verbose_status = 2; // return detailed info about components checked with their statuses 30 | StatusFlag.Status minimum_status = 3; // minimum status of issues to return 31 | uint32 maximum_level = 4; // maximum level of issues to return 32 | } 33 | 34 | message SelfCheckResponse { 35 | // After successfull completion must contain SelfCheckResult. 36 | Ydb.Operations.Operation operation = 1; 37 | } 38 | 39 | message NodeCheckRequest { 40 | Ydb.Operations.OperationParams operation_params = 1; // basic operation params, including timeout 41 | } 42 | 43 | message NodeCheckResponse { 44 | // After successfull completion must contain SelfCheckResult. 45 | Ydb.Operations.Operation operation = 1; 46 | } 47 | 48 | message SelfCheck { 49 | // Describes the result of self-check performed. 50 | enum Result { 51 | UNSPECIFIED = 0; 52 | GOOD = 1; 53 | DEGRADED = 2; 54 | MAINTENANCE_REQUIRED = 3; 55 | EMERGENCY = 4; 56 | } 57 | } 58 | 59 | message StoragePDiskStatus { 60 | string id = 1; 61 | StatusFlag.Status overall = 2; 62 | } 63 | 64 | message StorageVDiskStatus { 65 | string id = 1; 66 | StatusFlag.Status overall = 2; 67 | StatusFlag.Status vdisk_status = 3; 68 | StoragePDiskStatus pdisk = 4; 69 | } 70 | 71 | message StorageGroupStatus { 72 | string id = 1; 73 | StatusFlag.Status overall = 2; 74 | repeated StorageVDiskStatus vdisks = 3; 75 | } 76 | 77 | message StoragePoolStatus { 78 | string id = 1; 79 | StatusFlag.Status overall = 2; 80 | repeated StorageGroupStatus groups = 3; 81 | } 82 | 83 | message StorageStatus { 84 | StatusFlag.Status overall = 1; 85 | repeated StoragePoolStatus pools = 2; 86 | } 87 | 88 | // Describes the state of a tablet group. 89 | message ComputeTabletStatus { 90 | StatusFlag.Status overall = 1; 91 | string type = 2; 92 | string state = 3; 93 | uint32 count = 4; 94 | repeated string id = 5; 95 | } 96 | 97 | message ThreadPoolStatus { 98 | StatusFlag.Status overall = 1; 99 | string name = 2; 100 | float usage = 3; 101 | } 102 | 103 | message LoadAverageStatus { 104 | StatusFlag.Status overall = 1; 105 | float load = 2; 106 | uint32 cores = 3; 107 | } 108 | 109 | message ComputeNodeStatus { 110 | string id = 1; 111 | StatusFlag.Status overall = 2; 112 | repeated ComputeTabletStatus tablets = 3; 113 | repeated ThreadPoolStatus pools = 4; 114 | LoadAverageStatus load = 5; 115 | } 116 | 117 | message ComputeStatus { 118 | StatusFlag.Status overall = 1; 119 | repeated ComputeNodeStatus nodes = 2; 120 | repeated ComputeTabletStatus tablets = 3; 121 | } 122 | 123 | message LocationNode { 124 | uint32 id = 1; 125 | string host = 2; 126 | uint32 port = 3; 127 | } 128 | 129 | message LocationStoragePDisk { 130 | string id = 1; 131 | string path = 2; 132 | } 133 | 134 | message LocationStorageVDisk { 135 | repeated string id = 1; 136 | repeated LocationStoragePDisk pdisk = 2; 137 | } 138 | 139 | message LocationStorageGroup { 140 | repeated string id = 1; 141 | LocationStorageVDisk vdisk = 2; 142 | } 143 | 144 | message LocationStoragePool { 145 | string name = 1; 146 | LocationStorageGroup group = 2; 147 | } 148 | 149 | message LocationStorage { 150 | LocationNode node = 1; 151 | LocationStoragePool pool = 2; 152 | } 153 | 154 | message LocationComputePool { 155 | string name = 1; 156 | } 157 | 158 | message LocationComputeTablet { 159 | string type = 1; 160 | repeated string id = 2; 161 | uint32 count = 3; 162 | } 163 | 164 | message LocationCompute { 165 | LocationNode node = 1; 166 | LocationComputePool pool = 2; 167 | LocationComputeTablet tablet = 3; 168 | } 169 | 170 | message LocationDatabase { 171 | string name = 1; 172 | } 173 | 174 | message Location { 175 | LocationStorage storage = 1; 176 | LocationCompute compute = 2; 177 | LocationDatabase database = 3; 178 | } 179 | 180 | message IssueLog { 181 | string id = 1; 182 | StatusFlag.Status status = 2; 183 | string message = 3; 184 | Location location = 4; 185 | repeated string reason = 5; 186 | string type = 6; 187 | uint32 level = 7; 188 | uint32 listed = 8; 189 | uint32 count = 9; 190 | } 191 | 192 | message DatabaseStatus { 193 | string name = 1; 194 | StatusFlag.Status overall = 2; 195 | StorageStatus storage = 3; 196 | ComputeStatus compute = 4; 197 | } 198 | 199 | message SelfCheckResult { 200 | SelfCheck.Result self_check_result = 1; 201 | repeated IssueLog issue_log = 2; 202 | repeated DatabaseStatus database_status = 3; 203 | } 204 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_monitoring_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Monitoring.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Monitoring_V1"; 6 | option java_package = "tech.ydb.monitoring.v1"; 7 | 8 | import "protos/ydb_monitoring.proto"; 9 | 10 | service MonitoringService { 11 | // Gets the health status of the database. 12 | rpc SelfCheck(Monitoring.SelfCheckRequest) returns (Monitoring.SelfCheckResponse); 13 | // Checks current node health 14 | rpc NodeCheck(Monitoring.NodeCheckRequest) returns (Monitoring.NodeCheckResponse); 15 | } 16 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_operation.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | import "google/protobuf/any.proto"; 5 | import "google/protobuf/duration.proto"; 6 | 7 | import "protos/annotations/validation.proto"; 8 | import "protos/ydb_common.proto"; 9 | import "protos/ydb_issue_message.proto"; 10 | import "protos/ydb_status_codes.proto"; 11 | 12 | package Ydb.Operations; 13 | 14 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Operations"; 15 | option java_package = "tech.ydb"; 16 | option java_outer_classname = "OperationProtos"; 17 | 18 | message OperationParams { 19 | enum OperationMode { 20 | OPERATION_MODE_UNSPECIFIED = 0; 21 | 22 | // Server will only reply once operation is finished (ready=true), and operation object won't be 23 | // accessible after the reply. This is a basic request-response mode. 24 | SYNC = 1; 25 | 26 | ASYNC = 2; 27 | } 28 | 29 | OperationMode operation_mode = 1; 30 | 31 | // Indicates that client is no longer interested in the result of operation after the specified duration 32 | // starting from the time operation arrives at the server. 33 | // Server will try to stop the execution of operation and if no result is currently available the operation 34 | // will receive TIMEOUT status code, which will be sent back to client if it was waiting for the operation result. 35 | // Timeout of operation does not tell anything about its result, it might be completed successfully 36 | // or cancelled on server. 37 | google.protobuf.Duration operation_timeout = 2; 38 | 39 | // Server will try to cancel the operation after the specified duration starting from the time 40 | // the operation arrives at server. 41 | // In case of successful cancellation operation will receive CANCELLED status code, which will be 42 | // sent back to client if it was waiting for the operation result. 43 | // In case when cancellation isn't possible, no action will be performed. 44 | google.protobuf.Duration cancel_after = 3; 45 | 46 | // User-defined labels of operation. 47 | map labels = 4 [(map_key).length.le = 128, (length).le = 128]; 48 | 49 | // If enabled, server will report cost information, if supported by the operation. 50 | // This flag is mostly useful for SYNC operations, to get the cost information in the response. 51 | Ydb.FeatureFlag.Status report_cost_info = 5; 52 | } 53 | 54 | message GetOperationRequest { 55 | string id = 1 [(required) = true]; 56 | } 57 | 58 | message GetOperationResponse { 59 | Operation operation = 1; 60 | } 61 | 62 | message CancelOperationRequest { 63 | string id = 1 [(required) = true]; 64 | } 65 | 66 | message CancelOperationResponse { 67 | StatusIds.StatusCode status = 1; 68 | repeated Ydb.Issue.IssueMessage issues = 2; 69 | } 70 | 71 | message ForgetOperationRequest { 72 | string id = 1 [(required) = true]; 73 | } 74 | 75 | message ForgetOperationResponse { 76 | StatusIds.StatusCode status = 1; 77 | repeated Ydb.Issue.IssueMessage issues = 2; 78 | } 79 | 80 | message ListOperationsRequest { 81 | string kind = 1 [(required) = true]; 82 | uint64 page_size = 2; 83 | string page_token = 3; 84 | } 85 | 86 | message ListOperationsResponse { 87 | StatusIds.StatusCode status = 1; 88 | repeated Ydb.Issue.IssueMessage issues = 2; 89 | repeated Operation operations = 3; 90 | string next_page_token = 4; 91 | } 92 | 93 | message Operation { 94 | // Identifier of the operation, empty value means no active operation object is present (it was forgotten or 95 | // not created in the first place, as in SYNC operation mode). 96 | string id = 1; 97 | 98 | // true - this operation has beed finished (doesn't matter successful or not), 99 | // so Status field has status code, and Result field can contains result data. 100 | // false - this operation still running. You can repeat request using operation Id. 101 | bool ready = 2; 102 | 103 | StatusIds.StatusCode status = 3; 104 | 105 | repeated Ydb.Issue.IssueMessage issues = 4; 106 | // Result data 107 | google.protobuf.Any result = 5; 108 | 109 | google.protobuf.Any metadata = 6; 110 | 111 | // Contains information about the cost of the operation. 112 | // For completed operations, it shows the final cost of the operation. 113 | // For operations in progress, it might indicate the current cost of the operation (if supported). 114 | CostInfo cost_info = 7; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_operation_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Operation.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Operation_V1"; 6 | option java_package = "tech.ydb.operation.v1"; 7 | 8 | import "protos/ydb_operation.proto"; 9 | 10 | // All rpc calls to YDB are allowed to be asynchronous. Response message 11 | // of an rpc call contains Operation structure and OperationService 12 | // is used for polling operation completion. 13 | // 14 | // Operation has a field 'ready' to notify client if operation has been 15 | // completed or not. If result is ready a client has to handle 'result' field, 16 | // otherwise it is expected that client continues polling result via 17 | // GetOperation rpc of OperationService. Polling is made via unique 18 | // operation id provided in 'id' field of Operation. 19 | // 20 | // Note: Currently some operations have synchronous implementation and their result 21 | // is available when response is obtained. But a client must not make any 22 | // assumptions about synchronous or asynchronous nature of any operation and 23 | // be ready to poll operation status. 24 | 25 | service OperationService { 26 | 27 | // Check status for a given operation. 28 | rpc GetOperation(Operations.GetOperationRequest) returns (Operations.GetOperationResponse); 29 | 30 | // Starts cancellation of a long-running operation, 31 | // Clients can use GetOperation to check whether the cancellation succeeded 32 | // or whether the operation completed despite cancellation. 33 | rpc CancelOperation(Operations.CancelOperationRequest) returns (Operations.CancelOperationResponse); 34 | 35 | // Forgets long-running operation. It does not cancel the operation and returns 36 | // an error if operation was not completed. 37 | rpc ForgetOperation(Operations.ForgetOperationRequest) returns (Operations.ForgetOperationResponse); 38 | 39 | // Lists operations that match the specified filter in the request. 40 | rpc ListOperations(Operations.ListOperationsRequest) returns (Operations.ListOperationsResponse); 41 | } 42 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_query_stats.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb.TableStats; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_TableStats"; 7 | option java_package = "tech.ydb"; 8 | 9 | // Describes select, update (insert, upsert, replace) and delete operations 10 | message OperationStats { 11 | uint64 rows = 1; 12 | uint64 bytes = 2; 13 | } 14 | 15 | // Describes all operations on a table 16 | message TableAccessStats { 17 | string name = 1; 18 | reserved 2; // table id 19 | OperationStats reads = 3; 20 | OperationStats updates = 4; 21 | OperationStats deletes = 5; 22 | uint64 partitions_count = 6; 23 | } 24 | 25 | message QueryPhaseStats { 26 | uint64 duration_us = 1; 27 | repeated TableAccessStats table_access = 2; 28 | uint64 cpu_time_us = 3; 29 | uint64 affected_shards = 4; 30 | bool literal_phase = 5; 31 | } 32 | 33 | message CompilationStats { 34 | bool from_cache = 1; 35 | uint64 duration_us = 2; 36 | uint64 cpu_time_us = 3; 37 | } 38 | 39 | message QueryStats { 40 | // A query might have one or more execution phases 41 | repeated QueryPhaseStats query_phases = 1; 42 | CompilationStats compilation = 2; 43 | uint64 process_cpu_time_us = 3; 44 | string query_plan = 4; 45 | string query_ast = 5; 46 | uint64 total_duration_us = 6; 47 | uint64 total_cpu_time_us = 7; 48 | } 49 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_rate_limiter_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.RateLimiter.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_RateLimiter_V1"; 6 | option java_package = "tech.ydb.rate_limiter.v1"; 7 | option java_outer_classname = "RateLimiterGrpc"; 8 | option java_multiple_files = true; 9 | 10 | import "protos/ydb_rate_limiter.proto"; 11 | 12 | // Service that implements distributed rate limiting. 13 | // 14 | // To use rate limiter functionality you need an existing coordination node. 15 | 16 | service RateLimiterService { 17 | // Control plane API 18 | 19 | // Create a new resource in existing coordination node. 20 | rpc CreateResource(CreateResourceRequest) returns (CreateResourceResponse); 21 | 22 | // Update a resource in coordination node. 23 | rpc AlterResource(AlterResourceRequest) returns (AlterResourceResponse); 24 | 25 | // Delete a resource from coordination node. 26 | rpc DropResource(DropResourceRequest) returns (DropResourceResponse); 27 | 28 | // List resources in given coordination node. 29 | rpc ListResources(ListResourcesRequest) returns (ListResourcesResponse); 30 | 31 | // Describe properties of resource in coordination node. 32 | rpc DescribeResource(DescribeResourceRequest) returns (DescribeResourceResponse); 33 | 34 | // Take units for usage of a resource in coordination node. 35 | rpc AcquireResource(AcquireResourceRequest) returns (AcquireResourceResponse); 36 | } 37 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_scheme.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb.Scheme; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Scheme"; 7 | option java_package = "tech.ydb.scheme"; 8 | option java_outer_classname = "SchemeOperationProtos"; 9 | 10 | import "protos/ydb_common.proto"; 11 | import "protos/ydb_operation.proto"; 12 | 13 | // Create directory. 14 | // All intermediate directories must be created 15 | message MakeDirectoryRequest { 16 | Ydb.Operations.OperationParams operation_params = 1; 17 | string path = 2; 18 | } 19 | 20 | message MakeDirectoryResponse { 21 | Ydb.Operations.Operation operation = 1; 22 | } 23 | 24 | // Remove directory 25 | message RemoveDirectoryRequest { 26 | Ydb.Operations.OperationParams operation_params = 1; 27 | string path = 2; 28 | } 29 | 30 | message RemoveDirectoryResponse { 31 | Ydb.Operations.Operation operation = 1; 32 | } 33 | 34 | // List directory 35 | message ListDirectoryRequest { 36 | Ydb.Operations.OperationParams operation_params = 1; 37 | string path = 2; 38 | } 39 | 40 | message ListDirectoryResponse { 41 | // Holds ListDirectoryResult in case of successful call 42 | Ydb.Operations.Operation operation = 1; 43 | } 44 | 45 | message Permissions { 46 | // SID (Security ID) of user or group 47 | string subject = 1; 48 | repeated string permission_names = 2; 49 | } 50 | 51 | message Entry { 52 | enum Type { 53 | TYPE_UNSPECIFIED = 0; 54 | DIRECTORY = 1; 55 | TABLE = 2; 56 | PERS_QUEUE_GROUP = 3; 57 | DATABASE = 4; 58 | RTMR_VOLUME = 5; 59 | BLOCK_STORE_VOLUME = 6; 60 | COORDINATION_NODE = 7; 61 | COLUMN_STORE = 12; 62 | COLUMN_TABLE = 13; 63 | SEQUENCE = 15; 64 | REPLICATION = 16; 65 | TOPIC = 17; 66 | } 67 | 68 | // Name of scheme entry (dir2 of /dir1/dir2) 69 | string name = 1; 70 | // SID (Security ID) of user or group 71 | string owner = 2; 72 | Type type = 5; 73 | repeated Permissions effective_permissions = 6; 74 | repeated Permissions permissions = 7; 75 | 76 | // Size of entry in bytes. Currently filled for: 77 | // - TABLE; 78 | // - DATABASE. 79 | // Empty (zero) in other cases. 80 | uint64 size_bytes = 8; 81 | 82 | // Virtual timestamp when the object was created 83 | VirtualTimestamp created_at = 9; 84 | } 85 | 86 | message ListDirectoryResult { 87 | Entry self = 1; 88 | repeated Entry children = 2; 89 | } 90 | 91 | // Returns information about object with given path 92 | message DescribePathRequest { 93 | Ydb.Operations.OperationParams operation_params = 1; 94 | string path = 2; 95 | } 96 | 97 | message DescribePathResponse { 98 | // Holds DescribePathResult in case of DescribePathResult 99 | Ydb.Operations.Operation operation = 1; 100 | } 101 | 102 | message DescribePathResult { 103 | Entry self = 1; 104 | } 105 | 106 | message PermissionsAction { 107 | oneof action { 108 | // Grant permissions 109 | Permissions grant = 1; 110 | // Revoke permissions 111 | Permissions revoke = 2; 112 | // Rewrite permissions for given subject (last set win in case of multiple set for one subject) 113 | Permissions set = 3; 114 | // New owner for object 115 | string change_owner = 4; 116 | } 117 | } 118 | 119 | // Modify permissions of given object 120 | message ModifyPermissionsRequest { 121 | Ydb.Operations.OperationParams operation_params = 1; 122 | string path = 2; 123 | repeated PermissionsAction actions = 3; 124 | // Clear all permissions on the object for all subjects 125 | bool clear_permissions = 4; 126 | oneof inheritance { 127 | bool interrupt_inheritance = 5; 128 | } 129 | } 130 | 131 | message ModifyPermissionsResponse { 132 | Ydb.Operations.Operation operation = 1; 133 | } 134 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_scheme_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Scheme.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Scheme_V1"; 6 | option java_package = "tech.ydb.scheme.v1"; 7 | 8 | import "protos/ydb_scheme.proto"; 9 | 10 | // Every YDB Database Instance has set of objects organized a tree. 11 | // SchemeService provides some functionality to browse and modify 12 | // this tree. 13 | // 14 | // SchemeService provides a generic tree functionality, to create specific 15 | // objects like YDB Table or Persistent Queue use corresponding services. 16 | 17 | service SchemeService { 18 | 19 | // Make Directory. 20 | rpc MakeDirectory(Scheme.MakeDirectoryRequest) returns (Scheme.MakeDirectoryResponse); 21 | 22 | // Remove Directory. 23 | rpc RemoveDirectory(Scheme.RemoveDirectoryRequest) returns (Scheme.RemoveDirectoryResponse); 24 | 25 | // Returns information about given directory and objects inside it. 26 | rpc ListDirectory(Scheme.ListDirectoryRequest) returns (Scheme.ListDirectoryResponse); 27 | 28 | // Returns information about object with given path. 29 | rpc DescribePath(Scheme.DescribePathRequest) returns (Scheme.DescribePathResponse); 30 | 31 | // Modify permissions. 32 | rpc ModifyPermissions(Scheme.ModifyPermissionsRequest) returns (Scheme.ModifyPermissionsResponse); 33 | } 34 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_scripting.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb.Scripting; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Scripting"; 7 | option java_package = "tech.ydb.scripting"; 8 | option java_outer_classname = "ScriptingProtos"; 9 | 10 | import "protos/ydb_operation.proto"; 11 | import "protos/ydb_value.proto"; 12 | 13 | // TODO: Refactor to ydb_query usage. 14 | import "protos/ydb_table.proto"; 15 | import "protos/ydb_query_stats.proto"; 16 | import "protos/ydb_issue_message.proto"; 17 | import "protos/ydb_status_codes.proto"; 18 | 19 | message ExecuteYqlRequest { 20 | Ydb.Operations.OperationParams operation_params = 1; 21 | string script = 2; 22 | map parameters = 3; 23 | Ydb.Table.QueryStatsCollection.Mode collect_stats = 4; 24 | } 25 | 26 | message ExecuteYqlResponse { 27 | Ydb.Operations.Operation operation = 1; 28 | } 29 | 30 | message ExecuteYqlResult { 31 | repeated Ydb.ResultSet result_sets = 1; 32 | Ydb.TableStats.QueryStats query_stats = 2; 33 | } 34 | 35 | // Response for StreamExecuteYql is a stream of ExecuteYqlPartialResponse messages. 36 | // These responses can contain ExecuteYqlPartialResult messages with 37 | // results (or result parts) for data or scan queries in the script. 38 | // YqlScript can have multiple results (result sets). 39 | // Each result set has an index (starting at 0). 40 | message ExecuteYqlPartialResponse { 41 | StatusIds.StatusCode status = 1; 42 | repeated Ydb.Issue.IssueMessage issues = 2; 43 | ExecuteYqlPartialResult result = 3; 44 | } 45 | 46 | // Contains result set (or a result set part) for one data or scan query in the script. 47 | // One result set can be split into several responses with same result_index. 48 | // Only the final response can contain query stats. 49 | message ExecuteYqlPartialResult { 50 | // Index of current result 51 | uint32 result_set_index = 1; 52 | // Result set (or a result set part) for one data or scan query 53 | Ydb.ResultSet result_set = 2; 54 | Ydb.TableStats.QueryStats query_stats = 3; 55 | } 56 | 57 | message ExplainYqlRequest { 58 | enum Mode { 59 | MODE_UNSPECIFIED = 0; 60 | // PARSE = 1; 61 | VALIDATE = 2; 62 | PLAN = 3; 63 | } 64 | 65 | Ydb.Operations.OperationParams operation_params = 1; 66 | string script = 2; 67 | Mode mode = 3; 68 | } 69 | 70 | message ExplainYqlResponse { 71 | Ydb.Operations.Operation operation = 1; 72 | } 73 | 74 | message ExplainYqlResult { 75 | map parameters_types = 1; 76 | string plan = 2; 77 | } 78 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_scripting_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Scripting.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Scripting_V1"; 6 | option java_package = "tech.ydb.scripting.v1"; 7 | 8 | import "protos/ydb_scripting.proto"; 9 | 10 | service ScriptingService { 11 | rpc ExecuteYql(Scripting.ExecuteYqlRequest) returns (Scripting.ExecuteYqlResponse); 12 | 13 | // Executes yql request with streaming result. 14 | rpc StreamExecuteYql(Scripting.ExecuteYqlRequest) returns (stream Scripting.ExecuteYqlPartialResponse); 15 | 16 | rpc ExplainYql(Scripting.ExplainYqlRequest) returns (Scripting.ExplainYqlResponse); 17 | } 18 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_status_codes.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"; 6 | option java_package = "tech.ydb"; 7 | option java_outer_classname = "StatusCodesProtos"; 8 | 9 | message StatusIds { 10 | // reserved range [400000, 400999] 11 | enum StatusCode { 12 | STATUS_CODE_UNSPECIFIED = 0; 13 | SUCCESS = 400000; 14 | BAD_REQUEST = 400010; 15 | UNAUTHORIZED = 400020; 16 | INTERNAL_ERROR = 400030; 17 | ABORTED = 400040; 18 | UNAVAILABLE = 400050; 19 | OVERLOADED = 400060; 20 | SCHEME_ERROR = 400070; 21 | GENERIC_ERROR = 400080; 22 | TIMEOUT = 400090; 23 | BAD_SESSION = 400100; 24 | PRECONDITION_FAILED = 400120; 25 | ALREADY_EXISTS = 400130; 26 | NOT_FOUND = 400140; 27 | SESSION_EXPIRED = 400150; 28 | CANCELLED = 400160; 29 | UNDETERMINED = 400170; 30 | UNSUPPORTED = 400180; 31 | SESSION_BUSY = 400190; 32 | } 33 | // reserved range [401000, 402999] for internal client status 34 | } 35 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_table_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package Ydb.Table.V1; 4 | 5 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Table_V1"; 6 | option java_package = "tech.ydb.table.v1"; 7 | 8 | import "protos/ydb_table.proto"; 9 | 10 | service TableService { 11 | 12 | // Create new session. Implicit session creation is forbidden, 13 | // so user must create new session before execute any query, 14 | // otherwise BAD_SESSION status will be returned. 15 | // Simultaneous execution of requests are forbiden. 16 | // Sessions are volatile, can be invalidated by server, for example in case 17 | // of fatal errors. All requests with this session will fail with BAD_SESSION status. 18 | // So, client must be able to handle BAD_SESSION status. 19 | rpc CreateSession(Table.CreateSessionRequest) returns (Table.CreateSessionResponse); 20 | 21 | // Ends a session, releasing server resources associated with it. 22 | rpc DeleteSession(Table.DeleteSessionRequest) returns (Table.DeleteSessionResponse); 23 | 24 | // Idle sessions can be kept alive by calling KeepAlive periodically. 25 | rpc KeepAlive(Table.KeepAliveRequest) returns (Table.KeepAliveResponse); 26 | 27 | // Creates new table. 28 | rpc CreateTable(Table.CreateTableRequest) returns (Table.CreateTableResponse); 29 | 30 | // Drop table. 31 | rpc DropTable(Table.DropTableRequest) returns (Table.DropTableResponse); 32 | 33 | // Modifies schema of given table. 34 | rpc AlterTable(Table.AlterTableRequest) returns (Table.AlterTableResponse); 35 | 36 | // Creates copy of given table. 37 | rpc CopyTable(Table.CopyTableRequest) returns (Table.CopyTableResponse); 38 | 39 | // Creates consistent copy of given tables. 40 | rpc CopyTables(Table.CopyTablesRequest) returns (Table.CopyTablesResponse); 41 | 42 | // Creates consistent move of given tables. 43 | rpc RenameTables(Table.RenameTablesRequest) returns (Table.RenameTablesResponse); 44 | 45 | // Returns information about given table (metadata). 46 | rpc DescribeTable(Table.DescribeTableRequest) returns (Table.DescribeTableResponse); 47 | 48 | // Explains data query. 49 | // SessionId of previously created session must be provided. 50 | rpc ExplainDataQuery(Table.ExplainDataQueryRequest) returns (Table.ExplainDataQueryResponse); 51 | 52 | // Prepares data query, returns query id. 53 | // SessionId of previously created session must be provided. 54 | rpc PrepareDataQuery(Table.PrepareDataQueryRequest) returns (Table.PrepareDataQueryResponse); 55 | 56 | // Executes data query. 57 | // SessionId of previously created session must be provided. 58 | rpc ExecuteDataQuery(Table.ExecuteDataQueryRequest) returns (Table.ExecuteDataQueryResponse); 59 | 60 | // Executes scheme query. 61 | // SessionId of previously created session must be provided. 62 | rpc ExecuteSchemeQuery(Table.ExecuteSchemeQueryRequest) returns (Table.ExecuteSchemeQueryResponse); 63 | 64 | // Begins new transaction. 65 | rpc BeginTransaction(Table.BeginTransactionRequest) returns (Table.BeginTransactionResponse); 66 | 67 | // Commits specified active transaction. 68 | rpc CommitTransaction(Table.CommitTransactionRequest) returns (Table.CommitTransactionResponse); 69 | 70 | // Performs a rollback of the specified active transaction. 71 | rpc RollbackTransaction(Table.RollbackTransactionRequest) returns (Table.RollbackTransactionResponse); 72 | 73 | // Describe supported table options. 74 | rpc DescribeTableOptions(Table.DescribeTableOptionsRequest) returns (Table.DescribeTableOptionsResponse); 75 | 76 | // Streaming read table 77 | rpc StreamReadTable(Table.ReadTableRequest) returns (stream Table.ReadTableResponse); 78 | 79 | // Upserts a batch of rows non-transactionally. 80 | // Returns success only when all rows were successfully upserted. In case of an error some rows might 81 | // be upserted and some might not. 82 | rpc BulkUpsert(Table.BulkUpsertRequest) returns (Table.BulkUpsertResponse); 83 | 84 | // Executes scan query with streaming result. 85 | rpc StreamExecuteScanQuery(Table.ExecuteScanQueryRequest) returns (stream Table.ExecuteScanQueryPartialResponse); 86 | } 87 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver.Proto/protos/ydb_topic_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_enable_arenas = true; 3 | 4 | package Ydb.Topic.V1; 5 | 6 | option go_package = "github.com/ydb-platform/ydb-go-genproto/Ydb_Topic_V1"; 7 | option java_package = "tech.ydb.topic.v1"; 8 | 9 | import "protos/ydb_topic.proto"; 10 | 11 | service TopicService { 12 | // Create Write Session 13 | // Pipeline example: 14 | // client server 15 | // InitRequest(Topic, MessageGroupID, ...) 16 | // ----------------> 17 | // InitResponse(Partition, MaxSeqNo, ...) 18 | // <---------------- 19 | // WriteRequest(data1, seqNo1) 20 | // ----------------> 21 | // WriteRequest(data2, seqNo2) 22 | // ----------------> 23 | // WriteResponse(seqNo1, offset1, ...) 24 | // <---------------- 25 | // WriteRequest(data3, seqNo3) 26 | // ----------------> 27 | // WriteResponse(seqNo2, offset2, ...) 28 | // <---------------- 29 | // [something went wrong] (status != SUCCESS, issues not empty) 30 | // <---------------- 31 | rpc StreamWrite(stream StreamWriteMessage.FromClient) returns (stream StreamWriteMessage.FromServer); 32 | 33 | 34 | // Create Read Session 35 | // Pipeline: 36 | // client server 37 | // InitRequest(Topics, ClientId, ...) 38 | // ----------------> 39 | // InitResponse(SessionId) 40 | // <---------------- 41 | // ReadRequest 42 | // ----------------> 43 | // ReadRequest 44 | // ----------------> 45 | // StartPartitionSessionRequest(Topic1, Partition1, PartitionSessionID1, ...) 46 | // <---------------- 47 | // StartPartitionSessionRequest(Topic2, Partition2, PartitionSessionID2, ...) 48 | // <---------------- 49 | // StartPartitionSessionResponse(PartitionSessionID1, ...) 50 | // client must respond with this message to actually start recieving data messages from this partition 51 | // ----------------> 52 | // StopPartitionSessionRequest(PartitionSessionID1, ...) 53 | // <---------------- 54 | // StopPartitionSessionResponse(PartitionSessionID1, ...) 55 | // only after this response server will give this parittion to other session. 56 | // ----------------> 57 | // StartPartitionSessionResponse(PartitionSession2, ...) 58 | // ----------------> 59 | // ReadResponse(data, ...) 60 | // <---------------- 61 | // CommitRequest(PartitionCommit1, ...) 62 | // ----------------> 63 | // CommitResponse(PartitionCommitAck1, ...) 64 | // <---------------- 65 | // [something went wrong] (status != SUCCESS, issues not empty) 66 | // <---------------- 67 | rpc StreamRead(stream StreamReadMessage.FromClient) returns (stream StreamReadMessage.FromServer); 68 | 69 | 70 | // Create topic command. 71 | rpc CreateTopic(CreateTopicRequest) returns (CreateTopicResponse); 72 | 73 | // Describe topic command. 74 | rpc DescribeTopic(DescribeTopicRequest) returns (DescribeTopicResponse); 75 | 76 | // Describe topic's consumer command. 77 | rpc DescribeConsumer(DescribeConsumerRequest) returns (DescribeConsumerResponse); 78 | 79 | // Alter topic command. 80 | rpc AlterTopic(AlterTopicRequest) returns (AlterTopicResponse); 81 | 82 | // Drop topic command. 83 | rpc DropTopic(DropTopicRequest) returns (DropTopicResponse); 84 | } 85 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Common.cs: -------------------------------------------------------------------------------- 1 | using Ydb.Table; 2 | 3 | namespace Yandex.Ydb.Driver; 4 | 5 | public static class Common 6 | { 7 | public static readonly TransactionControl DefaultTxControl = new() 8 | { 9 | BeginTx = new TransactionSettings 10 | { 11 | SerializableReadWrite = new SerializableModeSettings() 12 | }, 13 | CommitTx = true 14 | }; 15 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Credentials/DefaultCredentialsProvider.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Cloud.Credentials; 2 | 3 | namespace Yandex.Ydb.Driver.Credentials; 4 | 5 | public class DefaultCredentialsProvider : ICredentialsProvider 6 | { 7 | public string GetToken() => string.Empty; 8 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Credentials/ServiceAccountTokenProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using Yandex.Cloud.Credentials; 3 | using Yandex.Cloud.SDK.IamJwtCredentialsProviderExtension; 4 | 5 | namespace Yandex.Ydb.Driver.Credentials; 6 | 7 | public class ServiceAccountTokenProvider : ICredentialsProvider 8 | { 9 | //TODO: Recreate own JwtCredProvider if issue will not be resolved, see https://github.com/RVShershnev/Yandex.Cloud.SDK.IamJwtCredentialsProviderExtension/issues/1 10 | private readonly IamJwtCredentialsProvider _provider; 11 | 12 | public ServiceAccountTokenProvider(string serviceAccountId, string keyId, string pemCert) 13 | { 14 | _provider = new IamJwtCredentialsProvider(serviceAccountId, keyId, pemCert); 15 | } 16 | 17 | /// 18 | /// Constructs new ServiceAccountTokenProvider 19 | /// 20 | /// Full path to .json file with private and public keys 21 | public ServiceAccountTokenProvider(string pathToFile) 22 | { 23 | var reader = File.OpenText(pathToFile); 24 | var keyJson = JsonDocument.Parse(reader.ReadToEnd()); 25 | _provider = new IamJwtCredentialsProvider( 26 | keyJson.RootElement.GetProperty("service_account_id").GetString()!, 27 | keyJson.RootElement.GetProperty("id").GetString()!, 28 | keyJson.RootElement.GetProperty("private_key").GetString()! 29 | ); 30 | } 31 | 32 | public string GetToken() 33 | { 34 | return _provider.GetToken(); 35 | } 36 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Helpers/TaskHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Runtime.ExceptionServices; 3 | 4 | namespace Yandex.Ydb.Driver.Helpers; 5 | 6 | internal static class TaskHelper 7 | { 8 | /// 9 | /// Call this method only for the task which is not async in any execution path 10 | /// 11 | internal static void WaitNonAsyncTask(ValueTask task) 12 | { 13 | try 14 | { 15 | task.AsTask().Wait(); 16 | } 17 | catch (AggregateException aggrEx) 18 | { 19 | if (aggrEx.InnerExceptions.Count == 1) 20 | ExceptionDispatchInfo.Capture(aggrEx.InnerExceptions[0]).Throw(); 21 | 22 | throw; 23 | } 24 | } 25 | 26 | /// 27 | /// Call this method only for the task which is not async in any execution path 28 | /// 29 | internal static T WaitNonAsyncTask(ValueTask task) 30 | { 31 | try 32 | { 33 | return task.Result; 34 | } 35 | catch (AggregateException aggrEx) 36 | { 37 | if (aggrEx.InnerExceptions.Count == 1) 38 | ExceptionDispatchInfo.Capture(aggrEx.InnerExceptions[0]).Throw(); 39 | 40 | throw; 41 | } 42 | } 43 | 44 | internal static T WaitSynchronously(Func> taskFactory) 45 | { 46 | if (taskFactory == null) 47 | throw new ArgumentNullException(nameof(taskFactory)); 48 | 49 | var innerTask = WaitInternal(taskFactory); 50 | try 51 | { 52 | var result = innerTask.Result; 53 | return result; 54 | } 55 | catch (AggregateException aggrEx) 56 | { 57 | if (aggrEx.InnerExceptions.Count == 1) 58 | ExceptionDispatchInfo.Capture(aggrEx.InnerExceptions[0]).Throw(); 59 | 60 | throw; 61 | } 62 | } 63 | 64 | internal static void WaitSynchronously([NotNull] Func taskFactory) 65 | { 66 | if (taskFactory == null) 67 | throw new ArgumentNullException(nameof(taskFactory)); 68 | 69 | var innerTask = WaitInternal(taskFactory); 70 | try 71 | { 72 | innerTask.Wait(); 73 | } 74 | catch (AggregateException aggrEx) 75 | { 76 | if (aggrEx.InnerExceptions.Count == 1) 77 | ExceptionDispatchInfo.Capture(aggrEx.InnerExceptions[0]).Throw(); 78 | 79 | throw; 80 | } 81 | } 82 | 83 | private static async Task WaitInternal([NotNull] Func> taskFactory) 84 | { 85 | return await Task.Run(async () => await taskFactory().ConfigureAwait(false)).ConfigureAwait(false); 86 | } 87 | 88 | private static async Task WaitInternal([NotNull] Func taskFactory) 89 | { 90 | await Task.Run(async () => await taskFactory().ConfigureAwait(false)).ConfigureAwait(false); 91 | } 92 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Helpers/ThrowHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace Yandex.Ydb.Driver.Helpers; 4 | 5 | public static class ThrowHelper 6 | { 7 | [DoesNotReturn] 8 | public static void ThrowDriverException(Exception exception, string? msg = null) 9 | { 10 | throw new YdbDriverException(msg, exception); 11 | } 12 | 13 | [DoesNotReturn] 14 | public static void ThrowUnsupported(string msg) 15 | { 16 | ThrowDriverException(new NotSupportedException(msg)); 17 | } 18 | 19 | [DoesNotReturn] 20 | public static void ThrowNullException(string param) 21 | { 22 | ThrowDriverException(new ArgumentNullException(param)); 23 | } 24 | 25 | [DoesNotReturn] 26 | public static void ThrowObjectDisposedException(string? fullName) 27 | { 28 | throw new ObjectDisposedException(fullName); 29 | } 30 | 31 | [DoesNotReturn] 32 | public static void InvalidDataException(string msg) 33 | { 34 | ThrowDriverException(new InvalidDataException(msg)); 35 | } 36 | 37 | [DoesNotReturn] 38 | public static void FileNotFound(string msg, string filename) 39 | { 40 | ThrowDriverException(new FileNotFoundException(msg, filename)); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/ISessionPool.cs: -------------------------------------------------------------------------------- 1 | namespace Yandex.Ydb.Driver; 2 | 3 | internal interface ISessionPool : IDisposable 4 | { 5 | internal void Return(string sessionId); 6 | internal ValueTask GetSession(string database); 7 | 8 | internal Task Initialize(string database); 9 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/IYdbConnection.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | 3 | namespace Yandex.Ydb.Driver; 4 | 5 | internal interface IYdbConnection : IDbConnection 6 | { 7 | internal YdbConnector GetBoundConnector(); 8 | 9 | internal string GetSessionId(); 10 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/IYdbConnector.cs: -------------------------------------------------------------------------------- 1 | namespace Yandex.Ydb.Driver; 2 | 3 | public interface IYdbConnector 4 | { 5 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/IYdbDataSourceBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Yandex.Ydb.Driver; 2 | 3 | public interface IYdbDataSourceBuilder 4 | { 5 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/IYdbSimpleTypeHandler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Internal.TypeHandling; 2 | 3 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers; 4 | 5 | public interface IYdbSimpleTypeHandler : IYdbTypeHandler 6 | { 7 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/BoolHandler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Ydb; 3 | 4 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 5 | 6 | public sealed class BoolHandler : YdbPrimitiveTypeHandler 7 | { 8 | public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) 9 | { 10 | return value.GetBool(); 11 | } 12 | 13 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 14 | new() 15 | { 16 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Bool 17 | }; 18 | 19 | protected override void WriteAsObject(object value, Value dest) 20 | { 21 | dest.BoolValue = Convert.ToBoolean(value); 22 | } 23 | 24 | public override void Write(byte value, Value dest) 25 | { 26 | dest.BoolValue = Convert.ToBoolean(value); 27 | } 28 | 29 | public override void Write(bool value, Value dest) 30 | { 31 | dest.BoolValue = Convert.ToBoolean(value); 32 | } 33 | 34 | public override void Write(int value, Value dest) 35 | { 36 | dest.BoolValue = Convert.ToBoolean(value); 37 | } 38 | 39 | public override void Write(long value, Value dest) 40 | { 41 | dest.BoolValue = Convert.ToBoolean(value); 42 | } 43 | 44 | public override void Write(sbyte value, Value dest) 45 | { 46 | dest.BoolValue = Convert.ToBoolean(value); 47 | } 48 | 49 | public override void Write(short value, Value dest) 50 | { 51 | dest.BoolValue = Convert.ToBoolean(value); 52 | } 53 | 54 | public override void Write(string value, Value dest) 55 | { 56 | dest.BoolValue = Convert.ToBoolean(value); 57 | } 58 | 59 | public override void Write(uint value, Value dest) 60 | { 61 | dest.BoolValue = Convert.ToBoolean(value); 62 | } 63 | 64 | public override void Write(ulong value, Value dest) 65 | { 66 | dest.BoolValue = Convert.ToBoolean(value); 67 | } 68 | 69 | public override void Write(ushort value, Value dest) 70 | { 71 | dest.BoolValue = Convert.ToBoolean(value); 72 | } 73 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/ContainerHandlerBase.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Internal.TypeMapping; 2 | using Ydb; 3 | 4 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 5 | 6 | public abstract class ContainerHandlerBase : YdbTypeHandler, IContainerHandler 7 | { 8 | protected TypeMapper? Mapper; 9 | 10 | public void SetMapper(TypeMapper mapper) 11 | { 12 | Mapper = mapper; 13 | } 14 | 15 | public abstract TAny ReadContainerAs(Value value, FieldDescription? fieldDescription); 16 | public abstract void WriteContainer(TAny value, Value dest); 17 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/DateOnlyHandler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Yandex.Ydb.Driver.Internal.TypeHandling; 3 | using Ydb; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class DateOnlyHandler : YdbTypeHandler, 8 | IYdbSimpleTypeHandler, IYdbSimpleTypeHandler 9 | { 10 | public override DateTime Read(Value value, FieldDescription? fieldDescription = null) 11 | { 12 | return DateTimeOffset.UnixEpoch.AddDays(value.GetUInt32()).Date; 13 | } 14 | 15 | public void Write(string value, Value dest) 16 | { 17 | throw new NotImplementedException(); 18 | } 19 | 20 | public override void Write(DateTime value, Value dest) 21 | { 22 | dest.Uint32Value = (uint)(value - DateTimeOffset.UnixEpoch).TotalDays; 23 | } 24 | 25 | string IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 26 | { 27 | return DateTimeOffset.UnixEpoch.AddDays(value.GetUInt32()).Date.ToString("dd.MM.yyyy"); 28 | } 29 | 30 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 31 | new() 32 | { 33 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Date 34 | }; 35 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/DateTimeHandler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class DateTimeHandler : YdbTypeHandler, IYdbSimpleTypeHandler 8 | { 9 | public override DateTime Read(Value value, FieldDescription? fieldDescription = null) 10 | { 11 | return DateTimeOffset.FromUnixTimeSeconds(value.GetInt32()).DateTime; 12 | } 13 | 14 | public override void Write(DateTime value, Value dest) 15 | { 16 | dest.Int64Value = new DateTimeOffset(value).ToUnixTimeSeconds(); 17 | } 18 | 19 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 20 | new() 21 | { 22 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Datetime 23 | }; 24 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/DecimalHandler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Internal.TypeHandling; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class DecimalHandler : YdbTypeHandler, IYdbSimpleTypeHandler, IYdbTypeHandler 8 | { 9 | public override decimal Read(Value value, FieldDescription? fieldDescription = null) 10 | { 11 | var decimalType = fieldDescription!.Type.DecimalType; 12 | return decimal.Round(Convert.ToDecimal(value.Low128) / ((ulong)Math.Pow(10, decimalType.Scale)), 13 | (int)decimalType.Precision); 14 | } 15 | 16 | public override void Write(decimal value, Value dest) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 22 | new() 23 | { 24 | DecimalType = new DecimalType() 25 | { 26 | //TODO: Add here values 27 | } 28 | }; 29 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/DictionaryHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Diagnostics; 3 | using Ydb; 4 | using Type = Ydb.Type; 5 | 6 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 7 | 8 | public sealed class DictionaryHandler : ContainerHandlerBase 9 | { 10 | public override IDictionary Read(Value value, FieldDescription? fieldDescription = null) 11 | { 12 | var keyType = fieldDescription.Type.DictType.Key; 13 | var valueType = fieldDescription.Type.DictType.Payload; 14 | 15 | var keyHandler = Mapper.ResolveByYdbType(keyType); 16 | var valueHandler = Mapper.ResolveByYdbType(valueType); 17 | 18 | var dictType = typeof(Dictionary<,>).MakeGenericType(keyHandler.GetFieldType(), valueHandler.GetFieldType()); 19 | var dict = (IDictionary)Activator.CreateInstance(dictType)!; 20 | 21 | foreach (var item in value.Pairs) 22 | { 23 | var key = item.Key; 24 | var payload = item.Payload; 25 | 26 | dict.Add(keyHandler.ReadAsObject(key)!, valueHandler.ReadAsObject(payload)); 27 | } 28 | 29 | return dict; 30 | } 31 | 32 | public override void Write(IDictionary value, Value dest) 33 | { 34 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 35 | 36 | YdbTypeHandler? keyHandler = null; 37 | YdbTypeHandler? valueHandler = null; 38 | foreach (DictionaryEntry kv in value) 39 | { 40 | keyHandler ??= Mapper.ResolveByValue(kv.Key); 41 | valueHandler ??= Mapper.ResolveByValue(kv.Value); 42 | 43 | var key = new Value(); 44 | var val = new Value(); 45 | 46 | keyHandler.Write(kv.Key, key); 47 | valueHandler.Write(kv.Value, val); 48 | 49 | dest.Pairs.Add(new ValuePair() 50 | { 51 | Key = key, 52 | Payload = val 53 | }); 54 | } 55 | } 56 | 57 | protected override Type GetYdbTypeInternal(TDefault? value) where TDefault : default 58 | { 59 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 60 | 61 | var type = typeof(TDefault); 62 | var key = type.GetGenericArguments()[0]; 63 | var payload = type.GetGenericArguments()[1]; 64 | 65 | return new global::Ydb.Type 66 | { 67 | DictType = new DictType() 68 | { 69 | Key = Mapper.ResolveByClrType(key).GetYdbType(value), 70 | Payload = Mapper.ResolveByClrType(payload).GetYdbType(value), 71 | } 72 | }; 73 | } 74 | 75 | public override TAny ReadContainerAs(Value value, FieldDescription? fieldDescription) 76 | { 77 | var dictType = typeof(TAny); 78 | var genericArguments = dictType.GetGenericArguments(); 79 | 80 | var keyType = genericArguments[0]; 81 | var valueType = genericArguments[1]; 82 | 83 | var keyHandler = Mapper.ResolveByClrType(keyType); 84 | var valueHandler = Mapper.ResolveByClrType(valueType); 85 | 86 | var dict = (IDictionary)Activator.CreateInstance(dictType)!; 87 | 88 | foreach (var item in value.Pairs) 89 | { 90 | var key = item.Key; 91 | var payload = item.Payload; 92 | 93 | dict.Add(keyHandler.ReadAsObject(key)!, valueHandler.ReadAsObject(payload)); 94 | } 95 | 96 | return (TAny)dict; 97 | } 98 | 99 | public override void WriteContainer(TAny value, Value dest) 100 | { 101 | Write((value as IDictionary)!, dest); 102 | } 103 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/DoubleHandler.cs: -------------------------------------------------------------------------------- 1 | using Ydb; 2 | using Type = Ydb.Type; 3 | 4 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 5 | 6 | public sealed class DoubleHandler : YdbTypeHandler, IYdbSimpleTypeHandler 7 | { 8 | public override double Read(Value value, FieldDescription? fieldDescription = null) 9 | { 10 | return value.DoubleValue; 11 | } 12 | 13 | public override void Write(double value, Value dest) 14 | { 15 | dest.DoubleValue = value; 16 | } 17 | 18 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 19 | new() 20 | { 21 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Double 22 | }; 23 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/FloatHandler.cs: -------------------------------------------------------------------------------- 1 | using Ydb; 2 | using Type = Ydb.Type; 3 | 4 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 5 | 6 | public sealed class FloatHandler : YdbTypeHandler, IYdbSimpleTypeHandler 7 | { 8 | public override float Read(Value value, FieldDescription? fieldDescription = null) 9 | { 10 | return value.FloatValue; 11 | } 12 | 13 | public override void Write(float value, Value dest) 14 | { 15 | dest.FloatValue = value; 16 | } 17 | 18 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 19 | new() 20 | { 21 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Float 22 | }; 23 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/GuidHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | // public sealed class GuidHandler : YdbPrimitiveTypeHandler 8 | // { 9 | // public override void Write(byte value, Value dest) => throw new NotSupportedException(); 10 | // public override void Write(bool value, Value dest) => throw new NotSupportedException(); 11 | // public override void Write(int value, Value dest) => throw new NotSupportedException(); 12 | // public override void Write(long value, Value dest) => throw new NotSupportedException(); 13 | // public override void Write(sbyte value, Value dest) => throw new NotSupportedException(); 14 | // public override void Write(short value, Value dest) => throw new NotSupportedException(); 15 | // public override void Write(string value, Value dest) => throw new NotSupportedException(); 16 | // public override void Write(uint value, Value dest) => throw new NotSupportedException(); 17 | // public override void Write(ulong value, Value dest) => throw new NotSupportedException(); 18 | // public override void Write(ushort value, Value dest) => throw new NotSupportedException(); 19 | // 20 | // public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) => 21 | // throw new NotSupportedException(); 22 | // } 23 | 24 | public sealed class GuidHandler : YdbTypeHandler 25 | { 26 | private static GuidConverter _converter; 27 | 28 | private static (long, long) FastGuidToLongs(Guid guid) 29 | { 30 | _converter.Guid = guid; 31 | return (_converter.Long1, _converter.Long2); 32 | } 33 | 34 | private static Guid FastLongsToGuid(long a, long b) 35 | { 36 | _converter.Long1 = a; 37 | _converter.Long2 = b; 38 | return _converter.Guid; 39 | } 40 | 41 | public override Guid Read(Value value, FieldDescription? fieldDescription = null) 42 | { 43 | var guid = FastLongsToGuid((long)value.Low128, (long)value.High128); 44 | return guid; 45 | } 46 | 47 | public override void Write(Guid value, Value dest) 48 | { 49 | var (low, high) = FastGuidToLongs(value); 50 | dest.Low128 = (ulong)low; 51 | dest.High128 = (ulong)high; 52 | } 53 | 54 | [StructLayout(LayoutKind.Explicit)] 55 | private struct GuidConverter 56 | { 57 | [FieldOffset(0)] public readonly decimal Decimal; 58 | [FieldOffset(0)] public Guid Guid; 59 | [FieldOffset(0)] public long Long1; 60 | [FieldOffset(8)] public long Long2; 61 | } 62 | 63 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 64 | new() 65 | { 66 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Uuid 67 | }; 68 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/IContainerHandler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Internal.TypeMapping; 2 | using Ydb; 3 | 4 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 5 | 6 | public interface IContainerHandler 7 | { 8 | void SetMapper(TypeMapper mapper); 9 | TAny ReadContainerAs(Value value, FieldDescription? fieldDescription); 10 | void WriteContainer(TAny value, Value dest); 11 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/Int16Handler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Ydb; 3 | 4 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 5 | 6 | public sealed class Int16Handler : YdbPrimitiveTypeHandler 7 | { 8 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 9 | new() 10 | { 11 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Int16 12 | }; 13 | 14 | protected override void WriteAsObject(object value, Value dest) 15 | { 16 | dest.Int32Value = Convert.ToInt16(value); 17 | } 18 | 19 | public override void Write(byte value, Value dest) 20 | { 21 | dest.Int32Value = Convert.ToInt16(value); 22 | } 23 | 24 | public override void Write(bool value, Value dest) 25 | { 26 | dest.Int32Value = Convert.ToInt16(value); 27 | } 28 | 29 | public override void Write(int value, Value dest) 30 | { 31 | dest.Int32Value = Convert.ToInt16(value); 32 | } 33 | 34 | public override void Write(long value, Value dest) 35 | { 36 | dest.Int32Value = Convert.ToInt16(value); 37 | } 38 | 39 | public override void Write(sbyte value, Value dest) 40 | { 41 | dest.Int32Value = Convert.ToInt16(value); 42 | } 43 | 44 | public override void Write(short value, Value dest) 45 | { 46 | dest.Int32Value = Convert.ToInt16(value); 47 | } 48 | 49 | public override void Write(string value, Value dest) 50 | { 51 | dest.Int32Value = Convert.ToInt16(value); 52 | } 53 | 54 | public override void Write(uint value, Value dest) 55 | { 56 | dest.Int32Value = Convert.ToInt16(value); 57 | } 58 | 59 | public override void Write(ulong value, Value dest) 60 | { 61 | dest.Int32Value = Convert.ToInt16(value); 62 | } 63 | 64 | public override void Write(ushort value, Value dest) 65 | { 66 | dest.Int32Value = Convert.ToInt16(value); 67 | } 68 | 69 | public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) 70 | { 71 | return value.GetInt16(); 72 | } 73 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/Int32Handler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class Int32Handler : YdbPrimitiveTypeHandler 8 | { 9 | public override void Write(byte value, Value dest) 10 | { 11 | dest.Int32Value = value; 12 | } 13 | 14 | protected override void WriteAsObject(object value, Value dest) 15 | { 16 | dest.Int32Value = Convert.ToInt32(value); 17 | } 18 | 19 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 20 | new() 21 | { 22 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Int32 23 | }; 24 | 25 | public override void Write(bool value, Value dest) 26 | { 27 | dest.Int32Value = Convert.ToInt32(value); 28 | } 29 | 30 | public override void Write(int value, Value dest) 31 | { 32 | dest.Int32Value = value; 33 | } 34 | 35 | public override void Write(long value, Value dest) 36 | { 37 | dest.Int32Value = Convert.ToInt32(value); 38 | } 39 | 40 | public override void Write(sbyte value, Value dest) 41 | { 42 | dest.Int32Value = value; 43 | } 44 | 45 | public override void Write(short value, Value dest) 46 | { 47 | dest.Int32Value = value; 48 | } 49 | 50 | public override void Write(string value, Value dest) 51 | { 52 | dest.Int32Value = Convert.ToInt32(value); 53 | } 54 | 55 | public override void Write(uint value, Value dest) 56 | { 57 | dest.Int32Value = Convert.ToInt32(value); 58 | } 59 | 60 | public override void Write(ulong value, Value dest) 61 | { 62 | dest.Int32Value = Convert.ToInt32(value); 63 | } 64 | 65 | public override void Write(ushort value, Value dest) 66 | { 67 | dest.Int32Value = Convert.ToInt32(value); 68 | } 69 | 70 | public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) 71 | { 72 | return value.GetInt32(); 73 | } 74 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/Int64Handler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class Int64Handler : YdbPrimitiveTypeHandler 8 | { 9 | public override void Write(byte value, Value dest) 10 | { 11 | dest.Int64Value = Convert.ToInt64(value); 12 | } 13 | 14 | protected override Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 15 | new() 16 | { 17 | TypeId = Type.Types.PrimitiveTypeId.Int64 18 | }; 19 | 20 | protected override void WriteAsObject(object value, Value dest) 21 | { 22 | dest.Int64Value = Convert.ToInt64(value); 23 | } 24 | 25 | public override void Write(bool value, Value dest) 26 | { 27 | dest.Int64Value = Convert.ToInt64(value); 28 | } 29 | 30 | public override void Write(int value, Value dest) 31 | { 32 | dest.Int64Value = Convert.ToInt64(value); 33 | } 34 | 35 | public override void Write(long value, Value dest) 36 | { 37 | dest.Int64Value = Convert.ToInt64(value); 38 | } 39 | 40 | public override void Write(sbyte value, Value dest) 41 | { 42 | dest.Int64Value = Convert.ToInt64(value); 43 | } 44 | 45 | public override void Write(short value, Value dest) 46 | { 47 | dest.Int64Value = Convert.ToInt64(value); 48 | } 49 | 50 | public override void Write(string value, Value dest) 51 | { 52 | dest.Int64Value = Convert.ToInt64(value); 53 | } 54 | 55 | public override void Write(uint value, Value dest) 56 | { 57 | dest.Int64Value = Convert.ToInt64(value); 58 | } 59 | 60 | public override void Write(ulong value, Value dest) 61 | { 62 | dest.Int64Value = Convert.ToInt64(value); 63 | } 64 | 65 | public override void Write(ushort value, Value dest) 66 | { 67 | dest.Int64Value = Convert.ToInt64(value); 68 | } 69 | 70 | public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) 71 | { 72 | return value.GetInt64(); 73 | } 74 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/Int8Handler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class Int8Handler : YdbPrimitiveTypeHandler 8 | { 9 | public override void Write(byte value, Value dest) 10 | { 11 | dest.Int32Value = value; 12 | } 13 | 14 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 15 | new() 16 | { 17 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Int8 18 | }; 19 | 20 | protected override void WriteAsObject(object value, Value dest) 21 | { 22 | dest.Int32Value = Convert.ToByte(value); 23 | } 24 | 25 | public override void Write(bool value, Value dest) 26 | { 27 | dest.Int32Value = Convert.ToByte(value); 28 | } 29 | 30 | public override void Write(int value, Value dest) 31 | { 32 | dest.Int32Value = value; 33 | } 34 | 35 | public override void Write(long value, Value dest) 36 | { 37 | dest.Int32Value = Convert.ToByte(value); 38 | } 39 | 40 | public override void Write(sbyte value, Value dest) 41 | { 42 | dest.Int32Value = value; 43 | } 44 | 45 | public override void Write(short value, Value dest) 46 | { 47 | dest.Int32Value = value; 48 | } 49 | 50 | public override void Write(string value, Value dest) 51 | { 52 | dest.Int32Value = Convert.ToByte(value); 53 | } 54 | 55 | public override void Write(uint value, Value dest) 56 | { 57 | dest.Int32Value = Convert.ToByte(value); 58 | } 59 | 60 | public override void Write(ulong value, Value dest) 61 | { 62 | dest.Int32Value = Convert.ToByte(value); 63 | } 64 | 65 | public override void Write(ushort value, Value dest) 66 | { 67 | dest.Int32Value = Convert.ToByte(value); 68 | } 69 | 70 | public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) 71 | { 72 | return value.GetByte(); 73 | } 74 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/JsonHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Text.Json; 3 | using Google.Protobuf; 4 | using Yandex.Ydb.Driver.Helpers; 5 | using Yandex.Ydb.Driver.Internal.TypeHandling; 6 | using Yandex.Ydb.Driver.Types.Primitives; 7 | using Ydb; 8 | using Type = Ydb.Type; 9 | 10 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 11 | 12 | public interface IYdbJsonTypeHandler 13 | { 14 | TAny ReadJson(Value value, FieldDescription? fieldDescription); 15 | } 16 | 17 | public sealed class JsonHandler : YdbTypeHandler, IYdbTypeHandler, IYdbSimpleTypeHandler, 18 | IYdbJsonTypeHandler 19 | { 20 | public override string Read(Value value, FieldDescription? fieldDescription = null) 21 | { 22 | return value.GetString() ?? string.Empty; 23 | } 24 | 25 | public void Write(JsonValue value, Value dest) 26 | { 27 | dest.TextValue = value.Value; 28 | } 29 | 30 | public override void Write(string value, Value dest) 31 | { 32 | dest.TextValue = value; 33 | } 34 | 35 | public TAny ReadJson(Value value, FieldDescription? fieldDescription) 36 | { 37 | var json = Read(value, fieldDescription); 38 | return JsonSerializer.Deserialize(json)!; 39 | } 40 | 41 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 42 | new() 43 | { 44 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Json 45 | }; 46 | 47 | JsonValue IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 48 | { 49 | return JsonValue.FromString(value.GetString()); 50 | } 51 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/ListHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Diagnostics; 3 | using Ydb; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class ListHandler : ContainerHandlerBase 8 | { 9 | public ListHandler() 10 | { 11 | } 12 | 13 | public override IEnumerable Read(Value value, FieldDescription? fieldDescription = null) 14 | { 15 | var handlerItem = Mapper!.ResolveByYdbType(fieldDescription!.Type.ListType.Item); 16 | var fieldType = handlerItem.GetFieldType(); 17 | var listType = typeof(List<>).MakeGenericType(fieldType); 18 | var list = (IList)Activator.CreateInstance(listType)!; 19 | 20 | var fd = new FieldDescription(fieldDescription.Type.ListType.Item, string.Empty, 0, Mapper); 21 | foreach (var item in value.Items) 22 | { 23 | var asObject = handlerItem.ReadAsObject(item, fd); 24 | list.Add(asObject); 25 | } 26 | 27 | return list; 28 | } 29 | 30 | public override TAny ReadContainerAs(Value value, FieldDescription? fieldDescription) 31 | { 32 | var handlerItem = Mapper!.ResolveByYdbType(fieldDescription!.Type.ListType.Item); 33 | var type = typeof(TAny); 34 | if (type.IsAbstract || type.IsInterface) 35 | { 36 | return (TAny)Read(value, fieldDescription); 37 | } 38 | 39 | var collection = Activator.CreateInstance(type); 40 | if (collection is not IList list) 41 | { 42 | if (collection is not IEnumerable) 43 | throw new NotSupportedException($"Type `{type.Name}` is not supported by `{GetType().Name}` mapper"); 44 | 45 | return (TAny)Read(value, fieldDescription); 46 | } 47 | 48 | var fd = new FieldDescription(fieldDescription.Type.ListType.Item, string.Empty, 0, Mapper); 49 | foreach (var item in value.Items) 50 | { 51 | var asObject = handlerItem.ReadAsObject(item, fd); 52 | list.Add(asObject); 53 | } 54 | 55 | return (TAny)collection; 56 | } 57 | 58 | public override void WriteContainer(TAny value, Value dest) 59 | { 60 | Write((value as IEnumerable)!, dest); 61 | } 62 | 63 | public override void Write(IEnumerable value, Value dest) 64 | { 65 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 66 | 67 | YdbTypeHandler? handler = null; 68 | foreach (var o in value) 69 | { 70 | handler ??= Mapper.ResolveByValue(o); 71 | var nestValue = new Value(); 72 | handler.Write(o, nestValue); 73 | dest.Items.Add(nestValue); 74 | } 75 | } 76 | 77 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default 78 | { 79 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 80 | var type = typeof(TDefault); 81 | var definition = type.IsArray ? type.GetElementType()! : type.GetGenericArguments()[0]; 82 | 83 | return new global::Ydb.Type 84 | { 85 | ListType = new ListType() 86 | { 87 | Item = Mapper.ResolveByClrType(definition) 88 | .GetYdbType(value) 89 | } 90 | }; 91 | } 92 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/StructHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class StructHandler : ContainerHandlerBase> 8 | { 9 | public override IDictionary Read(Value value, FieldDescription? fieldDescription = null) 10 | { 11 | Debug.Assert(fieldDescription != null, nameof(fieldDescription) + " != null"); 12 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 13 | 14 | var members = fieldDescription.Type.StructType.Members; 15 | 16 | var dict = new Dictionary(); 17 | for (var index = 0; index < members.Count; index++) 18 | { 19 | var member = members[index]; 20 | var resolveByYdbType = Mapper.ResolveByYdbType(member.Type); 21 | 22 | dict[member.Name] = resolveByYdbType.ReadAsObject(value.Items[index], 23 | new FieldDescription(member.Type, member.Name, index, Mapper)); 24 | } 25 | 26 | return dict; 27 | } 28 | 29 | public override void Write(IDictionary value, Value dest) 30 | { 31 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 32 | 33 | foreach (var (key, o) in value) 34 | { 35 | var val = new Value(); 36 | var typeHandler = Mapper.ResolveByValue(o); 37 | typeHandler.Write(o, val); 38 | dest.Items.Add(val); 39 | } 40 | } 41 | 42 | protected override Type GetYdbTypeInternal(TDefault? value) where TDefault : default 43 | { 44 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 45 | 46 | var structType = new StructType(); 47 | var result = new Type() { StructType = structType }; 48 | 49 | if (value is Dictionary dict) 50 | { 51 | foreach (var (key, o) in dict) 52 | { 53 | var typeHandler = Mapper.ResolveByValue(o); 54 | structType.Members.Add(new StructMember() { Name = key, Type = typeHandler.GetYdbType(o) }); 55 | } 56 | } 57 | else 58 | { 59 | var handler = Mapper.ResolveByClrType(typeof(TDefault)); 60 | return handler.GetYdbType(value); 61 | } 62 | 63 | return result; 64 | } 65 | 66 | public override TAny ReadContainerAs(Value value, FieldDescription? fieldDescription) 67 | { 68 | if (typeof(TAny) == typeof(Dictionary)) 69 | return (TAny)Read(value, fieldDescription); 70 | 71 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 72 | 73 | var handler = Mapper.ResolveByClrType(typeof(TAny)); 74 | return handler.Read(value, fieldDescription); 75 | } 76 | 77 | public override void WriteContainer(TAny value, Value dest) 78 | { 79 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 80 | 81 | if (value is Dictionary dict) 82 | { 83 | Write(dict, dest); 84 | } 85 | else 86 | { 87 | var handler = Mapper.ResolveByClrType(typeof(TAny)); 88 | handler.Write(value, dest); 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/TextTypeHandler.cs: -------------------------------------------------------------------------------- 1 | using Google.Protobuf; 2 | using Yandex.Ydb.Driver.Helpers; 3 | using Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 4 | using Yandex.Ydb.Driver.Internal.TypeHandling; 5 | using Ydb; 6 | 7 | namespace Yandex.Ydb.Driver.Internal.TypeMapping; 8 | 9 | public class TextTypeHandler : YdbPrimitiveTypeHandler, IYdbTypeHandler 10 | { 11 | protected override void WriteAsObject(object value, Value dest) 12 | { 13 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value)); 14 | } 15 | 16 | public override void Write(byte value, Value dest) 17 | { 18 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value)); 19 | } 20 | 21 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 22 | new() 23 | { 24 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.String 25 | }; 26 | 27 | public override void Write(bool value, Value dest) 28 | { 29 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value)); 30 | } 31 | 32 | public override void Write(int value, Value dest) 33 | { 34 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value)); 35 | } 36 | 37 | public override void Write(long value, Value dest) 38 | { 39 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value)); 40 | } 41 | 42 | public override void Write(sbyte value, Value dest) 43 | { 44 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value)); 45 | } 46 | 47 | public override void Write(short value, Value dest) 48 | { 49 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value)); 50 | } 51 | 52 | public override void Write(string value, Value dest) 53 | { 54 | dest.BytesValue = ByteString.CopyFromUtf8(value); 55 | } 56 | 57 | public override void Write(uint value, Value dest) 58 | { 59 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value)); 60 | } 61 | 62 | public override void Write(ulong value, Value dest) 63 | { 64 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value)); 65 | } 66 | 67 | public override void Write(ushort value, Value dest) 68 | { 69 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value)); 70 | } 71 | 72 | public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) 73 | { 74 | return value.GetString(); 75 | } 76 | 77 | public Guid Read(Value value, FieldDescription? fieldDescription) 78 | { 79 | return Guid.Parse(value.GetString()); 80 | } 81 | 82 | public void Write(Guid value, Value dest) 83 | { 84 | dest.BytesValue = ByteString.CopyFromUtf8(Convert.ToString(value.ToString())); 85 | } 86 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/TimeStampHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using Yandex.Cloud.Dns.V1; 3 | using Yandex.Ydb.Driver.Helpers; 4 | using Yandex.Ydb.Driver.Internal.TypeHandling; 5 | using Yandex.Ydb.Driver.Types.Primitives; 6 | using Ydb; 7 | using Type = System.Type; 8 | 9 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 10 | 11 | public sealed class TimeStampHandler : YdbTypeHandler, IYdbSimpleTypeHandler, 12 | IYdbSimpleTypeHandler, IYdbSimpleTypeHandler 13 | { 14 | public override DateTimeOffset Read(Value value, FieldDescription? fieldDescription = null) 15 | { 16 | return DateTimeOffset.UnixEpoch.AddTicks(value.GetInt64() * 10); 17 | } 18 | 19 | public void Write(Timestamp value, Value dest) 20 | { 21 | dest.Int64Value = value.Value; 22 | } 23 | 24 | public void Write(DateTime value, Value dest) 25 | { 26 | dest.Int64Value = new DateTimeOffset(value).ToUnixTimeMilliseconds(); 27 | } 28 | 29 | public override void Write(DateTimeOffset value, Value dest) 30 | { 31 | dest.Int64Value = value.ToUnixTimeMilliseconds(); 32 | } 33 | 34 | DateTime IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 35 | { 36 | return DateTimeOffset.UnixEpoch.AddTicks(value.GetInt64() * 10).DateTime; 37 | } 38 | 39 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 40 | new() 41 | { 42 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Timestamp 43 | }; 44 | 45 | Timestamp IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 46 | { 47 | return new Timestamp(value.GetInt64()); 48 | } 49 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/TupleHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Diagnostics; 3 | using System.Dynamic; 4 | using System.Runtime.CompilerServices; 5 | using Ydb; 6 | using Type = Ydb.Type; 7 | 8 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 9 | 10 | public sealed class TupleHandler : ContainerHandlerBase 11 | { 12 | private System.Type GetGenericTupleType(FieldDescription tupleInfo) 13 | { 14 | return tupleInfo.Type.TupleType.Elements.Count switch 15 | { 16 | 1 => typeof(Tuple<>), 17 | 2 => typeof(Tuple<,>), 18 | 3 => typeof(Tuple<,,>), 19 | 4 => typeof(Tuple<,,,>), 20 | 5 => typeof(Tuple<,,,,>), 21 | 6 => typeof(Tuple<,,,,,>), 22 | 7 => typeof(Tuple<,,,,,,>), 23 | _ => throw new NotSupportedException( 24 | $"Tuple with `{tupleInfo.Type.TupleType.Elements.Count}` count of elements is not supported. Use struct instead") 25 | }; 26 | } 27 | 28 | public override ITuple Read(Value value, FieldDescription? fieldDescription = null) 29 | { 30 | Debug.Assert(fieldDescription != null, nameof(fieldDescription) + " != null"); 31 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 32 | 33 | var tupleType = GetGenericTupleType(fieldDescription!); 34 | var tupleKeyTypes = 35 | fieldDescription.Type.TupleType.Elements.Select(x => new FieldDescription(x, string.Empty, 0, Mapper)) 36 | .ToArray(); 37 | 38 | var tupleKeyHandlers = tupleKeyTypes.Select(x => Mapper.ResolveByYdbType(x.Type)).ToArray(); 39 | 40 | var tupleValues = new object[tupleKeyTypes.Length]; 41 | 42 | for (var index = 0; index < value.Items.Count; index++) 43 | { 44 | var item = value.Items[index]; 45 | tupleValues[index] = tupleKeyHandlers[index].ReadAsObject(item, tupleKeyTypes[index])!; 46 | } 47 | 48 | var tuple = Activator.CreateInstance(tupleType, tupleValues); 49 | return (ITuple)tuple!; 50 | } 51 | 52 | public override void Write(ITuple value, Value dest) 53 | { 54 | throw new NotImplementedException(); 55 | } 56 | 57 | protected override Type GetYdbTypeInternal(TDefault? value) where TDefault : default 58 | { 59 | var tupleType = new TupleType(); 60 | var arguments = typeof(TDefault).GetGenericArguments(); 61 | var elements = arguments.Select(x => Mapper.ResolveByClrType(x).GetYdbType(value)); 62 | tupleType.Elements.Add(elements); 63 | 64 | return new Type() 65 | { 66 | TupleType = tupleType 67 | }; 68 | } 69 | 70 | public override TAny ReadContainerAs(Value value, FieldDescription? fieldDescription) 71 | { 72 | Debug.Assert(fieldDescription != null, nameof(fieldDescription) + " != null"); 73 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 74 | 75 | var tupleKeyTypes = 76 | fieldDescription.Type.TupleType.Elements.Select(x => new FieldDescription(x, string.Empty, 0, Mapper)) 77 | .ToArray(); 78 | 79 | var tupleKeyHandlers = tupleKeyTypes.Select(x => Mapper.ResolveByYdbType(x.Type)).ToArray(); 80 | var tupleValues = new object[tupleKeyTypes.Length]; 81 | 82 | for (var index = 0; index < value.Items.Count; index++) 83 | { 84 | var item = value.Items[index]; 85 | tupleValues[index] = tupleKeyHandlers[index].ReadAsObject(item, tupleKeyTypes[index])!; 86 | } 87 | 88 | var tuple = Activator.CreateInstance(typeof(TAny), tupleValues); 89 | return (TAny)tuple!; 90 | } 91 | 92 | public override void WriteContainer(TAny value, Value dest) 93 | { 94 | Debug.Assert(Mapper != null, nameof(Mapper) + " != null"); 95 | var tupleType = typeof(TAny); 96 | 97 | if (value is not ITuple tuple) throw new NotSupportedException($"{tupleType.Name} is not supported"); 98 | 99 | var tupleValueTypes = tupleType.GetGenericArguments(); 100 | var tupleValueHandlers = tupleValueTypes.Select(x => Mapper.ResolveByClrType(x)).ToArray(); 101 | 102 | for (int i = 0; i < tuple.Length; i++) 103 | { 104 | var val = new Value(); 105 | tupleValueHandlers[i].Write(tuple[i], val); 106 | dest.Items.Add(val); 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/UInt16Handler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class UInt16Handler : YdbPrimitiveTypeHandler 8 | { 9 | protected override void WriteAsObject(object value, Value dest) 10 | { 11 | dest.Uint32Value = Convert.ToUInt16(value); 12 | } 13 | 14 | public override void Write(byte value, Value dest) 15 | { 16 | dest.Uint32Value = Convert.ToUInt16(value); 17 | } 18 | 19 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 20 | new() 21 | { 22 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Uint16 23 | }; 24 | 25 | public override void Write(bool value, Value dest) 26 | { 27 | dest.Uint32Value = Convert.ToUInt16(value); 28 | } 29 | 30 | public override void Write(int value, Value dest) 31 | { 32 | dest.Uint32Value = Convert.ToUInt16(value); 33 | } 34 | 35 | public override void Write(long value, Value dest) 36 | { 37 | dest.Uint32Value = Convert.ToUInt16(value); 38 | } 39 | 40 | public override void Write(sbyte value, Value dest) 41 | { 42 | dest.Uint32Value = Convert.ToUInt16(value); 43 | } 44 | 45 | public override void Write(short value, Value dest) 46 | { 47 | dest.Uint32Value = Convert.ToUInt16(value); 48 | } 49 | 50 | public override void Write(string value, Value dest) 51 | { 52 | dest.Uint32Value = Convert.ToUInt16(value); 53 | } 54 | 55 | public override void Write(uint value, Value dest) 56 | { 57 | dest.Uint32Value = Convert.ToUInt16(value); 58 | } 59 | 60 | public override void Write(ulong value, Value dest) 61 | { 62 | dest.Uint32Value = Convert.ToUInt16(value); 63 | } 64 | 65 | public override void Write(ushort value, Value dest) 66 | { 67 | dest.Uint32Value = Convert.ToUInt16(value); 68 | } 69 | 70 | public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) 71 | { 72 | return value.GetUInt16(); 73 | } 74 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/UInt32Handler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class UInt32Handler : YdbPrimitiveTypeHandler 8 | { 9 | protected override void WriteAsObject(object value, Value dest) 10 | { 11 | dest.Uint32Value = Convert.ToUInt32(value); 12 | } 13 | 14 | public override void Write(byte value, Value dest) 15 | { 16 | dest.Uint32Value = Convert.ToUInt32(value); 17 | } 18 | 19 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 20 | new() 21 | { 22 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Uint32 23 | }; 24 | 25 | public override void Write(bool value, Value dest) 26 | { 27 | dest.Uint32Value = Convert.ToUInt32(value); 28 | } 29 | 30 | public override void Write(int value, Value dest) 31 | { 32 | dest.Uint32Value = Convert.ToUInt32(value); 33 | } 34 | 35 | public override void Write(long value, Value dest) 36 | { 37 | dest.Uint32Value = Convert.ToUInt32(value); 38 | } 39 | 40 | public override void Write(sbyte value, Value dest) 41 | { 42 | dest.Uint32Value = Convert.ToUInt32(value); 43 | } 44 | 45 | public override void Write(short value, Value dest) 46 | { 47 | dest.Uint32Value = Convert.ToUInt32(value); 48 | } 49 | 50 | public override void Write(string value, Value dest) 51 | { 52 | dest.Uint32Value = Convert.ToUInt32(value); 53 | } 54 | 55 | public override void Write(uint value, Value dest) 56 | { 57 | dest.Uint32Value = Convert.ToUInt32(value); 58 | } 59 | 60 | public override void Write(ulong value, Value dest) 61 | { 62 | dest.Uint32Value = Convert.ToUInt32(value); 63 | } 64 | 65 | public override void Write(ushort value, Value dest) 66 | { 67 | dest.Uint32Value = Convert.ToUInt32(value); 68 | } 69 | 70 | public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) 71 | { 72 | return value.GetUInt32(); 73 | } 74 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/UInt64Handler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class UInt64Handler : YdbPrimitiveTypeHandler 8 | { 9 | protected override void WriteAsObject(object value, Value dest) 10 | { 11 | dest.Uint64Value = Convert.ToUInt64(value); 12 | } 13 | 14 | public override void Write(byte value, Value dest) 15 | { 16 | dest.Uint64Value = Convert.ToUInt64(value); 17 | } 18 | 19 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 20 | new() 21 | { 22 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Uint64 23 | }; 24 | 25 | public override void Write(bool value, Value dest) 26 | { 27 | dest.Uint64Value = Convert.ToUInt64(value); 28 | } 29 | 30 | public override void Write(int value, Value dest) 31 | { 32 | dest.Uint64Value = Convert.ToUInt64(value); 33 | } 34 | 35 | public override void Write(long value, Value dest) 36 | { 37 | dest.Uint64Value = Convert.ToUInt64(value); 38 | } 39 | 40 | public override void Write(sbyte value, Value dest) 41 | { 42 | dest.Uint64Value = Convert.ToUInt64(value); 43 | } 44 | 45 | public override void Write(short value, Value dest) 46 | { 47 | dest.Uint64Value = Convert.ToUInt64(value); 48 | } 49 | 50 | public override void Write(string value, Value dest) 51 | { 52 | dest.Uint64Value = Convert.ToUInt64(value); 53 | } 54 | 55 | public override void Write(uint value, Value dest) 56 | { 57 | dest.Uint64Value = Convert.ToUInt64(value); 58 | } 59 | 60 | public override void Write(ulong value, Value dest) 61 | { 62 | dest.Uint64Value = Convert.ToUInt64(value); 63 | } 64 | 65 | public override void Write(ushort value, Value dest) 66 | { 67 | dest.Uint64Value = Convert.ToUInt64(value); 68 | } 69 | 70 | public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) 71 | { 72 | return value.GetUInt64(); 73 | } 74 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/UInt8Handler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 6 | 7 | public sealed class UInt8Handler : YdbPrimitiveTypeHandler 8 | { 9 | protected override void WriteAsObject(object value, Value dest) 10 | { 11 | dest.Int32Value = Convert.ToSByte(value); 12 | } 13 | 14 | public override void Write(byte value, Value dest) 15 | { 16 | dest.Int32Value = Convert.ToSByte(value); 17 | } 18 | 19 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 20 | new() 21 | { 22 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Uint8 23 | }; 24 | 25 | public override void Write(bool value, Value dest) 26 | { 27 | dest.Int32Value = Convert.ToSByte(value); 28 | } 29 | 30 | 31 | public override void Write(int value, Value dest) 32 | { 33 | dest.Int32Value = Convert.ToSByte(value); 34 | } 35 | 36 | public override void Write(long value, Value dest) 37 | { 38 | dest.Int32Value = Convert.ToSByte(value); 39 | } 40 | 41 | public override void Write(sbyte value, Value dest) 42 | { 43 | dest.Int32Value = Convert.ToSByte(value); 44 | } 45 | 46 | public override void Write(short value, Value dest) 47 | { 48 | dest.Int32Value = Convert.ToSByte(value); 49 | } 50 | 51 | public override void Write(string value, Value dest) 52 | { 53 | dest.Int32Value = Convert.ToSByte(value); 54 | } 55 | 56 | public override void Write(uint value, Value dest) 57 | { 58 | dest.Int32Value = Convert.ToSByte(value); 59 | } 60 | 61 | public override void Write(ulong value, Value dest) 62 | { 63 | dest.Int32Value = Convert.ToSByte(value); 64 | } 65 | 66 | public override void Write(ushort value, Value dest) 67 | { 68 | dest.Int32Value = Convert.ToSByte(value); 69 | } 70 | 71 | public override object ReadAsObject(Value value, FieldDescription? fieldDescription = null) 72 | { 73 | return value.GetSByte(); 74 | } 75 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/Utf8Handler.cs: -------------------------------------------------------------------------------- 1 | using Google.Protobuf; 2 | using Yandex.Ydb.Driver.Helpers; 3 | using Yandex.Ydb.Driver.Internal.TypeHandling; 4 | using Yandex.Ydb.Driver.Types.Primitives; 5 | using Ydb; 6 | 7 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 8 | 9 | public sealed class Utf8Handler : YdbTypeHandler, IYdbSimpleTypeHandler, 10 | IYdbSimpleTypeHandler 11 | { 12 | public override string Read(Value value, FieldDescription? fieldDescription = null) 13 | { 14 | return value.TextValue; 15 | } 16 | 17 | public void Write(Utf8String value, Value dest) 18 | { 19 | dest.BytesValue = ByteString.CopyFrom(value.Value.AsSpan()); 20 | } 21 | 22 | public override void Write(string value, Value dest) 23 | { 24 | dest.TextValue = value; 25 | } 26 | 27 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 28 | new() 29 | { 30 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Utf8 31 | }; 32 | 33 | Utf8String IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 34 | { 35 | return new Utf8String(value.GetString()); 36 | } 37 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/YdbPrimitiveTypeHandler.cs: -------------------------------------------------------------------------------- 1 | using Google.Protobuf.WellKnownTypes; 2 | using Yandex.Ydb.Driver.Helpers; 3 | using Yandex.Ydb.Driver.Internal.TypeHandling; 4 | using Ydb; 5 | using Type = System.Type; 6 | using Value = Ydb.Value; 7 | 8 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 9 | 10 | public abstract class YdbPrimitiveTypeHandler : YdbTypeHandler, IYdbSimpleTypeHandler, 11 | IYdbSimpleTypeHandler, 12 | IYdbSimpleTypeHandler, 13 | IYdbSimpleTypeHandler, IYdbSimpleTypeHandler, IYdbSimpleTypeHandler, 14 | IYdbSimpleTypeHandler, IYdbSimpleTypeHandler, IYdbSimpleTypeHandler, 15 | IYdbSimpleTypeHandler, IYdbSimpleTypeHandler 16 | { 17 | public override global::Ydb.Type GetYdbType(TDefault? value) where TDefault : default 18 | { 19 | if (value is null) 20 | { 21 | var type = new global::Ydb.Type 22 | { 23 | OptionalType = new OptionalType() 24 | { 25 | Item = GetYdbTypeInternal(value) 26 | } 27 | }; 28 | return type; 29 | } 30 | 31 | 32 | return GetYdbTypeInternal(value); 33 | } 34 | 35 | protected abstract global::Ydb.Type GetYdbTypeInternal(TDefault? value); 36 | 37 | public abstract void Write(bool value, Value dest); 38 | 39 | bool IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 40 | { 41 | return value.GetBool(); 42 | } 43 | 44 | protected abstract void WriteAsObject(object value, Value dest); 45 | 46 | public void Write(object? value, Value dest) 47 | { 48 | if (value is null) 49 | dest.NullFlagValue = NullValue.NullValue; 50 | else 51 | WriteAsObject(value, dest); 52 | } 53 | 54 | public abstract void Write(byte value, Value dest); 55 | 56 | byte IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 57 | { 58 | return value.GetByte(); 59 | } 60 | 61 | int IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 62 | { 63 | return value.GetInt32(); 64 | } 65 | 66 | public abstract void Write(int value, Value dest); 67 | 68 | long IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 69 | { 70 | return value.GetInt64(); 71 | } 72 | 73 | public abstract void Write(long value, Value dest); 74 | public abstract void Write(sbyte value, Value dest); 75 | 76 | sbyte IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 77 | { 78 | return value.GetSByte(); 79 | } 80 | 81 | public abstract void Write(short value, Value dest); 82 | 83 | short IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 84 | { 85 | return value.GetInt16(); 86 | } 87 | 88 | string IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 89 | { 90 | return value.GetString() ?? string.Empty; 91 | } 92 | 93 | public abstract void Write(string value, Value dest); 94 | 95 | uint IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 96 | { 97 | return value.GetUInt32(); 98 | } 99 | 100 | public abstract void Write(uint value, Value dest); 101 | 102 | ulong IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 103 | { 104 | return value.GetUInt64(); 105 | } 106 | 107 | public abstract void Write(ulong value, Value dest); 108 | 109 | public abstract void Write(ushort value, Value dest); 110 | 111 | ushort IYdbTypeHandler.Read(Value value, FieldDescription? fieldDescription) 112 | { 113 | return value.GetUInt16(); 114 | } 115 | 116 | public override Type GetFieldType(FieldDescription? fieldDescription = null) 117 | { 118 | return typeof(TAny); 119 | } 120 | 121 | public object Read(Value value, FieldDescription? fieldDescription) => ReadAsObject(value, fieldDescription); 122 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/Primitives/YsonHandler.cs: -------------------------------------------------------------------------------- 1 | using Google.Protobuf; 2 | using Yandex.Ydb.Driver.Helpers; 3 | using Ydb; 4 | using Type = Ydb.Type; 5 | 6 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 7 | 8 | public sealed class YsonHandler : YdbTypeHandler, IYdbSimpleTypeHandler 9 | { 10 | public override string Read(Value value, FieldDescription? fieldDescription = null) 11 | { 12 | return value.GetString() ?? string.Empty; 13 | } 14 | 15 | public override void Write(string value, Value dest) 16 | { 17 | dest.BytesValue = ByteString.CopyFromUtf8(value); 18 | } 19 | 20 | protected override global::Ydb.Type GetYdbTypeInternal(TDefault? value) where TDefault : default => 21 | new() 22 | { 23 | TypeId = global::Ydb.Type.Types.PrimitiveTypeId.Yson 24 | }; 25 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandlers/YdbTypeHandler.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 2 | using Yandex.Ydb.Driver.Internal.TypeHandling; 3 | using Ydb; 4 | using Type = System.Type; 5 | 6 | namespace Yandex.Ydb.Driver.Internal.TypeHandlers; 7 | 8 | public abstract class YdbTypeHandler 9 | { 10 | public abstract Type GetFieldType(FieldDescription? fieldDescription = null); 11 | 12 | public TAny Read(Value value, FieldDescription? fieldDescription = null) 13 | { 14 | return this switch 15 | { 16 | IYdbSimpleTypeHandler simpleTypeHandler => simpleTypeHandler.Read(value, fieldDescription), 17 | IYdbTypeHandler typeHandler => typeHandler.Read(value, fieldDescription), 18 | IYdbJsonTypeHandler jsonTypeHandler => jsonTypeHandler.ReadJson(value, fieldDescription), 19 | IContainerHandler containerHandler => containerHandler.ReadContainerAs(value, fieldDescription), 20 | _ => throw new NotSupportedException( 21 | $"Handler `{this.GetType().Name}` does not implement reading for type `{typeof(TAny).Name}`") 22 | }; 23 | } 24 | 25 | public void Write(TAny? value, Value dest) 26 | { 27 | switch (this) 28 | { 29 | case IYdbSimpleTypeHandler handler: 30 | { 31 | handler.Write(value, dest); 32 | break; 33 | } 34 | case IYdbTypeHandler handler: 35 | { 36 | handler.Write(value, dest); 37 | break; 38 | } 39 | case IContainerHandler handler: 40 | { 41 | handler.WriteContainer(value, dest); 42 | break; 43 | } 44 | default: 45 | throw new NotSupportedException( 46 | $"Writing `{typeof(TAny).Name}` does not supported by `{GetType().Name}` handler"); 47 | } 48 | } 49 | 50 | public abstract object? ReadAsObject(Value value, FieldDescription? fieldDescription = null); 51 | 52 | public abstract global::Ydb.Type GetYdbType(TAny? value); 53 | } 54 | 55 | public abstract class YdbTypeHandler : YdbTypeHandler, IYdbTypeHandler 56 | { 57 | public abstract TDefault Read(Value value, FieldDescription? fieldDescription = null); 58 | 59 | public abstract void Write(TDefault value, Value dest); 60 | 61 | public override object? ReadAsObject(Value value, FieldDescription? fieldDescription = null) 62 | { 63 | return Read(value, fieldDescription); 64 | } 65 | 66 | public override global::Ydb.Type GetYdbType(TAny? value) where TAny : default 67 | { 68 | if (value is null) 69 | { 70 | var type = new global::Ydb.Type 71 | { 72 | OptionalType = new OptionalType() 73 | { 74 | Item = GetYdbTypeInternal(value) 75 | } 76 | }; 77 | return type; 78 | } 79 | 80 | return GetYdbTypeInternal(value); 81 | } 82 | 83 | protected abstract global::Ydb.Type GetYdbTypeInternal(TDefault? value); 84 | 85 | public override Type GetFieldType(FieldDescription? fieldDescription = null) 86 | { 87 | return typeof(TDefault); 88 | } 89 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandling/BuiltInTypeHandlerResolverFactory.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Internal.TypeMapping; 2 | 3 | namespace Yandex.Ydb.Driver.Internal.TypeHandling; 4 | 5 | internal sealed class BuiltInTypeHandlerResolverFactory : TypeHandlerResolverFactory 6 | { 7 | public override TypeHandlerResolver Create() 8 | { 9 | return new BuiltInTypeHandlerResolver(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandling/IYdbTypeHandler.cs: -------------------------------------------------------------------------------- 1 | using Ydb; 2 | 3 | namespace Yandex.Ydb.Driver.Internal.TypeHandling; 4 | 5 | public interface IYdbTypeHandler 6 | { 7 | TDefault Read(Value value, FieldDescription? fieldDescription); 8 | 9 | void Write(TDefault value, Value dest); 10 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandling/OperationExtensions.cs: -------------------------------------------------------------------------------- 1 | using Google.Protobuf; 2 | using Ydb; 3 | using Ydb.Operations; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandling; 6 | 7 | public static class OperationExtensions 8 | { 9 | public static bool IsFailed(this Operation op) 10 | { 11 | return !IsSuccess(op); 12 | } 13 | 14 | public static bool IsSuccess(this Operation op) 15 | { 16 | return op.Status == StatusIds.Types.StatusCode.Success; 17 | } 18 | 19 | public static T GetResult(this Operation op) where T : IMessage, new() 20 | { 21 | if (op.IsFailed()) 22 | throw new YdbDriverException( 23 | $"Operation `{op.Id}` failed. Status code: `{op.Status}`. Issues: `{string.Join("\n", op.Issues?.Select(x => x.ToString()) ?? Array.Empty())}`"); 24 | 25 | return !op.Result.TryUnpack(out T result) 26 | ? throw new YdbDriverException($"Failed to unpack result to type `{typeof(T)}`") 27 | : result; 28 | } 29 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeHandling/UserDefinedTypeHandlerResolver.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using Yandex.Ydb.Driver.Internal.TypeHandlers; 3 | using Yandex.Ydb.Driver.Internal.TypeMapping; 4 | 5 | namespace Yandex.Ydb.Driver.Internal.TypeHandling; 6 | 7 | internal sealed class UserDefinedTypeHandlerResolver : TypeHandlerResolver 8 | { 9 | private readonly ConcurrentDictionary _handlersByClrType; 10 | 11 | internal UserDefinedTypeHandlerResolver(IEnumerable? typeMappings) 12 | { 13 | _handlersByClrType = new ConcurrentDictionary(); 14 | if (typeMappings != null) 15 | foreach (var mapping in typeMappings) 16 | { 17 | AddTypeMapping(mapping); 18 | } 19 | } 20 | 21 | internal void AddTypeMapping(IUserTypeMapping typeMapping) 22 | { 23 | _handlersByClrType[typeMapping.ClrType] = typeMapping.CreateHandler(); 24 | } 25 | 26 | public override YdbTypeHandler? ResolveByDataTypeName(string typeName) 27 | { 28 | //NOT SUPPORTED 29 | return null; 30 | } 31 | 32 | public override YdbTypeHandler? ResolveByClrType(System.Type type) 33 | { 34 | _handlersByClrType.TryGetValue(type, out var handler); 35 | return handler; 36 | } 37 | 38 | public override YdbTypeHandler? ResolveByYdbType(global::Ydb.Type type) 39 | { 40 | //NOT SUPPORTED 41 | return null; 42 | } 43 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeMapping/GlobalTypeMapper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Data; 3 | using Microsoft.Extensions.Logging.Abstractions; 4 | using Yandex.Ydb.Driver.Internal.TypeHandlers; 5 | using Yandex.Ydb.Driver.Internal.TypeHandling; 6 | using Type = Ydb.Type; 7 | 8 | namespace Yandex.Ydb.Driver.Internal.TypeMapping; 9 | 10 | public sealed class GlobalTypeMapper : IYdbTypeMapper 11 | { 12 | static GlobalTypeMapper() 13 | { 14 | Instance = new GlobalTypeMapper(); 15 | } 16 | 17 | private GlobalTypeMapper() 18 | { 19 | Reset(); 20 | } 21 | 22 | public static GlobalTypeMapper Instance { get; } 23 | 24 | internal ReaderWriterLockSlim Lock { get; } 25 | = new(LockRecursionPolicy.SupportsRecursion); 26 | 27 | internal List ResolverFactories { get; } = new(); 28 | 29 | public ConcurrentDictionary UserTypeMappings { get; } = new(); 30 | 31 | public void AddTypeResolverFactory(TypeHandlerResolverFactory resolverFactory) 32 | { 33 | Lock.EnterWriteLock(); 34 | try 35 | { 36 | var type = resolverFactory.GetType(); 37 | if (ResolverFactories[0].GetType() == type) 38 | { 39 | ResolverFactories[0] = resolverFactory; 40 | } 41 | else 42 | { 43 | for (var i = 0; i < ResolverFactories.Count; i++) 44 | if (ResolverFactories[i].GetType() == type) 45 | ResolverFactories.RemoveAt(i); 46 | 47 | ResolverFactories.Insert(0, resolverFactory); 48 | } 49 | } 50 | finally 51 | { 52 | Lock.ExitWriteLock(); 53 | } 54 | } 55 | 56 | public void Reset() 57 | { 58 | Lock.EnterWriteLock(); 59 | try 60 | { 61 | ResolverFactories.Clear(); 62 | ResolverFactories.Add(new BuiltInTypeHandlerResolverFactory()); 63 | UserTypeMappings.Clear(); 64 | } 65 | finally 66 | { 67 | Lock.ExitWriteLock(); 68 | } 69 | } 70 | 71 | internal static string? DbTypeToYdbType(DbType ydbType) 72 | { 73 | return ydbType switch 74 | { 75 | DbType.SByte => "Int8", 76 | DbType.Int16 => "Int16", 77 | DbType.Int32 => "Int32", 78 | DbType.Int64 => "Int64", 79 | DbType.Byte => "Uint8", 80 | DbType.UInt16 => "Uint16", 81 | DbType.UInt32 => "Uint32", 82 | DbType.UInt64 => "Uint64", 83 | DbType.Double => "Double", 84 | DbType.Decimal => "Decimal", 85 | DbType.Single => "Float", 86 | DbType.String => "Text", 87 | DbType.Guid => "Uuid", 88 | DbType.DateTime => "Timestamp", 89 | DbType.DateTime2 => "Interval", 90 | DbType.DateTimeOffset => "TzTimestamp", 91 | DbType.Binary => "Byte", 92 | DbType.Boolean => "Bool", 93 | _ => "Text" 94 | }; 95 | } 96 | 97 | internal static DbType YdbDbTypeToDbType(string ydbType) 98 | { 99 | return ydbType switch 100 | { 101 | // Numeric types 102 | "Int8" => DbType.SByte, 103 | "Int16" => DbType.Int16, 104 | "Int32" => DbType.Int32, 105 | "Int64" => DbType.Int64, 106 | 107 | "Uint8" => DbType.Byte, 108 | "Uint16" => DbType.UInt16, 109 | "Uint32" => DbType.UInt32, 110 | "Uint64" => DbType.UInt64, 111 | 112 | "Double" => DbType.Double, 113 | "Decimal" => DbType.Decimal, 114 | "Float" => DbType.Single, 115 | 116 | // Text types 117 | "String" => DbType.String, 118 | "Text" => DbType.String, 119 | "Utf8" => DbType.String, 120 | "Json" => DbType.String, 121 | "JsonDocument" => DbType.Binary, 122 | "Yson" => DbType.String, 123 | 124 | "Uuid" => DbType.Guid, 125 | 126 | // Date/time types 127 | "Timestamp" => DbType.DateTime, 128 | "Interval" => DbType.DateTime2, 129 | "TzDate" => DbType.DateTimeOffset, 130 | "TzDateTime" => DbType.DateTimeOffset, 131 | "TzTimestamp" => DbType.DateTimeOffset, 132 | 133 | // Misc data types 134 | "Byte" => DbType.Binary, 135 | "Bool" => DbType.Boolean, 136 | 137 | _ => DbType.Object 138 | }; 139 | } 140 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeMapping/IUserTypeMapping.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Internal.TypeHandlers; 2 | 3 | namespace Yandex.Ydb.Driver.Internal.TypeMapping; 4 | 5 | public interface IUserTypeMapping 6 | { 7 | public global::Ydb.Type YdbType { get; } 8 | public Type ClrType { get; } 9 | 10 | public YdbTypeHandler CreateHandler(); 11 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeMapping/IYdbTypeMapper.cs: -------------------------------------------------------------------------------- 1 | namespace Yandex.Ydb.Driver.Internal.TypeMapping; 2 | 3 | public interface IYdbTypeMapper 4 | { 5 | void AddTypeResolverFactory(TypeHandlerResolverFactory resolverFactory); 6 | 7 | void Reset(); 8 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeMapping/TypeHandlerResolver.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Internal.TypeHandlers; 2 | 3 | namespace Yandex.Ydb.Driver.Internal.TypeMapping; 4 | 5 | public abstract class TypeHandlerResolver 6 | { 7 | public abstract YdbTypeHandler? ResolveByDataTypeName(string typeName); 8 | 9 | public abstract YdbTypeHandler? ResolveByClrType(Type type); 10 | 11 | public virtual YdbTypeHandler? ResolveValueDependentValue(object value) 12 | { 13 | return null; 14 | } 15 | 16 | public virtual YdbTypeHandler? ResolveValueTypeGenerically(T value) 17 | { 18 | return null; 19 | } 20 | 21 | public abstract YdbTypeHandler? ResolveByYdbType(global::Ydb.Type type); 22 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Internal/TypeMapping/TypeHandlerResolverFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Yandex.Ydb.Driver.Internal.TypeMapping; 2 | 3 | public abstract class TypeHandlerResolverFactory 4 | { 5 | public abstract TypeHandlerResolver Create(); 6 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/LogMessages.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Yandex.Ydb.Driver; 4 | 5 | // ReSharper disable InconsistentNaming 6 | #pragma warning disable SYSLIB1015 // Argument is not referenced from the logging message 7 | #pragma warning disable SYSLIB1006 // Multiple logging methods are using event id 8 | 9 | internal static partial class LogMessages 10 | { 11 | 12 | [LoggerMessage(Level = LogLevel.Trace, Message = "Opening connection to {host}:{port}/{database}")] 13 | internal static partial void OpeningConnection(ILogger logger, string host, int port, string database); 14 | 15 | [LoggerMessage(Level = LogLevel.Trace, Message = "Execute command called with session `{session_id}`")] 16 | internal static partial void StartExecutingCommand(ILogger logger, string session_id); 17 | 18 | [LoggerMessage(Level = LogLevel.Trace, 19 | Message = "Retry send command with session `{session_id}`, retried count: {count}")] 20 | internal static partial void RetryExecutingCommand(ILogger logger, string session_id, int count); 21 | 22 | 23 | [LoggerMessage(Level = LogLevel.Debug, Message = "Opening grpc channel to `{url}`")] 24 | internal static partial void OpenningGrpcChannel(ILogger logger, string url); 25 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/PooledDataSource.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | 3 | namespace Yandex.Ydb.Driver; 4 | 5 | internal sealed class PooledDataSource : YdbDataSource 6 | { 7 | private readonly List _disposables = new(); 8 | private bool _isBootstrapped = false; 9 | private YdbConnector _connector; 10 | private ISessionPool _sessionPool; 11 | 12 | internal PooledDataSource(YDbConnectionStringBuilder connectionStringBuilder, YdbDataSourceConfiguration config) : 13 | base(connectionStringBuilder, config) 14 | { 15 | } 16 | 17 | internal override async ValueTask Get(YdbConnection conn, TimeSpan timeout, 18 | CancellationToken cancellationToken) 19 | { 20 | if (_isBootstrapped) 21 | return _connector; 22 | 23 | await Bootstrap(); 24 | return _connector; 25 | } 26 | 27 | public override (long, long, long) Statistics => 28 | (Interlocked.Read(ref _currentSessions), 0, 0); 29 | 30 | private long _currentSessions; 31 | 32 | internal override async ValueTask Bootstrap() 33 | { 34 | if (_isBootstrapped) 35 | return; 36 | 37 | _isBootstrapped = true; 38 | _connector = await OpenNewConnector(TimeSpan.FromSeconds(60), CancellationToken.None); 39 | _sessionPool = new SessionPool(_connector, this.Settings.MaxSessions); 40 | await _sessionPool.Initialize(Settings.Database); 41 | 42 | await base.Bootstrap(); 43 | } 44 | 45 | public override async ValueTask GetSession(string database) 46 | { 47 | return await _sessionPool.GetSession(database); 48 | } 49 | 50 | internal override async ValueTask ReturnAsync(string session) 51 | { 52 | _sessionPool.Return(session); 53 | return; 54 | } 55 | 56 | internal override void Return(string session) 57 | { 58 | _sessionPool.Return(session); 59 | return; 60 | } 61 | 62 | private async ValueTask OpenNewConnector(TimeSpan timeout, 63 | CancellationToken cancellationToken) 64 | { 65 | var connector = new YdbConnector(this); 66 | _disposables.Add(connector); 67 | 68 | await connector.Open(timeout, cancellationToken); 69 | return connector; 70 | } 71 | 72 | protected override async ValueTask ClearAsync() 73 | { 74 | foreach (var disposable in _disposables) 75 | await disposable.DisposeAsync(); 76 | 77 | _disposables.Clear(); 78 | } 79 | 80 | protected override void Clear() 81 | { 82 | _sessionPool?.Dispose(); 83 | ClearAsync().GetAwaiter().GetResult(); 84 | } 85 | 86 | internal override bool TryGetIdleConnector(out YdbConnector? connector) 87 | { 88 | connector = _connector; 89 | return true; 90 | } 91 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Session.cs: -------------------------------------------------------------------------------- 1 | namespace Yandex.Ydb.Driver; 2 | 3 | internal sealed class Session 4 | { 5 | public Session(string id, string database) 6 | { 7 | Id = id; 8 | Database = database; 9 | CreatedAt = DateTime.UtcNow; 10 | } 11 | 12 | public string Id { get; } 13 | public string Database { get; } 14 | public DateTime CreatedAt { get; } 15 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/SessionPool.cs: -------------------------------------------------------------------------------- 1 | using Grpc.Core; 2 | using Yandex.Ydb.Driver.Internal.TypeHandling; 3 | using Ydb.Table; 4 | using Ydb.Table.V1; 5 | 6 | namespace Yandex.Ydb.Driver; 7 | 8 | public sealed class SessionPool : ISessionPool 9 | { 10 | private readonly YdbConnector _connector; 11 | private readonly int _maxSessions; 12 | private readonly object _lck = new object(); 13 | 14 | private readonly Queue _idle = new Queue(); 15 | private readonly Dictionary _sessions; 16 | 17 | internal SessionPool(YdbConnector connector, int maxSessions) 18 | { 19 | _connector = connector; 20 | _maxSessions = maxSessions; 21 | semaphoreSlim = new SemaphoreSlim(maxSessions); 22 | _sessions = new Dictionary(maxSessions); 23 | } 24 | 25 | private SemaphoreSlim semaphoreSlim; 26 | 27 | async Task ISessionPool.Initialize(string database) 28 | { 29 | for (int i = 0; i < _maxSessions; i++) 30 | { 31 | var response = await _connector.UnaryCallAsync(TableService.CreateSessionMethod, createRequest, 32 | new CallOptions(new Metadata() 33 | { 34 | { YdbMetadata.RpcDatabaseHeader, database }, 35 | })); 36 | 37 | lock (_lck) 38 | { 39 | var result = response.Operation.GetResult(); 40 | var session = new Session(result.SessionId, database); 41 | _sessions.Add(result.SessionId, session); 42 | _idle.Enqueue(session.Id); 43 | } 44 | } 45 | } 46 | 47 | async ValueTask ISessionPool.GetSession(string database) 48 | { 49 | await semaphoreSlim.WaitAsync(); 50 | 51 | lock (_lck) 52 | { 53 | if (_idle.TryDequeue(out var session)) 54 | { 55 | return session; 56 | } 57 | } 58 | 59 | throw new YdbDriverException("No idle session"); 60 | } 61 | 62 | private CreateSessionRequest createRequest = new CreateSessionRequest(); 63 | 64 | void ISessionPool.Return(string sessionId) 65 | { 66 | lock (_lck) 67 | { 68 | _idle.Enqueue(sessionId); 69 | } 70 | 71 | semaphoreSlim.Release(); 72 | } 73 | 74 | public void Dispose() 75 | { 76 | lock (_lck) 77 | { 78 | foreach (var (key, value) in _sessions) 79 | { 80 | var response = _connector.UnaryCall(TableService.DeleteSessionMethod, 81 | new DeleteSessionRequest() { SessionId = key }, 82 | new CallOptions(new Metadata() { { YdbMetadata.RpcDatabaseHeader, value.Database } }) { }); 83 | } 84 | } 85 | 86 | semaphoreSlim.Dispose(); 87 | } 88 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Types/Primitives/Utf8String.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Text.Json; 3 | 4 | namespace Yandex.Ydb.Driver.Types.Primitives; 5 | 6 | public class Timestamp 7 | { 8 | public long Value { get; } 9 | 10 | public Timestamp(long unixts) 11 | { 12 | Value = unixts; 13 | } 14 | 15 | public static Timestamp GetCurrent() => new Timestamp(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); 16 | } 17 | 18 | public class JsonValue 19 | { 20 | public string Value { get; } 21 | 22 | private JsonValue(string value) 23 | { 24 | Value = value; 25 | } 26 | 27 | public static JsonValue FromString(string str) => new JsonValue(str); 28 | 29 | public static JsonValue FromObject(object obj) => new JsonValue(JsonSerializer.Serialize(obj)); 30 | 31 | public static JsonValue From(T obj) => new JsonValue(JsonSerializer.Serialize(obj)); 32 | 33 | public T? To() => JsonSerializer.Deserialize(Value); 34 | } 35 | 36 | public class Utf8String 37 | { 38 | public Utf8String(string txt) 39 | { 40 | Value = Encoding.UTF8.GetBytes(txt); 41 | } 42 | 43 | public Utf8String(byte[] value) 44 | { 45 | Value = value; 46 | } 47 | 48 | public Utf8String(Span bytes) 49 | { 50 | Value = bytes.ToArray(); 51 | } 52 | 53 | public byte[] Value { get; init; } 54 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/UnpooledYdbDataSource.cs: -------------------------------------------------------------------------------- 1 | using Grpc.Core; 2 | using Yandex.Ydb.Driver.Internal.TypeHandling; 3 | using Ydb.Table; 4 | using Ydb.Table.V1; 5 | 6 | namespace Yandex.Ydb.Driver; 7 | 8 | /// 9 | internal sealed class UnpooledYdbDataSource : YdbDataSource 10 | { 11 | private readonly List _disposables = new(); 12 | private bool _isBootstrapped = false; 13 | private YdbConnector _connector; 14 | 15 | /// 16 | public UnpooledYdbDataSource(YDbConnectionStringBuilder settings, YdbDataSourceConfiguration config) : base( 17 | settings, config) 18 | { 19 | } 20 | 21 | internal override async ValueTask Get(YdbConnection conn, TimeSpan timeout, 22 | CancellationToken cancellationToken) 23 | { 24 | await Bootstrap(); 25 | return _connector; 26 | } 27 | 28 | internal override async ValueTask Bootstrap() 29 | { 30 | if (_isBootstrapped) 31 | return; 32 | 33 | _isBootstrapped = true; 34 | 35 | _connector = await OpenNewConnector(TimeSpan.FromSeconds(60), CancellationToken.None); 36 | 37 | await base.Bootstrap(); 38 | } 39 | 40 | protected override async ValueTask ClearAsync() 41 | { 42 | foreach (var disposable in _disposables) 43 | await disposable.DisposeAsync(); 44 | 45 | _disposables.Clear(); 46 | } 47 | 48 | protected override void Clear() 49 | { 50 | ClearAsync().GetAwaiter().GetResult(); 51 | } 52 | 53 | internal override bool TryGetIdleConnector(out YdbConnector? connector) 54 | { 55 | connector = _connector; 56 | return true; 57 | } 58 | 59 | public override async ValueTask GetSession(string database) 60 | { 61 | try 62 | { 63 | var request = new CreateSessionRequest(); 64 | var response = await _connector.UnaryCallAsync(TableService.CreateSessionMethod, request, 65 | new CallOptions(new Metadata() { { YdbMetadata.RpcDatabaseHeader, database } })); 66 | var result = response.Operation.GetResult(); 67 | return result.SessionId; 68 | } 69 | catch (Exception e) 70 | { 71 | throw new YdbDriverException($"Failed to create session. Inner exception: {e}", e); 72 | } 73 | } 74 | 75 | internal override void Return(string session) 76 | { 77 | _connector.UnaryCall(TableService.DeleteSessionMethod, new DeleteSessionRequest { SessionId = session }, 78 | new CallOptions(new Metadata() { { YdbMetadata.RpcDatabaseHeader, Settings.Database } })); 79 | } 80 | 81 | internal override async ValueTask ReturnAsync(string session) 82 | { 83 | await _connector.UnaryCallAsync(TableService.DeleteSessionMethod, 84 | new DeleteSessionRequest { SessionId = session }, 85 | new CallOptions(new Metadata() { { YdbMetadata.RpcDatabaseHeader, Settings.Database } })); 86 | } 87 | 88 | private async ValueTask OpenNewConnector(TimeSpan timeout, 89 | CancellationToken cancellationToken) 90 | { 91 | var connector = new YdbConnector(this); 92 | _disposables.Add(connector); 93 | 94 | await connector.Open(timeout, cancellationToken); 95 | return connector; 96 | } 97 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/Yandex.Ydb.Driver.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | true 8 | Yandex.Ydb.ADO 9 | 0.3.5 10 | Roman Golenok 11 | ADO.NET integration for YDB database 12 | Copyright (c) Roman Golenok 13 | https://github.com/shersh/YdbDriver 14 | https://github.com/shersh/YdbDriver/blob/master/LICENSE.md 15 | https://github.com/shersh/YdbDriver 16 | git 17 | YDB ADO.NET yandex 18 | Roman Golenok 19 | Yandex.Ydb.ADO 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbBatchTransaction.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.Common; 3 | 4 | namespace Yandex.Ydb.Driver; 5 | 6 | public sealed class YdbBatchTransaction : DbTransaction 7 | { 8 | private readonly YdbConnection _connection; 9 | private readonly List _commands = new(); 10 | 11 | public YdbBatchTransaction(YdbConnection connection) 12 | { 13 | _connection = connection; 14 | } 15 | 16 | protected override DbConnection? DbConnection { get; } 17 | public override IsolationLevel IsolationLevel { get; } 18 | 19 | public void Append(YdbCommand command) 20 | { 21 | _commands.Add(command); 22 | } 23 | 24 | public override void Commit() 25 | { 26 | foreach (var cmd in _commands) cmd.ExecuteNonQuery(); 27 | 28 | _commands.Clear(); 29 | } 30 | 31 | public override void Rollback() 32 | { 33 | _commands.Clear(); 34 | } 35 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbConnection.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.Common; 3 | using System.Diagnostics; 4 | using System.Diagnostics.CodeAnalysis; 5 | using Grpc.Core; 6 | using Microsoft.Extensions.Logging; 7 | using Yandex.Ydb.Driver.Internal.TypeMapping; 8 | 9 | namespace Yandex.Ydb.Driver; 10 | 11 | public sealed class YdbConnection : DbConnection 12 | { 13 | private readonly YdbDataSource _dataSource; 14 | private YdbConnectionState _connectionState; 15 | private string _databaseName; 16 | 17 | private ILogger _logger; 18 | private string _sessionId; 19 | private ConnectionState _state; 20 | 21 | public YdbConnection() 22 | { 23 | GC.SuppressFinalize(this); 24 | } 25 | 26 | public YdbConnection(string? connectionString) : this() 27 | { 28 | ConnectionString = connectionString; 29 | } 30 | 31 | private YdbConnection(YdbDataSource dataSource) : this(dataSource.ConnectionString) 32 | { 33 | _dataSource = dataSource; 34 | _databaseName = _dataSource.Settings.Database; 35 | } 36 | 37 | internal YdbConnector? Connector { get; private set; } 38 | 39 | [AllowNull] 40 | public override string ConnectionString 41 | { 42 | get => ""; 43 | set => 44 | _connectionState = 45 | new YdbConnectionState(_state, new YdbConnectionSettings(new YDbConnectionStringBuilder(value))); 46 | } 47 | 48 | public override string Database => _databaseName; 49 | public override ConnectionState State => _state; 50 | 51 | public override string DataSource => string.Empty; 52 | 53 | public override string ServerVersion => "1.0"; 54 | public TypeMapper TypeMapper => _dataSource.TypeMapper; 55 | 56 | protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) 57 | { 58 | var transaction = new YdbTransaction(this); 59 | transaction.Init(isolationLevel); 60 | return transaction; 61 | } 62 | 63 | public override void ChangeDatabase(string databaseName) 64 | { 65 | _databaseName = databaseName; 66 | //TODO: Here we need to change session 67 | } 68 | 69 | public override async ValueTask DisposeAsync() 70 | { 71 | await CloseAsync(); 72 | await base.DisposeAsync(); 73 | } 74 | 75 | protected override void Dispose(bool disposing) 76 | { 77 | Close(); 78 | base.Dispose(disposing); 79 | } 80 | 81 | public override async Task CloseAsync() 82 | { 83 | _state = ConnectionState.Closed; 84 | 85 | if (!string.IsNullOrEmpty(_sessionId)) 86 | { 87 | await _dataSource.ReturnAsync(_sessionId); 88 | } 89 | 90 | if (Connector is not null) 91 | { 92 | Connector = null; 93 | } 94 | } 95 | 96 | public override void Close() 97 | { 98 | _state = ConnectionState.Closed; 99 | 100 | if (!string.IsNullOrEmpty(_sessionId)) 101 | { 102 | _dataSource.Return(_sessionId); 103 | } 104 | 105 | if (Connector is not null) 106 | { 107 | Connector = null; 108 | } 109 | } 110 | 111 | public override void Open() 112 | { 113 | OpenAsync(CancellationToken.None).GetAwaiter().GetResult(); 114 | } 115 | 116 | public override async Task OpenAsync(CancellationToken ctx) 117 | { 118 | if (State is ConnectionState.Connecting 119 | or ConnectionState.Open 120 | or ConnectionState.Fetching 121 | or ConnectionState.Executing) 122 | return; 123 | 124 | Debug.Assert(Connector is null, "Connector == null"); 125 | 126 | if (_dataSource is null) 127 | { 128 | Debug.Assert(string.IsNullOrEmpty(ConnectionString)); 129 | throw new InvalidOperationException("The ConnectionString property has not been initialized."); 130 | } 131 | 132 | _logger = _dataSource.LoggingConfiguration.ConnectionLogger; 133 | LogMessages.OpeningConnection(_logger, _connectionState.Settings.Host, _connectionState.Settings.Port, 134 | _databaseName); 135 | 136 | YdbConnector? connector = null; 137 | 138 | try 139 | { 140 | connector = await _dataSource.Get(this, TimeSpan.FromSeconds(ConnectionTimeout), ctx); 141 | Connector = connector; 142 | _sessionId = await _dataSource.GetSession(Database); 143 | _state = ConnectionState.Open; 144 | } 145 | catch (Exception) 146 | { 147 | _state = ConnectionState.Closed; 148 | throw; 149 | } 150 | } 151 | 152 | internal string GetSessionId() 153 | { 154 | return _sessionId; 155 | } 156 | 157 | protected override DbCommand CreateDbCommand() 158 | { 159 | return CreateYdbCommand(); 160 | } 161 | 162 | public YdbCommand CreateYdbCommand() 163 | { 164 | return new YdbCommand(this); 165 | } 166 | 167 | internal static YdbConnection FromDataSource(YdbDataSource dataSource) 168 | { 169 | return new(dataSource); 170 | } 171 | 172 | internal ILogger GetCommandLogger() => _dataSource.Configuration.LoggingConfiguration.CommandLogger; 173 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbConnectionSettings.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Helpers; 2 | 3 | namespace Yandex.Ydb.Driver; 4 | 5 | public sealed class YdbConnectionSettings 6 | { 7 | public YdbConnectionSettings(YDbConnectionStringBuilder builder) : this(builder.Host, builder.Port, 8 | builder.User, builder.Password, builder.Database, builder.UseSsl) 9 | { 10 | } 11 | 12 | public YdbConnectionSettings(string? host, ushort port, string? user, string? password, string database, bool useSsl) 13 | { 14 | if (string.IsNullOrEmpty(host)) 15 | ThrowHelper.ThrowNullException(nameof(host)); 16 | 17 | Host = host; 18 | Port = port; 19 | User = user; 20 | Password = password; 21 | Database = database; 22 | UseSsl = useSsl; 23 | } 24 | 25 | public string Host { get; init; } 26 | public ushort Port { get; init; } 27 | public string? User { get; init; } 28 | public string? Password { get; init; } 29 | public string Database { get; init; } 30 | public bool UseSsl { get; init; } 31 | 32 | public void Deconstruct(out string host, out ushort port, out string? user, out string? password, 33 | out string database) 34 | { 35 | host = Host; 36 | port = Port; 37 | user = User; 38 | password = Password; 39 | database = Database; 40 | } 41 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbConnectionState.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | 3 | namespace Yandex.Ydb.Driver; 4 | 5 | internal sealed record YdbConnectionState(ConnectionState ConnectionState, YdbConnectionSettings Settings); -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbConnector.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Security.Cryptography.X509Certificates; 3 | using Grpc.Core; 4 | using Grpc.Net.Client; 5 | 6 | namespace Yandex.Ydb.Driver; 7 | 8 | internal sealed class YdbConnector : IYdbConnector, IAsyncDisposable 9 | { 10 | private GrpcChannel? _channel; 11 | private CallInvoker _invoker; 12 | 13 | internal YdbConnector(YdbDataSource dataSource) 14 | { 15 | DataSource = dataSource; 16 | } 17 | 18 | internal YdbDataSource DataSource { get; } 19 | 20 | public async ValueTask DisposeAsync() 21 | { 22 | if (_channel is not null) 23 | { 24 | await _channel.ShutdownAsync(); 25 | _channel.Dispose(); 26 | } 27 | } 28 | 29 | internal async Task Open(TimeSpan timeout, CancellationToken token) 30 | { 31 | Debug.Assert(_channel == null); 32 | var settings = DataSource.Settings; 33 | 34 | var handler = new SocketsHttpHandler 35 | { 36 | EnableMultipleHttp2Connections = true, 37 | PooledConnectionIdleTimeout = Timeout.InfiniteTimeSpan, 38 | KeepAlivePingDelay = TimeSpan.FromSeconds(60), 39 | KeepAlivePingTimeout = TimeSpan.FromSeconds(30), 40 | MaxConnectionsPerServer = 1000 41 | }; 42 | 43 | var url = $"{(settings.UseSsl ? "https" : "http")}://{settings.Host}:{settings.Port}"; 44 | LogMessages.OpenningGrpcChannel(DataSource.LoggingConfiguration.ConnectionLogger, url); 45 | 46 | if (settings.UseSsl) 47 | { 48 | var path = settings.RootCertificate; 49 | if (path != null) 50 | { 51 | if (!File.Exists(Path.Combine(path, "cert.pem"))) 52 | Helpers.ThrowHelper.FileNotFound($"Cert.pem file does not exist in path `{path}`", "cert.pem"); 53 | 54 | if (!File.Exists(Path.Combine(path, "key.pem"))) 55 | Helpers.ThrowHelper.FileNotFound($"Key.pem file does not exist in path `{path}`", "key.pem"); 56 | 57 | var cert = X509Certificate2.CreateFromPemFile(Path.Combine(path, "cert.pem"), 58 | Path.Combine(path, "key.pem")); 59 | handler.SslOptions.ClientCertificates ??= new X509CertificateCollection(); 60 | handler.SslOptions.ClientCertificates.Add(cert); 61 | 62 | if (settings.TrustSsl) 63 | handler.SslOptions.CertificateChainPolicy = new X509ChainPolicy() 64 | { TrustMode = X509ChainTrustMode.CustomRootTrust, CustomTrustStore = { cert } }; 65 | } 66 | } 67 | 68 | _channel = GrpcChannel.ForAddress(url, new GrpcChannelOptions() 69 | { 70 | HttpHandler = handler, 71 | }); 72 | await _channel.ConnectAsync(token); 73 | 74 | _invoker = _channel.CreateCallInvoker(); 75 | } 76 | 77 | private CallOptions PopulateHeaders(CallOptions options) 78 | { 79 | var token = DataSource.CredentialsProvider.GetToken(); 80 | var headers = options.Headers ?? new Metadata(); 81 | if (!string.IsNullOrEmpty(token) && headers.All(x => x.Key != YdbMetadata.RpcAuthHeader)) 82 | headers.Add(YdbMetadata.RpcAuthHeader, token); 83 | 84 | if (headers.All(x => x.Key != YdbMetadata.RpcDatabaseHeader)) 85 | headers.Add(YdbMetadata.RpcDatabaseHeader, DataSource.Settings.Database); 86 | 87 | return options.WithHeaders(headers); 88 | } 89 | 90 | public async ValueTask UnaryCallAsync(Method method, 91 | TRequest request, CallOptions? options = null) where TRequest : class where TResponse : class 92 | { 93 | var token = DataSource.CredentialsProvider.GetToken(); 94 | var callOptions = PopulateHeaders(options ?? GetDefaultOptions()); 95 | 96 | return await _invoker.AsyncUnaryCall(method, null, callOptions, request); 97 | } 98 | 99 | private CallOptions GetDefaultOptions() 100 | { 101 | return new CallOptions() 102 | { 103 | Headers = { } 104 | }; 105 | } 106 | 107 | public TResponse UnaryCall(Method method, 108 | TRequest request, CallOptions? options = null) where TRequest : class where TResponse : class 109 | { 110 | var token = DataSource.CredentialsProvider.GetToken(); 111 | var callOptions = PopulateHeaders(options ?? GetDefaultOptions()); 112 | 113 | return _invoker.BlockingUnaryCall(method, null, callOptions, request); 114 | } 115 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbDataSourceBuilder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Yandex.Cloud.Credentials; 3 | using Yandex.Ydb.Driver.Credentials; 4 | using Yandex.Ydb.Driver.Internal.TypeMapping; 5 | 6 | namespace Yandex.Ydb.Driver; 7 | 8 | public class YdbDataSourceBuilder : IYdbDataSourceBuilder 9 | { 10 | private readonly List _resolverFactories = new(); 11 | private readonly Dictionary _userTypeMappings = new(); 12 | private ILoggerFactory? _loggerFactory; 13 | private ICredentialsProvider? _provider; 14 | 15 | public YdbDataSourceBuilder(string? connectionString = default) 16 | { 17 | ConnectionStringBuilder = new YDbConnectionStringBuilder(connectionString); 18 | ResetTypeMappings(); 19 | } 20 | 21 | /// 22 | /// A connection string builder that can be used to configured the connection string on the builder. 23 | /// 24 | public YDbConnectionStringBuilder ConnectionStringBuilder { get; } 25 | 26 | /// 27 | /// Returns the connection string, as currently configured on the builder. 28 | /// 29 | public string ConnectionString => ConnectionStringBuilder.ToString(); 30 | 31 | /// 32 | /// Sets the that will be used for logging. 33 | /// 34 | /// The logger factory to be used. 35 | /// The same builder instance so that multiple calls can be chained. 36 | public YdbDataSourceBuilder UseLoggerFactory(ILoggerFactory? loggerFactory) 37 | { 38 | _loggerFactory = loggerFactory; 39 | return this; 40 | } 41 | 42 | public YdbDataSourceBuilder UseCredentials(ICredentialsProvider provider) 43 | { 44 | _provider = provider; 45 | return this; 46 | } 47 | 48 | public void AddTypeResolverFactory(TypeHandlerResolverFactory resolverFactory) 49 | { 50 | _resolverFactories.Insert(0, resolverFactory); 51 | } 52 | 53 | private void ResetTypeMappings() 54 | { 55 | var globalMapper = GlobalTypeMapper.Instance; 56 | globalMapper.Lock.EnterReadLock(); 57 | try 58 | { 59 | _resolverFactories.Clear(); 60 | foreach (var resolverFactory in globalMapper.ResolverFactories) 61 | _resolverFactories.Add(resolverFactory); 62 | 63 | _userTypeMappings.Clear(); 64 | foreach (var kv in globalMapper.UserTypeMappings) 65 | _userTypeMappings[kv.Key] = kv.Value; 66 | } 67 | finally 68 | { 69 | globalMapper.Lock.ExitReadLock(); 70 | } 71 | } 72 | 73 | /// 74 | /// Builds and returns an which is ready for use. 75 | /// 76 | public YdbDataSource Build() 77 | { 78 | var config = PrepareConfiguration(); 79 | 80 | return ConnectionStringBuilder.Pooling 81 | ? new PooledDataSource(ConnectionStringBuilder, config) 82 | : new UnpooledYdbDataSource(ConnectionStringBuilder, config); 83 | } 84 | 85 | private YdbDataSourceConfiguration PrepareConfiguration() 86 | { 87 | ConnectionStringBuilder.PostProcessAndValidate(); 88 | return new YdbDataSourceConfiguration(_loggerFactory is null 89 | ? YdbLoggingConfiguration.NullConfiguration 90 | : new YdbLoggingConfiguration(_loggerFactory), _resolverFactories, _userTypeMappings, 91 | _provider ?? new DefaultCredentialsProvider()); 92 | } 93 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbDataSourceCommand.cs: -------------------------------------------------------------------------------- 1 | namespace Yandex.Ydb.Driver; 2 | 3 | public sealed class YdbDataSourceCommand : YdbCommand 4 | { 5 | public YdbDataSourceCommand(YdbConnection connection) : base(connection) 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbDataSourceConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Cloud.Credentials; 2 | using Yandex.Ydb.Driver.Internal.TypeMapping; 3 | 4 | namespace Yandex.Ydb.Driver; 5 | 6 | internal sealed record YdbDataSourceConfiguration(YdbLoggingConfiguration LoggingConfiguration, 7 | List ResolverFactories, 8 | Dictionary UserTypeMappings, ICredentialsProvider CredentialsProvider); -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbDriverException.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | 3 | namespace Yandex.Ydb.Driver; 4 | 5 | public class YdbDriverException : DbException 6 | { 7 | public YdbDriverException() 8 | { 9 | } 10 | 11 | public YdbDriverException(string msg) : base(msg) 12 | { 13 | } 14 | 15 | public YdbDriverException(string? msg, Exception exception) : base(msg, exception) 16 | { 17 | } 18 | 19 | public YdbDriverException(string? msg, int error) : base(msg, error) 20 | { 21 | } 22 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbLoggingConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Microsoft.Extensions.Logging.Abstractions; 3 | 4 | namespace Yandex.Ydb.Driver; 5 | 6 | public class YdbLoggingConfiguration 7 | { 8 | internal static readonly YdbLoggingConfiguration NullConfiguration 9 | = new(NullLoggerFactory.Instance); 10 | 11 | internal static ILoggerFactory GlobalLoggerFactory = NullLoggerFactory.Instance; 12 | 13 | public YdbLoggingConfiguration(ILoggerFactory loggerFactory) 14 | { 15 | ConnectionLogger = loggerFactory.CreateLogger("Ydb.Connection"); 16 | CommandLogger = loggerFactory.CreateLogger("Ydb.Command"); 17 | TransactionLogger = loggerFactory.CreateLogger("Ydb.Transaction"); 18 | ExceptionLogger = loggerFactory.CreateLogger("Ydb.Exception"); 19 | } 20 | 21 | internal ILogger ConnectionLogger { get; } 22 | internal ILogger CommandLogger { get; } 23 | internal ILogger TransactionLogger { get; } 24 | internal ILogger ExceptionLogger { get; } 25 | 26 | public static void InitializeLogging(ILoggerFactory loggerFactory) 27 | { 28 | GlobalLoggerFactory = loggerFactory; 29 | } 30 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbMetadata.cs: -------------------------------------------------------------------------------- 1 | namespace Yandex.Ydb.Driver; 2 | 3 | internal static class YdbMetadata 4 | { 5 | public const string RpcDatabaseHeader = "x-ydb-database"; 6 | public const string RpcAuthHeader = "x-ydb-auth-ticket"; 7 | public const string RpcRequestTypeHeader = "x-ydb-request-type"; 8 | public const string RpcTraceIdHeader = "x-ydb-trace-id"; 9 | public const string RpcSdkInfoHeader = "x-ydb-sdk-build-info"; 10 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbParameter.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.Common; 3 | using System.Diagnostics; 4 | using Yandex.Ydb.Driver.Internal.TypeHandlers; 5 | using Yandex.Ydb.Driver.Internal.TypeMapping; 6 | using Ydb; 7 | 8 | namespace Yandex.Ydb.Driver; 9 | 10 | public sealed class YdbParameter : YdbParameter 11 | { 12 | public YdbParameter(string name, T value) 13 | { 14 | TypedValue = value; 15 | ParameterName = name; 16 | } 17 | 18 | public T? TypedValue { get; set; } 19 | 20 | public override object? Value 21 | { 22 | get => TypedValue; 23 | set => TypedValue = (T?)value; 24 | } 25 | 26 | internal override void ResolveHandler(TypeMapper mapper) 27 | { 28 | _handler = mapper.ResolveByValue(TypedValue); 29 | } 30 | 31 | public override TypedValue ToProto() 32 | { 33 | var proto = new TypedValue() 34 | { 35 | Value = new Value() 36 | }; 37 | 38 | Debug.Assert(_handler != null, nameof(_handler) + " != null"); 39 | 40 | _handler.Write(TypedValue, proto.Value); 41 | proto.Type = _handler.GetYdbType(TypedValue); 42 | 43 | return proto; 44 | } 45 | } 46 | 47 | public class YdbParameter : DbParameter 48 | { 49 | private object? _value; 50 | protected YdbTypeHandler? _handler; 51 | 52 | public YdbParameter() 53 | { 54 | ParameterName = string.Empty; 55 | SourceColumn = string.Empty; 56 | ResetDbType(); 57 | } 58 | 59 | public YdbParameter(string name, object value) 60 | { 61 | ResetDbType(); 62 | ParameterName = name; 63 | Value = value; 64 | } 65 | 66 | public override DbType DbType { get; set; } = DbType.Object; 67 | public override ParameterDirection Direction { get; set; } 68 | 69 | public override bool IsNullable { get; set; } 70 | public override string ParameterName { get; set; } 71 | public override string SourceColumn { get; set; } 72 | 73 | internal virtual void ResolveHandler(TypeMapper mapper) 74 | { 75 | _handler = mapper.ResolveByValue(_value); 76 | } 77 | 78 | public override object? Value 79 | { 80 | get => _value; 81 | set 82 | { 83 | _value = value; 84 | _handler = null; 85 | } 86 | } 87 | 88 | public override bool SourceColumnNullMapping { get; set; } 89 | 90 | public override int Size { get; set; } 91 | 92 | public override void ResetDbType() 93 | { 94 | DbType = DbType.Object; 95 | } 96 | 97 | public virtual TypedValue ToProto() 98 | { 99 | var proto = new TypedValue() 100 | { 101 | Value = new Value() 102 | }; 103 | 104 | Debug.Assert(_handler != null, nameof(_handler) + " != null"); 105 | 106 | _handler.Write(_value, proto.Value); 107 | proto.Type = _handler.GetYdbType(_value); 108 | 109 | return proto; 110 | } 111 | } -------------------------------------------------------------------------------- /src/Yandex.Ydb.Driver/Yandex.Ydb.Driver/YdbTransaction.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.Common; 3 | using System.Diagnostics; 4 | using Google.Protobuf.WellKnownTypes; 5 | using Grpc.Core; 6 | using Yandex.Ydb.Driver.Internal.TypeHandling; 7 | using Ydb.Operations; 8 | using Ydb.Table; 9 | using Ydb.Table.V1; 10 | 11 | namespace Yandex.Ydb.Driver; 12 | 13 | public sealed class YdbTransaction : DbTransaction 14 | { 15 | private readonly YdbConnection _connection; 16 | private IsolationLevel _isolationLevel = IsolationLevel.Unspecified; 17 | 18 | public YdbTransaction(YdbConnection connection) 19 | { 20 | _connection = connection; 21 | } 22 | 23 | protected override DbConnection? DbConnection => _connection; 24 | 25 | public override IsolationLevel IsolationLevel => _isolationLevel; 26 | public string TransactionId { get; private set; } 27 | 28 | public string Init(IsolationLevel isolationLevel) 29 | { 30 | Debug.Assert(_connection.Connector != null, "_connection.Connector != null"); 31 | 32 | _isolationLevel = isolationLevel; 33 | var transactionSettings = new TransactionSettings(); 34 | 35 | switch (isolationLevel) 36 | { 37 | case IsolationLevel.ReadUncommitted: 38 | transactionSettings.OnlineReadOnly = new OnlineModeSettings { AllowInconsistentReads = true }; 39 | break; 40 | case IsolationLevel.ReadCommitted: 41 | transactionSettings.StaleReadOnly = new StaleModeSettings(); 42 | break; 43 | case IsolationLevel.Serializable: 44 | transactionSettings.SerializableReadWrite = new SerializableModeSettings(); 45 | break; 46 | case IsolationLevel.Unspecified: 47 | case IsolationLevel.Chaos: 48 | case IsolationLevel.RepeatableRead: 49 | default: 50 | throw new ArgumentOutOfRangeException(nameof(isolationLevel), isolationLevel, null); 51 | } 52 | 53 | var transaction = _connection.Connector.UnaryCall(TableService.BeginTransactionMethod, 54 | new BeginTransactionRequest 55 | { 56 | TxSettings = transactionSettings, 57 | SessionId = _connection.GetSessionId(), 58 | OperationParams = new OperationParams 59 | { 60 | OperationMode = OperationParams.Types.OperationMode.Sync, 61 | CancelAfter = Duration.FromTimeSpan(TimeSpan.FromSeconds(1)), 62 | OperationTimeout = Duration.FromTimeSpan(TimeSpan.FromSeconds(1)) 63 | } 64 | }, GetOptions()); 65 | 66 | var result = transaction.Operation.GetResult(); 67 | TransactionId = result.TxMeta.Id; 68 | 69 | return TransactionId; 70 | } 71 | 72 | private CallOptions GetOptions() 73 | { 74 | return new CallOptions(new Metadata() 75 | { 76 | { YdbMetadata.RpcDatabaseHeader, Connection?.Database ?? string.Empty } 77 | }) 78 | { 79 | }; 80 | } 81 | 82 | public override void Commit() 83 | { 84 | Debug.Assert(_connection.Connector != null, "_connection.Connector != null"); 85 | 86 | var request = new CommitTransactionRequest 87 | { 88 | TxId = TransactionId, 89 | SessionId = _connection.GetSessionId() 90 | }; 91 | 92 | var response = _connection.Connector.UnaryCall(TableService.CommitTransactionMethod, request, GetOptions()); 93 | 94 | //TODO: Unpack only if in settings stats processing is set to true 95 | var result = response.Operation.GetResult(); 96 | } 97 | 98 | public override void Rollback() 99 | { 100 | Debug.Assert(_connection.Connector != null, "_connection.Connector != null"); 101 | 102 | var request = new RollbackTransactionRequest 103 | { 104 | TxId = TransactionId, 105 | SessionId = _connection.GetSessionId() 106 | }; 107 | 108 | var response = _connection.Connector.UnaryCall(TableService.RollbackTransactionMethod, request, GetOptions()); 109 | if (response.Operation.IsFailed()) 110 | throw new YdbDriverException( 111 | $"Failed to rollback transaction `{TransactionId}`. Status: `{response.Operation.Status}`"); 112 | } 113 | } -------------------------------------------------------------------------------- /tests/Yandex.Ydb.Driver.Tests/Yandex.Ydb.Driver.Tests/DapperTests.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | 3 | namespace Yandex.Ydb.Driver.Tests; 4 | 5 | public class DapperTests 6 | { 7 | [Fact] 8 | public async Task QueryDynamic_Success() 9 | { 10 | var connection = TestHelper.GetDefaultConnectionAndOpen(); 11 | var queryAsync = await connection.QueryAsync(@"SELECT 1;"); 12 | 13 | Assert.NotEmpty(queryAsync); 14 | } 15 | 16 | [Fact] 17 | public async Task QueryCast_Success() 18 | { 19 | await using var connection = TestHelper.GetDefaultConnectionAndOpen(); 20 | var queryAsync = await connection.QueryAsync(@"SELECT 123 as id;"); 21 | 22 | Assert.NotNull(queryAsync); 23 | var testClasses = queryAsync as TestClass[] ?? queryAsync.ToArray(); 24 | Assert.NotEmpty(testClasses); 25 | Assert.Equal(123, testClasses[0].Id); 26 | } 27 | 28 | [Fact] 29 | public async Task QueryDynamicParameter_Success() 30 | { 31 | await using var connection = TestHelper.GetDefaultConnectionAndOpen(); 32 | var queryAsync = 33 | await connection.QueryAsync(@"DECLARE $id AS Int32; SELECT $id as id;", 34 | new { }.WithParams(("$id", 123))); 35 | 36 | Assert.NotNull(queryAsync); 37 | var testClasses = queryAsync as TestClass[] ?? queryAsync.ToArray(); 38 | Assert.NotEmpty(testClasses); 39 | Assert.Equal(123, testClasses[0].Id); 40 | } 41 | 42 | public class TestClass 43 | { 44 | public int Id { get; set; } 45 | 46 | public Guid Uuid { get; set; } 47 | } 48 | } 49 | 50 | public static class DapperExt 51 | { 52 | public static DynamicParameters WithParams(this object obj, params (string key, object value)[] pairs) 53 | { 54 | if (obj is DynamicParameters @params) 55 | { 56 | } 57 | else 58 | @params = new DynamicParameters() 59 | { 60 | }; 61 | 62 | foreach (var (key, value) in pairs) 63 | { 64 | @params.Add(key, value); 65 | } 66 | 67 | return @params; 68 | } 69 | } -------------------------------------------------------------------------------- /tests/Yandex.Ydb.Driver.Tests/Yandex.Ydb.Driver.Tests/TestHelper.cs: -------------------------------------------------------------------------------- 1 | namespace Yandex.Ydb.Driver.Tests; 2 | 3 | public static class TestHelper 4 | { 5 | public static YdbConnection GetDefaultConnectionAndOpen() 6 | { 7 | var source = YdbDataSource.Create("Host=localhost;Port=2136"); 8 | var connection = source.CreateConnection(); 9 | 10 | connection.Open(); 11 | 12 | return connection; 13 | } 14 | } -------------------------------------------------------------------------------- /tests/Yandex.Ydb.Driver.Tests/Yandex.Ydb.Driver.Tests/TypeMapperTests.cs: -------------------------------------------------------------------------------- 1 | using Yandex.Ydb.Driver.Internal.TypeHandlers.Primitives; 2 | using Ydb; 3 | using Type = Ydb.Type; 4 | 5 | namespace Yandex.Ydb.Driver.Tests; 6 | 7 | public class TypeMapperTests 8 | { 9 | [Fact] 10 | public void Int64Handler_WriteInt64Value() 11 | { 12 | var tv = new TypedValue() 13 | { 14 | Type = new Type() { TypeId = Type.Types.PrimitiveTypeId.Int32 }, 15 | Value = new Value() { } 16 | }; 17 | 18 | var handler = new Int64Handler(); 19 | handler.Write(321321, tv.Value); 20 | Assert.Equal(321321, tv.Value.Int64Value); 21 | 22 | handler.Write("1111", tv.Value); 23 | Assert.Equal(1111, tv.Value.Int64Value); 24 | 25 | handler.Write(true, tv.Value); 26 | Assert.Equal(1, tv.Value.Int64Value); 27 | 28 | handler.Write(1.0, tv.Value); 29 | Assert.Equal(1, tv.Value.Int64Value); 30 | } 31 | 32 | [Fact] 33 | public void Int32Handler_writeIntValue() 34 | { 35 | var tv = new TypedValue() 36 | { 37 | Type = new Type() { TypeId = Type.Types.PrimitiveTypeId.Int32 }, 38 | Value = new Value() { } 39 | }; 40 | 41 | var handler = new Int32Handler(); 42 | handler.Write(321321, tv.Value); 43 | Assert.Equal(321321, tv.Value.Int32Value); 44 | 45 | handler.Write("1111", tv.Value); 46 | Assert.Equal(1111, tv.Value.Int32Value); 47 | 48 | handler.Write(true, tv.Value); 49 | Assert.Equal(1, tv.Value.Int32Value); 50 | } 51 | 52 | [Fact] 53 | public void Int32Handler_ReturnsIntValue() 54 | { 55 | var tv = new TypedValue() 56 | { 57 | Type = new Type() { TypeId = Type.Types.PrimitiveTypeId.Int32 }, 58 | Value = new Value() { Int32Value = 123123 } 59 | }; 60 | 61 | var handler = new Int32Handler(); 62 | var read = handler.Read(tv.Value); 63 | Assert.Equal(123123, read); 64 | 65 | var readLong = handler.Read(tv.Value); 66 | Assert.Equal(123123L, readLong); 67 | 68 | var readString = handler.Read(tv.Value); 69 | Assert.Equal("123123", readString); 70 | } 71 | } -------------------------------------------------------------------------------- /tests/Yandex.Ydb.Driver.Tests/Yandex.Ydb.Driver.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; -------------------------------------------------------------------------------- /tests/Yandex.Ydb.Driver.Tests/Yandex.Ydb.Driver.Tests/Yandex.Ydb.Driver.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | all 21 | 22 | 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | all 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | PreserveNewest 35 | 36 | 37 | PreserveNewest 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/Yandex.Ydb.Driver.Tests/Yandex.Ydb.Driver.Tests/YdbConnectionTests.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | 3 | namespace Yandex.Ydb.Driver.Tests; 4 | 5 | public class YdbConnectionTests 6 | { 7 | [Fact] 8 | public void YdbConnection_BeginTransaction_Success() 9 | { 10 | var connection = TestHelper.GetDefaultConnectionAndOpen(); 11 | var transaction = connection.BeginTransaction(IsolationLevel.Serializable) as YdbTransaction; 12 | Assert.NotNull(transaction); 13 | Assert.NotNull(transaction.TransactionId); 14 | Assert.NotEmpty(transaction.TransactionId); 15 | } 16 | } -------------------------------------------------------------------------------- /tests/Yandex.Ydb.Driver.Tests/Yandex.Ydb.Driver.Tests/YdbTransactionTests.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | 3 | namespace Yandex.Ydb.Driver.Tests; 4 | 5 | public class YdbTransactionTests 6 | { 7 | [Fact] 8 | public void YdbTransaction_Commit_Success() 9 | { 10 | using var connection = TestHelper.GetDefaultConnectionAndOpen(); 11 | using var transaction = connection.BeginTransaction(IsolationLevel.Serializable); 12 | transaction.Commit(); 13 | } 14 | 15 | [Fact] 16 | public void YdbTransaction_Rollback_Success() 17 | { 18 | using var connection = TestHelper.GetDefaultConnectionAndOpen(); 19 | using var transaction = connection.BeginTransaction(IsolationLevel.Serializable); 20 | transaction.Rollback(); 21 | } 22 | } -------------------------------------------------------------------------------- /tests/Yandex.Ydb.Driver.Tests/Yandex.Ydb.Driver.Tests/certs/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB0zCCATygAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJbG9j 3 | YWxob3N0MB4XDTIzMDEwNjE1MzYyMFoXDTMzMDEwMzE1MzYyMFowFDESMBAGA1UE 4 | AwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4Rh774yH4 5 | PrxVlJFf5LZ2XXE9ZhDG8t/Ie1GWB+3TGV+C1gO5hgpnzSgdrxh+G6cyaU3VqWwv 6 | 9aKy09N4ljrjcHK6wdFbqFWdXNUghM38tb3rf4EEj571LpDnb+qHeAFKy62hdcV1 7 | VxymioEK6f7xDrNG5+36S6F0CXWDlsLPJQIDAQABozQwMjAPBgNVHRMECDAGAQH/ 8 | AgEAMB8GA1UdEQQYMBaCCWxvY2FsaG9zdIIJbG9jYWxob3N0MA0GCSqGSIb3DQEB 9 | CwUAA4GBAGuHIDfzJ8c6nTPhBC2/O2s+Sqp8bgTQhbNnIbdHk+aLSL1YS9YzQ29s 10 | PEjal5nt2HEUBdcxqjduSt1NPjnzVQJ5GSum6wZNoYwRUhnfBJ6JL63Sqsg6ngkT 11 | AmNfiVlYSSMhwv3J05Lh9oog2ifDLZqrgw4GOfcdGNoWTbVOyvcI 12 | -----END CERTIFICATE----- 13 | -------------------------------------------------------------------------------- /tests/Yandex.Ydb.Driver.Tests/Yandex.Ydb.Driver.Tests/certs/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXAIBAAKBgQC4Rh774yH4PrxVlJFf5LZ2XXE9ZhDG8t/Ie1GWB+3TGV+C1gO5 3 | hgpnzSgdrxh+G6cyaU3VqWwv9aKy09N4ljrjcHK6wdFbqFWdXNUghM38tb3rf4EE 4 | j571LpDnb+qHeAFKy62hdcV1VxymioEK6f7xDrNG5+36S6F0CXWDlsLPJQIDAQAB 5 | AoGAYSBcjml+aykt/XGsWj3jymmgGTul1icHutT9ALY3LVAvXnfNSMkUzPd+kH7M 6 | yxNqQhDs/JQrOPAgjF9IFEQizv54lqqo5poR7z/iQQS07QOQsEoyB+dpj1lnehI5 7 | KgVYGM4UfNTMrzlQqJa0YpyPuHCzPWc2/DZYx6MbyIkz9yECQQDt9ISlmAVKURte 8 | 2L84SDq0KuNDjiV6/ugS6bMgjG2N7L4TfFrmSbzi5TfUhVkK3+X+uwndUopiJXBu 9 | AonT7zNJAkEAxj95zQwoXBJqfFF/Km6bl01TKw56EnFitLjpyWVvtVekDjuOL6l2 10 | HDfzsxQHxgKZfga0PMjXbVtU2v0GIVQg/QJAKSuUQ75gs/IChU+FDizZE1EUTxzp 11 | +TTfXF5Y4rnJPrQGUwLCC3QYnT1BgqCrvkjs1zzvQP7F+KM3p6ECzctmGQJAYCI/ 12 | yjLvD1bO1GIgrE7enEwe3G40u+TH3KMem07ZELLjFxPCK1Kdt6laP6ii7F4uWHKf 13 | zCoIbTswttCjvF2zcQJBAMQwfxnRCzOtsWN2eLINTGFXVEbzvOSLHNQmVMJ0dgtf 14 | 95L1+lI2TVKEy0wU3ZIpgOjDG7DROEOHYS3myW79bWc= 15 | -----END RSA PRIVATE KEY----- 16 | --------------------------------------------------------------------------------