From 7c2418b01be6333340d568838196240cfef431c6 Mon Sep 17 00:00:00 2001 From: Thiago Oliveira Santos Date: Thu, 7 Nov 2024 22:35:00 -0300 Subject: [PATCH] feat: first version --- .editorconfig | 182 +++ .github/CODEOWNERS | 31 + .github/workflows/build.yml | 27 + .github/workflows/lint.yml | 27 + .github/workflows/publish.yml | 38 + .github/workflows/semantic.yml | 55 + .github/workflows/test.yml | 47 + .gitignore | 5 + .husky/pre-commit | 1 + .lintstagedrc.json | 3 + .pnpm-debug.log | 1177 +++++++++++++++ .releaserc.json | 28 + CHANGELOG.md | 105 ++ Codibre.Enumerable.sln | 36 + README.md | 158 +- package-lock.json | 1280 +++++++++++++++++ package.json | 28 + run-tests.sh | 4 + .../AsyncBranchingBuilder.cs | 25 + .../AsyncEnumerableExtensions.cs | 9 + .../BranchResult.cs | 27 + .../BranchingBuilder.cs | 25 + .../Codibre.Enumerable.Branching.csproj | 17 + .../Internal/BranchContext.cs | 6 + .../Internal/BranchingHelper.cs | 54 + .../Internal/LinkedNode.cs | 6 + src/Codibre.Enumerable.Branching/README.md | 165 +++ .../Codibre.Enumerable.Branching.Test.csproj | 27 + .../EnumerableExtensionsTest.cs | 28 + .../GlobalUsings.cs | 2 + 30 files changed, 3466 insertions(+), 157 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/CODEOWNERS create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/semantic.yml create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 .husky/pre-commit create mode 100644 .lintstagedrc.json create mode 100644 .pnpm-debug.log create mode 100644 .releaserc.json create mode 100644 CHANGELOG.md create mode 100644 Codibre.Enumerable.sln create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 run-tests.sh create mode 100644 src/Codibre.Enumerable.Branching/AsyncBranchingBuilder.cs create mode 100644 src/Codibre.Enumerable.Branching/AsyncEnumerableExtensions.cs create mode 100644 src/Codibre.Enumerable.Branching/BranchResult.cs create mode 100644 src/Codibre.Enumerable.Branching/BranchingBuilder.cs create mode 100644 src/Codibre.Enumerable.Branching/Codibre.Enumerable.Branching.csproj create mode 100644 src/Codibre.Enumerable.Branching/Internal/BranchContext.cs create mode 100644 src/Codibre.Enumerable.Branching/Internal/BranchingHelper.cs create mode 100644 src/Codibre.Enumerable.Branching/Internal/LinkedNode.cs create mode 100644 src/Codibre.Enumerable.Branching/README.md create mode 100644 test/Codibre.Enumerable.Branching.Test/Codibre.Enumerable.Branching.Test.csproj create mode 100644 test/Codibre.Enumerable.Branching.Test/EnumerableExtensionsTest.cs create mode 100644 test/Codibre.Enumerable.Branching.Test/GlobalUsings.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c1b4787 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,182 @@ +############################### +# Core EditorConfig Options # +############################### +root = true +# All files +[*] + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# Code files +[*.{cs,csx,vb,vbx}] +indent_size = 4 +insert_final_newline = false +charset = utf-8-bom +dotnet_analyzer_diagnostic.category-Style.severity = error +############################### +# .NET Coding Conventions # +############################### +[*.{cs,vb}] +# Organize usings +dotnet_sort_system_directives_first = true +# this. preferences +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_readonly_field = true +# Expression-level preferences +dotnet_style_object_initializer = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_null_propagation = true +dotnet_style_coalesce_expression = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_auto_properties = true +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_analyzer_diagnostic.category-nullable.severity = error +############################### +# Naming Conventions # +############################### +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_simplified_interpolation = true +dotnet_style_namespace_match_folder = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +# Define what we will treat as private fields. +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private +# Define rule that something must begin with an underscore and be in camel case. +dotnet_naming_style.require_underscore_prefix_and_camel_case.required_prefix = _ +dotnet_naming_style.require_underscore_prefix_and_camel_case.capitalization = camel_case +# Appy our rule to private fields. +dotnet_naming_rule.private_fields_must_begin_with_underscore_and_be_in_camel_case.symbols = private_fields +dotnet_naming_rule.private_fields_must_begin_with_underscore_and_be_in_camel_case.style = require_underscore_prefix_and_camel_case +dotnet_naming_rule.private_fields_must_begin_with_underscore_and_be_in_camel_case.severity = error +tab_width = 4 +end_of_line = lf +############################### +# C# Coding Conventions # +############################### + +# IDE0046: Convert to conditional expression +dotnet_diagnostic.IDE0046.severity = none + +[*.cs] +# var preferences +csharp_style_var_for_built_in_types = true +csharp_style_var_when_type_is_apparent = true +csharp_style_var_elsewhere = true +# Expression-bodied members +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = none +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true +csharp_style_expression_bodied_indexers = true +csharp_style_expression_bodied_accessors = true +# Pattern matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_pattern_matching_over_as_with_null_check = true +# Null-checking preferences +csharp_style_throw_expression = true +csharp_style_conditional_delegate_call = true +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async +# Expression-level preferences +csharp_prefer_braces = true +csharp_style_deconstructed_variable_declaration = true +csharp_prefer_simple_default_expression = true +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_inlined_variable_declaration = true +############################### +# C# Formatting Rules # +############################### +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true +# Indentation preferences +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left +# Space preferences +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +# Wrapping preferences +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true +csharp_style_namespace_declarations = file_scoped:silent +csharp_style_prefer_method_group_conversion = true +csharp_style_prefer_top_level_statements = true +csharp_style_expression_bodied_lambdas = true +csharp_style_expression_bodied_local_functions = false:silent +############################### + +# IDE0021: Use block body for constructor +dotnet_diagnostic.IDE0021.severity = none + +# IDE0022: Use block body for method +dotnet_diagnostic.IDE0022.severity = none + +# IDE0011: Add braces +dotnet_diagnostic.IDE0011.severity = none + +# IDE1006: Naming rule violation +dotnet_diagnostic.IDE1006.severity = error + +# IDE0010: Add missing cases to switch statement +dotnet_diagnostic.IDE0010.severity = none + +#IDE0051: unused private methods, fields, properties, and events +dotnet_diagnostic.IDE0051.severity = error + +#IDE0051: unused private methods, fields, properties, and events (entire category of rules) +dotnet_analyzer_diagnostic.category-CodeQuality.severity = error + +# IDE0058: Expression value is never used +dotnet_diagnostic.IDE0058.severity = none + +dotnet_diagnostic.IDE0005.severity = none \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..a69c32d --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,31 @@ +# This is a comment. +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# @global-owner1 and @global-owner2 will be requested for +# review when someone opens a pull request. +* @Farenheith @gustavobeavis @danielgalleni @Dodt @pedrosodre @douglasdrdc @fgabrielsilva @pauloandreget + +# Order is important; the last matching pattern takes the most +# precedence. When someone opens a pull request that only +# modifies JS files, only @js-owner and not the global +# owner(s) will be requested for a review. + +# You can also use email addresses if you prefer. They'll be +# used to look up users just like we do for commit author +# emails. + +# In this example, @doctocat owns any files in the build/logs +# directory at the root of the repository and any of its +# subdirectories. + +# The `docs/*` pattern will match files like +# `docs/getting-started.md` but not further nested files like +# `docs/build-app/troubleshooting.md`. + +# In this example, @octocat owns any file in an apps directory +# anywhere in your repository. + +# In this example, @doctocat owns any file in the `/docs` +# directory in the root of your repository. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..6f7b025 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,27 @@ +# This is a basic workflow to help you get started with Actions + +name: build +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + # Install the .NET SDK indicated in the global.json file + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 7.x.x + 8.x.x + 9.x.x + + - name: Install dependencies + run: npm ci + - name: Build + run: npm run build diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..5165287 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,27 @@ +# This is a basic workflow to help you get started with Actions + +name: lint +on: + pull_request: + branches: [main] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v3 + with: + node-version: "lts/*" + # Install the .NET SDK indicated in the global.json file + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 7.x.x + 8.x.x + 9.x.x + - name: install + run: npm ci + - name: Lint + run: npm run lint diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..22f2699 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,38 @@ +name: publish + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + with: + token: ${{ secrets.GH_TOKEN }} + - name: Log in to Docker Hub + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: codibre/dotnet-grpc-sql-proxy + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Build and push Docker image + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/semantic.yml b/.github/workflows/semantic.yml new file mode 100644 index 0000000..2975cd0 --- /dev/null +++ b/.github/workflows/semantic.yml @@ -0,0 +1,55 @@ +name: semantic-release + +on: + push: + branches: [main] + +env: + ConnectionStrings__SqlConnection: ${{ secrets.CONNECTIONSTRINGS__SQLCONNECTION }} + +jobs: + semantic: + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + NUGET_TOKEN: ${{secrets.NUGET_TOKEN}} + HUSKY: 0 + CI: true + steps: + - uses: actions/checkout@v4 + # Install the .NET SDK indicated in the global.json file + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 7.x.x + 8.x.x + 9.x.x + + - name: Prepare Node + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + + - name: Install dependencies + run: npm ci + - name: Build + run: npm run build + + - name: Test + uses: paambaati/codeclimate-action@v9.0.0 + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + with: + coverageCommand: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage/lcov.info + coverageLocations: ${{github.workspace}}/test/Codibre.GrpcSqlProxy.Test/coverage/lcov.info:lcov + + - name: Semantic Release + run: npm i -g @semantic-release/changelog @semantic-release/commit-analyzer @semantic-release/git @semantic-release/github @semantic-release/exec @droidsolutions-oss/semantic-release-nuget @semantic-release/release-notes-generator semantic-release @semantic-release/error + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + NUGET_TOKEN: ${{secrets.NUGET_TOKEN}} + HUSKY: 0 + CI: true + - run: npx semantic-release --ci + - run: git push diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..749a9c3 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,47 @@ +# This is a basic workflow to help you get started with Actions + +name: test +on: + pull_request: + branches: [main] + +env: + ConnectionStrings__SqlConnection: ${{ secrets.CONNECTIONSTRINGS__SQLCONNECTION }} + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v3 + with: + node-version: "lts/*" + # Install the .NET SDK indicated in the global.json file + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 7.x.x + 8.x.x + 9.x.x + + - name: Prepare Node + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + + - name: Install dependencies + run: npm ci + + # - name: Docker build + # run: npm run docker:build + # - name: Docker run + # run: npm run docker:run + + - name: Test + uses: paambaati/codeclimate-action@v9.0.0 + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + with: + coverageCommand: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage/lcov.info + coverageLocations: ${{github.workspace}}/test/Codibre.GrpcSqlProxy.Test/coverage/lcov.info:lcov diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f038c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin +obj +appsettings.json +coverage +node_modules \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..2312dc5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000..38770d5 --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,3 @@ +{ + "*.cs": "dotnet format --include" +} \ No newline at end of file diff --git a/.pnpm-debug.log b/.pnpm-debug.log new file mode 100644 index 0000000..2b5d1ed --- /dev/null +++ b/.pnpm-debug.log @@ -0,0 +1,1177 @@ +{ + "0 debug pnpm:scope": { + "selected": 1 + }, + "1 debug pnpm:package-manifest": { + "initial": { + "name": "dotnet-grpc-sql-proxy", + "version": "0.0.0", + "description": "Grpc Proxy for Sql Server", + "scripts": { + "build": "dotnet build", + "start": "dotnet start", + "prepare": "husky", + "lint:stage:fix": "lint-staged --relative", + "lint:fix": "dotnet format", + "lint": "dotnet format --verify-no-changes", + "restore": "dotnet restore", + "test": "dotnet test", + "prepare-test-db": "cd devops && sh prepare-db.sh && cd ..", + "unload-test-db": "cd devops && docker compose down && cd ..", + "test:coverage": "dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage/lcov.info" + }, + "devDependencies": { + "husky": "^9.0.11", + "lint-staged": "^15.2.5" + }, + "lint-staged": { + "*.cs": "dotnet format --include" + }, + "keywords": [], + "author": "", + "license": "ISC" + }, + "prefix": "/home/thiago/projects/personal/codibre/grpc-sql-proxy" + }, + "2 debug pnpm:context": { + "currentLockfileExists": false, + "storeDir": "/home/thiago/.pnpm-store/v3", + "virtualStoreDir": "/home/thiago/projects/personal/codibre/grpc-sql-proxy/node_modules/.pnpm" + }, + "3 debug pnpm:stage": { + "prefix": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "stage": "resolution_started" + }, + "4 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/husky/9.1.6", + "wanted": { + "dependentId": ".", + "name": "husky", + "rawSpec": "^9.0.11" + } + }, + "5 debug pnpm:progress": { + "packageId": "registry.npmjs.org/husky/9.1.6", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "6 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/lint-staged/15.2.10", + "wanted": { + "dependentId": ".", + "name": "lint-staged", + "rawSpec": "^15.2.5" + } + }, + "7 debug pnpm:progress": { + "packageId": "registry.npmjs.org/lint-staged/15.2.10", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "8 debug pnpm:progress": { + "packageId": "registry.npmjs.org/husky/9.1.6", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "9 debug pnpm:progress": { + "packageId": "registry.npmjs.org/lint-staged/15.2.10", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "10 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/commander/12.1.0", + "wanted": { + "dependentId": "/lint-staged/15.2.10", + "name": "commander", + "rawSpec": "~12.1.0" + } + }, + "11 debug pnpm:progress": { + "packageId": "registry.npmjs.org/commander/12.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "12 debug pnpm:progress": { + "packageId": "registry.npmjs.org/commander/12.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "13 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/chalk/5.3.0", + "wanted": { + "dependentId": "/lint-staged/15.2.10", + "name": "chalk", + "rawSpec": "~5.3.0" + } + }, + "14 debug pnpm:progress": { + "packageId": "registry.npmjs.org/chalk/5.3.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "15 debug pnpm:progress": { + "packageId": "registry.npmjs.org/chalk/5.3.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "16 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/lilconfig/3.1.2", + "wanted": { + "dependentId": "/lint-staged/15.2.10", + "name": "lilconfig", + "rawSpec": "~3.1.2" + } + }, + "17 debug pnpm:progress": { + "packageId": "registry.npmjs.org/lilconfig/3.1.2", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "18 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/pidtree/0.6.0", + "wanted": { + "dependentId": "/lint-staged/15.2.10", + "name": "pidtree", + "rawSpec": "~0.6.0" + } + }, + "19 debug pnpm:progress": { + "packageId": "registry.npmjs.org/pidtree/0.6.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "20 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/debug/4.3.7", + "wanted": { + "dependentId": "/lint-staged/15.2.10", + "name": "debug", + "rawSpec": "~4.3.6" + } + }, + "21 debug pnpm:progress": { + "packageId": "registry.npmjs.org/debug/4.3.7", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "22 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/execa/8.0.1", + "wanted": { + "dependentId": "/lint-staged/15.2.10", + "name": "execa", + "rawSpec": "~8.0.1" + } + }, + "23 debug pnpm:progress": { + "packageId": "registry.npmjs.org/execa/8.0.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "24 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/micromatch/4.0.8", + "wanted": { + "dependentId": "/lint-staged/15.2.10", + "name": "micromatch", + "rawSpec": "~4.0.8" + } + }, + "25 debug pnpm:progress": { + "packageId": "registry.npmjs.org/micromatch/4.0.8", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "26 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/string-argv/0.3.2", + "wanted": { + "dependentId": "/lint-staged/15.2.10", + "name": "string-argv", + "rawSpec": "~0.3.2" + } + }, + "27 debug pnpm:progress": { + "packageId": "registry.npmjs.org/string-argv/0.3.2", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "28 debug pnpm:progress": { + "packageId": "registry.npmjs.org/lilconfig/3.1.2", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "29 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/listr2/8.2.5", + "wanted": { + "dependentId": "/lint-staged/15.2.10", + "name": "listr2", + "rawSpec": "~8.2.4" + } + }, + "30 debug pnpm:progress": { + "packageId": "registry.npmjs.org/listr2/8.2.5", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "31 debug pnpm:progress": { + "packageId": "registry.npmjs.org/pidtree/0.6.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "32 debug pnpm:progress": { + "packageId": "registry.npmjs.org/debug/4.3.7", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "33 debug pnpm:progress": { + "packageId": "registry.npmjs.org/execa/8.0.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "34 debug pnpm:progress": { + "packageId": "registry.npmjs.org/micromatch/4.0.8", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "35 debug pnpm:progress": { + "packageId": "registry.npmjs.org/string-argv/0.3.2", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "36 debug pnpm:progress": { + "packageId": "registry.npmjs.org/listr2/8.2.5", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "37 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/yaml/2.5.1", + "wanted": { + "dependentId": "/lint-staged/15.2.10", + "name": "yaml", + "rawSpec": "~2.5.0" + } + }, + "38 debug pnpm:progress": { + "packageId": "registry.npmjs.org/yaml/2.5.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "39 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/strip-final-newline/3.0.0", + "wanted": { + "dependentId": "/execa/8.0.1", + "name": "strip-final-newline", + "rawSpec": "^3.0.0" + } + }, + "40 debug pnpm:progress": { + "packageId": "registry.npmjs.org/strip-final-newline/3.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "41 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/npm-run-path/5.3.0", + "wanted": { + "dependentId": "/execa/8.0.1", + "name": "npm-run-path", + "rawSpec": "^5.1.0" + } + }, + "42 debug pnpm:progress": { + "packageId": "registry.npmjs.org/npm-run-path/5.3.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "43 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/is-stream/3.0.0", + "wanted": { + "dependentId": "/execa/8.0.1", + "name": "is-stream", + "rawSpec": "^3.0.0" + } + }, + "44 debug pnpm:progress": { + "packageId": "registry.npmjs.org/is-stream/3.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "45 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/signal-exit/4.1.0", + "wanted": { + "dependentId": "/execa/8.0.1", + "name": "signal-exit", + "rawSpec": "^4.1.0" + } + }, + "46 debug pnpm:progress": { + "packageId": "registry.npmjs.org/signal-exit/4.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "47 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/get-stream/8.0.1", + "wanted": { + "dependentId": "/execa/8.0.1", + "name": "get-stream", + "rawSpec": "^8.0.1" + } + }, + "48 debug pnpm:progress": { + "packageId": "registry.npmjs.org/get-stream/8.0.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "49 debug pnpm:progress": { + "packageId": "registry.npmjs.org/yaml/2.5.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "50 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/merge-stream/2.0.0", + "wanted": { + "dependentId": "/execa/8.0.1", + "name": "merge-stream", + "rawSpec": "^2.0.0" + } + }, + "51 debug pnpm:progress": { + "packageId": "registry.npmjs.org/merge-stream/2.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "52 debug pnpm:progress": { + "packageId": "registry.npmjs.org/strip-final-newline/3.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "53 debug pnpm:progress": { + "packageId": "registry.npmjs.org/npm-run-path/5.3.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "54 debug pnpm:progress": { + "packageId": "registry.npmjs.org/is-stream/3.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "55 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/ms/2.1.3", + "wanted": { + "dependentId": "/debug/4.3.7", + "name": "ms", + "rawSpec": "^2.1.3" + } + }, + "56 debug pnpm:progress": { + "packageId": "registry.npmjs.org/ms/2.1.3", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "57 debug pnpm:progress": { + "packageId": "registry.npmjs.org/signal-exit/4.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "58 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/cross-spawn/7.0.3", + "wanted": { + "dependentId": "/execa/8.0.1", + "name": "cross-spawn", + "rawSpec": "^7.0.3" + } + }, + "59 debug pnpm:progress": { + "packageId": "registry.npmjs.org/cross-spawn/7.0.3", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "60 debug pnpm:progress": { + "packageId": "registry.npmjs.org/get-stream/8.0.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "61 debug pnpm:progress": { + "packageId": "registry.npmjs.org/merge-stream/2.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "62 debug pnpm:progress": { + "packageId": "registry.npmjs.org/ms/2.1.3", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "63 debug pnpm:progress": { + "packageId": "registry.npmjs.org/cross-spawn/7.0.3", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "64 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/braces/3.0.3", + "wanted": { + "dependentId": "/micromatch/4.0.8", + "name": "braces", + "rawSpec": "^3.0.3" + } + }, + "65 debug pnpm:progress": { + "packageId": "registry.npmjs.org/braces/3.0.3", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "66 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/onetime/6.0.0", + "wanted": { + "dependentId": "/execa/8.0.1", + "name": "onetime", + "rawSpec": "^6.0.0" + } + }, + "67 debug pnpm:progress": { + "packageId": "registry.npmjs.org/onetime/6.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "68 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/rfdc/1.4.1", + "wanted": { + "dependentId": "/listr2/8.2.5", + "name": "rfdc", + "rawSpec": "^1.4.1" + } + }, + "69 debug pnpm:progress": { + "packageId": "registry.npmjs.org/rfdc/1.4.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "70 debug pnpm:progress": { + "packageId": "registry.npmjs.org/braces/3.0.3", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "71 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/wrap-ansi/9.0.0", + "wanted": { + "dependentId": "/listr2/8.2.5", + "name": "wrap-ansi", + "rawSpec": "^9.0.0" + } + }, + "72 debug pnpm:progress": { + "packageId": "registry.npmjs.org/wrap-ansi/9.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "73 debug pnpm:progress": { + "packageId": "registry.npmjs.org/onetime/6.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "74 debug pnpm:progress": { + "packageId": "registry.npmjs.org/wrap-ansi/9.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "75 debug pnpm:progress": { + "packageId": "registry.npmjs.org/rfdc/1.4.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "76 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/cli-truncate/4.0.0", + "wanted": { + "dependentId": "/listr2/8.2.5", + "name": "cli-truncate", + "rawSpec": "^4.0.0" + } + }, + "77 debug pnpm:progress": { + "packageId": "registry.npmjs.org/cli-truncate/4.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "78 debug pnpm:progress": { + "packageId": "registry.npmjs.org/cli-truncate/4.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "79 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/eventemitter3/5.0.1", + "wanted": { + "dependentId": "/listr2/8.2.5", + "name": "eventemitter3", + "rawSpec": "^5.0.1" + } + }, + "80 debug pnpm:progress": { + "packageId": "registry.npmjs.org/eventemitter3/5.0.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "81 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/colorette/2.0.20", + "wanted": { + "dependentId": "/listr2/8.2.5", + "name": "colorette", + "rawSpec": "^2.0.20" + } + }, + "82 debug pnpm:progress": { + "packageId": "registry.npmjs.org/colorette/2.0.20", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "83 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/picomatch/2.3.1", + "wanted": { + "dependentId": "/micromatch/4.0.8", + "name": "picomatch", + "rawSpec": "^2.3.1" + } + }, + "84 debug pnpm:progress": { + "packageId": "registry.npmjs.org/picomatch/2.3.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "85 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/log-update/6.1.0", + "wanted": { + "dependentId": "/listr2/8.2.5", + "name": "log-update", + "rawSpec": "^6.1.0" + } + }, + "86 debug pnpm:progress": { + "packageId": "registry.npmjs.org/log-update/6.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "87 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/wrap-ansi/9.0.0", + "wanted": { + "dependentId": "/log-update/6.1.0", + "name": "wrap-ansi", + "rawSpec": "^9.0.0" + } + }, + "88 debug pnpm:progress": { + "packageId": "registry.npmjs.org/colorette/2.0.20", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "89 debug pnpm:progress": { + "packageId": "registry.npmjs.org/eventemitter3/5.0.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "90 debug pnpm:progress": { + "packageId": "registry.npmjs.org/log-update/6.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "91 debug pnpm:progress": { + "packageId": "registry.npmjs.org/picomatch/2.3.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "92 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/slice-ansi/5.0.0", + "wanted": { + "dependentId": "/cli-truncate/4.0.0", + "name": "slice-ansi", + "rawSpec": "^5.0.0" + } + }, + "93 debug pnpm:progress": { + "packageId": "registry.npmjs.org/slice-ansi/5.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "94 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/slice-ansi/7.1.0", + "wanted": { + "dependentId": "/log-update/6.1.0", + "name": "slice-ansi", + "rawSpec": "^7.1.0" + } + }, + "95 debug pnpm:progress": { + "packageId": "registry.npmjs.org/slice-ansi/7.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "96 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/cli-cursor/5.0.0", + "wanted": { + "dependentId": "/log-update/6.1.0", + "name": "cli-cursor", + "rawSpec": "^5.0.0" + } + }, + "97 debug pnpm:progress": { + "packageId": "registry.npmjs.org/cli-cursor/5.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "98 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/ansi-styles/6.2.1", + "wanted": { + "dependentId": "/wrap-ansi/9.0.0", + "name": "ansi-styles", + "rawSpec": "^6.2.1" + } + }, + "99 debug pnpm:progress": { + "packageId": "registry.npmjs.org/ansi-styles/6.2.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "100 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/strip-ansi/7.1.0", + "wanted": { + "dependentId": "/wrap-ansi/9.0.0", + "name": "strip-ansi", + "rawSpec": "^7.1.0" + } + }, + "101 debug pnpm:progress": { + "packageId": "registry.npmjs.org/strip-ansi/7.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "102 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/strip-ansi/7.1.0", + "wanted": { + "dependentId": "/log-update/6.1.0", + "name": "strip-ansi", + "rawSpec": "^7.1.0" + } + }, + "103 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/ansi-escapes/7.0.0", + "wanted": { + "dependentId": "/log-update/6.1.0", + "name": "ansi-escapes", + "rawSpec": "^7.0.0" + } + }, + "104 debug pnpm:progress": { + "packageId": "registry.npmjs.org/ansi-escapes/7.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "105 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/ansi-styles/6.2.1", + "wanted": { + "dependentId": "/slice-ansi/7.1.0", + "name": "ansi-styles", + "rawSpec": "^6.2.1" + } + }, + "106 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/string-width/7.2.0", + "wanted": { + "dependentId": "/wrap-ansi/9.0.0", + "name": "string-width", + "rawSpec": "^7.0.0" + } + }, + "107 debug pnpm:progress": { + "packageId": "registry.npmjs.org/string-width/7.2.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "108 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/string-width/7.2.0", + "wanted": { + "dependentId": "/cli-truncate/4.0.0", + "name": "string-width", + "rawSpec": "^7.0.0" + } + }, + "109 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/strip-ansi/7.1.0", + "wanted": { + "dependentId": "/string-width/7.2.0", + "name": "strip-ansi", + "rawSpec": "^7.1.0" + } + }, + "110 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/ansi-styles/6.2.1", + "wanted": { + "dependentId": "/slice-ansi/5.0.0", + "name": "ansi-styles", + "rawSpec": "^6.0.0" + } + }, + "111 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/fill-range/7.1.1", + "wanted": { + "dependentId": "/braces/3.0.3", + "name": "fill-range", + "rawSpec": "^7.1.1" + } + }, + "112 debug pnpm:progress": { + "packageId": "registry.npmjs.org/fill-range/7.1.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "113 debug pnpm:progress": { + "packageId": "registry.npmjs.org/slice-ansi/5.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "114 debug pnpm:progress": { + "packageId": "registry.npmjs.org/slice-ansi/7.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "115 debug pnpm:progress": { + "packageId": "registry.npmjs.org/strip-ansi/7.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "116 debug pnpm:progress": { + "packageId": "registry.npmjs.org/ansi-styles/6.2.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "117 debug pnpm:progress": { + "packageId": "registry.npmjs.org/cli-cursor/5.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "118 debug pnpm:progress": { + "packageId": "registry.npmjs.org/string-width/7.2.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "119 debug pnpm:progress": { + "packageId": "registry.npmjs.org/fill-range/7.1.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "120 debug pnpm:progress": { + "packageId": "registry.npmjs.org/ansi-escapes/7.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "121 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/environment/1.1.0", + "wanted": { + "dependentId": "/ansi-escapes/7.0.0", + "name": "environment", + "rawSpec": "^1.0.0" + } + }, + "122 debug pnpm:progress": { + "packageId": "registry.npmjs.org/environment/1.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "123 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/restore-cursor/5.1.0", + "wanted": { + "dependentId": "/cli-cursor/5.0.0", + "name": "restore-cursor", + "rawSpec": "^5.0.0" + } + }, + "124 debug pnpm:progress": { + "packageId": "registry.npmjs.org/restore-cursor/5.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "125 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/onetime/7.0.0", + "wanted": { + "dependentId": "/restore-cursor/5.1.0", + "name": "onetime", + "rawSpec": "^7.0.0" + } + }, + "126 debug pnpm:progress": { + "packageId": "registry.npmjs.org/onetime/7.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "127 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/signal-exit/4.1.0", + "wanted": { + "dependentId": "/restore-cursor/5.1.0", + "name": "signal-exit", + "rawSpec": "^4.1.0" + } + }, + "128 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/ansi-regex/6.1.0", + "wanted": { + "dependentId": "/strip-ansi/7.1.0", + "name": "ansi-regex", + "rawSpec": "^6.0.1" + } + }, + "129 debug pnpm:progress": { + "packageId": "registry.npmjs.org/ansi-regex/6.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "130 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/get-east-asian-width/1.2.0", + "wanted": { + "dependentId": "/string-width/7.2.0", + "name": "get-east-asian-width", + "rawSpec": "^1.0.0" + } + }, + "131 debug pnpm:progress": { + "packageId": "registry.npmjs.org/get-east-asian-width/1.2.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "132 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/emoji-regex/10.4.0", + "wanted": { + "dependentId": "/string-width/7.2.0", + "name": "emoji-regex", + "rawSpec": "^10.3.0" + } + }, + "133 debug pnpm:progress": { + "packageId": "registry.npmjs.org/emoji-regex/10.4.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "134 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/is-fullwidth-code-point/5.0.0", + "wanted": { + "dependentId": "/slice-ansi/7.1.0", + "name": "is-fullwidth-code-point", + "rawSpec": "^5.0.0" + } + }, + "135 debug pnpm:progress": { + "packageId": "registry.npmjs.org/is-fullwidth-code-point/5.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "136 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/is-fullwidth-code-point/4.0.0", + "wanted": { + "dependentId": "/slice-ansi/5.0.0", + "name": "is-fullwidth-code-point", + "rawSpec": "^4.0.0" + } + }, + "137 debug pnpm:progress": { + "packageId": "registry.npmjs.org/is-fullwidth-code-point/4.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "138 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/get-east-asian-width/1.2.0", + "wanted": { + "dependentId": "/is-fullwidth-code-point/5.0.0", + "name": "get-east-asian-width", + "rawSpec": "^1.0.0" + } + }, + "139 debug pnpm:progress": { + "packageId": "registry.npmjs.org/environment/1.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "140 debug pnpm:progress": { + "packageId": "registry.npmjs.org/onetime/7.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "141 debug pnpm:progress": { + "packageId": "registry.npmjs.org/restore-cursor/5.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "142 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/to-regex-range/5.0.1", + "wanted": { + "dependentId": "/fill-range/7.1.1", + "name": "to-regex-range", + "rawSpec": "^5.0.1" + } + }, + "143 debug pnpm:progress": { + "packageId": "registry.npmjs.org/to-regex-range/5.0.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "144 debug pnpm:progress": { + "packageId": "registry.npmjs.org/ansi-regex/6.1.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "145 debug pnpm:progress": { + "packageId": "registry.npmjs.org/get-east-asian-width/1.2.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "146 debug pnpm:progress": { + "packageId": "registry.npmjs.org/is-fullwidth-code-point/5.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "147 debug pnpm:progress": { + "packageId": "registry.npmjs.org/to-regex-range/5.0.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "148 debug pnpm:progress": { + "packageId": "registry.npmjs.org/is-fullwidth-code-point/4.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "149 debug pnpm:progress": { + "packageId": "registry.npmjs.org/emoji-regex/10.4.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "150 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/mimic-function/5.0.1", + "wanted": { + "dependentId": "/onetime/7.0.0", + "name": "mimic-function", + "rawSpec": "^5.0.0" + } + }, + "151 debug pnpm:progress": { + "packageId": "registry.npmjs.org/mimic-function/5.0.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "152 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/is-number/7.0.0", + "wanted": { + "dependentId": "/to-regex-range/5.0.1", + "name": "is-number", + "rawSpec": "^7.0.0" + } + }, + "153 debug pnpm:progress": { + "packageId": "registry.npmjs.org/is-number/7.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "154 debug pnpm:progress": { + "packageId": "registry.npmjs.org/mimic-function/5.0.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "155 debug pnpm:progress": { + "packageId": "registry.npmjs.org/is-number/7.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "156 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/human-signals/5.0.0", + "wanted": { + "dependentId": "/execa/8.0.1", + "name": "human-signals", + "rawSpec": "^5.0.0" + } + }, + "157 debug pnpm:progress": { + "packageId": "registry.npmjs.org/human-signals/5.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "158 debug pnpm:progress": { + "packageId": "registry.npmjs.org/human-signals/5.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "159 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/which/2.0.2", + "wanted": { + "dependentId": "/cross-spawn/7.0.3", + "name": "which", + "rawSpec": "^2.0.1" + } + }, + "160 debug pnpm:progress": { + "packageId": "registry.npmjs.org/which/2.0.2", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "161 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/shebang-command/2.0.0", + "wanted": { + "dependentId": "/cross-spawn/7.0.3", + "name": "shebang-command", + "rawSpec": "^2.0.0" + } + }, + "162 debug pnpm:progress": { + "packageId": "registry.npmjs.org/shebang-command/2.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "163 debug pnpm:progress": { + "packageId": "registry.npmjs.org/shebang-command/2.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "164 debug pnpm:progress": { + "packageId": "registry.npmjs.org/which/2.0.2", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "165 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/path-key/4.0.0", + "wanted": { + "dependentId": "/npm-run-path/5.3.0", + "name": "path-key", + "rawSpec": "^4.0.0" + } + }, + "166 debug pnpm:progress": { + "packageId": "registry.npmjs.org/path-key/4.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "167 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/path-key/3.1.1", + "wanted": { + "dependentId": "/cross-spawn/7.0.3", + "name": "path-key", + "rawSpec": "^3.1.0" + } + }, + "168 debug pnpm:progress": { + "packageId": "registry.npmjs.org/path-key/3.1.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "169 debug pnpm:progress": { + "packageId": "registry.npmjs.org/path-key/3.1.1", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "170 debug pnpm:progress": { + "packageId": "registry.npmjs.org/path-key/4.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "171 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/mimic-fn/4.0.0", + "wanted": { + "dependentId": "/onetime/6.0.0", + "name": "mimic-fn", + "rawSpec": "^4.0.0" + } + }, + "172 debug pnpm:progress": { + "packageId": "registry.npmjs.org/mimic-fn/4.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "173 debug pnpm:progress": { + "packageId": "registry.npmjs.org/mimic-fn/4.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "174 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/shebang-regex/3.0.0", + "wanted": { + "dependentId": "/shebang-command/2.0.0", + "name": "shebang-regex", + "rawSpec": "^3.0.0" + } + }, + "175 debug pnpm:progress": { + "packageId": "registry.npmjs.org/shebang-regex/3.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "176 debug pnpm:_dependency_resolved": { + "resolution": "registry.npmjs.org/isexe/2.0.0", + "wanted": { + "dependentId": "/which/2.0.2", + "name": "isexe", + "rawSpec": "^2.0.0" + } + }, + "177 debug pnpm:progress": { + "packageId": "registry.npmjs.org/isexe/2.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "resolved" + }, + "178 debug pnpm:package-manifest": { + "prefix": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "updated": { + "name": "dotnet-grpc-sql-proxy", + "version": "0.0.0", + "description": "Grpc Proxy for Sql Server", + "scripts": { + "build": "dotnet build", + "start": "dotnet start", + "prepare": "husky", + "lint:stage:fix": "lint-staged --relative", + "lint:fix": "dotnet format", + "lint": "dotnet format --verify-no-changes", + "restore": "dotnet restore", + "test": "dotnet test", + "prepare-test-db": "cd devops && sh prepare-db.sh && cd ..", + "unload-test-db": "cd devops && docker compose down && cd ..", + "test:coverage": "dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage/lcov.info" + }, + "devDependencies": { + "husky": "^9.0.11", + "lint-staged": "^15.2.5" + }, + "lint-staged": { + "*.cs": "dotnet format --include" + }, + "keywords": [], + "author": "", + "license": "ISC" + } + }, + "179 debug pnpm:stage": { + "prefix": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "stage": "resolution_done" + }, + "180 debug pnpm:progress": { + "packageId": "registry.npmjs.org/shebang-regex/3.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "181 debug pnpm:progress": { + "packageId": "registry.npmjs.org/isexe/2.0.0", + "requester": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "status": "found_in_store" + }, + "182 debug pnpm:stage": { + "prefix": "/home/thiago/projects/personal/codibre/grpc-sql-proxy", + "stage": "importing_done" + }, + "183 debug pnpm:summary": { + "prefix": "/home/thiago/projects/personal/codibre/grpc-sql-proxy" + }, + "184 error pnpm": { + "message": { + "code": "ELIFECYCLE", + "errno": "ENOENT", + "syscall": "spawn", + "file": "sh", + "pkgid": "dotnet-grpc-sql-proxy@0.0.0", + "stage": "prepare", + "script": "husky", + "pkgname": "dotnet-grpc-sql-proxy" + }, + "err": { + "name": "Error", + "message": "dotnet-grpc-sql-proxy@0.0.0 prepare: `husky`\nspawn ENOENT", + "code": "ELIFECYCLE", + "stack": "Error: dotnet-grpc-sql-proxy@0.0.0 prepare: `husky`\nspawn ENOENT\n at ChildProcess. (/home/thiago/.nvm/versions/node/v20.17.0/lib/node_modules/pnpm/dist/pnpm.js:87651:20)\n at ChildProcess.emit (node:events:519:28)\n at maybeClose (node:internal/child_process:1105:16)\n at ChildProcess._handle.onexit (node:internal/child_process:305:5)" + } + } +} \ No newline at end of file diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 0000000..4839212 --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,28 @@ +{ + "branches": [ + "main" + ], + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/changelog", + "@semantic-release/release-notes-generator", + "@droidsolutions-oss/semantic-release-nuget", + "@semantic-release/github", + "@semantic-release/git" + ], + "preset": "angular", + "npmPublish": false, + "projectPath": "src/Codibre.GrpcSqlProxy.Client/Codibre.GrpcSqlProxy.Client.csproj", + "usePackageVersion": true, + "files": [ + { + "type": "xml", + "replacements": [ + { + "key": "VersionPrefix", + "value": "${nextRelease.version}" + } + ] + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5a3da2f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,105 @@ +## [0.3.2](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.3.1...v0.3.2) (2024-10-29) + + +### Bug Fixes + +* preparing tests using docker ([dc2a12e](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/dc2a12ea5720f5ae29c3f218d433a03235b13337)) + +## [0.3.1](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.3.0...v0.3.1) (2024-10-21) + + +### Bug Fixes + +* bettering channel flow ([af41f90](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/af41f906dc674bbf064ac060e9da35cc60ca5e1d)) + +# [0.3.0](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.2.5...v0.3.0) (2024-10-21) + + +### Features + +* Creating async local controlled Channel ([f19cdcb](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/f19cdcbaddb52d03f82bae6724716652fa8104a1)) + +## [0.2.5](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.2.4...v0.2.5) (2024-10-20) + + +### Bug Fixes + +* refactor monitor for better maintainabillity ([3bad475](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/3bad4752aa886e249622f02f1696101ab28a70b6)) + +## [0.2.4](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.2.3...v0.2.4) (2024-10-20) + + +### Bug Fixes + +* refactor in transaction for better maintainabillity ([0397f0c](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/0397f0c13fa11e0775d3bc113c710c005a9f03ec)) + +## [0.2.3](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.2.2...v0.2.3) (2024-10-20) + + +### Bug Fixes + +* refactor batch query for better maintainability ([e7471d9](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/e7471d91c434a78c3445a4c8afa8ca76e8313082)) + +## [0.2.2](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.2.1...v0.2.2) (2024-10-20) + + +### Bug Fixes + +* fixing batch query options and unused code ([43c255c](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/43c255ca5bbf12af40d2c5d899b7c2f2c08e2015)) + +## [0.2.1](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.2.0...v0.2.1) (2024-10-20) + + +### Bug Fixes + +* fixing badges ([7dad33e](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/7dad33eeef2f5fe3c03f15839f80fc3d1a9c114b)) + +# [0.2.0](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.1.3...v0.2.0) (2024-10-16) + + +### Features + +* supporting batchquery ([488427a](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/488427a69cfcdd62eb5afcdc11ff7cc983021425)) + +## [0.1.3](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.1.2...v0.1.3) (2024-10-14) + + +### Bug Fixes + +* fixing readme ([d71e49b](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/d71e49b945ccd54ab57a5e31f54d0879d6593b22)) + +## [0.1.2](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.1.1...v0.1.2) (2024-10-14) + + +### Bug Fixes + +* preparing transaction for MARS ([624f35e](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/624f35e37ee2c1399670a3ad199fa018838565a5)) + +## [0.1.1](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.1.0...v0.1.1) (2024-10-14) + + +### Bug Fixes + +* fixing readme ([cf02cca](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/cf02ccaf33144d052cdcbb7d2aaa461da5553a79)) + +# [0.1.0](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.0.2...v0.1.0) (2024-10-14) + + +### Features + +* creating params support ([9c4b040](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/9c4b0406d2555d9f2d752c65b674e262e0d5e09b)) +* creating params support ([dc8cb4d](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/dc8cb4d5ee32c6183d257a85b348c904cbf9ec5e)) + +## [0.0.2](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.0.1...v0.0.2) (2024-10-13) + + +### Bug Fixes + +* fixing image name ([ae7a1d6](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/ae7a1d687497e5e507da9499732af8053bd56382)) + +## [0.0.1](https://github.com/codibre/dotnet-grpc-sql-proxy/compare/v0.0.0...v0.0.1) (2024-10-13) + + +### Bug Fixes + +* prepare pipes ([7b37efb](https://github.com/codibre/dotnet-grpc-sql-proxy/commit/7b37efb735aac4f9170beaa1514ffb41d94a1427)) diff --git a/Codibre.Enumerable.sln b/Codibre.Enumerable.sln new file mode 100644 index 0000000..48de987 --- /dev/null +++ b/Codibre.Enumerable.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3316A7AD-74AF-49D1-8782-ADFBDF723572}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codibre.Enumerable.Branching", "src\Codibre.Enumerable.Branching\Codibre.Enumerable.Branching.csproj", "{48406767-8859-46F6-9592-1FD21F94ABA6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{86E3225D-3E86-42C2-AA6D-C9EA1B7380B4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codibre.Enumerable.Branching.Test", "test\Codibre.Enumerable.Branching.Test\Codibre.Enumerable.Branching.Test.csproj", "{FA00C287-9BF8-4E3A-B107-CE7E4EAD15B6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {48406767-8859-46F6-9592-1FD21F94ABA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {48406767-8859-46F6-9592-1FD21F94ABA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {48406767-8859-46F6-9592-1FD21F94ABA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {48406767-8859-46F6-9592-1FD21F94ABA6}.Release|Any CPU.Build.0 = Release|Any CPU + {FA00C287-9BF8-4E3A-B107-CE7E4EAD15B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FA00C287-9BF8-4E3A-B107-CE7E4EAD15B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA00C287-9BF8-4E3A-B107-CE7E4EAD15B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FA00C287-9BF8-4E3A-B107-CE7E4EAD15B6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {48406767-8859-46F6-9592-1FD21F94ABA6} = {3316A7AD-74AF-49D1-8782-ADFBDF723572} + {FA00C287-9BF8-4E3A-B107-CE7E4EAD15B6} = {86E3225D-3E86-42C2-AA6D-C9EA1B7380B4} + EndGlobalSection +EndGlobal diff --git a/README.md b/README.md index ae65ff4..ed007d0 100644 --- a/README.md +++ b/README.md @@ -6,160 +6,4 @@ # Codibre.Enumerable -A library to connect to a grpc sql proxy - -## Why? - -SQlClient has an issue establishing concurrent connections, as described [here](https://github.com/dotnet/SqlClient/issues/601), which may not be a big deal in most cases, but if you have a high latency connection (like when you're connecting to a remote database), this can really escalate quickly on high demanding scenarios. -That said, this library tries to provide a workaround if it's not possible to keep the application close to the database, but you may be vulnerable to big loads of requests. There are other strategies that can also be used (cache, batching queries, etc). This repository just offer another option (very alpha stage), to deal with this situation until Microsoft resolve the issue once for all. - -## How to use? - -First of all, you have to prepare the server. The docker image is ready to be used [here](https://hub.docker.com/r/codibre/dotnet-grpc-sql-proxy). You need to put it as services in the same cloud and region of your SQL Server. - -About the client, you can check the test folder for some other examples, but the usage is quite simple. First, create a the client. You can create it manually, like this: - -```c# -var client = new GrpcSqlProxyClient( - new SqlProxyClientOptions( - _url, // Grpc Proxy Url - sqlConnection // Sql Connection String - ) { - Compress = true, // Where the packets must be compressed - PacketSize = 2000 // How many rows are in each packet (default 1000) - } -); -``` - -You can also inject the client using its built in extensions: - -```c# -servicesCollection.AddGrpcSqlProxy(); -``` - -The configuration will be obtained from **IConfiguration**. You need to declare it like this: - -```json -{ - "ConnectionStrings": { - "SqlConnection": "Server=127.0.0.1;Database=SampleDb;User Id=sa;Password=Sa12345!;Trusted_Connection=False;TrustServerCertificate=True;Integrated Security=False;" - }, - "GrpcSqlProxy": { - "Url": "Proxy Url", - "Compress": "True", - "PacketSize": "2000" - } -} -``` - -Now that you have a client created, you have to establish a channel: - -```c# -using var channel = client.CreateChannel(); -``` - -Finally, you can run your queries: - -```c# -await channel.BeginTransaction(); -await channel.Execute("INSERT INTO MyTable (Field1, Field2) VALUES ('test1', 123)"); -await channel.Commit(); -var result = await channel.QueryFirstOrDefault("SELECT * FROM MyTable"); -``` - -While using the same channel, every command you'll be sent the same connection, so, you can normally create transactions and, when the channel is disposed, the connections will be sent back to the connection pool to be reused. - -The details for each connection are sent by the application client, so, if you have two applications with the exact same connection string, the chances are that they'll share the same connection pools. - -You can also pass parameters, and it's possible to change compression or packetSize options for a single request, as showed below: - -```c# -var result = await channel.QueryFirstOrDefault("SELECT * FROM MyTable WHERE id = @Id", new() -{ - Params = new - { - Id = 1 - }, - PacketSize = 10, - Compress = false -}); -``` - -The result sets returned by the method **Query** are IAsyncEnumerable instances because the packets returned are processed on demand. This is done to keep the memory usage of the proxy controlled. For now, the methods available to execute sql commands are: - -* Execute: To run a query without getting its result (feasible to insert, update, etc); -* Query: To return multiple rows; -* QueryFirst: To get one result and to throw an error if it's not found; -* QueryFirstOrDefault: To get one result or the default value for the type; - -The model passed as a generic parameter for the query methods must be a reference type. You can't use int, bool, or other value types yet, but it can be done in the future. - -# Batch Operations - -One of the features offered by this package is batch operation. With that, you can accumulate many sql operations in a single script, run them, and get separated, properly typed results. To do that as showed below: - -```c# -// Prepare operations -channel.AddNoScriptResult($"UPDATE MyTable SET Field3 = {myValue} WHERE Id = {myId}"); -var itemsHook = channel.QueryHook($"SELECT * FROM MyTable2 WHERE parentId = {myId}"); -var singleItemHook = channel.QueryFirstHook($"SELECT TOP 1 * FROM MyTable3 WHERE parentId = {myId}"); -var optionalSingleItemHook = channel.QueryFirstOrDefaultHook(@$"SELECT - TOP 1 * - FROM MyTable4 - WHERE parentId = {myId}" -); -// Execute all the accumulated operations -await channel.RunQueries(); - -// Get The desired results -var items = itemsHook.Result; -var singleItem = singleItemHook.Result; -var optionalSingleItem = optionalSingleItemHook.Result; -``` - -If you want to accumulate many script but don't want to get any results. You can use `Execute` instead of `RunQueries`. -Theare limitations, though, to how many operations can be executed in a single script: the number of parameters. **SqlClient** only support the maximum of 2100 parameters, so, an error will be thrown if you created a script that have more than 2000 parameters. There tools, though, offered to deal seamlessly with that limitation. -The first one is the **PrepareEnumerable**. This method allow you to execute the batching operations -while iterating through an enumerable, and it will run the partial batches before the maximum number of parameters is reached. The only condition is that you don't reach it during the callback. Here's an example of its use: - -```c# -await channel.Batch.PrepareEnumerable(pars, async (i, b) => - { - return b.QueryFirstHook(@$"SELECT * - FROM MyTable - WHERE Id = {i}"); - }) - // The result if a Enumerable of KeyValue where - // the Key is the input, and the value the result of - // the callback - .ForEachAsync(x => list.Add((x.Key, x.Value.Result))); -``` - -Notice that parameters passed to the batch method are not interpolated string, but FormattableString. -They're used under the hood to build parameterized queries without the need for you to inform the parameters explicitly. - -The second options is the **RunInTransaction** + **AddTransactionScript** methods. This one -servers the purpose of adding persistence operations preferentially in one round trip, but -if the parameter limit is about to be reached, the transaction will be split in many round trips -during the AddTransactionScript call (thus the ValueTask return). Here's an example: - -```c# -await channel.RunInTransaction(async () => -{ - await channel.AddTransactionScript(@$"UPDATE MyTable SET - Field1 = {Value1}, - Field2 = {Value2}, - Field3 = {Value3} - WHERE id = {Id1}"); - await channel.AddTransactionScript(@$"UPDATE MyTable2 SET - Field1 = {Value4}, - Field2 = {Value5}, - Field3 = {Value6} - WHERE id = {Id2}"); - await channel.AddTransactionScript(@$"UPDATE MyTable3 SET - Field1 = {Value6}, - Field2 = {Value7}, - Field3 = {Value8} - WHERE id = {Id3}"); -}); -``` +Repository with many useful extensions for enumerables diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3f63740 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1280 @@ +{ + "name": "dotnet-enumerable", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dotnet-enumerable", + "version": "0.0.0", + "license": "ISC", + "devDependencies": { + "@types/lint-staged": "^13.3.0", + "husky": "^9.0.11", + "lint-staged": "^15.2.10", + "run-container": "^2.0.12" + } + }, + "node_modules/@balena/dockerignore": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz", + "integrity": "sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==", + "dev": true + }, + "node_modules/@types/docker-modem": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/docker-modem/-/docker-modem-3.0.6.tgz", + "integrity": "sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/ssh2": "*" + } + }, + "node_modules/@types/dockerode": { + "version": "3.3.31", + "resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.31.tgz", + "integrity": "sha512-42R9eoVqJDSvVspV89g7RwRqfNExgievLNWoHkg7NoWIqAmavIbgQBb4oc0qRtHkxE+I3Xxvqv7qVXFABKPBTg==", + "dev": true, + "dependencies": { + "@types/docker-modem": "*", + "@types/node": "*", + "@types/ssh2": "*" + } + }, + "node_modules/@types/lint-staged": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@types/lint-staged/-/lint-staged-13.3.0.tgz", + "integrity": "sha512-WxGjVP+rA4OJlEdbZdT9MS9PFKQ7kVPhLn26gC+2tnBWBEFEj/KW+IbFfz6sxdxY5U6V7BvyF+3BzCGsAMHhNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.8.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.1.tgz", + "integrity": "sha512-k6Gi8Yyo8EtrNtkHXutUu2corfDf9su95VYVP10aGYMMROM6SAItZi0w1XszA6RtWTHSVp5OeFof37w0IEqCQg==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/@types/ssh2": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.15.1.tgz", + "integrity": "sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==", + "dev": true, + "dependencies": { + "@types/node": "^18.11.18" + } + }, + "node_modules/@types/ssh2/node_modules/@types/node": { + "version": "18.19.59", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.59.tgz", + "integrity": "sha512-vizm2EqwV/7Zay+A6J3tGl9Lhr7CjZe2HmWS988sefiEmsyP9CeXEleho6i4hJk/8UtZAo0bWN4QPZZr83RxvQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/ssh2/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buildcheck": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz", + "integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/cpu-features": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz", + "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "buildcheck": "~0.0.6", + "nan": "^2.19.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/docker-modem": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-5.0.3.tgz", + "integrity": "sha512-89zhop5YVhcPEt5FpUFGr3cDyceGhq/F9J+ZndQ4KfqNvfbJpPMfgeixFgUj5OjCYAboElqODxY5Z1EBsSa6sg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "readable-stream": "^3.5.0", + "split-ca": "^1.0.1", + "ssh2": "^1.15.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/dockerode": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-4.0.2.tgz", + "integrity": "sha512-9wM1BVpVMFr2Pw3eJNXrYYt6DT9k0xMcsSCjtPvyQ+xa1iPg/Mo3T/gUcwI0B2cczqCeCYRPF8yFYDwtFXT0+w==", + "dev": true, + "dependencies": { + "@balena/dockerignore": "^1.0.2", + "docker-modem": "^5.0.3", + "tar-fs": "~2.0.1" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", + "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", + "dev": true, + "bin": { + "husky": "bin.mjs" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lint-staged": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz", + "integrity": "sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.6", + "execa": "~8.0.1", + "lilconfig": "~3.1.2", + "listr2": "~8.2.4", + "micromatch": "~4.0.8", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.5.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", + "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nan": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", + "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==", + "dev": true, + "optional": true + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-container": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/run-container/-/run-container-2.0.12.tgz", + "integrity": "sha512-edsmzIQx1/T5eb89qiTxz6Yvm3j+5NUONCItadUcNeQoHf/1zm3xO+x0rs429lNLUXWqTzKouIDCtT9AOp5O0Q==", + "dev": true, + "dependencies": { + "@types/dockerode": "^3.3.19", + "dockerode": "^4.0.0", + "execa": "^5.0.0" + } + }, + "node_modules/run-container/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/run-container/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-container/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/run-container/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-container/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/run-container/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-container/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-container/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/run-container/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/split-ca": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz", + "integrity": "sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==", + "dev": true + }, + "node_modules/ssh2": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.16.0.tgz", + "integrity": "sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "asn1": "^0.2.6", + "bcrypt-pbkdf": "^1.0.2" + }, + "engines": { + "node": ">=10.16.0" + }, + "optionalDependencies": { + "cpu-features": "~0.0.10", + "nan": "^2.20.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tar-fs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz", + "integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..43c96de --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "dotnet-enumerable", + "version": "0.0.0", + "description": "Grpc Proxy for Sql Server", + "scripts": { + "build": "dotnet build", + "start": "dotnet start", + "prepare": "husky", + "lint:stage:fix": "lint-staged --relative", + "lint:fix": "dotnet format", + "lint": "dotnet format --verify-no-changes", + "restore": "dotnet restore", + "test": "dotnet test", + "test:coverage": "dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage/lcov.info" + }, + "devDependencies": { + "@types/lint-staged": "^13.3.0", + "husky": "^9.0.11", + "lint-staged": "^15.2.10", + "run-container": "^2.0.12" + }, + "lint-staged": { + "*.cs": "dotnet format --include" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/run-tests.sh b/run-tests.sh new file mode 100644 index 0000000..a5d590e --- /dev/null +++ b/run-tests.sh @@ -0,0 +1,4 @@ +npm run docker:build +docker_id=$(docker run -d --network=host test-grpc-client) +npm run test:coverage +docker kill $docker_id \ No newline at end of file diff --git a/src/Codibre.Enumerable.Branching/AsyncBranchingBuilder.cs b/src/Codibre.Enumerable.Branching/AsyncBranchingBuilder.cs new file mode 100644 index 0000000..d3a5d85 --- /dev/null +++ b/src/Codibre.Enumerable.Branching/AsyncBranchingBuilder.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Codibre.Enumerable.Branching.Internal; + +namespace Codibre.Enumerable.Branching; +public class AsyncBranchingBuilder(IAsyncEnumerable source) +{ + private readonly List, Task>> _branches = []; + public AsyncBranchingBuilder Add(Func, ValueTask> branch, out BranchResult result) + { + var refResult = result = new(); + _branches.Add(async (x) => refResult.Result = await branch(x)); + return this; + } + + public async Task Run() + { + var enumerator = source.GetAsyncEnumerator(); + LinkedNode? node = await enumerator.MoveNextAsync() ? new(enumerator.Current) : null; + var context = new BranchContext(); + await Task.WhenAll(_branches.Select(x => x(node.GetBranchedAsyncIterable(enumerator, context)))); + } +} \ No newline at end of file diff --git a/src/Codibre.Enumerable.Branching/AsyncEnumerableExtensions.cs b/src/Codibre.Enumerable.Branching/AsyncEnumerableExtensions.cs new file mode 100644 index 0000000..a15770d --- /dev/null +++ b/src/Codibre.Enumerable.Branching/AsyncEnumerableExtensions.cs @@ -0,0 +1,9 @@ +using Codibre.Enumerable.Branching.Internal; + +namespace Codibre.Enumerable.Branching; + +public static class EnumerableExtensions +{ + public static AsyncBranchingBuilder Branch(this IAsyncEnumerable enumerable) => new(enumerable); + public static BranchingBuilder Branch(this IEnumerable enumerable) => new(enumerable); +} diff --git a/src/Codibre.Enumerable.Branching/BranchResult.cs b/src/Codibre.Enumerable.Branching/BranchResult.cs new file mode 100644 index 0000000..3a0e0a3 --- /dev/null +++ b/src/Codibre.Enumerable.Branching/BranchResult.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Codibre.Enumerable.Branching; + +public class BranchResult +{ + private bool _set = false; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + private R _result; +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + public R Result + { + get + { + if (_set) return _result; + throw new InvalidOperationException("Result not set yet"); + } + internal set + { + _result = value; + _set = true; + } + } +} \ No newline at end of file diff --git a/src/Codibre.Enumerable.Branching/BranchingBuilder.cs b/src/Codibre.Enumerable.Branching/BranchingBuilder.cs new file mode 100644 index 0000000..5a1495d --- /dev/null +++ b/src/Codibre.Enumerable.Branching/BranchingBuilder.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Codibre.Enumerable.Branching.Internal; + +namespace Codibre.Enumerable.Branching; + +public class BranchingBuilder(IEnumerable source) +{ + private readonly List, Task>> _branches = []; + public BranchingBuilder Add(Func, ValueTask> branch, out BranchResult result) + { + var refResult = result = new(); + _branches.Add(async (x) => refResult.Result = await branch(x)); + return this; + } + + public Task Run() + { + var enumerator = source.GetEnumerator(); + LinkedNode? node = enumerator.MoveNext() ? new(enumerator.Current) : null; + return Task.WhenAll(_branches.Select(x => x(node.GetBranchedIterable(enumerator)))); + } +} \ No newline at end of file diff --git a/src/Codibre.Enumerable.Branching/Codibre.Enumerable.Branching.csproj b/src/Codibre.Enumerable.Branching/Codibre.Enumerable.Branching.csproj new file mode 100644 index 0000000..cf35aed --- /dev/null +++ b/src/Codibre.Enumerable.Branching/Codibre.Enumerable.Branching.csproj @@ -0,0 +1,17 @@ + + + + net9.0 + enable + enable + + + + + + + + + + + diff --git a/src/Codibre.Enumerable.Branching/Internal/BranchContext.cs b/src/Codibre.Enumerable.Branching/Internal/BranchContext.cs new file mode 100644 index 0000000..0e5bebd --- /dev/null +++ b/src/Codibre.Enumerable.Branching/Internal/BranchContext.cs @@ -0,0 +1,6 @@ +namespace Codibre.Enumerable.Branching.Internal; + +internal class BranchContext +{ + public Task? Next { get; set; } +} diff --git a/src/Codibre.Enumerable.Branching/Internal/BranchingHelper.cs b/src/Codibre.Enumerable.Branching/Internal/BranchingHelper.cs new file mode 100644 index 0000000..89bf876 --- /dev/null +++ b/src/Codibre.Enumerable.Branching/Internal/BranchingHelper.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Codibre.Enumerable.Branching.Internal; + +internal static class BranchingHelper +{ + internal static async IAsyncEnumerable GetBranchedIterable(this LinkedNode? node, IEnumerator enumerator) + { + while (node is not null) + { + yield return await Task.FromResult(node.Value); + if (node.Next is null) + { + lock (enumerator) + { + if (node.Next is null && enumerator.MoveNext()) + { + node.Next = new(enumerator.Current); + } + } + } + node = node.Next; + } + } + + internal static async IAsyncEnumerable GetBranchedAsyncIterable(this LinkedNode? node, IAsyncEnumerator enumerator, BranchContext context) + { + while (node is not null) + { + yield return node.Value; + if (node.Next is null) + { + lock (enumerator) context.Next = GetNext(enumerator, node, context); + await context.Next; + } + node = node.Next; + } + } + + internal static async Task GetNext(IAsyncEnumerator enumerator, LinkedNode node, BranchContext context) + { + try + { + if (node.Next is null && await enumerator.MoveNextAsync()) node.Next = new(enumerator.Current); + } + finally + { + context.Next = null; + } + } +} \ No newline at end of file diff --git a/src/Codibre.Enumerable.Branching/Internal/LinkedNode.cs b/src/Codibre.Enumerable.Branching/Internal/LinkedNode.cs new file mode 100644 index 0000000..ace7440 --- /dev/null +++ b/src/Codibre.Enumerable.Branching/Internal/LinkedNode.cs @@ -0,0 +1,6 @@ +namespace Codibre.Enumerable.Branching.Internal; + +internal record LinkedNode(T Value) +{ + public LinkedNode? Next { get; set; } +} diff --git a/src/Codibre.Enumerable.Branching/README.md b/src/Codibre.Enumerable.Branching/README.md new file mode 100644 index 0000000..ae65ff4 --- /dev/null +++ b/src/Codibre.Enumerable.Branching/README.md @@ -0,0 +1,165 @@ +[![Actions Status](https://github.com/Codibre/dotnet-grpc-sql-proxy/workflows/build/badge.svg)](https://github.com/Codibre/dotnet-grpc-sql-proxy/actions) +[![Actions Status](https://github.com/Codibre/dotnet-grpc-sql-proxy/workflows/test/badge.svg)](https://github.com/Codibre/dotnet-grpc-sql-proxy/actions) +[![Actions Status](https://github.com/Codibre/dotnet-grpc-sql-proxy/workflows/lint/badge.svg)](https://github.com/Codibre/dotnet-grpc-sql-proxy/actions) +[![Test Coverage](https://api.codeclimate.com/v1/badges/1a86a06e659ab9e87820/test_coverage)](https://codeclimate.com/github/codibre/dotnet-grpc-sql-proxy/test_coverage) +[![Maintainability](https://api.codeclimate.com/v1/badges/1a86a06e659ab9e87820/maintainability)](https://codeclimate.com/github/codibre/dotnet-grpc-sql-proxy/maintainability) + +# Codibre.Enumerable + +A library to connect to a grpc sql proxy + +## Why? + +SQlClient has an issue establishing concurrent connections, as described [here](https://github.com/dotnet/SqlClient/issues/601), which may not be a big deal in most cases, but if you have a high latency connection (like when you're connecting to a remote database), this can really escalate quickly on high demanding scenarios. +That said, this library tries to provide a workaround if it's not possible to keep the application close to the database, but you may be vulnerable to big loads of requests. There are other strategies that can also be used (cache, batching queries, etc). This repository just offer another option (very alpha stage), to deal with this situation until Microsoft resolve the issue once for all. + +## How to use? + +First of all, you have to prepare the server. The docker image is ready to be used [here](https://hub.docker.com/r/codibre/dotnet-grpc-sql-proxy). You need to put it as services in the same cloud and region of your SQL Server. + +About the client, you can check the test folder for some other examples, but the usage is quite simple. First, create a the client. You can create it manually, like this: + +```c# +var client = new GrpcSqlProxyClient( + new SqlProxyClientOptions( + _url, // Grpc Proxy Url + sqlConnection // Sql Connection String + ) { + Compress = true, // Where the packets must be compressed + PacketSize = 2000 // How many rows are in each packet (default 1000) + } +); +``` + +You can also inject the client using its built in extensions: + +```c# +servicesCollection.AddGrpcSqlProxy(); +``` + +The configuration will be obtained from **IConfiguration**. You need to declare it like this: + +```json +{ + "ConnectionStrings": { + "SqlConnection": "Server=127.0.0.1;Database=SampleDb;User Id=sa;Password=Sa12345!;Trusted_Connection=False;TrustServerCertificate=True;Integrated Security=False;" + }, + "GrpcSqlProxy": { + "Url": "Proxy Url", + "Compress": "True", + "PacketSize": "2000" + } +} +``` + +Now that you have a client created, you have to establish a channel: + +```c# +using var channel = client.CreateChannel(); +``` + +Finally, you can run your queries: + +```c# +await channel.BeginTransaction(); +await channel.Execute("INSERT INTO MyTable (Field1, Field2) VALUES ('test1', 123)"); +await channel.Commit(); +var result = await channel.QueryFirstOrDefault("SELECT * FROM MyTable"); +``` + +While using the same channel, every command you'll be sent the same connection, so, you can normally create transactions and, when the channel is disposed, the connections will be sent back to the connection pool to be reused. + +The details for each connection are sent by the application client, so, if you have two applications with the exact same connection string, the chances are that they'll share the same connection pools. + +You can also pass parameters, and it's possible to change compression or packetSize options for a single request, as showed below: + +```c# +var result = await channel.QueryFirstOrDefault("SELECT * FROM MyTable WHERE id = @Id", new() +{ + Params = new + { + Id = 1 + }, + PacketSize = 10, + Compress = false +}); +``` + +The result sets returned by the method **Query** are IAsyncEnumerable instances because the packets returned are processed on demand. This is done to keep the memory usage of the proxy controlled. For now, the methods available to execute sql commands are: + +* Execute: To run a query without getting its result (feasible to insert, update, etc); +* Query: To return multiple rows; +* QueryFirst: To get one result and to throw an error if it's not found; +* QueryFirstOrDefault: To get one result or the default value for the type; + +The model passed as a generic parameter for the query methods must be a reference type. You can't use int, bool, or other value types yet, but it can be done in the future. + +# Batch Operations + +One of the features offered by this package is batch operation. With that, you can accumulate many sql operations in a single script, run them, and get separated, properly typed results. To do that as showed below: + +```c# +// Prepare operations +channel.AddNoScriptResult($"UPDATE MyTable SET Field3 = {myValue} WHERE Id = {myId}"); +var itemsHook = channel.QueryHook($"SELECT * FROM MyTable2 WHERE parentId = {myId}"); +var singleItemHook = channel.QueryFirstHook($"SELECT TOP 1 * FROM MyTable3 WHERE parentId = {myId}"); +var optionalSingleItemHook = channel.QueryFirstOrDefaultHook(@$"SELECT + TOP 1 * + FROM MyTable4 + WHERE parentId = {myId}" +); +// Execute all the accumulated operations +await channel.RunQueries(); + +// Get The desired results +var items = itemsHook.Result; +var singleItem = singleItemHook.Result; +var optionalSingleItem = optionalSingleItemHook.Result; +``` + +If you want to accumulate many script but don't want to get any results. You can use `Execute` instead of `RunQueries`. +Theare limitations, though, to how many operations can be executed in a single script: the number of parameters. **SqlClient** only support the maximum of 2100 parameters, so, an error will be thrown if you created a script that have more than 2000 parameters. There tools, though, offered to deal seamlessly with that limitation. +The first one is the **PrepareEnumerable**. This method allow you to execute the batching operations +while iterating through an enumerable, and it will run the partial batches before the maximum number of parameters is reached. The only condition is that you don't reach it during the callback. Here's an example of its use: + +```c# +await channel.Batch.PrepareEnumerable(pars, async (i, b) => + { + return b.QueryFirstHook(@$"SELECT * + FROM MyTable + WHERE Id = {i}"); + }) + // The result if a Enumerable of KeyValue where + // the Key is the input, and the value the result of + // the callback + .ForEachAsync(x => list.Add((x.Key, x.Value.Result))); +``` + +Notice that parameters passed to the batch method are not interpolated string, but FormattableString. +They're used under the hood to build parameterized queries without the need for you to inform the parameters explicitly. + +The second options is the **RunInTransaction** + **AddTransactionScript** methods. This one +servers the purpose of adding persistence operations preferentially in one round trip, but +if the parameter limit is about to be reached, the transaction will be split in many round trips +during the AddTransactionScript call (thus the ValueTask return). Here's an example: + +```c# +await channel.RunInTransaction(async () => +{ + await channel.AddTransactionScript(@$"UPDATE MyTable SET + Field1 = {Value1}, + Field2 = {Value2}, + Field3 = {Value3} + WHERE id = {Id1}"); + await channel.AddTransactionScript(@$"UPDATE MyTable2 SET + Field1 = {Value4}, + Field2 = {Value5}, + Field3 = {Value6} + WHERE id = {Id2}"); + await channel.AddTransactionScript(@$"UPDATE MyTable3 SET + Field1 = {Value6}, + Field2 = {Value7}, + Field3 = {Value8} + WHERE id = {Id3}"); +}); +``` diff --git a/test/Codibre.Enumerable.Branching.Test/Codibre.Enumerable.Branching.Test.csproj b/test/Codibre.Enumerable.Branching.Test/Codibre.Enumerable.Branching.Test.csproj new file mode 100644 index 0000000..32531ab --- /dev/null +++ b/test/Codibre.Enumerable.Branching.Test/Codibre.Enumerable.Branching.Test.csproj @@ -0,0 +1,27 @@ + + + + net9.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + + diff --git a/test/Codibre.Enumerable.Branching.Test/EnumerableExtensionsTest.cs b/test/Codibre.Enumerable.Branching.Test/EnumerableExtensionsTest.cs new file mode 100644 index 0000000..33a3a27 --- /dev/null +++ b/test/Codibre.Enumerable.Branching.Test/EnumerableExtensionsTest.cs @@ -0,0 +1,28 @@ +namespace Codibre.Enumerable.Branching.Test; + +public class UnitTest1 +{ + private static IEnumerable Op(int[] list) => list + .Select(x => x * 2) + .Select(x => x + 2) + .Select(x => x / 2); + [Fact] + public async Task Should_Branch_Results() + { + // Arrange + int[] list = [1, 2, 3]; + var enumerable = Op(list); + + // Act + await enumerable.Branch() + .Add(x => x.ToArrayAsync(), out var a) + .Add(x => x.ToArrayAsync(), out var b) + .Add(x => x.ToArrayAsync(), out var c) + .Run(); + + // Assert + a.Result.Should().BeEquivalentTo(enumerable.ToArray()); + b.Result.Should().BeEquivalentTo(enumerable.ToArray()); + c.Result.Should().BeEquivalentTo(enumerable.ToArray()); + } +} diff --git a/test/Codibre.Enumerable.Branching.Test/GlobalUsings.cs b/test/Codibre.Enumerable.Branching.Test/GlobalUsings.cs new file mode 100644 index 0000000..a9ca8da --- /dev/null +++ b/test/Codibre.Enumerable.Branching.Test/GlobalUsings.cs @@ -0,0 +1,2 @@ +global using FluentAssertions; +global using Xunit; \ No newline at end of file