1.1, 1.2
This commit is contained in:
parent
dea62c2434
commit
87273f6fcf
@ -42,7 +42,8 @@
|
|||||||
"WebFetch(domain:blog.rsuter.com)",
|
"WebFetch(domain:blog.rsuter.com)",
|
||||||
"WebFetch(domain:natemcmaster.com)",
|
"WebFetch(domain:natemcmaster.com)",
|
||||||
"WebFetch(domain:www.nuget.org)",
|
"WebFetch(domain:www.nuget.org)",
|
||||||
"Bash(mkdir:*)"
|
"Bash(mkdir:*)",
|
||||||
|
"Bash(nul)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -3,6 +3,9 @@
|
|||||||
##
|
##
|
||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
nul
|
||||||
|
Svrnty.Sample/nul
|
||||||
|
|
||||||
.research/
|
.research/
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
|
|||||||
@ -6,46 +6,45 @@ namespace Svrnty.CQRS.Abstractions.Discovery;
|
|||||||
|
|
||||||
public sealed class CommandMeta : ICommandMeta
|
public sealed class CommandMeta : ICommandMeta
|
||||||
{
|
{
|
||||||
|
private readonly string _name;
|
||||||
|
private readonly string _lowerCamelCaseName;
|
||||||
|
|
||||||
public CommandMeta(Type commandType, Type serviceType, Type commandResultType)
|
public CommandMeta(Type commandType, Type serviceType, Type commandResultType)
|
||||||
{
|
{
|
||||||
CommandType = commandType;
|
CommandType = commandType;
|
||||||
ServiceType = serviceType;
|
ServiceType = serviceType;
|
||||||
CommandResultType = commandResultType;
|
CommandResultType = commandResultType;
|
||||||
|
|
||||||
|
// Cache reflection and computed values once in constructor
|
||||||
|
var nameAttribute = commandType.GetCustomAttribute<CommandNameAttribute>();
|
||||||
|
_name = nameAttribute?.Name ?? commandType.Name.Replace("Command", string.Empty);
|
||||||
|
_lowerCamelCaseName = ComputeLowerCamelCaseName(_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandMeta(Type commandType, Type serviceType)
|
public CommandMeta(Type commandType, Type serviceType)
|
||||||
{
|
{
|
||||||
CommandType = commandType;
|
CommandType = commandType;
|
||||||
ServiceType = serviceType;
|
ServiceType = serviceType;
|
||||||
|
|
||||||
|
// Cache reflection and computed values once in constructor
|
||||||
|
var nameAttribute = commandType.GetCustomAttribute<CommandNameAttribute>();
|
||||||
|
_name = nameAttribute?.Name ?? commandType.Name.Replace("Command", string.Empty);
|
||||||
|
_lowerCamelCaseName = ComputeLowerCamelCaseName(_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandNameAttribute NameAttribute => CommandType.GetCustomAttribute<CommandNameAttribute>();
|
private static string ComputeLowerCamelCaseName(string name)
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
{
|
||||||
get
|
if (string.IsNullOrEmpty(name))
|
||||||
{
|
|
||||||
var name = NameAttribute?.Name ?? CommandType.Name.Replace("Command", string.Empty);
|
|
||||||
return name;
|
return name;
|
||||||
}
|
|
||||||
|
var firstLetter = char.ToLowerInvariant(name[0]);
|
||||||
|
return $"{firstLetter}{name.Substring(1)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Name => _name;
|
||||||
public Type CommandType { get; }
|
public Type CommandType { get; }
|
||||||
public Type ServiceType { get; }
|
public Type ServiceType { get; }
|
||||||
public Type CommandResultType { get; }
|
public Type CommandResultType { get; }
|
||||||
|
public string LowerCamelCaseName => _lowerCamelCaseName;
|
||||||
public string LowerCamelCaseName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(Name))
|
|
||||||
return Name;
|
|
||||||
|
|
||||||
var name = Name;
|
|
||||||
var firstLetter = Char.ToLowerInvariant(name[0]);
|
|
||||||
var ret = $"{firstLetter}{name.Substring(1)}";
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,23 +6,20 @@ namespace Svrnty.CQRS.Abstractions.Discovery;
|
|||||||
|
|
||||||
public class QueryMeta : IQueryMeta
|
public class QueryMeta : IQueryMeta
|
||||||
{
|
{
|
||||||
|
private readonly string _name;
|
||||||
|
|
||||||
public QueryMeta(Type queryType, Type serviceType, Type queryResultType)
|
public QueryMeta(Type queryType, Type serviceType, Type queryResultType)
|
||||||
{
|
{
|
||||||
QueryType = queryType;
|
QueryType = queryType;
|
||||||
ServiceType = serviceType;
|
ServiceType = serviceType;
|
||||||
QueryResultType = queryResultType;
|
QueryResultType = queryResultType;
|
||||||
|
|
||||||
|
// Cache reflection and computed value once in constructor
|
||||||
|
var nameAttribute = queryType.GetCustomAttribute<QueryNameAttribute>();
|
||||||
|
_name = nameAttribute?.Name ?? queryType.Name.Replace("Query", string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual QueryNameAttribute NameAttribute => QueryType.GetCustomAttribute<QueryNameAttribute>();
|
public virtual string Name => _name;
|
||||||
|
|
||||||
public virtual string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var name = NameAttribute?.Name ?? QueryType.Name.Replace("Query", string.Empty);
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Type QueryType { get; }
|
public virtual Type QueryType { get; }
|
||||||
public virtual Type ServiceType { get; }
|
public virtual Type ServiceType { get; }
|
||||||
@ -33,13 +30,13 @@ public class QueryMeta : IQueryMeta
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(Name))
|
// Use virtual Name property so derived classes can override
|
||||||
return Name;
|
|
||||||
|
|
||||||
var name = Name;
|
var name = Name;
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
return name;
|
||||||
|
|
||||||
var firstLetter = char.ToLowerInvariant(name[0]);
|
var firstLetter = char.ToLowerInvariant(name[0]);
|
||||||
var ret = $"{firstLetter}{name[1..]}";
|
return $"{firstLetter}{name[1..]}";
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,16 +7,37 @@ namespace Svrnty.CQRS.Discovery;
|
|||||||
|
|
||||||
public sealed class CommandDiscovery : ICommandDiscovery
|
public sealed class CommandDiscovery : ICommandDiscovery
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<ICommandMeta> _commandMetas;
|
private readonly List<ICommandMeta> _commandMetas;
|
||||||
|
private readonly Dictionary<string, ICommandMeta> _commandsByName;
|
||||||
|
private readonly Dictionary<Type, ICommandMeta> _commandsByType;
|
||||||
|
|
||||||
public CommandDiscovery(IEnumerable<ICommandMeta> commandMetas)
|
public CommandDiscovery(IEnumerable<ICommandMeta> commandMetas)
|
||||||
{
|
{
|
||||||
_commandMetas = commandMetas;
|
// Materialize the enumerable to a list once
|
||||||
|
_commandMetas = commandMetas.ToList();
|
||||||
|
|
||||||
|
// Build lookup dictionaries for O(1) access
|
||||||
|
_commandsByName = new Dictionary<string, ICommandMeta>(_commandMetas.Count);
|
||||||
|
_commandsByType = new Dictionary<Type, ICommandMeta>(_commandMetas.Count);
|
||||||
|
|
||||||
|
foreach (var meta in _commandMetas)
|
||||||
|
{
|
||||||
|
_commandsByName[meta.Name] = meta;
|
||||||
|
_commandsByType[meta.CommandType] = meta;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<ICommandMeta> GetCommands() => _commandMetas;
|
public IEnumerable<ICommandMeta> GetCommands() => _commandMetas;
|
||||||
public ICommandMeta FindCommand(string name) => _commandMetas.FirstOrDefault(t => t.Name == name);
|
|
||||||
public ICommandMeta FindCommand(Type commandType) => _commandMetas.FirstOrDefault(t => t.CommandType == commandType);
|
public ICommandMeta FindCommand(string name) =>
|
||||||
public bool CommandExists(string name) => _commandMetas.Any(t => t.Name == name);
|
_commandsByName.TryGetValue(name, out var meta) ? meta : null;
|
||||||
public bool CommandExists(Type commandType) => _commandMetas.Any(t => t.CommandType == commandType);
|
|
||||||
|
public ICommandMeta FindCommand(Type commandType) =>
|
||||||
|
_commandsByType.TryGetValue(commandType, out var meta) ? meta : null;
|
||||||
|
|
||||||
|
public bool CommandExists(string name) =>
|
||||||
|
_commandsByName.ContainsKey(name);
|
||||||
|
|
||||||
|
public bool CommandExists(Type commandType) =>
|
||||||
|
_commandsByType.ContainsKey(commandType);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,17 +7,38 @@ namespace Svrnty.CQRS.Discovery;
|
|||||||
|
|
||||||
public sealed class QueryDiscovery : IQueryDiscovery
|
public sealed class QueryDiscovery : IQueryDiscovery
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<IQueryMeta> _queryMetas;
|
private readonly List<IQueryMeta> _queryMetas;
|
||||||
|
private readonly Dictionary<string, IQueryMeta> _queriesByName;
|
||||||
|
private readonly Dictionary<Type, IQueryMeta> _queriesByType;
|
||||||
|
|
||||||
public QueryDiscovery(IEnumerable<IQueryMeta> queryMetas)
|
public QueryDiscovery(IEnumerable<IQueryMeta> queryMetas)
|
||||||
{
|
{
|
||||||
_queryMetas = queryMetas;
|
// Materialize the enumerable to a list once
|
||||||
|
_queryMetas = queryMetas.ToList();
|
||||||
|
|
||||||
|
// Build lookup dictionaries for O(1) access
|
||||||
|
_queriesByName = new Dictionary<string, IQueryMeta>(_queryMetas.Count);
|
||||||
|
_queriesByType = new Dictionary<Type, IQueryMeta>(_queryMetas.Count);
|
||||||
|
|
||||||
|
foreach (var meta in _queryMetas)
|
||||||
|
{
|
||||||
|
_queriesByName[meta.Name] = meta;
|
||||||
|
_queriesByType[meta.QueryType] = meta;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IQueryMeta> GetQueries() => _queryMetas;
|
public IEnumerable<IQueryMeta> GetQueries() => _queryMetas;
|
||||||
public IQueryMeta FindQuery(string name) => _queryMetas.FirstOrDefault(t => t.Name == name);
|
|
||||||
public IQueryMeta FindQuery(Type queryType) => _queryMetas.FirstOrDefault(t => t.QueryType == queryType);
|
public IQueryMeta FindQuery(string name) =>
|
||||||
public bool QueryExists(string name) => _queryMetas.Any(t => t.Name == name);
|
_queriesByName.TryGetValue(name, out var meta) ? meta : null;
|
||||||
public bool QueryExists(Type queryType) => _queryMetas.Any(t => t.QueryType == queryType);
|
|
||||||
|
public IQueryMeta FindQuery(Type queryType) =>
|
||||||
|
_queriesByType.TryGetValue(queryType, out var meta) ? meta : null;
|
||||||
|
|
||||||
|
public bool QueryExists(string name) =>
|
||||||
|
_queriesByName.ContainsKey(name);
|
||||||
|
|
||||||
|
public bool QueryExists(Type queryType) =>
|
||||||
|
_queriesByType.ContainsKey(queryType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,13 +22,13 @@ public static class ServiceCollectionExtensions
|
|||||||
|
|
||||||
public static IServiceCollection AddDefaultQueryDiscovery(this IServiceCollection services)
|
public static IServiceCollection AddDefaultQueryDiscovery(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.TryAddTransient<IQueryDiscovery, QueryDiscovery>();
|
services.TryAddSingleton<IQueryDiscovery, QueryDiscovery>();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IServiceCollection AddDefaultCommandDiscovery(this IServiceCollection services)
|
public static IServiceCollection AddDefaultCommandDiscovery(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.TryAddTransient<ICommandDiscovery, CommandDiscovery>();
|
services.TryAddSingleton<ICommandDiscovery, CommandDiscovery>();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1182
roadmap-2026/quick-analyze-improvements.md
Normal file
1182
roadmap-2026/quick-analyze-improvements.md
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user