@@ -51,7 +51,12 @@ TimeSpan before
5151 @start_time,
5252 @end_time
5353 ) AS ""Bucket"",
54- locf(last(p.value, p.time)) AS ""Value""
54+ locf(
55+ last(p.value, p.time),
56+ (SELECT p2.value FROM player_portfolios p2
57+ WHERE p2.player_id = p.player_id AND p2.time < @start_time
58+ ORDER BY p2.time DESC LIMIT 1)
59+ ) AS ""Value""
5560 FROM player_portfolios p
5661 WHERE p.player_id = ANY(@ids)
5762 AND p.time >= @start_time
@@ -77,9 +82,10 @@ FROM player_portfolios p
7782
7883 while ( await rows . ReadAsync ( ) )
7984 {
85+ if ( rows . IsDBNull ( 2 ) ) continue ;
8086 int playerId = rows . GetInt32 ( 0 ) ;
8187 DateTime bucketTime = rows . GetDateTime ( 1 ) ;
82- double value = rows . IsDBNull ( 2 ) ? Player . MinPortfolio : rows . GetDouble ( 2 ) ;
88+ double value = rows . GetDouble ( 2 ) ;
8389
8490 if ( ! playerLookup . TryGetValue ( playerId , out var player ) ) continue ;
8591
@@ -119,63 +125,58 @@ TimeSpan before
119125 }
120126
121127 DateTimeOffset now = DateTimeOffset . UtcNow ;
122- Dictionary < int , Creator > creatorLookup = creators . ToDictionary ( c => c . Id . Value ) ;
123- int [ ] creatorIds = [ .. creatorLookup . Keys ] ;
124128 string interval = step . ToTimescaleString ( ) ;
125-
126- DateTimeOffset globalEndTime = creators . Max ( c =>
127- c . StreamStatus . IsLive ? now : c . StreamStatus . EndedAt ) ;
128- DateTimeOffset globalStartTime = globalEndTime - before ;
129129 Dictionary < int , List < Vote > > result = creators . ToDictionary (
130130 c => c . Id . Value ,
131131 _ => new List < Vote > ( )
132132 ) ;
133133
134- using DbCommand command = _dbContext . Database . GetDbConnection ( ) . CreateCommand ( ) ;
135- command . CommandText = $@ "
134+ DbConnection connection = _dbContext . Database . GetDbConnection ( ) ;
135+ if ( connection . State != ConnectionState . Open )
136+ {
137+ await connection . OpenAsync ( ) ;
138+ }
139+
140+ foreach ( Creator creator in creators )
141+ {
142+ DateTimeOffset endTime = creator . StreamStatus . IsLive ? now : creator . StreamStatus . EndedAt ;
143+ DateTimeOffset startTime = endTime - before ;
144+
145+ using DbCommand command = connection . CreateCommand ( ) ;
146+ command . CommandText = $@ "
136147 SELECT
137- v.creator_id AS ""CreatorId"",
138148 time_bucket_gapfill(
139149 @interval::interval,
140150 v.time,
141151 @start_time,
142152 @end_time
143153 ) AS ""Bucket"",
144- locf(last(v.value, v.time)) AS ""Value""
154+ locf(
155+ last(v.value, v.time),
156+ (SELECT v2.value FROM votes v2
157+ WHERE v2.creator_id = @id AND v2.time < @start_time
158+ ORDER BY v2.time DESC LIMIT 1)
159+ ) AS ""Value""
145160 FROM votes v
146- WHERE v.creator_id = ANY(@ids)
161+ WHERE v.creator_id = @id
147162 AND v.time >= @start_time
148163 AND v.time <= @end_time
149- GROUP BY ""CreatorId"", "" Bucket""
164+ GROUP BY ""Bucket""
150165 ORDER BY ""Bucket"" ASC" ;
151- command . Parameters . Add ( new NpgsqlParameter ( "ids " , creatorIds ) ) ;
152- command . Parameters . Add ( new NpgsqlParameter ( "interval" , interval ) ) ;
153- command . Parameters . Add ( new NpgsqlParameter ( "start_time" , globalStartTime ) ) ;
154- command . Parameters . Add ( new NpgsqlParameter ( "end_time" , globalEndTime ) ) ;
166+ command . Parameters . Add ( new NpgsqlParameter ( "id " , creator . Id . Value ) ) ;
167+ command . Parameters . Add ( new NpgsqlParameter ( "interval" , interval ) ) ;
168+ command . Parameters . Add ( new NpgsqlParameter ( "start_time" , startTime ) ) ;
169+ command . Parameters . Add ( new NpgsqlParameter ( "end_time" , endTime ) ) ;
155170
156- if ( command . Connection ! . State != ConnectionState . Open )
157- {
158- await command . Connection . OpenAsync ( ) ;
159- }
160-
161- using DbDataReader rows = await command . ExecuteReaderAsync ( ) ;
162-
163- while ( await rows . ReadAsync ( ) )
164- {
165- int creatorId = rows . GetInt32 ( 0 ) ;
166- DateTime bucketTime = rows . GetDateTime ( 1 ) ;
167- double value = rows . IsDBNull ( 2 ) ? Creator . MinValue : rows . GetDouble ( 2 ) ;
168-
169- if ( ! creatorLookup . TryGetValue ( creatorId , out var creator ) ) continue ;
171+ using DbDataReader rows = await command . ExecuteReaderAsync ( ) ;
172+ List < Vote > list = result [ creator . Id . Value ] ;
170173
171- if ( ! creator . StreamStatus . IsLive &&
172- bucketTime > creator . StreamStatus . EndedAt . UtcDateTime )
174+ while ( await rows . ReadAsync ( ) )
173175 {
174- continue ;
175- }
176+ if ( rows . IsDBNull ( 1 ) ) continue ;
177+ DateTime bucketTime = rows . GetDateTime ( 0 ) ;
178+ double value = rows . GetDouble ( 1 ) ;
176179
177- if ( result . TryGetValue ( creatorId , out var list ) )
178- {
179180 list . Add ( new Vote
180181 {
181182 Creator = creator ,
@@ -186,7 +187,6 @@ FROM votes v
186187 }
187188 }
188189
189- // Convert Lists to Arrays for the return type
190190 return result . ToDictionary ( kvp => kvp . Key , kvp => kvp . Value . ToArray ( ) ) ;
191191 }
192192}
0 commit comments