1
+ 'use server' ;
2
+
3
+ import { ObjectId } from 'mongodb' ;
4
+ import { connectToDatabase } from '@/lib/db' ;
5
+ import { ReviewEventDocument , ReviewResult , CardDocument } from '@/types' ;
6
+
7
+ interface LastReviewResult {
8
+ cardId : string ;
9
+ lastResult : ReviewResult ;
10
+ timestamp : Date ;
11
+ }
12
+
13
+ // Fetches the most recent review event for each card within a specific deck.
14
+ export async function getLastReviewEventPerCard ( deckId : string ) : Promise < Map < string , LastReviewResult > > {
15
+ if ( ! deckId || ! ObjectId . isValid ( deckId ) ) {
16
+ throw new Error ( 'Invalid Deck ID provided.' ) ;
17
+ }
18
+
19
+ const { db } = await connectToDatabase ( ) ;
20
+ const reviewEventsCollection = db . collection < ReviewEventDocument > ( 'review_events' ) ;
21
+ const cardsCollection = db . collection < CardDocument > ( 'cards' ) ;
22
+
23
+ try {
24
+ // 1. Find all card IDs belonging to the deck
25
+ const cardIdsInDeck = await cardsCollection
26
+ . find ( { deck_id : new ObjectId ( deckId ) } , { projection : { _id : 1 } } )
27
+ . map ( ( doc : { _id : ObjectId } ) => doc . _id )
28
+ . toArray ( ) ;
29
+
30
+ if ( cardIdsInDeck . length === 0 ) {
31
+ return new Map ( ) ; // No cards in deck, so no review history
32
+ }
33
+
34
+ // 2. Use aggregation to find the last review event for each relevant card
35
+ const aggregationPipeline = [
36
+ // Match only events for cards in the target deck
37
+ { $match : { card_id : { $in : cardIdsInDeck } } } ,
38
+ // Sort by timestamp descending to get the latest first
39
+ { $sort : { timestamp : - 1 } } ,
40
+ // Group by card_id and take the first document (which is the latest due to sorting)
41
+ {
42
+ $group : {
43
+ _id : "$card_id" ,
44
+ lastEvent : { $first : "$$ROOT" } // Get the whole document
45
+ }
46
+ } ,
47
+ // Reshape the output
48
+ {
49
+ $project : {
50
+ _id : 0 , // Exclude the grouping _id
51
+ cardId : { $toString : "$_id" } , // Convert card_id ObjectId to string
52
+ lastResult : "$lastEvent.result" ,
53
+ timestamp : "$lastEvent.timestamp"
54
+ }
55
+ }
56
+ ] ;
57
+
58
+ const results : LastReviewResult [ ] = await reviewEventsCollection . aggregate < LastReviewResult > ( aggregationPipeline ) . toArray ( ) ;
59
+
60
+ // Convert the array of results into a Map for easy lookup by cardId
61
+ const resultMap = new Map < string , LastReviewResult > ( ) ;
62
+ results . forEach ( item => {
63
+ resultMap . set ( item . cardId , item ) ;
64
+ } ) ;
65
+
66
+ return resultMap ;
67
+
68
+ } catch ( error ) {
69
+ console . error ( "Error fetching last review events:" , error ) ;
70
+ throw new Error ( "Failed to fetch review history." ) ;
71
+ }
72
+ }
0 commit comments