@@ -428,6 +428,93 @@ async function sendCommandWithRetry(command: any, maxRetries = 8, initialDelay =
428428 }
429429}
430430
431+ async function verifyAndCorrectCountWithData ( metaGame : string , countType : "currentgames" | "completedgames" | "standingchallenges" , actualCount : number , countsData : any ) {
432+ try {
433+ if ( ! countsData . Item ) {
434+ console . log ( `No METAGAMES COUNTS found, creating initial record for ${ metaGame } ` ) ;
435+ await ddbDocClient . send ( new UpdateCommand ( {
436+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
437+ Key : { "pk" : "METAGAMES" , "sk" : "COUNTS" } ,
438+ ExpressionAttributeNames : { "#g" : metaGame } ,
439+ ExpressionAttributeValues : { ":count" : actualCount } ,
440+ UpdateExpression : `set #g.${ countType } = :count`
441+ } ) ) ;
442+ console . log ( `Initialized ${ countType } for ${ metaGame } to ${ actualCount } ` ) ;
443+ return ;
444+ }
445+
446+ const details = countsData . Item as MetaGameCounts ;
447+ const storedCount = details [ metaGame ] ?. [ countType ] || 0 ;
448+
449+ if ( storedCount !== actualCount ) {
450+ console . log ( `Count mismatch for ${ metaGame } .${ countType } : stored=${ storedCount } , actual=${ actualCount } . Correcting...` ) ;
451+
452+ await ddbDocClient . send ( new UpdateCommand ( {
453+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
454+ Key : { "pk" : "METAGAMES" , "sk" : "COUNTS" } ,
455+ ExpressionAttributeNames : { "#g" : metaGame } ,
456+ ExpressionAttributeValues : { ":count" : actualCount } ,
457+ UpdateExpression : `set #g.${ countType } = :count`
458+ } ) ) ;
459+
460+ console . log ( `Corrected ${ countType } for ${ metaGame } from ${ storedCount } to ${ actualCount } ` ) ;
461+ }
462+ } catch ( error ) {
463+ console . error ( `Error verifying/correcting count for ${ metaGame } .${ countType } :` , error ) ;
464+ // Don't throw - we don't want to break the main query if count correction fails
465+ }
466+ }
467+
468+ async function verifyAndCorrectRatingsCountWithData ( metaGame : string , actualRatings : any [ ] , countsData : any ) {
469+ try {
470+ // Extract unique player IDs from actual ratings data as a Set
471+ const actualPlayerIds = new Set ( actualRatings . map ( rating => rating . sk ) ) ;
472+ const actualCount = actualPlayerIds . size ;
473+
474+ if ( ! countsData . Item && actualCount > 0 ) {
475+ console . log ( `No METAGAMES COUNTS found, creating initial ratings record for ${ metaGame } ` ) ;
476+ await ddbDocClient . send ( new UpdateCommand ( {
477+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
478+ Key : { "pk" : "METAGAMES" , "sk" : "COUNTS" } ,
479+ ExpressionAttributeNames : { "#gr" : metaGame + "_ratings" } ,
480+ ExpressionAttributeValues : { ":players" : actualPlayerIds } ,
481+ UpdateExpression : `set #gr = :players`
482+ } ) ) ;
483+ console . log ( `Initialized ratings for ${ metaGame } with ${ actualCount } players` ) ;
484+ return ;
485+ }
486+
487+ const details = countsData . Item as any ;
488+ const storedPlayerIds = details [ metaGame + "_ratings" ] || new Set ( ) ;
489+ const storedCount = storedPlayerIds . size ;
490+
491+ if ( storedCount !== actualCount || ! setsEqual ( storedPlayerIds , actualPlayerIds ) ) {
492+ console . log ( `Ratings mismatch for ${ metaGame } : stored=${ storedCount } players, actual=${ actualCount } players. Updating player list...` ) ;
493+
494+ await ddbDocClient . send ( new UpdateCommand ( {
495+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
496+ Key : { "pk" : "METAGAMES" , "sk" : "COUNTS" } ,
497+ ExpressionAttributeNames : { "#gr" : metaGame + "_ratings" } ,
498+ ExpressionAttributeValues : { ":players" : actualPlayerIds } ,
499+ UpdateExpression : `set #gr = :players`
500+ } ) ) ;
501+
502+ console . log ( `Updated ratings list for ${ metaGame } from ${ storedCount } to ${ actualCount } players` ) ;
503+ }
504+ } catch ( error ) {
505+ console . error ( `Error verifying/correcting ratings for ${ metaGame } :` , error ) ;
506+ // Don't throw - we don't want to break the main query if count correction fails
507+ }
508+ }
509+
510+ function setsEqual ( a : Set < any > , b : Set < any > ) : boolean {
511+ if ( a . size !== b . size ) return false ;
512+ for ( let item of a ) {
513+ if ( ! b . has ( item ) ) return false ;
514+ }
515+ return true ;
516+ }
517+
431518module . exports . query = async ( event : { queryStringParameters : any ; } ) => {
432519 console . log ( event ) ;
433520 const pars = event . queryStringParameters ;
@@ -672,16 +759,36 @@ async function challengeDetails(pars: { id: string; }) {
672759async function games ( pars : { metaGame : string , type : string ; } ) {
673760 const game = pars . metaGame ;
674761 console . log ( game ) ;
762+
763+ // Start fetching counts in parallel
764+ const countsPromise = ddbDocClient . send (
765+ new GetCommand ( {
766+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
767+ Key : {
768+ "pk" : "METAGAMES" , "sk" : "COUNTS"
769+ } ,
770+ } )
771+ ) ;
772+
675773 if ( pars . type === "current" ) {
676774 try {
677- const gamesData = await ddbDocClient . send (
678- new QueryCommand ( {
679- TableName : process . env . ABSTRACT_PLAY_TABLE ,
680- KeyConditionExpression : "#pk = :pk and begins_with(#sk, :sk)" ,
681- ExpressionAttributeValues : { ":pk" : "GAME" , ":sk" : game + '#0#' } ,
682- ExpressionAttributeNames : { "#pk" : "pk" , "#sk" : "sk" } ,
683- } ) ) ;
775+ const [ gamesData , countsData ] = await Promise . all ( [
776+ ddbDocClient . send (
777+ new QueryCommand ( {
778+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
779+ KeyConditionExpression : "#pk = :pk and begins_with(#sk, :sk)" ,
780+ ExpressionAttributeValues : { ":pk" : "GAME" , ":sk" : game + '#0#' } ,
781+ ExpressionAttributeNames : { "#pk" : "pk" , "#sk" : "sk" } ,
782+ } ) ) ,
783+ countsPromise
784+ ] ) ;
785+
684786 const gamelist = gamesData . Items as FullGame [ ] ;
787+
788+ // Verify and correct current games count
789+ const actualCount = gamelist . length ;
790+ await verifyAndCorrectCountWithData ( game , "currentgames" , actualCount , countsData ) ;
791+
685792 const returnlist = gamelist . map ( g => {
686793 const state = GameFactory ( g . metaGame , g . state ) ; // JSON.parse(g.state);
687794 if ( state === undefined ) {
@@ -701,13 +808,21 @@ async function games(pars: { metaGame: string, type: string; }) {
701808 }
702809 } else if ( pars . type === "completed" ) {
703810 try {
704- const gamesData = await ddbDocClient . send (
705- new QueryCommand ( {
706- TableName : process . env . ABSTRACT_PLAY_TABLE ,
707- KeyConditionExpression : "#pk = :pk" ,
708- ExpressionAttributeValues : { ":pk" : "COMPLETEDGAMES#" + game } ,
709- ExpressionAttributeNames : { "#pk" : "pk" }
710- } ) ) ;
811+ const [ gamesData , countsData ] = await Promise . all ( [
812+ ddbDocClient . send (
813+ new QueryCommand ( {
814+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
815+ KeyConditionExpression : "#pk = :pk" ,
816+ ExpressionAttributeValues : { ":pk" : "COMPLETEDGAMES#" + game } ,
817+ ExpressionAttributeNames : { "#pk" : "pk" }
818+ } ) ) ,
819+ countsPromise
820+ ] ) ;
821+
822+ // Verify and correct completed games count
823+ const actualCount = gamesData . Items ?. length || 0 ;
824+ await verifyAndCorrectCountWithData ( game , "completedgames" , actualCount , countsData ) ;
825+
711826 return {
712827 statusCode : 200 ,
713828 body : JSON . stringify ( gamesData . Items ) ,
@@ -725,14 +840,33 @@ async function games(pars: { metaGame: string, type: string; }) {
725840
726841async function ratings ( pars : { metaGame : string } ) {
727842 const game = pars . metaGame ;
843+
844+ // Start fetching counts in parallel
845+ const countsPromise = ddbDocClient . send (
846+ new GetCommand ( {
847+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
848+ Key : {
849+ "pk" : "METAGAMES" , "sk" : "COUNTS"
850+ } ,
851+ } )
852+ ) ;
853+
728854 try {
729- const ratingsData = await ddbDocClient . send (
730- new QueryCommand ( {
731- TableName : process . env . ABSTRACT_PLAY_TABLE ,
732- KeyConditionExpression : "#pk = :pk" ,
733- ExpressionAttributeValues : { ":pk" : "RATINGS#" + game } ,
734- ExpressionAttributeNames : { "#pk" : "pk" }
735- } ) ) ;
855+ const [ ratingsData , countsData ] = await Promise . all ( [
856+ ddbDocClient . send (
857+ new QueryCommand ( {
858+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
859+ KeyConditionExpression : "#pk = :pk" ,
860+ ExpressionAttributeValues : { ":pk" : "RATINGS#" + game } ,
861+ ExpressionAttributeNames : { "#pk" : "pk" }
862+ } ) ) ,
863+ countsPromise
864+ ] ) ;
865+
866+ // Verify and correct ratings count
867+ const actualRatings = ratingsData . Items || [ ] ;
868+ await verifyAndCorrectRatingsCountWithData ( game , actualRatings , countsData ) ;
869+
736870 return {
737871 statusCode : 200 ,
738872 body : JSON . stringify ( ratingsData . Items ) ,
@@ -748,17 +882,36 @@ async function ratings(pars: { metaGame: string }) {
748882async function standingChallenges ( pars : { metaGame : string ; } ) {
749883 const game = pars . metaGame ;
750884 console . log ( game ) ;
885+
886+ // Start fetching counts in parallel
887+ const countsPromise = ddbDocClient . send (
888+ new GetCommand ( {
889+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
890+ Key : {
891+ "pk" : "METAGAMES" , "sk" : "COUNTS"
892+ } ,
893+ } )
894+ ) ;
895+
751896 try {
752- const challenges = await ddbDocClient . send (
753- new QueryCommand ( {
754- TableName : process . env . ABSTRACT_PLAY_TABLE ,
755- KeyConditionExpression : "#pk = :pk" ,
756- ExpressionAttributeValues : { ":pk" : "STANDINGCHALLENGE#" + game } ,
757- ExpressionAttributeNames : { "#pk" : "pk" }
758- } ) ) ;
897+ const [ challengesData , countsData ] = await Promise . all ( [
898+ ddbDocClient . send (
899+ new QueryCommand ( {
900+ TableName : process . env . ABSTRACT_PLAY_TABLE ,
901+ KeyConditionExpression : "#pk = :pk" ,
902+ ExpressionAttributeValues : { ":pk" : "STANDINGCHALLENGE#" + game } ,
903+ ExpressionAttributeNames : { "#pk" : "pk" }
904+ } ) ) ,
905+ countsPromise
906+ ] ) ;
907+
908+ // Verify and correct standing challenges count
909+ const actualCount = challengesData . Items ?. length || 0 ;
910+ await verifyAndCorrectCountWithData ( game , "standingchallenges" , actualCount , countsData ) ;
911+
759912 return {
760913 statusCode : 200 ,
761- body : JSON . stringify ( challenges . Items ) ,
914+ body : JSON . stringify ( challengesData . Items ) ,
762915 headers
763916 } ;
764917 }
0 commit comments