Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using CrestApps.Core.Models;
using CrestApps.Core.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace CrestApps.Core;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddDocumentCatalog<TModel, T>(this IServiceCollection services)
where TModel : CatalogItem
where T : class, ICatalog<TModel>
{
services.RemoveAll<ICatalog<TModel>>();

services.AddScoped<T>();
services.AddScoped<ICatalog<TModel>>(sp => sp.GetRequiredService<T>());

return services;
}

public static IServiceCollection AddNamedDocumentCatalog<TModel, T>(this IServiceCollection services)
where TModel : CatalogItem, INameAwareModel
where T : class, INamedCatalog<TModel>
{
services.RemoveAll<ICatalog<TModel>>();
services.RemoveAll<INamedCatalog<TModel>>();

services.AddScoped<T>();
services.AddScoped<ICatalog<TModel>>(sp => sp.GetRequiredService<T>());
services.AddScoped<INamedCatalog<TModel>>(sp => sp.GetRequiredService<T>());

return services;
}

public static IServiceCollection AddSourceDocumentCatalog<TModel, T>(this IServiceCollection services)
where TModel : CatalogItem, ISourceAwareModel
where T : class, ISourceCatalog<TModel>
{
services.RemoveAll<ICatalog<TModel>>();
services.RemoveAll<ISourceCatalog<TModel>>();

services.AddScoped<T>();
services.AddScoped<ICatalog<TModel>>(sp => sp.GetRequiredService<T>());
services.AddScoped<ISourceCatalog<TModel>>(sp => sp.GetRequiredService<T>());

return services;
}

public static IServiceCollection AddNamedSourceDocumentCatalog<TModel, T>(this IServiceCollection services)
where TModel : CatalogItem, INameAwareModel, ISourceAwareModel
where T : class, INamedSourceCatalog<TModel>
{
services.RemoveAll<ICatalog<TModel>>();
services.RemoveAll<INamedCatalog<TModel>>();
services.RemoveAll<ISourceCatalog<TModel>>();
services.RemoveAll<INamedSourceCatalog<TModel>>();

services.AddScoped<T>();
services.AddScoped<ICatalog<TModel>>(sp => sp.GetRequiredService<T>());
services.AddScoped<INamedCatalog<TModel>>(sp => sp.GetRequiredService<T>());
services.AddScoped<ISourceCatalog<TModel>>(sp => sp.GetRequiredService<T>());
services.AddScoped<INamedSourceCatalog<TModel>>(sp => sp.GetRequiredService<T>());

return services;
}
}
20 changes: 10 additions & 10 deletions src/CrestApps.Core.Docs/docs/core/data-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ builder.Services.AddCrestAppsCore(crestApps => crestApps
.UseSqLite("Data Source=app.db;Cache=Shared")
.SetTablePrefix("CA_")));

builder.Services.AddNamedSourceDocumentCatalog<AIProfile, AIProfileIndex>();
builder.Services.AddYesSqlNamedSourceDocumentCatalog<AIProfile, AIProfileIndex>();

// Entity Framework Core + SQLite
builder.Services.AddCrestAppsCore(crestApps => crestApps
.AddEntityCoreSqliteDataStore("Data Source=app.db"));
builder.Services.AddCoreEntityCoreStores();
builder.Services.AddEntityCoreStores();
```

`AddYesSqlDataStore(...)` on the root CrestApps builder maps to `AddCoreYesSqlDataStore(...)`, while `AddEntityCoreSqliteDataStore(...)` maps to `AddCoreEntityCoreSqliteDataStore(...)`. The YesSql and Entity Framework Core packages are both optional: consumers can register either flavor or replace them with their own persistence layer entirely.
`AddYesSqlDataStore(...)` on the root CrestApps builder maps to `AddCoreYesSqlDataStore(...)`, while `AddEntityCoreSqliteDataStore(...)` maps to `AddCoreEntityCoreSqliteDataStore(...)`. The YesSql and Entity Framework Core packages are both optional: consumers can register either flavor or replace them with their own persistence layer entirely. After configuring the EF Core data store, call `AddEntityCoreStores()` to register the built-in CrestApps stores and catalog services.

Reusable AI-related YesSql index models, `IndexProvider` types, and schema helpers now live in `CrestApps.Core.Data.YesSql` as well, so hosts can register the shared AI storage surface without copying provider implementations out of the sample app. Within that project, feature assets are grouped directly under `Indexes/{Feature}`, their namespaces follow the same `CrestApps.Core.Data.YesSql.Indexes.{Feature}` shape, each shared schema-helper file is scoped to a single index type, and each shared index file now keeps the index model beside its matching `IndexProvider` for easier maintenance.

Expand Down Expand Up @@ -105,10 +105,10 @@ public interface INamedSourceCatalog<T> : INamedCatalog<T>, ISourceCatalog<T>

| Method | Registers | Requires |
|--------|-----------|----------|
| `AddDocumentCatalog<TModel, TIndex>()` | `ICatalog<T>` | `CatalogItem` + `CatalogItemIndex` |
| `AddNamedDocumentCatalog<TModel, TIndex>()` | `ICatalog<T>` + `INamedCatalog<T>` | + `INameAwareModel` + `INameAwareIndex` |
| `AddSourceDocumentCatalog<TModel, TIndex>()` | `ICatalog<T>` + `ISourceCatalog<T>` | + `ISourceAwareModel` + `ISourceAwareIndex` |
| `AddNamedSourceDocumentCatalog<TModel, TIndex>()` | All four interfaces | Both `INameAware*` + `ISourceAware*` |
| `AddYesSqlDocumentCatalog<TModel, TIndex>()` | `ICatalog<T>` | `CatalogItem` + `CatalogItemIndex` |
| `AddYesSqlNamedDocumentCatalog<TModel, TIndex>()` | `ICatalog<T>` + `INamedCatalog<T>` | + `INameAwareModel` + `INameAwareIndex` |
| `AddYesSqlSourceDocumentCatalog<TModel, TIndex>()` | `ICatalog<T>` + `ISourceCatalog<T>` | + `ISourceAwareModel` + `ISourceAwareIndex` |
| `AddYesSqlNamedSourceDocumentCatalog<TModel, TIndex>()` | All four interfaces | Both `INameAware*` + `ISourceAware*` |

The Entity Framework Core package exposes the same service-registration shape without YesSql indexes:

Expand All @@ -119,7 +119,7 @@ The Entity Framework Core package exposes the same service-registration shape wi
| `AddSourceDocumentCatalog<TModel>()` | `ICatalog<T>` + `ISourceCatalog<T>` | `CatalogItem` + `ISourceAwareModel` |
| `AddNamedSourceDocumentCatalog<TModel>()` | All four interfaces | `CatalogItem` + both awareness interfaces |

`AddCoreEntityCoreStores()` registers the built-in CrestApps store interfaces (`IAIChatSessionManager`, prompt stores, document stores, memory stores, search index profile store, and related catalog registrations) against the Entity Framework Core package.
`AddEntityCoreStores()` registers the built-in CrestApps store interfaces (`IAIChatSessionManager`, prompt stores, document stores, memory stores, search index profile store, and related catalog registrations) against the Entity Framework Core package.


## Catalog Entry Handlers
Expand Down Expand Up @@ -204,7 +204,7 @@ The `CrestApps.Core.Data.EntityCore` package gives you a ready-made alternative
builder.Services.AddCoreEntityCoreSqliteDataStore(
$"Data Source={Path.Combine(builder.Environment.ContentRootPath, "App_Data", "crestapps.db")}");

builder.Services.AddCoreEntityCoreStores();
builder.Services.AddEntityCoreStores();
```

Create the schema during startup:
Expand Down Expand Up @@ -313,7 +313,7 @@ Register additional read-only sources alongside the primary catalog:

```csharp
// Primary writable catalog (YesSql-backed)
builder.Services.AddNamedSourceDocumentCatalog<AIProfile, AIProfileIndex>();
builder.Services.AddYesSqlNamedSourceDocumentCatalog<AIProfile, AIProfileIndex>();

// Additional read-only source (e.g., code-defined defaults)
builder.Services.AddScoped<IReadCatalog<AIProfile>, DefaultProfilesCatalog>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ For local SQLite-backed EF Core development:
builder.Services.AddCoreEntityCoreSqliteDataStore(
$"Data Source={Path.Combine(builder.Environment.ContentRootPath, "App_Data", "crestapps.db")}");

builder.Services.AddCoreEntityCoreStores();
builder.Services.AddEntityCoreStores();
```

For YesSql, keep using `AddCoreYesSqlDataStore(...)` plus the YesSql catalog registrations. If you already use another ORM or storage model, implement the same catalog/store abstractions against your preferred backend.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ public static IServiceCollection AddCoreYesSqlDataStore(this IServiceCollection

Data.YesSql.ServiceCollectionExtensions.AddCoreYesSqlDataStore(services, configuration => configuration.UseSqLite(connectionStringBuilder.ToString()).SetTablePrefix("CA_"));
// YesSql-backed catalogs and managers.
services.AddNamedSourceDocumentCatalog<AIProfile, AIProfileIndex>()
.AddNamedSourceDocumentCatalog<AIProviderConnection, AIProviderConnectionIndex>()
.AddDocumentCatalog<A2AConnection, A2AConnectionIndex>()
.AddSourceDocumentCatalog<McpConnection, McpConnectionIndex>()
.AddNamedDocumentCatalog<McpPrompt, McpPromptIndex>()
.AddSourceDocumentCatalog<McpResource, McpResourceIndex>()
.AddNamedSourceDocumentCatalog<AIProfileTemplate, AIProfileTemplateIndex>()
services.AddYesSqlNamedSourceDocumentCatalog<AIProfile, AIProfileIndex>()
.AddYesSqlNamedSourceDocumentCatalog<AIProviderConnection, AIProviderConnectionIndex>()
.AddYesSqlDocumentCatalog<A2AConnection, A2AConnectionIndex>()
.AddYesSqlSourceDocumentCatalog<McpConnection, McpConnectionIndex>()
.AddYesSqlNamedDocumentCatalog<McpPrompt, McpPromptIndex>()
.AddYesSqlSourceDocumentCatalog<McpResource, McpResourceIndex>()
.AddYesSqlNamedSourceDocumentCatalog<AIProfileTemplate, AIProfileTemplateIndex>()
.AddScoped<DefaultAIProfileTemplateManager>()
.AddScoped<IAIProfileTemplateManager>(sp => sp.GetRequiredService<DefaultAIProfileTemplateManager>())
.AddScoped<INamedSourceCatalogManager<AIProfileTemplate>>(sp => sp.GetRequiredService<DefaultAIProfileTemplateManager>())
Expand Down Expand Up @@ -105,18 +105,18 @@ public static IServiceCollection AddCoreYesSqlDataStore(this IServiceCollection
.AddScoped<IAuthorizationHandler, MvcChatInteractionDocumentAuthorizationHandler>()
.AddScoped<IAuthorizationHandler, MvcAIChatSessionDocumentAuthorizationHandler>()
.AddScoped<IAIChatDocumentEventHandler, MvcAIChatDocumentEventHandler>()
.AddDocumentCatalog<ChatInteraction, ChatInteractionIndex>()
.AddYesSqlDocumentCatalog<ChatInteraction, ChatInteractionIndex>()
.AddScoped<IChatInteractionPromptStore, YesSqlChatInteractionPromptStore>()
.AddDocumentCatalog<Article, ArticleIndex>()
.AddYesSqlDocumentCatalog<Article, ArticleIndex>()
.AddScoped<ICatalogEntryHandler<AIDataSource>, AIDataSourceIndexingHandler>()
.AddScoped<ICatalogEntryHandler<Article>, ArticleIndexingHandler>()
.AddScoped<ArticleIndexingService>();

services.AddKeyedScoped<INamedSourceCatalog<AIProviderConnection>, NamedSourceDocumentCatalog<AIProviderConnection, AIProviderConnectionIndex>>(ConfigurationAIProviderConnectionCatalog.PersistedCatalogKey)
.AddNamedSourceDocumentCatalog<AIProviderConnection, AIProviderConnectionIndex, ConfigurationAIProviderConnectionCatalog>();
.AddYesSqlNamedSourceDocumentCatalog<AIProviderConnection, AIProviderConnectionIndex, ConfigurationAIProviderConnectionCatalog>();

services.AddKeyedScoped<INamedSourceCatalog<AIDeployment>, NamedSourceDocumentCatalog<AIDeployment, AIDeploymentIndex>>(ConfigurationAIDeploymentCatalog.PersistedCatalogKey)
.AddNamedSourceDocumentCatalog<AIDeployment, AIDeploymentIndex, ConfigurationAIDeploymentCatalog>();
.AddYesSqlNamedSourceDocumentCatalog<AIDeployment, AIDeploymentIndex, ConfigurationAIDeploymentCatalog>();

return services;
}
Expand Down
Loading
Loading