Home → Documentation → Foundation → Extensibility
Foundgine is designed to be extended through well-defined contracts rather than inheritance or runtime discovery. This document describes the framework’s extensibility model and identifies the supported extension points.
Foundgine follows the Open/Closed Principle.
The framework should be:
Applications should be able to customize behavior without changing the Runtime.
Every extension point lives behind a Foundation interface.
Application
↓
Custom Implementation
↓
Foundation Interface
↓
Runtime
Runtime never depends upon application code directly.
Foundgine exposes extension points in several areas:
Metadata
Planning
SQL
Materialization
Dematerialization
Graph
Interceptors
Dependency Injection
Transports
Each category has a clearly defined responsibility.
Metadata is supplied through IMetadataProvider.
public interface IMetadataProvider
{
EntityMetadata GetEntity(ushort storageEntityId);
ModelMetadata GetModel(ushort modelId);
JoinMetadata? GetJoin(
ushort leftStorageEntity,
ushort rightStorageEntity);
GraphMetadata? GetGraph(ushort graphId);
}
Most applications use the generated implementation.
Advanced scenarios may provide custom metadata sources.
The planner registry maps models to generated planners.
Example contract:
public interface IPlannerRegistry
{
QueryPlanner GetQueryPlanner(ushort modelId);
MutationPlanner GetMutationPlanner(ushort modelId);
}
Generated registries are the default implementation.
SQL generation is intentionally database-independent.
A dialect implementation owns provider-specific syntax.
public interface ISqlDialect
{
string QuoteIdentifier(string identifier);
void WriteLimit(...);
void WriteReturning(...);
void WriteConflict(...);
}
Potential implementations:
Applications may replace SQL writers.
Example:
ISqlWriter
Possible customizations:
Materializers convert rows into CLR objects.
IEntityMaterializer
Generated implementations should satisfy most scenarios.
Custom materializers may support:
Dematerializers convert CLR objects into mutation values.
IEntityDematerializer
Custom implementations may support:
Graph support is isolated behind a strategy interface.
Example:
IGraphStrategy
Possible implementations:
This isolates graph behavior from Runtime.
Interceptors provide lifecycle hooks.
Typical events include:
Before Planning
After Planning
Before SQL
After SQL
Before Execution
After Execution
Before Materialization
After Materialization
Interceptors should observe or augment behavior rather than replace core execution.
Every generated component should be replaceable.
Example:
services.AddSingleton<IMetadataProvider,
GeneratedMetadataProvider>();
Applications may substitute:
services.AddSingleton<IMetadataProvider,
CustomMetadataProvider>();
Runtime remains unchanged.
Runtime is transport agnostic.
New transports can integrate by translating requests into immutable plans.
Potential transports include:
No Runtime changes should be required.
Although Foundgine currently targets PostgreSQL, the architecture supports additional storage engines.
Potential future providers:
Each provider implements SQL abstractions while reusing the same planners and Runtime.
The Mapping Generator can evolve through additional emitters.
Examples:
IdEmitter
MetadataEmitter
PlannerEmitter
MaterializerEmitter
InterceptorEmitter
DependencyInjectionEmitter
Future emitters can generate additional compile-time artifacts without affecting existing Runtime components.
When extending Foundgine:
Extensions should integrate with the framework rather than bypass it.
Foundgine is intentionally extensible through Foundation contracts.
By exposing clear interfaces for metadata, planning, SQL generation, materialization, graph strategies, and transports, the framework can evolve without compromising its core architecture of compile-time generation, immutable execution plans, and transport-independent Runtime.
| ← Previous: Components | Next: Runtime → |