#!/usr/bin/env python3 """ Cleanup Public Nouns NFT Data This script removes all Public Nouns NFT data from the database, including NFT holdings, the data source entry, and contacts that were created solely because of their Public Nouns NFT holdings. Usage: python cleanup_public_nouns.py """ import os import sys import argparse from dotenv import load_dotenv # Add parent directory to path to import utils sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from utils.db_connector import DatabaseConnector from utils.logger import setup_logger # Load environment variables load_dotenv() # Setup logging logger = setup_logger("cleanup_public_nouns") def cleanup_public_nouns_data(contract_address="0x93ecac71499147627DFEc6d0E494d50fCFFf10EE", collection_name="Public Nouns"): """ Remove all Public Nouns NFT data from the database. Args: contract_address: The contract address of the Public Nouns NFT collection_name: The name of the collection """ logger.info(f"Cleaning up data for {collection_name} ({contract_address})") db = DatabaseConnector() # First, identify contacts that only have Public Nouns NFT holdings query = """ WITH public_nouns_contacts AS ( SELECT DISTINCT "contactId" FROM "NftHolding" WHERE "contractAddress" = %(contract_address)s ), contacts_with_other_data AS ( -- Contacts with other NFT holdings SELECT DISTINCT "contactId" FROM "NftHolding" WHERE "contractAddress" != %(contract_address)s UNION -- Contacts with token holdings SELECT DISTINCT "contactId" FROM "TokenHolding" UNION -- Contacts with DAO memberships SELECT DISTINCT "contactId" FROM "DaoMembership" UNION -- Contacts with notes SELECT DISTINCT "contactId" FROM "Note" UNION -- Contacts with tags SELECT DISTINCT "contactId" FROM "TagsOnContacts" ), contacts_to_delete AS ( SELECT "contactId" FROM public_nouns_contacts WHERE "contactId" NOT IN (SELECT "contactId" FROM contacts_with_other_data) ) SELECT id FROM "Contact" WHERE id IN (SELECT "contactId" FROM contacts_to_delete) """ contacts_to_delete = db.execute_query(query, {"contract_address": contract_address}) contact_ids_to_delete = [contact["id"] for contact in contacts_to_delete] logger.info(f"Found {len(contact_ids_to_delete)} contacts to delete") # Delete NFT holdings for this contract query = """ DELETE FROM "NftHolding" WHERE "contractAddress" = %(contract_address)s RETURNING id """ result = db.execute_query(query, {"contract_address": contract_address}) deleted_holdings = len(result) logger.info(f"Deleted {deleted_holdings} NFT holdings") # Delete contacts that only had Public Nouns NFT holdings if contact_ids_to_delete: placeholders = ", ".join([f"%(id{i})s" for i in range(len(contact_ids_to_delete))]) params = {f"id{i}": contact_id for i, contact_id in enumerate(contact_ids_to_delete)} query = f""" DELETE FROM "Contact" WHERE id IN ({placeholders}) RETURNING id """ result = db.execute_query(query, params) deleted_contacts = len(result) logger.info(f"Deleted {deleted_contacts} contacts") # Delete scraping jobs for this collection query = """ DELETE FROM "ScrapingJob" WHERE "sourceName" = %(source_name)s RETURNING id """ result = db.execute_query(query, {"source_name": f"NFT:{collection_name}"}) deleted_jobs = len(result) logger.info(f"Deleted {deleted_jobs} scraping jobs") # Delete data source query = """ DELETE FROM "DataSource" WHERE name = %(source_name)s RETURNING id """ result = db.execute_query(query, {"source_name": f"NFT:{collection_name}"}) deleted_sources = len(result) logger.info(f"Deleted {deleted_sources} data sources") logger.info("Cleanup completed successfully") def main(): """Main entry point for the script.""" parser = argparse.ArgumentParser(description="Clean up Public Nouns NFT data") parser.add_argument("--contract", default="0x93ecac71499147627DFEc6d0E494d50fCFFf10EE", help="NFT contract address") parser.add_argument("--name", default="Public Nouns", help="NFT collection name") args = parser.parse_args() cleanup_public_nouns_data(args.contract, args.name) if __name__ == "__main__": main()