#!/usr/bin/env python3 """Pre/post invariants for the FIFA17 Rust production migration rehearsal. Covers every domain the authorization names: coins, ownership, squads, managers, staff, consumables, club items, transfer state, packs/unassigned, SBC state, match state/history. Read-only; run against a COPY. """ import json import sqlite3 import sys db = sys.argv[1] out = sys.argv[2] if len(sys.argv) > 2 else None con = sqlite3.connect("file:%s?mode=ro" % db, uri=True) tables = {r[0] for r in con.execute( "SELECT name FROM sqlite_master WHERE type='table'")} def one(sql, default=None): try: r = con.execute(sql).fetchone() return r[0] if r else default except sqlite3.Error: return default def count(t): return one("SELECT COUNT(*) FROM %s" % t) if t in tables else None def group(t, col): if t not in tables: return None try: return dict(con.execute("SELECT %s, COUNT(*) FROM %s GROUP BY 1" % (col, t))) except sqlite3.Error: return None inv = { "schema_version": one("SELECT MAX(version) FROM _sqlx_migrations"), "tables": len(tables), # economy "coins": one("SELECT coins FROM clubs LIMIT 1"), "clubs": count("clubs"), "profiles": count("profiles"), # ownership "owned_cards": count("owned_cards"), "owned_by_kind": group("owned_cards", "content_kind"), "owned_distinct_cards": one("SELECT COUNT(DISTINCT card_id) FROM owned_cards"), "owned_loans": one("SELECT COUNT(*) FROM owned_cards WHERE is_loan=1"), "owned_chem_styles": one( "SELECT COUNT(*) FROM owned_cards WHERE chemistry_style IS NOT NULL"), "owned_pos_overrides": one( "SELECT COUNT(*) FROM owned_cards WHERE position_override IS NOT NULL"), # squads / managers "squads": count("squads"), "squad_managers": count("squad_managers"), # club items "club_active_items": count("club_active_items"), "club_kit_assignments": count("club_kit_assignments"), # transfer / market / piles "market_listings": count("market_listings"), "market_listings_by_status": group("market_listings", "status"), "market_history": count("market_history"), "packs": count("packs"), # FIFA17 opaque squad extension (adapter-owned blob) "game_entity_ext": count("game_entity_ext"), "squad_players": count("squad_players"), "seasons": count("seasons"), "events": count("events"), "notifications": count("notifications"), # sbc "sbc_submissions": count("sbc_submissions"), "sbc_challenge_squads": count("sbc_challenge_squads"), # matches / history "matches": count("matches"), "match_completions": count("match_completions"), "season_history": count("season_history"), "statistics": count("statistics"), "consumable_applications": count("consumable_applications"), } # integrity inv["integrity_check"] = one("PRAGMA integrity_check") inv["foreign_key_violations"] = len(list(con.execute("PRAGMA foreign_key_check"))) con.close() print(json.dumps(inv, indent=2, sort_keys=True)) if out: open(out, "w").write(json.dumps(inv, sort_keys=True, indent=2))