Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
cc14a25
fix: resolve issues found with initial POC tests
ClasicRando Aug 29, 2025
b3472d6
feat: Add IBufferWriter interface to WriteBuffer, clean up WriteBuffer
ClasicRando Sep 1, 2025
ef0691b
feat: Start writing tests, clean up ReadBuffer
ClasicRando Sep 1, 2025
66a771d
feat: Add more tests and documentation, change connection state to cu…
ClasicRando Sep 1, 2025
34672ff
feat: rework Either to take up less memory
ClasicRando Sep 2, 2025
9cf15f3
feat: Remove frontend message objects for stream methods, fix deadloc…
ClasicRando Sep 3, 2025
001161d
feat: add more tests and docs, simplify some interfaces
ClasicRando Sep 5, 2025
1d32e07
feat: expand upon the query API, change IDataRow to not provide a gen…
ClasicRando Sep 7, 2025
81a96bd
feat: make range types easier, add array type, complete base range types
ClasicRando Sep 8, 2025
e21f411
feat: clean up array type, data row and executable query for postgres…
ClasicRando Sep 8, 2025
f42c4a8
feat: make tinyint extracted sbyte to match SQL standard, make array …
ClasicRando Sep 10, 2025
861c399
feat: add array type decoding
ClasicRando Sep 10, 2025
6d8181d
feat: clean up some type definitions
ClasicRando Sep 10, 2025
f03f5c2
feat: add doc comments, rework IQuery to use extension methods for nu…
ClasicRando Sep 11, 2025
3df7b86
feat: convert nullable decoding to extension methods, consolidate pos…
ClasicRando Sep 12, 2025
19ac175
feat: use source generation to make pg decode methods
ClasicRando Sep 13, 2025
0b6bed4
feat: simplify array type source generation
ClasicRando Sep 13, 2025
244c30d
chore: rename ColumnDecodeError to ColumnDecodeException
ClasicRando Sep 14, 2025
52457fa
chore: add doc comments
ClasicRando Sep 16, 2025
7deddac
feat: include more docs, small chnages to buffers, reduce usage of cu…
ClasicRando Sep 16, 2025
4b2bd8e
feat: remove need to supply lambda for length prefixed writing, expos…
ClasicRando Sep 17, 2025
8a2e93c
feat: More doc comments, change simple password auth to not create te…
ClasicRando Sep 20, 2025
45d4251
feat: simplify notification type, add more doc comments
ClasicRando Sep 22, 2025
c76e848
feat: Add source generation for bind methods, clean up query paramete…
ClasicRando Sep 23, 2025
875824c
feat: Make column metadata to a struct, update ref structs that use i…
ClasicRando Sep 24, 2025
e83bb80
feat: implement disposal pattern for connections, change connection t…
ClasicRando Sep 26, 2025
af1593d
feat: add and fix more docs, fix stackalloc overflows bugs
ClasicRando Sep 29, 2025
ae9b15c
feat: add more docs, small changes/fixes
ClasicRando Oct 10, 2025
7e794cb
feat: add postgres tests project
ClasicRando Oct 10, 2025
c7701a1
feat: add tests for types, fix issues
ClasicRando Oct 13, 2025
c673a6e
feat: add tests for connection specs
ClasicRando Nov 11, 2025
451c849
feat: add tests for type encoding and decoding against a real database
ClasicRando Nov 11, 2025
fd0c180
feat: set up query batching components without actually implementatin…
ClasicRando Nov 15, 2025
3195cc1
feat: allow for non-simple types to check compatiability, split macad…
ClasicRando Nov 21, 2025
faa9b0f
feat: update to .net10, account for breaking change to IPNetwork wher…
ClasicRando Nov 22, 2025
6590c8b
feat: allow for internal async stream buffer to be reallocated when n…
ClasicRando Nov 23, 2025
5e87a77
feat: reduce copying of data to temp buffers when backend message is …
ClasicRando Nov 23, 2025
f291dda
feat: create specific type for postgres' oid, use uint for type ID
ClasicRando Nov 24, 2025
ac9c028
feat: add bit string types, add missing data row extractors
ClasicRando Nov 27, 2025
e2eaef7
feat: allow for mapping enum and composite types for connection pools…
ClasicRando Nov 29, 2025
e225b80
feat: allow for composite type encoding and decoding, remove IQueryEx…
ClasicRando Dec 2, 2025
4a5f3b7
chore: simplify test suite, fix broken tests
ClasicRando Dec 2, 2025
ffef8b5
feat: remove self return on IBindable methods, update docs and rename…
ClasicRando Dec 16, 2025
03bd633
feat: add IPgDataRow as postgres specific type, remove extension meth…
ClasicRando Dec 19, 2025
b8199de
feat: rework library to avoid using core library types everywhere and…
ClasicRando Dec 19, 2025
d1f3c14
feat: simplify binding, remove source generation for bind methods, ad…
ClasicRando Dec 19, 2025
998c045
feat: implement connection pooling in core module, leverage pooling i…
ClasicRando Dec 23, 2025
21c7000
feat: add tests for query pipeling, add Async suffix to async methods…
ClasicRando Dec 24, 2025
b9aedc6
feat: Simplify connection options object, small cleanups
ClasicRando Dec 27, 2025
1950c84
feat: migrate to tunit testing framework
ClasicRando Dec 29, 2025
397a265
feat: add COPY functionality to postgres connections
ClasicRando Jan 2, 2026
4212837
chore: simplify API to avoid unexpected behaviour where queries are "…
ClasicRando Jan 2, 2026
676b97e
feat: rely upon extension methods of IBufferWriter rather than custom…
ClasicRando Jan 3, 2026
5dc2b50
feat: change IPgDbType.Encode to use IBufferWriter
ClasicRando Jan 3, 2026
67bf4c3
feat: Remove write buffering from PgStream, expose write buffer from …
ClasicRando Jan 3, 2026
8c193cd
feat: strip down AsyncStream, leverage ReadOnlySequence for messages
ClasicRando Jan 4, 2026
1cb4c89
feat: add copy in with data rows feature, simplify parameter writing,…
ClasicRando Jan 4, 2026
4a89f56
chore: doc comment updates, rename property
ClasicRando Jan 8, 2026
56b576e
feat: add listen/notify capabilities to postgres repo, remove notific…
ClasicRando Jan 15, 2026
83fc33d
chore: enable analyzers, fix analyzer warning, enable warnings as err…
ClasicRando Jan 17, 2026
e99b4e3
feat: use in parameters where possible, make ref variables ref readon…
ClasicRando Jan 19, 2026
1ca1b1a
feat: add interface for binding many values, create extension methods…
ClasicRando Jan 25, 2026
1871ed4
feat: add source generator for enum definitions as pg types
ClasicRando Jan 27, 2026
3731bba
feat: add tests for enum type generator, rework source generation to …
ClasicRando Jan 27, 2026
fc452ec
feat: add source generation for composite type, IFromRow and IBindMany
ClasicRando Feb 4, 2026
d20db1d
feat: get ready for CI actions, use TUnit property injection for fixture
ClasicRando Feb 9, 2026
6b05149
feat: remove ability to send query as copy to row command, specify to…
ClasicRando Feb 9, 2026
854822c
test: include more details about span creation argument exception
ClasicRando Feb 9, 2026
77338a1
fix: use buffer for query execution before exiting method
ClasicRando Feb 9, 2026
0574a93
fix: nullable field FromRow deserialization
ClasicRando Feb 11, 2026
5112048
feat: use async linq where possible, remove boxing of reference
ClasicRando Feb 12, 2026
5c5e912
feat: remove PipeReader to improve throughput of application
ClasicRando Feb 12, 2026
9f57b6b
feat: remove semaphore and use interlocked variable to control query …
ClasicRando Feb 12, 2026
2ce31fd
feat: make Either a simple struct
ClasicRando Feb 12, 2026
4cd65be
feat: remove async streams that yield to async stream, etc.; update c…
ClasicRando Feb 13, 2026
b8a221f
feat: remove message processing to check message type and deserialize…
ClasicRando Feb 15, 2026
5f7c7db
feat: remove batch query specifc result set type
ClasicRando Feb 16, 2026
efbbe36
feat: add more benchmarks, small changes
ClasicRando Feb 16, 2026
c76d0ba
perf: pool more arrays
ClasicRando Feb 19, 2026
2c28277
feat: simplify result set collection when query batch, consolidate so…
ClasicRando Feb 23, 2026
20c4131
chore: clean up API, remove some things
ClasicRando Feb 23, 2026
97627b7
feat: expand README, remove unnecessary API components, add more exte…
ClasicRando Feb 25, 2026
d829dd5
fix: revert to use extended protocol by default for simple queries if…
ClasicRando Feb 26, 2026
2416991
feat: create benchmarks markdown, move postgres specific benchmarks t…
ClasicRando Feb 26, 2026
d0ee638
feat: remove open method, seal classes, make executable query async d…
ClasicRando Feb 26, 2026
5a0f272
feat: add copy benchmarks, modify copy API to improve performance
ClasicRando Feb 26, 2026
b4a128d
perf: fix performance issues with binary copy out actions, add bencha…
ClasicRando Mar 2, 2026
bb0e527
feat: add more copy benchmarks, improve memory allocations for copy out
ClasicRando Mar 2, 2026
9c8b5c7
feat: simplify copy operations, remove array pooling for direct memor…
ClasicRando Mar 2, 2026
510ea4a
feat: remove cached values for colum name lookup and row data ranges
ClasicRando Mar 2, 2026
6c56cc3
chore: simplify benchmark code, move types to files, use main file
ClasicRando Mar 5, 2026
7df05d7
feat: add batch query benchmarks
ClasicRando Mar 5, 2026
1813f83
feat: simplify the IAsyncConnector API
ClasicRando Mar 7, 2026
f162ed8
feat: Add missing SqlState variants, move methods to extension block
ClasicRando Mar 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ indent_size = 4
csharp_new_line_before_members_in_object_initializers = false
csharp_preferred_modifier_order = public, private, protected, internal, file, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async, required:suggestion
csharp_style_var_for_built_in_types = true:suggestion
csharp_wrap_parameters_style = chop_if_long
csharp_wrap_arguments_style = chop_if_long
csharp_keep_user_linebreaks = true
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
Expand All @@ -21,11 +24,15 @@ dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
csharp_arguments_named = named
dotnet_code_quality.ca1051.exclude_structs = true

# ReSharper properties
resharper_csharp_insert_final_newline = true
resharper_for_simple_types = use_var_when_evident
resharper_trailing_comma_in_multiline_lists = true
resharper_csharp_wrap_arguments_style = chop_if_long
resharper_csharp_keep_existing_linebreaks = true

[{*.yaml,*.yml}]
indent_size = 2
Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,12 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.408'
dotnet-version: '10.0'
- run: dotnet build
- name: Run Tests
run: |
dotnet test
env:
POSTGRES_PORT: ${{ env.POSTGRES_PORT }}
POSTGRES_USERNAME: ${{ env.POSTGRES_USERNAME }}
POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
POSTGRES_DATABASE: ${{ env.POSTGRES_DATABASE }}
PG_USERNAME: ${{ env.POSTGRES_USERNAME }}
PG_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
PG_DATABASE: ${{ env.POSTGRES_DATABASE }}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/
/_ReSharper.Caches/
run_actions
186 changes: 185 additions & 1 deletion README.MD
Original file line number Diff line number Diff line change
@@ -1,2 +1,186 @@
# SQLx C#
.NET Library for database access that leverages new features in C# to improve upon the ADO.NET API.
## Overview
.NET Library for database access that leverages new features in C# to improve upon the ADO.NET API.
The aim of the library is to include other databases with open/available client protocol
documentation.

## Core
### Basic Query
```c#
struct Row : IFromRow<DbRow, Row>
{
public required int Id { get; init; }

public required string Name { get; init; }

public required int? ChildId { get; init; }

public static Row FromRow(DbRow dataRow)
{
return new Row
{
Id = dataRow.GetIntNotNull("id"),
Name = dataRow.GetStringNotNull("name"),
ChildId = dataRow.GetInt("child_id"),
};
}
}

// Full usage
await using var connection = pool.CreateConnection();
using var query = connection.CreateQuery(sql);
var rows = await query.FetchAllAsync<Row>();

// With no query
// Creates query, executes query to fetch all and disposes of the query
await using var connection = pool.CreateConnection();
var rows = await connection.FetchAllAsync<Row>(sql);

// With no connection
// Create connection, create query, executes query to fetch all and disposes of connection and query
var rows = await pool.FetchAllAsync<Row>(sql);
```

### Parameterized Query
```c#
struct Param : IBindMany<DbBindable>
{
public required int Id { get; init; }

public void BindMany(DbBindable bindable)
{
bindable.Bind(Id);
}
}

// Full usage with manual binding
await using var connection = pool.CreateConnection();
using var query = connection.CreateQuery(parameterizedQuery);
// Binds to first parameter present in query
query.Bind(1);
var rows = await query.FetchAllAsync<Row>();

// With no query and param type
await using var connection = pool.CreateConnection();
var rows = await connection.FetchAllAsync<Param, Row>(sql, new Param { Id = 1 });

// With no connection or query and param type
var rows = await pool.FetchAllAsync<Param, Row>(sql, new Param { Id = 1 });
```

### Batch Queries
```c#
// With query batch, manually binding parameters
await using var connection = pool.CreateConnection();
using var queryBatch = connection.CreateQueryBatch();

Param[] paramBatches;
foreach (Param param in paramBatches)
{
var query = queryBatch.CreateQuery(insertSql);
param.BindMany(query);
}

var rowsAffected = await queryBatch.ExecuteNonQueryAsync();

// With extension method
await using var connection = pool.CreateConnection();
Param[] paramBatches;
var rowsAffected = await connection.ExecuteNonQueryBatchAsync(insertSql, paramBatches);
```

### FromRow
`IFromRow` allows for defining how data row deserialization is facilitated to create a new instance
of the type that implements this interface. For examples of its usage, see the code blocks above.
The interface can be implemented manually or source generated. The source generated option is
implemented for each database and might provide different options. Example of a database
implementation:
```c#
[Sqlx.Postgres.Generated.FromRow]
partial struct Row
{
public required int Id { get; init; }

public required string Name { get; init; }

public required int? ChildId { get; init; }
}
```

## Philosophy
### Implement General Use Cases as Extension Methods
When interfacing with databases, a few use cases/patterns show up WAY more than others. Rather
than ask others to handle that duplication themselves through extension members or god forbid
copy and paste code, extension members are made available on the library level. For example, in a
lot of cases we execute a parameterized query with 1 result set and map those rows to a type. Other
libraries require the ceremony of:
1. Creating a command
2. Binding parameters
3. Executing a reader
4. Iterating over that reader
5. Mapping each row as a new type

This is fine and there are libraries on top of the drivers that make this much easier, but we would
rather have that behaviour provided for you to make the interaction with the DB streamlined. As long
as the row type has `IFromRow` implemented for itself against your database, you can simply call,
`await connection.FetchAll<RowType(sql)`. There is also a case for handling parameterized queries
where you implement `IBindAll` for your database on a parameter type so that you call
`await connection.FetchAll<ParamType, RowType>(sql, param)`. This has the downside of obfuscating
the actual row parsing and parameter binding to implementations but it at least makes it explicit.

### Result Mapping
Although sqlx-cs can be used to deal with dynamic result sets and row shapes, it thrives when row
types are known and clearly defined as CLR types. Each database provides a source generator for
creating implementations of `IFromRow` for that database and the type itself. Developers should lean
on that functionality rather than trying to deal with rows as opaque tuples.

### Embracing new C# features
The original intention of the library was to make an ADO.NET with modern features of the language.
Although some features such as:
- Using `IAsyncEnumerable` for result sets
- Using `PipeReader` on the connection stream

were dropped due to performance concerns, the library tries to set itself up for future additions
to the language such as:
- Extension interfaces
- Sealed enums
- Union types

### Opinionated Design
You might notice that there are some core module interfaces for connections, queries or data rows.
You might have also noticed that they have complex generics types associated with them.

THIS IS BY DESIGN.

This means that you will have a hard time interacting with the library as though every connection,
query or data row is essentially the same thing even though they are linked to separate databases.
It's this library's opinion that generic repositories are not the best solution and should only be
chosen with care and concern for the downsides. You might notice similar takes on other options or
functionality in this library where certain patterns are discouraged but not impossible. This is not
to say that someone cannot make that decision, it's just that the author(s) of this library do not
want to encourage to make certain decisions. If you would like fewer restrictions like this, ADO.NET
would be an easier option.

## Database Support
### [Postgres](sqlx-cs-pg/Postgres.md)

### Connection Encryption
SSL connections are not implemented.... yet!

### FAQs
#### Is there support for non-async/blocking connections?
No. Database interactions generally involve some sort of IO so it would be best to put that into an
async operation. However, if there is enough desire to use this library for blocking connections
than it could be a future addition.

#### Why does everything involve extension methods?
As mentioned [here](#implement-general-use-cases-as-extension-methods), extension methods are the
best way to add behaviour and compose multiple concepts/types into a single general use case.

There are also cases where extension methods may seem a little overkill such as row field
deserialization. Honestly, I agree that it's a little convoluted, but it's the only way to add the
ability to deserialize certain types without making a general `IDataRow.Get<T>`. These types of
generic methods without bounds are rife for developers to add values that can never be deserialized,
and you won't know until you run your application. With that in mind, we hope to remove those
methods when this [feature](https://github.com/dotnet/csharplang/issues/9319) is finally implemented
in C#.
89 changes: 89 additions & 0 deletions benchmarks/Benchmarks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Benchmarks
## Queries
### Overview
Benchmarks are run using BenchmarkDotNet and run the same SQL query and deserialization. Init SQL:
```postgresql
DROP TABLE IF EXISTS public.posts;
CREATE TABLE public.posts (
id int primary key generated always as identity,
text_field text not null,
creation_date timestamp not null,
last_change_date timestamp not null,
counter int
);

INSERT INTO public.posts(text_field, creation_date, last_change_date)
SELECT REPEAT('x', 2000), current_timestamp, current_timestamp
FROM generate_series(1, 5000) s
```
Queries executed during benchmarks:
```postgresql
-- Single row
SELECT id, text_field, creation_date, last_change_date, counter
FROM public.posts
WHERE id = $1;

-- Multi row
SELECT id, text_field, creation_date, last_change_date, counter
FROM public.posts
WHERE id BETWEEN $1 AND $2;

-- All rows
SELECT id, text_field, creation_date, last_change_date, counter
FROM public.posts;
```

### Results
Results seen below are from a single run so the stats can vary due to IO. However, the general trend
is minimal difference between the 2 drivers.

| Method | Categories | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio |
|------------|------------------------------------------------|-------------|-------------|-------------|-------------|-------|---------|------------|------------|-----------|--------------|-------------|
| Npgsql | Batched Queries | 337.9 us | 13.53 us | 38.83 us | 330.0 us | 1.01 | 0.16 | - | - | - | 53.48 KB | 1.00 |
| sqlx-cs-pg | Batched Queries | 254.8 us | 9.54 us | 27.05 us | 251.8 us | 0.76 | 0.12 | - | - | - | 51.4 KB | 0.96 |
| | | | | | | | | | | | | |
| Npgsql | Simple Query, All Rows | 13,671.0 us | 780.23 us | 2,263.58 us | 13,259.5 us | 1.03 | 0.24 | 1000.0000 | - | - | 20309.25 KB | 1.00 |
| sqlx-cs-pg | Simple Query, All Rows | 12,771.2 us | 1,148.92 us | 3,183.64 us | 11,856.5 us | 0.96 | 0.29 | 1000.0000 | - | - | 20528.64 KB | 1.01 |
| | | | | | | | | | | | | |
| Npgsql | Simple Query, Concurrent Connections, All Rows | 70,377.9 us | 1,406.02 us | 3,679.30 us | 70,570.3 us | 1.00 | 0.07 | 14000.0000 | 13000.0000 | 2000.0000 | 202920.96 KB | 1.00 |
| sqlx-cs-pg | Simple Query, Concurrent Connections, All Rows | 69,889.5 us | 1,389.41 us | 3,660.27 us | 69,462.0 us | 1.00 | 0.07 | 13000.0000 | 12000.0000 | 1000.0000 | 205268.41 KB | 1.01 |
| | | | | | | | | | | | | |
| Npgsql | Simple Query, Multi Row | 327.4 us | 10.10 us | 29.30 us | 326.2 us | 1.01 | 0.13 | - | - | - | 48.48 KB | 1.00 |
| sqlx-cs-pg | Simple Query, Multi Row | 229.2 us | 7.59 us | 21.65 us | 231.0 us | 0.71 | 0.09 | - | - | - | 47.18 KB | 0.97 |
| | | | | | | | | | | | | |
| Npgsql | Simple Query, Single Row | 239.2 us | 6.59 us | 18.37 us | 235.6 us | 1.01 | 0.11 | - | - | - | 7.38 KB | 1.00 |
| sqlx-cs-pg | Simple Query, Single Row | 155.6 us | 3.93 us | 11.35 us | 154.2 us | 0.65 | 0.07 | - | - | - | 6.43 KB | 0.87 |
## PostgreSQL COPY
### Overview
Benchmarks are run using BenchmarkDotNet and run the same SQL query and copy data. Init SQL:
```postgresql
DROP TABLE IF EXISTS public.copy_target;
CREATE TABLE public.copy_target(
id int primary key,
text_field text not null,
creation_date timestamp not null,
last_change_date timestamp not null,
counter int
);
```
Queries executed during benchmarks:
```postgresql
COPY public.copy_target FROM STDIN WITH (FORMAT CSV);

COPY public.copy_target FROM STDIN WITH (FORMAT binary);
```

### Results
| Method | Categories | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|------------|-----------------|----------|----------|----------|----------|-------|---------|-----------|-------------|-------------|
| Npgsql | CopyIn, Binary | 66.76 ms | 1.500 ms | 4.350 ms | 65.93 ms | 1.00 | 0.09 | - | 1566.61 KB | 1.00 |
| sqlx-cs-pg | CopyIn, Binary | 69.67 ms | 1.381 ms | 3.564 ms | 68.08 ms | 1.05 | 0.08 | - | 1572.19 KB | 1.00 |
| | | | | | | | | | | |
| Npgsql | CopyIn, CSV | 86.91 ms | 1.734 ms | 4.350 ms | 87.04 ms | 1.00 | 0.07 | - | 4.76 KB | 1.00 |
| sqlx-cs-pg | CopyIn, CSV | 87.62 ms | 1.748 ms | 4.544 ms | 87.39 ms | 1.01 | 0.07 | - | 3.81 KB | 0.80 |
| | | | | | | | | | | |
| Npgsql | CopyOut, Binary | 15.44 ms | 2.086 ms | 6.118 ms | 12.44 ms | 1.14 | 0.60 | 1000.0000 | 20300.69 KB | 1.00 |
| sqlx-cs-pg | CopyOut, Binary | 14.61 ms | 1.432 ms | 4.154 ms | 13.24 ms | 1.08 | 0.47 | 1000.0000 | 20530.5 KB | 1.01 |
| | | | | | | | | | | |
| Npgsql | CopyOut, CSV | 17.81 ms | 0.679 ms | 1.948 ms | 17.22 ms | 1.01 | 0.15 | - | 526.79 KB | 1.00 |
| sqlx-cs-pg | CopyOut, CSV | 18.65 ms | 0.827 ms | 2.425 ms | 17.77 ms | 1.06 | 0.17 | - | 117.51 KB | 0.22 |
17 changes: 17 additions & 0 deletions benchmarks/IdPairParam.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Sqlx.Core.Query;
using Sqlx.Postgres.Query;

namespace benchmarks;

public readonly struct IdPairParam : IBindMany<IPgBindable>
{
public required int Id1 { get; init; }

public required int Id2 { get; init; }

public void BindMany(IPgBindable bindable)
{
bindable.Bind(Id1);
bindable.Bind(Id2);
}
}
14 changes: 14 additions & 0 deletions benchmarks/IdParam.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Sqlx.Core.Query;
using Sqlx.Postgres.Query;

namespace benchmarks;

public readonly struct IdParam : IBindMany<IPgBindable>
{
public required int Id { get; init; }

public void BindMany(IPgBindable bindable)
{
bindable.Bind(Id);
}
}
Loading