-
Notifications
You must be signed in to change notification settings - Fork 0
20251217 #1 postgre sql 연결 및 테이블 생성 #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
The head ref may contain hidden characters: "20251217_#1_PostgreSQL_\uC5F0\uACB0_\uBC0F_\uD14C\uC774\uBE14_\uC0DD\uC131"
Changes from 10 commits
47413ea
9066e5c
45655d0
280c968
5beeb5c
5cb7cef
a7fec07
8e26b45
6ec67cd
3b3d060
c7e3c0e
7aeea4d
474b474
53a8285
5fae0f8
483169e
3bb40da
9adbab9
f7024c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json | ||
| language: "ko-KR" | ||
| early_access: false | ||
| reviews: | ||
| profile: "chill" | ||
| request_changes_workflow: false | ||
| high_level_summary: true | ||
| poem: true | ||
| review_status: true | ||
| collapse_walkthrough: false | ||
| auto_review: | ||
| enabled: true | ||
| drafts: false | ||
| base_branches: | ||
| - main | ||
| - test | ||
| chat: | ||
| auto_reply: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,27 @@ | ||
| # 빈 파일 - DB 연결 설정 | ||
| from typing import AsyncGenerator | ||
|
|
||
| from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine | ||
|
|
||
| from app.config.settings import get_settings | ||
|
|
||
| _settings = get_settings() | ||
|
|
||
| _engine = create_async_engine( | ||
| _settings.postgres_url, | ||
| pool_pre_ping=True, | ||
| ) | ||
|
|
||
| _async_session_factory = async_sessionmaker( | ||
| bind=_engine, | ||
| expire_on_commit=False, | ||
| autoflush=False, | ||
| ) | ||
|
|
||
|
|
||
| def get_async_session_factory() -> async_sessionmaker[AsyncSession]: | ||
| return _async_session_factory | ||
|
|
||
|
|
||
| async def get_async_session() -> AsyncGenerator[AsyncSession, None]: | ||
| async with _async_session_factory() as session: | ||
| yield session | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,46 @@ | ||
| # 빈 파일 - 환경 변수 설정 | ||
| from functools import lru_cache | ||
|
|
||
| from pydantic_settings import BaseSettings, SettingsConfigDict | ||
|
|
||
|
|
||
| class Settings(BaseSettings): | ||
| """ | ||
| .env 에서 환경변수 로딩 | ||
| """ | ||
|
|
||
| model_config = SettingsConfigDict( | ||
| env_file=".env", | ||
| env_file_encoding="utf-8", | ||
| case_sensitive=False, | ||
| extra="ignore" | ||
| ) | ||
|
|
||
| # GitHub API 설정 | ||
| github_api_base_url: str | ||
|
|
||
| # Ollama 설정 | ||
| ollama_base_url: str | ||
| ollama_api_key: str | ||
| ollama_model: str | ||
| ollama_timeout_seconds: int | ||
|
|
||
| # Qdrant 설정 | ||
| qdrant_base_url: str | ||
| qdrant_collection: str | ||
| qdrant_api_key: str | ||
|
|
||
| # 텍스트 청크 설정 | ||
| text_chunk_max_chars: int | ||
| text_chunk_overlap_chars: int | ||
| text_chunk_hard_max_chars: int | ||
|
|
||
| # 동시성 설정 | ||
| concurrency_embedding_max_concurrency: int | ||
|
|
||
| # PostgreSQL 설정 | ||
| postgres_url: str | ||
|
Comment on lines
6
to
42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Environment variable field and .env example file check
echo "=== Settings 클래스의 필수 필드 확인 ==="
rg -A 1 "^\s+[a-z_]+:" app/config/settings.py
echo -e "\n=== .env 또는 .env.example 파일 존재 확인 ==="
fd -t f "^\.env" -H
fd -t f "\.env\.example$" -HRepository: Team-Romi/romi-chatbot Length of output: 506 🏁 Script executed: # Check the full settings.py file to understand validation setup
cat -n app/config/settings.pyRepository: Team-Romi/romi-chatbot Length of output: 1205 🏁 Script executed: # Check for any Field imports or validation patterns
rg "Field|validator|field_validator" app/config/settings.pyRepository: Team-Romi/romi-chatbot Length of output: 48 🏁 Script executed: # Search for get_settings usage and error handling
rg "get_settings" --type py -B 2 -A 2
# Check main.py or app initialization
fd -t f "main\.py$|app\.py$|__main__\.py$"Repository: Team-Romi/romi-chatbot Length of output: 603 🏁 Script executed: # Check for .env documentation or example in README or docs
fd -t f "README|\.md$" | head -20
rg "\.env|환경변수|environment" --type md -B 2 -A 2 | head -50Repository: Team-Romi/romi-chatbot Length of output: 75 🏁 Script executed: # Check main.py for settings initialization
cat -n app/main.py
# Check claude.md for documentation
cat -n claude.md | head -100Repository: Team-Romi/romi-chatbot Length of output: 1177 🏁 Script executed: # Check database.py to see how _settings is used
cat -n app/config/database.pyRepository: Team-Romi/romi-chatbot Length of output: 885
모든 설정 필드가 필수이며 기본값이 없지만
🤖 Prompt for AI Agents
Comment on lines
+18
to
+42
|
||
|
|
||
|
|
||
| @lru_cache(maxsize=1) | ||
| def get_settings() -> Settings: | ||
| return Settings() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| from sqlalchemy.orm import DeclarativeBase | ||
|
|
||
|
|
||
| class Base(DeclarativeBase): | ||
| """ | ||
| SQLAlchemy Declarative Base | ||
| - 모든 엔티티는 Base 상속 | ||
| """ | ||
| pass |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| from enum import Enum | ||
|
|
||
|
|
||
| class SourceType(str, Enum): | ||
| """ | ||
| 깃허브 임베딩 대상 SourceType | ||
| - Repository: 레포 파일/문서 (README 등) | ||
| - ISSUE: 이슈 | ||
| - PULL_REQUEST: PR | ||
| - COMMIT: 커밋 | ||
| - RELEASE: 릴리즈 | ||
| """ | ||
| REPOSITORY = "REPOSITORY" | ||
| ISSUE = "ISSUE" | ||
| PULL_REQUEST = "PULL_REQUEST" | ||
| COMMIT = "COMMIT" | ||
| RELEASE = "RELEASE" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import uuid | ||
| from datetime import datetime | ||
|
|
||
| from sqlalchemy import Enum as SqlEnum | ||
| from sqlalchemy import UniqueConstraint, Index, String, DateTime, func | ||
| from sqlalchemy.dialects.postgresql.base import UUID | ||
| from sqlalchemy.orm import Mapped, mapped_column | ||
|
|
||
| from app.models.base import Base | ||
| from app.models.enums.source_type import SourceType | ||
|
|
||
|
|
||
| class GithubCursorEntity(Base): | ||
| __tablename__ = "github_cursor" | ||
| __table_args__ = ( | ||
| UniqueConstraint("repository_name", "source_type", name="uq_github_cursor"), | ||
| Index("idx_github_cursor_repo_type", "repository_name", "source_type") | ||
| ) | ||
|
|
||
| id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) | ||
|
|
||
| repository_name: Mapped[str] = mapped_column(String(200), nullable=False) | ||
|
|
||
| source_type: Mapped[SourceType] = mapped_column(SqlEnum(SourceType, native_enum=False), nullable=False) | ||
|
|
||
| cursor_value: Mapped[str] = mapped_column(String(500), nullable=False) | ||
|
|
||
| created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now()) | ||
| updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()) |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import uuid | ||
| from typing import Optional | ||
|
|
||
| from sqlalchemy import select, func | ||
| from sqlalchemy.dialects.postgresql import insert | ||
| from sqlalchemy.ext.asyncio import AsyncSession | ||
|
|
||
| from app.models.enums.source_type import SourceType | ||
| from app.models.github_cursor import GithubCursorEntity | ||
|
|
||
|
|
||
| class GithubCursorRepository: | ||
| async def find_by_repository_name_and_source_type( | ||
| self, | ||
| session: AsyncSession, | ||
| repository_name: str, | ||
| source_type: SourceType, | ||
| ) -> Optional[GithubCursorEntity]: | ||
| query = select(GithubCursorEntity).where( | ||
| GithubCursorEntity.repository_name == repository_name, | ||
| GithubCursorEntity.source_type == source_type, | ||
| ) | ||
| result = await session.execute(query) | ||
| return result.scalar_one_or_none() | ||
|
|
||
| async def upsert( | ||
| self, | ||
| session: AsyncSession, | ||
| repository_name: str, | ||
| source_type: SourceType, | ||
| cursor_value: str, | ||
| ) -> None: | ||
| query = insert(GithubCursorEntity).values( | ||
| id=uuid.uuid4(), | ||
| repository_name=repository_name, | ||
| source_type=source_type, | ||
| cursor_value=cursor_value, | ||
| ).on_conflict_do_update( | ||
| index_elements=["repository_name", "source_type"], | ||
| set_={ | ||
| "cursor_value": cursor_value, | ||
| "updated_at": func.now(), | ||
| }, | ||
| ) | ||
| await session.execute(query) | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,45 @@ | ||
| alembic==1.17.2 | ||
| annotated-doc==0.0.4 | ||
| annotated-types==0.7.0 | ||
| anyio==4.12.0 | ||
| asyncpg==0.31.0 | ||
| certifi==2025.11.12 | ||
| cffi==2.0.0 | ||
| charset-normalizer==3.4.4 | ||
| click==8.3.1 | ||
| fastapi==0.124.4 | ||
| cryptography==46.0.3 | ||
| Deprecated==1.3.1 | ||
| fastapi==0.127.0 | ||
| greenlet==3.3.0 | ||
| grpcio==1.76.0 | ||
| grpcio-tools==1.76.0 | ||
| h11==0.16.0 | ||
| h2==4.3.0 | ||
| hpack==4.1.0 | ||
| httpcore==1.0.9 | ||
| httpx==0.28.1 | ||
| hyperframe==6.1.0 | ||
| idna==3.11 | ||
| Mako==1.3.10 | ||
| MarkupSafe==3.0.3 | ||
| numpy==2.4.0 | ||
| portalocker==3.2.0 | ||
| protobuf==6.33.2 | ||
| pycparser==2.23 | ||
| pydantic==2.12.5 | ||
| pydantic-settings==2.12.0 | ||
| pydantic_core==2.41.5 | ||
| PyGithub==2.8.1 | ||
| PyJWT==2.10.1 | ||
| PyNaCl==1.6.1 | ||
| python-dotenv==1.2.1 | ||
| qdrant-client==1.16.2 | ||
| requests==2.32.5 | ||
| setuptools==80.9.0 | ||
| SQLAlchemy==2.0.45 | ||
| starlette==0.50.0 | ||
| typing-inspection==0.4.2 | ||
| typing_extensions==4.15.0 | ||
| uvicorn==0.38.0 | ||
| urllib3==2.6.2 | ||
| uvicorn==0.40.0 | ||
| wrapt==2.0.1 | ||
|
Comment on lines
+1
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 의존성 버전 호환성 검증 및 테스트 필요 FastAPI 0.127.0과 SQLAlchemy 2.0.45, asyncpg 0.31.0의 조합에 대한 호환성 검증이 필요합니다. 특히 asyncpg 0.31.0은 SQLAlchemy 2.0에서 권장되는 버전 범위(0.29.0 이상)를 초과하므로, 프로덕션 배포 전에 데이터베이스 쿼리와 비동기 세션 동작을 철저히 테스트하시기 바랍니다. 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,16 @@ | ||||||||||||||
| CREATE TABLE IF NOT EXISTS github_cursor ( | ||||||||||||||
| id UUID PRIMARY KEY, | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. UUID PRIMARY KEY에 DEFAULT 값이 누락되었습니다.
🔎 제안하는 수정- id UUID PRIMARY KEY,
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),참고: 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| repository_name VARCHAR(200) NOT NULL, | ||||||||||||||
| source_type VARCHAR(50) NOT NULL, | ||||||||||||||
| cursor_value VARCHAR(500) NOT NULL, | ||||||||||||||
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | ||||||||||||||
| updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🔎 제안하는 수정 (트리거 추가)테이블 생성 후 다음 트리거를 추가하세요: -- updated_at 자동 업데이트 함수 생성
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
-- 트리거 생성
CREATE TRIGGER update_github_cursor_updated_at
BEFORE UPDATE ON github_cursor
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();🤖 Prompt for AI Agents
|
||||||||||||||
| CONSTRAINT uq_github_cursor UNIQUE (repository_name, source_type), | ||||||||||||||
|
|
||||||||||||||
| CONSTRAINT ck_github_cursor_source_type | ||||||||||||||
| CHECK (source_type IN ('REPOSITORY', 'ISSUE', 'PULL_REQUEST', 'COMMIT', 'RELEASE')) | ||||||||||||||
| ); | ||||||||||||||
|
|
||||||||||||||
| -- 인덱스 생성 | ||||||||||||||
| CREATE INDEX IF NOT EXISTS idx_github_cursor_repo_type | ||||||||||||||
| ON github_cursor (repository_name, source_type); | ||||||||||||||
|
Comment on lines
+12
to
+16
|
||||||||||||||
| ); | |
| -- 인덱스 생성 | |
| CREATE INDEX IF NOT EXISTS idx_github_cursor_repo_type | |
| ON github_cursor (repository_name, source_type); | |
| ); |
Uh oh!
There was an error while loading. Please reload this page.