2026년 7월 21일 화요일

main.py



from database import async_session
from models.answer import Answer
from models import Question
from sqlalchemy import select, insert
from sqlalchemy.exc import SQLAlchemyError

import asyncio
import SpreadsheetExporter

async def create_user_with_transaction(username: str):
    # 1. 세션 생성
    async with async_session() as session:
        # 2. 트랜잭션 시작 (비동기 컨텍스트 매니저)
        async with session.begin():
            try:
                # 데이터 생성 작업
                new_user = Answer(username=username)
                session.add(new_user)
                
                # 추가 작업 (예: 로그 기록 등)
                # 이 블록 안에서 에러가 발생하면 전체 작업이 롤백됩니다.
                
            except Exception as e:
                # session.begin()을 사용하면 에러 발생 시 자동 롤백되지만, 
                # 추가적인 로깅이 필요하면 여기서 처리합니다.
                print(f"에러 발생: {e}")
                raise

        # 블록을 나가면 자동으로 commit 완료
    print("트랜잭션이 성공적으로 커밋되었습니다.")

async def manual_transaction_example(username: str):
    session = async_session()
    try:
        # 작업 수행
        new_user = Answer(username=username)
        session.add(new_user)
        
        # 명시적 커밋
        await session.commit()
        print("커밋 성공")
    except SQLAlchemyError as e:
        # 에러 발생 시 명시적 롤백
        await session.rollback()
        print(f"롤백 실행: {e}")
    finally:
        # 세션 닫기
        await session.close()


async def create_user_and_post(username: str, title: str):
    async with async_session() as session:
        async with session.begin():
            # 1. 사용자 생성
            user = Answer(username=username)
            session.add(user)
            await session.flush()  # DB에 임시 반영하여 user.id를 확보

            # 2. 해당 사용자의 포스트 생성
            post = Question(title=title, owner_id=user.id)
            session.add(post)
            
            # 여기서 에러 발생 시 User 생성도 취소됨

async def fast_bulk_insert(user_data_list: list):
    async with async_session() as session:
        async with session.begin():
            # Core의 insert 구문 사용
            stmt = insert(Answer).values(user_data_list)
            await session.execute(stmt)

import gspread_asyncio

# from google-auth package
from google.oauth2.service_account import Credentials 

# First, set up a callback function that fetches our credentials off the disk.
# gspread_asyncio needs this to re-authenticate when credentials expire.
def get_creds():
  # To obtain a service account JSON file, follow these steps:
  # https://gspread.readthedocs.io/en/latest/oauth2.html#for-bots-using-service-account

  #path = os.environ.get('GOOGLE_APPLICATION_CREDENTIALS')
  path = "./sheets-xxxxxx-xxxxxxxxxxxx.json"
  creds = Credentials.from_service_account_file(path)
  scoped = creds.with_scopes([
      "https://spreadsheets.google.com/feeds",
      "https://www.googleapis.com/auth/spreadsheets",
      "https://www.googleapis.com/auth/drive",
  ])
  return scoped


if __name__ == "__main__":
  # Execute when the module is not initialized from an import statement.
  #main()

  # --- 사용 예시 ---
  async def main():
    # Create an AsyncioGspreadClientManager object which
    # will give us access to the Spreadsheet API.
    agcm = gspread_asyncio.AsyncioGspreadClientManager(get_creds)

    # Always authorize first.
    # If you have a long-running program call authorize() repeatedly.
    agc = await agcm.authorize()

    spreadsheet_id = "xxxxxxxxx-xxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    exporter = SpreadsheetExporter.SpreadsheetExporter(agc, spreadsheet_id)

    print("--- SQL 스키마 추출 시작 (병렬 처리) ---")
    # 내부적으로 _execute_parallel을 호출하여 SCHEMA 시트의 TRUE 항목을 병렬 처리합니다.
    schema_sql = await exporter.export_schema()
    print(f"{schema_sql}")

    with open("output_schema.sql", "w", encoding="utf-8") as f:
        f.write(schema_sql)
    print("✅ 스키마 추출 완료: output_schema.sql")

    print("\n--- 데이터 INSERT 구문 추출 시작 (병렬 처리) ---")
    # 내부적으로 _execute_parallel을 호출하여 DATA 시트의 TRUE 항목을 병렬 처리합니다.
    data_sql = await exporter.export_data()
    print(f"{data_sql}")

    with open("output_data.sql", "w", encoding="utf-8") as f:
        f.write(data_sql)
    print("✅ 데이터 추출 완료: output_data.sql")
    
  # Turn on debugging if you're new to asyncio!
  asyncio.run(main(), debug=True)    



database.py

import os from contextlib import contextmanager # contextmanager 임포트 from typing import Generator from dotenv...