1+ using System ;
2+ using System . Threading ;
3+ using System . Threading . Tasks ;
4+ using Core . ElasticSearch . Indices ;
5+ using Core . Events ;
6+ using Core . Projections ;
7+ using MediatR ;
8+ using Microsoft . Extensions . DependencyInjection ;
9+ using Nest ;
10+
11+ namespace Core . ElasticSearch . Projections
12+ {
13+ public class ElasticSearchProjection < TEvent , TView > : IEventHandler < TEvent >
14+ where TView : class , IProjection
15+ where TEvent : IEvent
16+ {
17+ private readonly IElasticClient elasticClient ;
18+ private readonly Func < TEvent , string > getId ;
19+
20+ public ElasticSearchProjection (
21+ IElasticClient elasticClient ,
22+ Func < TEvent , string > getId
23+ )
24+ {
25+ this . elasticClient = elasticClient ?? throw new ArgumentNullException ( nameof ( elasticClient ) ) ;
26+ this . getId = getId ?? throw new ArgumentNullException ( nameof ( getId ) ) ;
27+ }
28+
29+ public async Task Handle ( TEvent @event , CancellationToken ct )
30+ {
31+ string id = getId ( @event ) ;
32+
33+ var entity = ( await elasticClient . GetAsync < TView > ( id , ct : ct ) ) ? . Source
34+ ?? ( TView ) Activator . CreateInstance ( typeof ( TView ) , true ) ! ;
35+
36+ entity . When ( @event ) ;
37+
38+ var result = await elasticClient . UpdateAsync < TView > ( id ,
39+ u => u . Doc ( entity ) . Upsert ( entity ) . Index ( IndexNameMapper . ToIndexName < TView > ( ) ) ,
40+ ct
41+ ) ;
42+ }
43+ }
44+
45+ public static class ElasticSearchProjectionConfig
46+ {
47+ public static IServiceCollection Project < TEvent , TView > ( this IServiceCollection services ,
48+ Func < TEvent , string > getId )
49+ where TView : class , IProjection
50+ where TEvent : IEvent
51+ {
52+ services . AddTransient < INotificationHandler < TEvent > > ( sp =>
53+ {
54+ var session = sp . GetRequiredService < IElasticClient > ( ) ;
55+
56+ return new ElasticSearchProjection < TEvent , TView > ( session , getId ) ;
57+ } ) ;
58+
59+ return services ;
60+ }
61+ }
62+ }
0 commit comments