stones/scripts/nft_holders/cleanup_public_nouns.py

150 lines
4.6 KiB
Python
Executable File

#!/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()