Development Guides
Guides for developing and extending Jaunty.
Core Guides
Quick Reference
Adding a New Query Method
- Create file in
src/Jaunty/Read/ (e.g., QueryFoo.cs)
- Add extension method in
partial class Jaunty
- Add
where T : new() constraint if needed
- Delegate to
QueryCore or QueryCoreAsync
- Create async variant in
QueryFooAsync.cs
- Add tests in
tests/Jaunty.Tests/Integration/Sqlite/Read/
Adding a New Attribute
- Create in
src/Jaunty/Attributes/
- Use appropriate
AttributeTargets
- Update
MetadataBuilder.cs to read the attribute
- Add tests for attribute resolution
- Document priority:
[Attribute] > JauntyConfig > default
Modifying Parameter Binding
- Update
SqlParameterParser.cs for parsing changes
- Update
ParameterBinder.cs for binding changes
- Update caches if needed
- Add unit tests for edge cases
File Organization
Public API Files
| Location |
Naming |
Example |
Read/ |
MethodName.cs |
Query.cs, QueryFirst.cs |
Read/ |
MethodNameAsync.cs |
QueryAsync.cs |
Write/ |
Operation.cs |
Insert.cs, BulkInsert.cs |
Streaming/ |
MethodStream.cs |
QueryStream.cs |
Internal Files
| Location |
Purpose |
Internals/Entity/ |
Metadata caching system |
Internals/Parameters/ |
Parameter parsing and binding |
Internals/Dialects/ |
SQL dialect implementations |
Internals/Write/ |
Internal write helpers |
Coding Standards
C# Language Features
| Feature |
Usage |
| File-scoped namespaces |
Required |
| Primary constructors |
Use for simple cases |
| Pattern matching |
Encouraged |
| Records |
For immutable data |
readonly struct |
For small value types |
Span<T> |
For zero-allocation slicing |
| LINQ |
Avoid in hot paths |
Naming Conventions
| Element |
Convention |
Example |
| Namespaces |
Hierarchical |
Jaunty.Internals.Entity |
| Public classes |
PascalCase |
GridReader, CommandOptions |
| Internal classes |
internal sealed |
internal sealed class MetadataCache<T> |
| Methods |
PascalCase, verb-based |
Query<T>(), CreateSetter() |
| Properties |
PascalCase, noun-based |
ColumnName, Mapper |
| Parameters |
camelCase |
sql, reader, columnName |
| Private fields |
_camelCase |
_cache, _columnNameResolver |
| Generic type params |
Single letter |
<T>, <TResult> |
Async Patterns
// Pass-through async (no resource management)
public static Task<T> QueryAsync<T>(...)
=> QueryCoreAsync<T>(...);
// Resource management async
public static async Task<T> QueryAsync<T>(...)
{
await using var resource = await GetResourceAsync();
return await ProcessAsync(resource);
}
// Always use ConfigureAwait(false)
await something.ConfigureAwait(false);
Memory
| Rule |
Example |
| Pre-size collections |
new List<T>(expectedCount) |
Use Span<T> |
ReadOnlySpan<char> sqlSpan = sql.AsSpan() |
| Avoid boxing |
Use generic constraints |
| Cache reflection |
Compile once, reuse forever |
Execution
| Rule |
Example |
| No LINQ in hot paths |
Use for loops |
| Inline small methods |
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
Use FrozenDictionary |
On .NET 8+ for lookups |
| String comparison |
StringComparison.Ordinal |
Testing Requirements
| Requirement |
Details |
| Unit tests |
For internal components (parser, binder) |
| Integration tests |
For all public APIs |
| Error case tests |
Test all exception paths |
| Coverage goal |
100% for public APIs |
See ../05-quality/code-coverage.md for how coverage is
measured and what the current baseline says.
Git Workflow
Commit Messages
type: short description
Optional longer description.
- Bullet points for details
- Explain why, not just what
Types:
feat: New feature
fix: Bug fix
docs: Documentation
test: Tests
refactor: Code restructuring
perf: Performance improvements
Branch Naming
feature/description - New features
fix/description - Bug fixes
docs/description - Documentation
refactor/description - Refactoring
See Also