@@ -260,6 +260,10 @@ async def create_agent(
260260 return agent
261261
262262
263+ async def delete_agent (agent_id : str ) -> None :
264+ await db .execute ("DELETE FROM market_town.agents WHERE id = :agent_id" , {"agent_id" : agent_id })
265+
266+
263267async def get_agent (agent_id : str ) -> Agent | None :
264268 return await db .fetchone (
265269 "SELECT * FROM market_town.agents WHERE id = :id" ,
@@ -318,6 +322,13 @@ async def create_business(
318322 return business
319323
320324
325+ async def delete_business (business_id : str ) -> None :
326+ await db .execute (
327+ "DELETE FROM market_town.businesses WHERE id = :business_id" ,
328+ {"business_id" : business_id },
329+ )
330+
331+
321332async def get_business (business_id : str ) -> Business | None :
322333 return await db .fetchone (
323334 "SELECT * FROM market_town.businesses WHERE id = :id" ,
@@ -381,6 +392,33 @@ async def get_epoch(world_id: str, epoch_number: int) -> Epoch | None:
381392 )
382393
383394
395+ async def claim_epoch_for_resolution (world_id : str , epoch_number : int , stale_before : datetime ) -> bool :
396+ result = await db .execute (
397+ f"""
398+ UPDATE market_town.epochs
399+ SET status = 'resolving',
400+ updated_at = { db .timestamp_placeholder ("now" )}
401+ WHERE world_id = :world_id
402+ AND epoch_number = :epoch_number
403+ AND resolved_at IS NULL
404+ AND (
405+ status = 'open'
406+ OR (
407+ status = 'resolving'
408+ AND updated_at <= { db .timestamp_placeholder ("stale_before" )}
409+ )
410+ )
411+ """ ,
412+ {
413+ "world_id" : world_id ,
414+ "epoch_number" : epoch_number ,
415+ "now" : utc_now ().timestamp (),
416+ "stale_before" : stale_before .timestamp (),
417+ },
418+ )
419+ return bool (result .rowcount )
420+
421+
384422async def get_latest_epoch (world_id : str ) -> Epoch | None :
385423 return await db .fetchone (
386424 """
@@ -511,6 +549,26 @@ async def create_snapshot(snapshot: BusinessEpochSnapshot) -> BusinessEpochSnaps
511549 return snapshot
512550
513551
552+ async def get_snapshot_for_business_epoch (
553+ world_id : str , epoch_number : int , business_id : str
554+ ) -> BusinessEpochSnapshot | None :
555+ return await db .fetchone (
556+ """
557+ SELECT * FROM market_town.business_epoch_snapshots
558+ WHERE world_id = :world_id
559+ AND epoch_number = :epoch_number
560+ AND business_id = :business_id
561+ LIMIT 1
562+ """ ,
563+ {
564+ "world_id" : world_id ,
565+ "epoch_number" : epoch_number ,
566+ "business_id" : business_id ,
567+ },
568+ BusinessEpochSnapshot ,
569+ )
570+
571+
514572async def list_snapshots_for_business (business_id : str , limit : int = 10 ) -> list [BusinessEpochSnapshot ]:
515573 return await db .fetchall (
516574 f"""
@@ -528,6 +586,18 @@ async def create_season_result(season_result: SeasonResult) -> SeasonResult:
528586 return season_result
529587
530588
589+ async def get_season_result (world_id : str , season_number : int ) -> SeasonResult | None :
590+ return await db .fetchone (
591+ """
592+ SELECT * FROM market_town.season_results
593+ WHERE world_id = :world_id AND season_number = :season_number
594+ LIMIT 1
595+ """ ,
596+ {"world_id" : world_id , "season_number" : season_number },
597+ SeasonResult ,
598+ )
599+
600+
531601async def update_season_result (season_result : SeasonResult ) -> SeasonResult :
532602 updated = season_result .copy (update = {"updated_at" : utc_now ()})
533603 await db .update ("market_town.season_results" , updated )
@@ -553,11 +623,7 @@ async def list_paid_payment_requests_for_season(
553623 * ,
554624 include_before_start : bool = False ,
555625) -> list [PaymentRequestRecord ]:
556- lower_clause = (
557- ""
558- if include_before_start
559- else f"AND paid_at >= { db .timestamp_placeholder ('season_started_at' )} "
560- )
626+ lower_clause = "" if include_before_start else f"AND paid_at >= { db .timestamp_placeholder ('season_started_at' )} "
561627 return await db .fetchall (
562628 f"""
563629 SELECT * FROM market_town.payment_requests
@@ -602,6 +668,35 @@ async def get_payment_request_by_hash(payment_hash: str) -> PaymentRequestRecord
602668 )
603669
604670
671+ async def claim_payment_request_for_settlement (
672+ payment_hash : str , stale_before : datetime
673+ ) -> PaymentRequestRecord | None :
674+ result = await db .execute (
675+ f"""
676+ UPDATE market_town.payment_requests
677+ SET status = 'settling',
678+ updated_at = { db .timestamp_placeholder ("now" )}
679+ WHERE payment_hash = :payment_hash
680+ AND (
681+ status = 'pending'
682+ OR status = 'expired'
683+ OR (
684+ status = 'settling'
685+ AND updated_at <= { db .timestamp_placeholder ("stale_before" )}
686+ )
687+ )
688+ """ ,
689+ {
690+ "payment_hash" : payment_hash ,
691+ "now" : utc_now ().timestamp (),
692+ "stale_before" : stale_before .timestamp (),
693+ },
694+ )
695+ if not result .rowcount :
696+ return None
697+ return await get_payment_request_by_hash (payment_hash )
698+
699+
605700async def get_payment_request_by_claim_token (claim_token : str ) -> PaymentRequestRecord | None :
606701 return await db .fetchone (
607702 """
@@ -614,6 +709,41 @@ async def get_payment_request_by_claim_token(claim_token: str) -> PaymentRequest
614709 )
615710
616711
712+ async def claim_payment_request_credentials_reveal (
713+ claim_token : str ,
714+ ) -> PaymentRequestRecord | None :
715+ result = await db .execute (
716+ f"""
717+ UPDATE market_town.payment_requests
718+ SET credentials_revealed = TRUE,
719+ issued_api_key = NULL,
720+ updated_at = { db .timestamp_placeholder ("now" )}
721+ WHERE claim_token = :claim_token
722+ AND status = 'paid'
723+ AND credentials_revealed = FALSE
724+ AND agent_id IS NOT NULL
725+ AND business_id IS NOT NULL
726+ """ ,
727+ {"claim_token" : claim_token , "now" : utc_now ().timestamp ()},
728+ )
729+ if not result .rowcount :
730+ return None
731+ return await get_payment_request_by_claim_token (claim_token )
732+
733+
734+ async def reset_payment_request_credentials_reveal (claim_token : str ) -> None :
735+ await db .execute (
736+ f"""
737+ UPDATE market_town.payment_requests
738+ SET credentials_revealed = FALSE,
739+ updated_at = { db .timestamp_placeholder ("now" )}
740+ WHERE claim_token = :claim_token
741+ AND credentials_revealed = TRUE
742+ """ ,
743+ {"claim_token" : claim_token , "now" : utc_now ().timestamp ()},
744+ )
745+
746+
617747async def list_pending_payment_requests (world_id : str ) -> list [PaymentRequestRecord ]:
618748 return await db .fetchall (
619749 """
@@ -626,6 +756,53 @@ async def list_pending_payment_requests(world_id: str) -> list[PaymentRequestRec
626756 )
627757
628758
759+ async def list_active_pending_payment_requests (world_id : str , before_time : datetime ) -> list [PaymentRequestRecord ]:
760+ now = utc_now ()
761+ return await db .fetchall (
762+ f"""
763+ SELECT * FROM market_town.payment_requests
764+ WHERE world_id = :world_id
765+ AND status = 'pending'
766+ AND created_at > { db .timestamp_placeholder ("before_time" )}
767+ AND (
768+ reservation_expires_at IS NULL
769+ OR reservation_expires_at > { db .timestamp_placeholder ("now" )}
770+ )
771+ ORDER BY created_at DESC
772+ """ ,
773+ {
774+ "world_id" : world_id ,
775+ "before_time" : before_time .timestamp (),
776+ "now" : now .timestamp (),
777+ },
778+ PaymentRequestRecord ,
779+ )
780+
781+
782+ async def expire_pending_payment_requests (world_id : str , before_time : datetime ) -> None :
783+ await db .execute (
784+ f"""
785+ UPDATE market_town.payment_requests
786+ SET status = 'expired',
787+ updated_at = { db .timestamp_placeholder ("now" )}
788+ WHERE world_id = :world_id
789+ AND status = 'pending'
790+ AND (
791+ created_at <= { db .timestamp_placeholder ("before_time" )}
792+ OR (
793+ reservation_expires_at IS NOT NULL
794+ AND reservation_expires_at <= { db .timestamp_placeholder ("now" )}
795+ )
796+ )
797+ """ ,
798+ {
799+ "world_id" : world_id ,
800+ "now" : utc_now ().timestamp (),
801+ "before_time" : before_time .timestamp (),
802+ },
803+ )
804+
805+
629806async def update_payment_request (payment_request : PaymentRequestRecord ) -> PaymentRequestRecord :
630807 updated = payment_request .copy (update = {"updated_at" : utc_now ()})
631808 await db .update ("market_town.payment_requests" , updated )
0 commit comments