jaunty Architecture › Jaunty Architecture Specification

Jaunty Architecture Specification

Version: 2026.02.19
Status: Active
Maintainer: Project Team

This document provides a complete architectural specification of the Jaunty micro-ORM, including system overview, component specifications, data flows, and performance characteristics.


Table of Contents

  1. System Overview
  2. Architectural Layers
  3. Component Specifications
  4. Data Flow
  5. Performance Architecture
  6. Threading Model
  7. Multi-Targeting Strategy
  8. Extension Points

System Overview

Purpose

Jaunty is a lightweight, high-performance micro-ORM for .NET that:

  • Executes raw SQL and maps results to objects
  • Uses strict mapping by default (catches bugs early)
  • Has zero external dependencies (framework-only)
  • Targets netstandard2.0 and net8.0

Design Goals

ExtensibilityCompatibilitySimplicityCorrectnessPerformanceLow PriorityHigh PriorityEasyCriticalJaunty Design Goal Priorities
Goal Priority Description
Performance Critical Minimal allocations, compiled delegates, cached metadata
Correctness Critical Strict mapping by default, clear error messages
Simplicity High No magic, explicit SQL, predictable behavior
Compatibility High Support netstandard2.0 and net8.0
Extensibility Medium Custom mappers, configuration, dialects

Non-Goals (What Jaunty Does NOT Do)

Jaunty Does NOT Do

Query Building

LINQ Translation

Change Tracking

Unit of Work

Migrations

Connection Pooling


Architectural Layers

Layer Diagram

SQL Generation Layer

CrudSqlCache

CachedCrudSql

ISqlDialect

Parameter Layer

SqlParameterParser

ParameterBinder

ParameterCache

SqlParameterParserCache

Metadata Layer

MetadataCache

MetadataBuilder

EntityMetadata

MappedCache

Core Execution Layer

QueryCore / QueryCoreAsync

ExecuteReader / ExecuteReaderAsync

DrDispatcher

ExecuteQueryMultiple

Public API Layer

Query()

QueryPartial()

Insert()

Update()

Delete()

QueryMultiple()

Layer Responsibilities

Layer Components Responsibility
Public API Extension methods on IDbConnection User-facing API, parameter validation, options handling
Core Execution QueryCore, ExecuteReader, DrDispatcher Command execution, connection management, mapper resolution
Metadata MetadataCache<T>, MetadataBuilder Entity metadata caching, compiled expression trees
Parameter SqlParameterParser, ParameterBinder SQL parameter extraction, object-to-parameter binding
SQL Generation CrudSqlCache<T>, ISqlDialect CRUD SQL generation, database-specific syntax

Component Specifications

1. Public API Layer

Location: src/Jaunty/Read/, src/Jaunty/Write/, src/Jaunty/Multiple/, etc.

Pattern: Extension methods on IDbConnection using C# 13 extension syntax.

extends

«static partial»

Jaunty

+Query(sql, params, options) : List

+QueryPartial(sql, params, options) : List

+QueryFirst(sql, params, options) : T

+QueryFirstOrDefault(sql, params, options) : T?

+QuerySingle(sql, params, options) : T

+QuerySingleOrDefault(sql, params, options) : T?

+QueryScalar(sql, params, options) : T

+Insert(entity) : long

+Update(entity) : int

+Delete(entityOrId) : int

+QueryMultiple(sql, params) : GridReader

«interface»

IDbConnection

+Open()

+Close()

+CreateCommand()

+BeginTransaction()

Key Characteristics:

  • All methods are extension methods
  • Consistent parameter ordering: sql, parameters, options, cancellationToken
  • where T : new() constraint for entity types
  • Sync uses IDbConnection, async uses DbConnection

2. Core Execution Layer

QueryCore Flow

HandlerDrDispatcherExecuteReaderQueryCoreUserHandlerDrDispatcherExecuteReaderQueryCoreUserQuery<T>(sql, params)ExecuteReader(sql, params, handler)Manage connection stateCreate commandBind parametersExecuteReader()Resolve mapperCheck options.MapperCheck special typesCheck MappedCache<T>Build from MetadataCache<T>Func<IDataReader, T>handler(reader)while reader.Read()map(reader)List<T>List<T>List<T>

Connection State Management

wasClosed = true

wasClosed = false

connection.Open()

wasClosed && stillOpen

wasClosed = false

connection.Close()

CheckState

OpenConnection

Execute

CloseConnection

Connection state is preserved:
- If closed: open, execute, close
- If open: execute, leave open


3. Metadata Layer

MetadataCache Initialization

Yes

No

Yes

No

static MetadataCache()

MetadataBuilder.Build()

Get Columns from Metadata

For each column

CreateSetter(property)

Build expression tree

Compile to delegate

Create PropertyContext

Add to ColumnToIndex dictionary

More columns?

NET8_0_OR_GREATER?

ToFrozenDictionary()

ToDictionary()

MetadataCache initialized

Metadata Resolution Priority

Yes

No

Yes

No

Property

Has [Column] attribute?

Use [Column] name

JauntyConfig.ColumnNameResolver?

Use resolver result

Use property name

Final column name


4. Parameter Layer

SqlParameterParser State Machine

--

/*

'

" or [

@

End of SQL

\n

*/

' (unescaped)

" or ]

After parameter name

Normal

SingleLineComment

BlockComment

StringLiteral

QuotedIdentifier

ExtractParam

In Normal state:
- Look for @param
- Skip comments
- Skip string literals
- Skip quoted identifiers

Extract parameter name:
- Start after @
- Continue while letter/digit/_
- Add to HashSet (deduplicates)

Parameter Binding Flow

DbParameterDbCommandParameterCacheParameterBinderCallerDbParameterDbCommandParameterCacheParameterBinderCallerloop[For each property]Bind(command, parameters)GetProperties(type)PropertyInfo[]prop.GetValue(parameters)CreateParameter()new DbParameterParameterName = prop.NameValue = value ?? DBNull.ValueParameters.Add(param)

5. SQL Generation Layer

CRUD SQL Generation

CrudSqlCache static constructor

Get MetadataCache.Metadata

Find key property

Get non-key properties

Build INSERT SQL

Column names

Parameter placeholders

INSERT INTO table (cols) VALUES (params)

Build UPDATE SQL

SET col = @param

WHERE key = @key

UPDATE table SET ... WHERE ...

Build DELETE SQL

DELETE FROM table WHERE key = @key

Store in static fields

SQL cached for lifetime


Data Flow

Query Execution Flow

Map

while reader.Read()

map(reader)

Add to List

MapResolve

DrDispatcher
Resolve mapper

MappedCache
IMapped

Special types
Dictionary, etc.

Compiled delegates
Property setters

Exec

ExecuteReader
Connection mgmt

DbCommand.ExecuteReader
Execute SQL

IDataReader
Result set

MetaResolve

MetadataCache
Static cache

MetadataBuilder
Build from attributes

Compiled setters
Expression trees

ParamBind

SqlParameterParser
Extract @params from SQL

SqlParameterParserCache
Cache parsed params

ParameterBinder
Bind to DbCommand

User calls Query()

Return List

Insert Execution Flow

Exec

ExecuteReader
Connection mgmt

command.ExecuteReader()

reader.Read()

reader.GetValue(0)
Get identity

ParamBind

Bind entity properties
to DbCommand.Parameters

Skip identity columns
Database generates

SqlGen

CrudSqlCache
Get cached INSERT SQL

Build: INSERT INTO table
(cols) VALUES (params)

Add: SELECT identity
(dialect-specific)

Meta

MetadataCache
Get entity metadata

Find key property
For WHERE clause

Get identity property
For RETURNING

User calls Insert(entity)

Return identity (long)


Performance Architecture

Caching Strategy

Cache Hierarchy

MetadataCache
Per type
Application lifetime

ParameterCache
Per type
Application lifetime

SqlParameterParserCache
Per SQL string
Application lifetime

CrudSqlCache
Per type
Application lifetime

MappedCache
Per type
Application lifetime

Read-only after init
Thread-safe
Zero locks

Allocation Optimization

25%20%15%25%5%10%Allocation Reduction TechniquesPre-sized collectionsSpan<T> slicingFrozenDictionaryCompiled delegatesreadonly structValueTask<T>

Performance Comparison

Query Performance: Reflection vs Compiled DelegatesReflection (PropertyInfo.SetValue)Compiled Delegates110100100010000Rows1009080706050403020100Time (ms)

Threading Model

Thread Safety Guarantees

Not Thread-Safe

DbConnection
(user responsibility)

DbCommand
(created per operation)

DbTransaction
(user responsibility)

Thread-Safe

Public API methods

Static caches
(MetadataCache, ParameterCache)

Compiled delegates

FrozenDictionary

Static Initialization Sequence

MetadataCacheThread2Thread1CLRMetadataCacheThread2Thread1CLRThread-safe by CLR guaranteeAll subsequent accessesare lock-free readsAccess MetadataCache<Product>Run static constructorAccess MetadataCache<Product>Wait for constructorBuild metadataCompile settersCreate FrozenDictionaryConstructor completeReturn initialized cacheReturn initialized cache

Multi-Targeting Strategy

Framework Feature Matrix

SearchValuesSpanstring.CreateValueTaskFrozenDictionarynetstandard2.0net8.0CompatibilityPerformance".NET 8.0 Optimizations"

Conditional Compilation Pattern

Yes

No

#if NET8_0_OR_GREATER?

Use modern APIs

Use compatible APIs

FrozenDictionary

ValueTask

string.Create()

Span/ReadOnlySpan

Dictionary

Task

String concatenation

Substring()


Extension Points

Custom Mapper Registration

Yes

No

User implements IMapped

MappedCache.Mapper set

DrDispatcher.Resolve()

MappedCache.Mapper
not null?

Use custom mapper

Fallback to MetadataCache

Skip metadata reflection

Use compiled delegates

Configuration Extension

JauntyConfig

ColumnNameResolver
Func

TableNameResolver
Func

SchemaNameResolver
Func

MetadataBuilder.Build()

Resolve names at startup

Cache in MetadataCache


Error Handling

Exception Hierarchy

Pass-Through Exceptions

DbException
Database errors

SqlException
SQL syntax errors

Jaunty Exceptions

InvalidOperationException
Strict mapping, no results,
multiple results

ArgumentException
Parameter mismatch,
invalid parameter

ArgumentNullException
Null required argument

Error Message Format

text
┌─────────────────────────────────────────────────────────────────┐
│ Strict mapping failed: property 'Price' on type 'Product'      │
│ has no matching column.                                         │
│                                                                 │
│ SQL columns: [id, name, category_id]                           │
│ Missing: [Price]                                                │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ Parameter count mismatch: SQL contains 2 unique parameter(s),  │
│ but 3 value(s) provided.                                        │
│                                                                 │
│ SQL parameters: [@CategoryId, @MinPrice]                       │
│ Provided: [1, 100, 200]                                         │
└─────────────────────────────────────────────────────────────────┘

See Also

Document Purpose
design-philosophy.md Design philosophy and trade-offs
metadata-system-spec.md Metadata caching system details
parameter-binding-spec.md Parameter binding details
performance-spec.md Performance optimization guide
../../01-api-reference/README.md API documentation