Skip to content

[#176] 프로젝트 레이아웃 재구성#183

Merged
myyrakle merged 1 commit intomasterfrom
refac/#176
Nov 19, 2025
Merged

[#176] 프로젝트 레이아웃 재구성#183
myyrakle merged 1 commit intomasterfrom
refac/#176

Conversation

@myyrakle
Copy link
Copy Markdown
Owner

@myyrakle myyrakle commented Nov 17, 2025

resolves: #176

설명

가독성, 유지보수를 고려해서 계층 구조로 재구성

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 데이터베이스 및 테이블 스키마 검사 기능 추가 (테이블 구조 조회, 데이터베이스 목록 표시, 테이블 목록 표시)
    • 데이터베이스 간 전환 시 확인 메시지 반환
  • Refactor

    • 내부 아키텍처 구조 최적화 및 모듈 네임스페이스 정리

@myyrakle myyrakle self-assigned this Nov 17, 2025
@myyrakle myyrakle linked an issue Nov 17, 2025 that may be closed by this pull request
@github-actions
Copy link
Copy Markdown

Pull reviewers stats

Stats of the last 14 days for rrdb:

User Total reviews Time to review Total comments

⚡️ Pull request stats

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 17, 2025

코드 리뷰 요약

Walkthrough

프로젝트 아키텍처를 크게 개선하는 리팩토링입니다. Executor 타입을 DBEngine으로 재명명하고 모듈 구조를 재편성합니다. AST 및 어휘분석기를 엔진 네임스페이스 아래로 이동하며, 설정 타입을 GlobalConfig에서 LaunchConfig로 변경합니다. 새로운 커맨드 추상화와 스키마 검사 작업들이 추가됩니다.

Changes

결집 / 파일(들) 변경 요약
커맨드 추상화
src/common/command.rs, src/common/fs.rs, src/common/mod.rs
새로운 CommandRunner 특성과 RealCommandRunner 구현을 도입하고, 모의 객체(MockCommandRunner)를 지원합니다. fs.rs에서 기존 커맨드 러너를 제거하고 mod.rs에서 모듈을 공개합니다.
설정 타입 재명명
src/config/launch_config.rs, src/config/mod.rs
GlobalConfigLaunchConfig로 재명명하고, 관련된 모든 구현과 기본값 특성을 업데이트합니다.
DDL 작업 마이그레이션
src/engine/actions/ddl/alter_database.rs, alter_table.rs, create_database.rs, create_table.rs, drop_database.rs, drop_table.rs
모든 DDL 작업을 Executor에서 DBEngine으로 이동하고, 임포트 경로를 crate::engine::ast로 업데이트합니다. TableConfigTableSchema로, DatabaseConfigDatabaseSchema로 변경합니다.
DML 작업 마이그레이션
src/engine/actions/dml/delete.rs, insert.rs, scan.rs, select.rs, update.rs
모든 DML 작업 구현을 Executor에서 DBEngine으로 재배치하고, 엔진 스코프 임포트 경로로 통합합니다.
기타 작업
src/engine/actions/mod.rs, src/engine/actions/etc.rs
공개 모듈을 pub mod other;에서 pub mod etc;로 변경하고, 새로운 스키마 검사 메서드(desc_table, show_databases, show_tables, use_databases, find_database)를 추가합니다.
초기화 로직
src/engine/initialize.rs
Executor에서 DBEngine으로 마이그레이션하고, init_configinit_database의 가시성을 낮춥니다. 새로운 공개 initialize() 메서드를 추가하고 LaunchConfig를 사용합니다.
AST 모듈 통합
src/engine/ast/**/ (43개 파일)
모든 AST 관련 파일의 임포트 경로를 crate::ast에서 crate::engine::ast로 업데이트합니다. 구조나 논리 변경은 없습니다.
엔진 모듈 재구성
src/engine/mod.rs
ExecutorDBEngine으로 재명명하고, 생성자 서명을 LaunchConfig 수용으로 변경합니다. get_table_config()get_data_directory() 메서드를 추가하고 새 모듈 선언을 노출합니다.
어휘분석기 임포트 업데이트
src/engine/lexer/**/ (6개 파일)
모든 어휘분석기 관련 파일의 임포트 경로를 엔진 네임스페이스로 업데이트합니다.
파서 임포트 업데이트
src/engine/parser/**/ (38개 파일)
모든 파서 구현 및 테스트 파일의 임포트를 crate::engine 경로로 업데이트합니다.
인코더 및 표현식
src/engine/encoder/mod.rs, src/engine/expression.rs
새 모듈 pub mod schema_encoder;를 추가하고, reduce_expressionExecutor에서 DBEngine으로 이동하며 가시성을 낮춥니다.
최적화 유틸
src/engine/optimizer/optimizer.rs
임포트 문을 개별 문장으로 재구성합니다(논리 변경 없음).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant DBEngine
    participant StorageEncoder
    participant FileSystem

    Client->>DBEngine: desc_table(DescTableQuery)
    DBEngine->>StorageEncoder: decode(table.config)
    StorageEncoder->>FileSystem: read(table.config)
    FileSystem-->>StorageEncoder: config bytes
    StorageEncoder-->>DBEngine: TableSchema
    DBEngine->>DBEngine: construct ExecuteResult<br/>(Field, Type, Null, Default, Comment)
    DBEngine-->>Client: Result<ExecuteResult>

    Client->>DBEngine: show_databases()
    DBEngine->>FileSystem: read_dir(data_dir)
    par Parallel Reads
        DBEngine->>StorageEncoder: decode(database.config)
        StorageEncoder->>FileSystem: read(database.config)
        FileSystem-->>StorageEncoder: config bytes
        StorageEncoder-->>DBEngine: DatabaseSchema
    end
    DBEngine->>DBEngine: collect database names
    DBEngine-->>Client: Result<ExecuteResult>
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

특별 주의 영역:

  • src/engine/initialize.rs: 초기화 흐름의 큰 변화, 타입 변경(GlobalConfigLaunchConfig), 가시성 수정
  • src/engine/actions/etc.rs: 새로운 5개 메서드의 비동기 파일 IO 로직, 병렬 처리(tokio::join_all), 에러 처리 메커니즘
  • src/engine/mod.rs: DBEngine 공개 인터페이스의 주요 변경, 생성자 서명 수정, 새 공개 메서드 추가
  • 43개 AST 관련 파일의 일관성 있는 임포트 경로 변경 검증
  • src/engine/actions/ddl/src/engine/actions/dml/ 전체: TableConfigTableSchema 변환이 모든 작업에 걸쳐 올바르게 적용되었는지 확인

Poem

🐰 새로운 엔진이 모습을 드러내고,

이전의 구조는 말끔히 정리되네!

Executor의 역할을 DBEngine이 이어받으며,

스키마는 더욱 우아하게 검사되고,

모듈과 네임스페이스는 한 곳으로 모여,

코드의 정원이 다시 꽃을 피운다! 🌸✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.39% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목 '[#176] 프로젝트 레이아웃 재구성'은 주요 변경사항을 명확하게 설명하고 있으며, 링크된 이슈 #176과 직접 관련이 있습니다.
Linked Issues check ✅ Passed PR은 #176 이슈의 요구사항을 충족합니다: 프로젝트 구조를 engine 모듈 기반으로 재구성하고, 모듈 계층 구조를 개선했습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 프로젝트 레이아웃 재구성이라는 범위 내에 있습니다. 기능적 동작은 유지되고 모듈 경로만 조정되었습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refac/#176

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@myyrakle
Copy link
Copy Markdown
Owner Author

Total Coverage: 54.50%
🔗 Coverage View (최대 몇분 정도의 지연시간이 발생할 수 있습니다.)

@myyrakle myyrakle force-pushed the refac/#176 branch 2 times, most recently from 4432707 to ddf61f9 Compare November 18, 2025 17:39
@myyrakle myyrakle marked this pull request as ready for review November 18, 2025 17:40
@myyrakle
Copy link
Copy Markdown
Owner Author

Total Coverage: 54.48%
🔗 Coverage View (최대 몇분 정도의 지연시간이 발생할 수 있습니다.)

@myyrakle
Copy link
Copy Markdown
Owner Author

Total Coverage: 54.48%
🔗 Coverage View (최대 몇분 정도의 지연시간이 발생할 수 있습니다.)

@myyrakle
Copy link
Copy Markdown
Owner Author

Total Coverage: 54.48%
🔗 Coverage View (최대 몇분 정도의 지연시간이 발생할 수 있습니다.)

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
src/engine/parser/implements/dml/select.rs (1)

191-196: E0332 에러 메시지에서 잘못된 변수 출력 (디버깅 혼동 가능).

GROUP BY 검증 로직에서 집계 컬럼이 group_by_columns 에 포함된 경우 에러를 내는데, 에러 메시지에는 실제로 문제가 된 개별 컬럼(aggregate_column) 대신 group_by_columns 전체를 출력하고 있습니다.

for aggregate_column in aggregate_columns {
    if group_by_columns.contains(&aggregate_column) {
        return Err(ParsingError::wrap(format!(
            "E0332: column '{:?}' cannot be in a GROUP BY clause",
            group_by_columns
        )));
    }
}

디버깅 편의를 위해서는 아래처럼 aggregate_column 을 출력하는 편이 더 자연스럽고, 메시지와 실제 문제 대상이 정확히 일치합니다.

-                        return Err(ParsingError::wrap(format!(
-                            "E0332: column '{:?}' cannot be in a GROUP BY clause",
-                            group_by_columns
-                        )));
+                        return Err(ParsingError::wrap(format!(
+                            "E0332: column '{:?}' cannot be in a GROUP BY clause",
+                            aggregate_column
+                        )));

동작에는 영향이 없지만, 에러 해석 시 혼동을 줄이기 위해 한 번 손보시는 것을 추천드립니다.

src/engine/parser/implements/ddl/top_level.rs (1)

60-65: DROP 핸들러의 에러 메시지 내용이 실제 명령과 맞지 않습니다.

handle_drop_query 에서 지원하지 않는 명령일 때 "possible commands: (create table)" 라고 안내하고 있어 사용자가 DROP 문에서 헷갈릴 수 있습니다. 아래처럼 텍스트를 DROP 에 맞게 바꾸는 것을 제안합니다.

-            _ => Err(ParsingError::wrap(
-                "E1106 not supported command. possible commands: (create table)",
-            )),
+            _ => Err(ParsingError::wrap(
+                "E1106 not supported command. possible commands: (drop table, drop database)",
+            )),

(정확한 지원 범위에 맞춰 문구는 조정해 주시면 될 것 같습니다.)

src/engine/actions/ddl/alter_database.rs (1)

63-76: config 쓰기 실패 시 에러 메시지가 실제 원인과 어긋납니다.

if let Err(_error) = tokio::fs::write(...).await {
    return Err(ExecuteError::wrap("no database name"));
}

부분에서, 실제로는 database.config 파일 쓰기 실패인데 메시지는 "no database name" 으로 되어 있어 디버깅 시 혼란을 줄 수 있습니다. 또한 database_config: Option<DatabaseSchema> 변수를 그대로 두고 있어 타입과 이름이 어울리지 않는 부분도 살짝 거슬립니다.

예를 들어 다음처럼 고치는 것을 고려해 볼 수 있습니다.

-                            let database_config: Option<DatabaseSchema> =
+                            let database_schema_opt: Option<DatabaseSchema> =
                                 encoder.decode(data.as_slice());
@@
-                            match database_config {
-                                Some(mut database_config) => {
-                                    database_config.database_name = to_database_name;
-                                    if let Err(_error) = tokio::fs::write(
+                            match database_schema_opt {
+                                Some(mut database_schema) => {
+                                    database_schema.database_name = to_database_name;
+                                    if let Err(error) = tokio::fs::write(
                                         config_path,
-                                        encoder.encode(database_config),
+                                        encoder.encode(database_schema),
                                     )
                                     .await
                                     {
-                                        return Err(ExecuteError::wrap("no database name"));
+                                        return Err(ExecuteError::wrap(format!(
+                                            "database config write failed: {}",
+                                            error
+                                        )));
                                     }

이렇게 하면 에러 메시지가 실제 실패 지점과 맞아떨어지고, 변수명도 타입과 더 잘 대응됩니다.

src/engine/actions/ddl/create_table.rs (1)

17-19: query.tabledatabase_name에 대한 unwrap() 체인 제거 필요

create_table.rs 17-19 라인의 unwrap() 사용이 실제로 확인되었습니다:

  • CreateTableQuery.tableOption<TableName> 타입
  • TableName.database_nameOption<String> 타입
  • 테스트 코드에서 database_name을 None으로 설정하는 경우 존재

같은 레이어의 create_database.rs에서는 이미 ok_or_else(|| ExecuteError::wrap(...))? 패턴으로 안전하게 처리하고 있으므로, 동일한 방식으로 수정이 필요합니다. 단, 수정 후 query.into()를 호출할 때 TableSchema::from()query.table.unwrap()도 고려하여, 이미 추출된 table 정보를 직접 사용하거나 From impl을 함께 검토하는 것을 권장합니다.

src/engine/actions/dml/insert.rs (1)

88-126: columns_map.get(...).unwrap() 호출로 인한 런타임 패닉 가능성 제거 필요

검증 결과, 리뷰 의견이 정확합니다. 다음 두 위치에서 동일한 패턴이 확인되었습니다:

  • Line 90: let column_config_info = columns_map.get(column_name).unwrap();
    • Line 101의 match 문에서 None 분기가 도달 불가능 상태
  • Line 140: let column_config_info = columns_map.get(column_name).unwrap();
    • Line 161의 match 문에서 None 분기가 도달 불가능 상태

컬럼이 존재하지 않는 경우, .unwrap()에서 먼저 패닉이 발생하므로 아래의 명시적 에러 처리 분기는 절대 실행되지 않습니다. 제안된 대로 match 문으로 통합하여 일관된 에러 처리(ExecuteError 반환)를 구현하시기 바랍니다.

-                    for (i, column_name) in query.columns.iter().enumerate() {
-                        let column_config_info = columns_map.get(column_name).unwrap();
+                    for (i, column_name) in query.columns.iter().enumerate() {
+                        let column_config_info = match columns_map.get(column_name) {
+                            Some(info) => info,
+                            None => {
+                                return Err(ExecuteError::wrap(format!(
+                                    "column '{}' not exists",
+                                    column_name
+                                )));
+                            }
+                        };

라인 140부터 시작하는 remain_columns 루프도 동일하게 수정이 필요합니다.

src/engine/initialize.rs (1)

59-69: if let Err(error) = ... && error.kind() 패턴은 현재 안정적인 Rust에서 컴파일되지 않습니다.

웹 조사 결과, if-let guards 기능은 2025년 11월 현재 안정화되지 않았으며 Lang-team FCP 논의 단계에 있습니다. 코드의 모든 위치(59-69, 96-104, 108-116, 156-169줄)에서 이 불안정한 기능을 사용하고 있으므로 안정적인 Rust에서는 컴파일되지 않습니다.

제시된 중첩 if-let 해결책이 올바른 수정 방법입니다:

if let Err(error) = self.file_system.create_dir(base_path).await {
    if error.kind() != std::io::ErrorKind::AlreadyExists {
        println!("path {:?}", base_path);
        println!("error: {:?}", error.to_string());
        return Err(ExecuteError::wrap(error.to_string()));
    }
}

create_data_directory_if_not_exists, create_wal_directory_if_not_exists, write_and_check_err 모두 동일한 방식으로 수정이 필요합니다.

src/engine/actions/dml/delete.rs (1)

52-55: ScanType::IndexScan 분기에서 unimplemented!() 호출은 런타임 패닉을 유발할 수 있습니다

ScanType::IndexScan(_index) => { unimplemented!() }로 되어 있어, 옵티마이저가 인덱스 스캔 플랜을 생성하는 순간 프로세스가 패닉으로 종료됩니다.

인덱스 스캔이 아직 미구현 상태라면:

  • 최소한 ExecuteError::wrap("index scan for DELETE is not implemented yet") 형태의 에러를 반환하도록 바꾸거나,
  • 옵티마이저 단계에서 인덱스 스캔 플랜 자체를 생성하지 않도록 막는 편이 안전합니다.

현재처럼 unimplemented!()를 남겨두면, 실제 환경에서 특정 쿼리만 프로세스를 전부 죽여버리는 상황이 생길 수 있습니다.

🧹 Nitpick comments (17)
src/engine/parser/implements/debug.rs (1)

1-1: 임포트 경로 업데이트가 리팩토링 목표와 일치합니다.

파서 모듈을 engine 네임스페이스 아래로 이동하는 것이 프로젝트 재구성 목표와 잘 맞습니다.

참고: 모듈 이름 preduleprelude의 오타일 가능성이 있습니다 (Rust에서 일반적인 컨벤션). 그러나 이것이 의도적인 이름이거나 코드베이스 전체에서 일관되게 사용되고 있다면 무시하셔도 됩니다.

src/engine/actions/dml/scan.rs (1)

20-21: database_name.unwrap() 대신 명시적인 에러로 변환하는 방안을 고려해보면 좋겠습니다.

table_name.database_name.unwrap()는 호출 시점에 DB 이름이 항상 Some 이라는 강한 인바리언트를 전제로 합니다. 파서/플래너 단계에서 이 보장이 깨질 여지가 조금이라도 있다면, 여기에서 패닉 대신 ExecuteError/RRDBError로 변환해 반환하는 쪽이 디버깅과 안정성 측면에서 더 안전합니다.

src/engine/ast/types/expression.rs (1)

330-353: 테스트에서 fully-qualified 경로 대신 이미 import 된 타입명을 사용하면 가독성이 더 좋아집니다.

테스트 모듈 상단에서 BetweenExpression, NotBetweenExpression, ParenthesesExpression를 import 하고 있으므로, 본문에서는

  • crate::engine::ast::dml::expressions::between::BetweenExpression { ... }
  • crate::engine::ast::dml::expressions::not_between::NotBetweenExpression { ... }
  • crate::engine::ast::dml::expressions::parentheses::ParenthesesExpression { ... }

대신 각각 BetweenExpression { ... }, NotBetweenExpression { ... }, ParenthesesExpression { ... } 형태로 써 주면 라인이 짧아지고 변경 시 중복 수정도 줄어듭니다.

Also applies to: 341-345, 352-357

src/engine/parser/implements/tcl/begin.rs (1)

1-6: 엔진 네임스페이스로의 경로 이관은 자연스럽습니다.

BeginTransactionQuery, SQLStatement, Token, Parser/ParserContext 를 모두 crate::engine::... 아래로 옮긴 건 전체 레이아웃 리팩토링 방향과 잘 맞습니다.

한 가지 정도만 참고용으로 말씀드리면, 이 파일은 Tokenlexer::tokens::Token 에서 직접 가져오고, 다른 구현(src/engine/parser/implements/other/use.rs 등)은 lexer::predule::Token 을 쓰고 있어서 경로 스타일이 조금씩 다릅니다. 추후에 정리하실 때 prelude 경로를 통일해 두면 모듈 구조를 추적하기 조금 더 수월해질 것 같습니다.

src/engine/parser/implements/other/use.rs (1)

1-6: USE 구문 파서의 엔진 경로 이관은 적절합니다.

UseDatabaseQuery, SQLStatement, Token, Parser/ParserContextcrate::engine::... 아래로 옮긴 부분이 전체 레이아웃과 잘 맞고, parse_use_query 구현은 그대로라 동작 변화는 없어 보입니다.

추가로, 이 파일은 Tokenlexer::predule::Token 에서 가져오고, tcl/begin.rslexer::tokens::Token 을 직접 import 하고 있어 prelude 사용 여부가 파일마다 조금 다릅니다. 장기적으로는 prelude 사용 여부를 한쪽으로 통일해 두면 추후 리팩토링 시 추적이 더 쉬울 것 같습니다.

src/engine/actions/ddl/drop_database.rs (1)

3-8: DBEngine 이전 및 결과 스키마는 문제 없어 보입니다 (사소한 최적화 여지).

ExecutorDBEngine 이전과 engine::ast, engine::types 사용으로 네임스페이스 정리는 잘 된 것 같습니다. 동작도 기존과 동일하게 유지되는 것으로 보입니다.

사소한 부분으로는:

  • tokio::fs::remove_dir_all(database_path.clone()).await 에서 clone() 없이 참조를 넘겨도 됩니다.

처럼 불필요한 복사를 줄여서 조금 더 깔끔하게 정리할 수 있습니다.

Also applies to: 10-12, 36-47

src/engine/actions/ddl/alter_table.rs (2)

14-24: query.action 매치 이후 query.table.unwrap() 사용 패턴은 소유권 측면에서 위험합니다.

현재 구현은 다음과 같은 구조입니다:

  • Line 20-24: let TableName { .. } = query.table.clone().unwrap();
  • Line 30: match query.action { ... }
  • 각 분기 내부에서 여러 번 self.get_table_config(query.table.unwrap()).await?; 호출

Rust 소유권 규칙상, match query.action 으로 query.action 필드를 move 한 뒤에 같은 query의 다른 필드(query.table)를 사용하는 패턴은 컴파일 에러(부분 move)로 이어질 수 있습니다. 현재 코드가 실제로 빌드되는지, 혹은 이 부분이 다른 타입 정의/파생 구현에 의존해서 우연히 통과하고 있는지 꼭 한 번 확인하는 편이 좋겠습니다.

보다 안전하고 명확한 방법은, 초기에 한 번만 table 값을 꺼내서 재사용하는 것입니다. 예를 들어:

-        let TableName {
-            database_name,
-            table_name,
-        } = query.table.clone().unwrap();
+        let table = query.table.clone().ok_or_else(|| ExecuteError::wrap("no table"))?;
+        let TableName {
+            database_name,
+            table_name,
+        } = table.clone();
...
-                let mut table_config = self.get_table_config(query.table.unwrap()).await?;
+                let mut table_config = self.get_table_config(Some(table.clone())).await?;

처럼 table을 별도 변수로 유지하고, 이후에는 query.table.unwrap() 대신 그 변수를 넘기면 소유권 문제가 사라지고 의도도 더 분명해집니다.
또한 TableConfig → TableSchema 변경(예: Line 121, 173, 225, 277)은 encoder가 동일 타입으로 encode하고 있는지만 확인되면 크게 문제 없어 보입니다.

Also applies to: 30-32, 46-49, 63-66, 90-93, 121-122, 173-174, 225-226, 277-278


121-155: 반복되는 config read/modify/write 로직은 헬퍼로 추출하면 유지보수가 쉬워집니다.

AlterColumnDropDefault, AlterColumnSetNotNull, AlterColumnDropNotNull, AlterColumnSetType 네 분기에서 모두:

  • tokio::fs::read(config_path).await
  • encoder.decode::<Option<TableSchema>>(...)
  • columns.iter_mut().find(|e| e.name == column_name)
  • 값 수정 후 다시 encode + write

같은 패턴을 거의 그대로 반복하고 있습니다. 기능상 문제는 없어 보이지만, 향후 schema 구조 변경이나 에러 메시지 개선 시 네 군데를 모두 수정해야 해서 유지보수 비용이 큽니다.

예를 들어 “컬럼을 찾고 수정한 뒤 table.config를 다시 저장하는” 공통 헬퍼를 하나 두고, 각 분기에서는 “무엇을 어떻게 수정할지”만 클로저로 넘기는 형태로 정리하면 가독성과 변경 용이성이 좋아질 것 같습니다.

Also applies to: 173-207, 225-259, 277-311

src/engine/actions/dml/insert.rs (1)

35-45: TableSchema 디코드 변경은 일관되어 보이지만 encoder 쪽 타입도 같이 맞춰야 합니다.

Line 37에서 let table_config: Option<TableSchema> = encoder.decode(data.as_slice()); 로 타입을 바꾼 것은 전체적인 TableConfigTableSchema 마이그레이션과 잘 맞습니다. 다만:

  • 같은 encoder가 다른 곳에서도 TableSchema 기준으로 encode하고 있는지,
  • 기존 table.config 파일과의 호환성이 필요한지

는 한번 더 확인해 보시는 게 좋겠습니다. 새로운 버전만 고려한다면 크게 문제는 없어 보입니다.

src/engine/initialize.rs (2)

79-94: create_global_config_if_not_exists가 항상 덮어쓰기 하는 점은 의도 확인이 필요합니다.

함수 이름은 “if_not_exists”인데, 실제 구현은:

  • 파일 존재 여부를 확인하지 않고,
  • 매 호출마다 LaunchConfig::default()를 TOML로 직렬화하여 그대로 덮어씁니다.

이미 사용자가 수정한 설정이 있을 수 있는 시나리오까지 고려한다면, 최초 1회만 생성하고 이후에는 덮어쓰지 않도록 read/metadata 등을 확인하는 로직이 필요한지 한 번 검토해 보시는 것이 좋겠습니다.


195-201: 데몬 시작 시 프로세스 실행 실패만 확인하고 exit code는 무시하고 있습니다.

check_output_status는 현재:

if output.is_err() {
    Err(ExecuteError::wrap("failed to start daemon"))
} else {
    Ok(())
}

으로, 커맨드 실행 자체가 실패했는지만 보고 실제 status.success() 여부는 확인하지 않습니다.

서비스 등록/시작 커맨드가 비정상 종료(exit code ≠ 0) 하는 경우까지 감지하고 싶다면, Output가 Ok일 때 추가로 status.success()를 체크하는 것이 더 견고할 것 같습니다.

src/engine/actions/ddl/drop_table.rs (1)

3-8: DBEngine 기반 drop_table 리팩토링은 무난해 보입니다.

ExecutorDBEngine, engine::ast/engine::types 경로 정리 모두 일관되게 적용되어 있고, 에러 처리와 결과 포맷도 기존과 동일한 것으로 보입니다.

Optional하게는, tokio::fs::remove_dir_all 호출 시 base_path.clone() 대신 참조를 넘겨 불필요한 복사를 줄일 수 있습니다.

Also applies to: 10-12, 36-47

src/engine/actions/dml/delete.rs (1)

26-40: Delete 플랜에서 table_infos가 사용되지 않아 불필요한 IO가 발생합니다

DeletePlanItem::DeleteFrom 분기에서:

  • self.get_table_config(table_name.clone()).await? 호출로 디스크에서 스키마를 읽어오고,
  • 그 결과를 table_infos.push(table_config);로 누적하지만,

이후 table_infos는 어디에서도 사용되지 않습니다. 현재 구현 기준으로는 삭제 대상 로우를 수집하는 데에만 집중하고 있어, 이 호출은 검증/스키마 활용 없이 단순히 비용만 증가시키는 형태입니다.

  • 정말 스키마 정보가 필요 없다면, get_table_config 호출과 table_infos 벡터 자체를 제거하는 쪽이 더 낫고,
  • 향후 ReduceContext.config_columns 등에서 스키마를 활용할 계획이라면, 그 용도에 맞게 실제로 사용되도록 연결해 두는 편이 좋습니다.
src/engine/actions/dml/update.rs (2)

64-75: Update 필터 단계에서 total_count: 0은 delete 구현과 일관되지 않습니다

UpdatePlanItem::Filter에서 ReduceContext를 생성할 때:

let reduce_context = ReduceContext {
    row: Some(row.to_owned()),
    table_alias_map,
    config_columns: vec![],
    total_count: 0,
};

으로 고정 0을 넘기고 있습니다. 반면 delete 구현에서는 같은 필터링 단계에서 total_count = rows.len()을 사용합니다.

reduce_expressiontotal_count를 활용하는 표현식(예: 전체 행 수 기반 계산)을 지원한다면, 두 연산(Update/Delete)의 동작이 일관되지 않을 수 있습니다. 특별한 이유가 없다면, 여기서도 rows.len() 값을 전달하거나, 최소한 주석으로 설계 의도를 명시해 두는 편이 좋겠습니다.


116-132: SET 표현식에서 기존 행(row) 참조가 필요한지 여부를 명확히 할 필요가 있습니다

Update 적용 루프에서:

let reduce_context = ReduceContext {
    row: None,
    table_alias_map: table_alias_map.clone(),
    config_columns: config_columns.clone(),
    total_count: 0,
};

for update_item in &update_items {
    let set_value = self
        .reduce_expression(set_value, reduce_context.clone())
        .await?;
    // ...
}

Filter 단계에서는 row: Some(row.to_owned())를 넘기지만, SET 표현식 평가 시에는 row: None으로 전달하고 있습니다.

  • 만약 SET col = col + 1 같이 기존 행의 값을 참조하는 표현식을 지원할 계획이라면, 여기서도 현재 행을 ReduceContext.row에 넣어주는 것이 자연스럽고,
  • 반대로 Update가 상수/리터럴/함수 호출만 허용되고 기존 행 참조를 명시적으로 금지하는 설계라면, 코드나 타입/도큐먼트로 그 제약을 표현해 두는 편이 오해를 줄일 수 있습니다.

현재 설계 의도가 어느 쪽인지 한 번 점검해 보시는 것이 좋겠습니다.

src/engine/actions/etc.rs (2)

96-145: show_databases / show_tablesstd::fs::read_dir 역시 비동기 환경에서 블로킹입니다

두 함수 모두 async fn이지만, 디렉터리 나열에는 동기식 std::fs::read_dir를 사용하고 있습니다:

match std::fs::read_dir(&base_path) { ... }
match std::fs::read_dir(&tables_path) { ... }

목록이 매우 많은 경우 이 호출도 꽤 시간이 걸릴 수 있고, 해당 async 함수가 실행되는 런타임 스레드를 블로킹하게 됩니다. 가능하다면:

  • tokio::fs::read_dir + 비동기 이터레이션을 사용하거나,
  • 또는 tokio::task::spawn_blocking으로 동기 디렉터리 탐색을 별도 스레드로 분리하는 방식

을 고려해 볼 수 있습니다. 현재 규모에서 문제가 되지 않더라도, 데이터베이스/테이블 수가 늘어날 경우 병목이 될 수 있는 부분입니다.


224-237: use_databases가 실제 엔진 상태를 변경하지 않는 점에 대한 의도 공유가 있으면 좋겠습니다

현재 use_databases는 다음과 같이 단순 메시지만 반환합니다:

Ok(ExecuteResult {
    columns: vec![...],
    rows: vec![ExecuteRow {
        fields: vec![ExecuteField::String(format!(
            "database changed: {}",
            query.database_name
        ))],
    }],
})

DBEngine 내부에는 선택된 데이터베이스를 나타내는 상태 필드가 없어서, 이 함수가 이후 쿼리의 기본 데이터베이스 컨텍스트에 영향을 주지는 않는 것으로 보입니다.

  • 클라이언트/상위 레이어에서 USE 명령을 해석해 별도의 세션 상태를 관리하고, 여기서는 단순히 사용자에게 메시지만 돌려주는 구조라면 지금 구현도 일관된 선택이고,
  • 그렇지 않고 엔진 레벨에서 현재 데이터베이스를 기억해야 한다면, DBEngine에 세션/컨텍스트 상태를 추가하거나, LaunchConfig/연결 단위 상태와 연계하는 설계가 필요해 보입니다.

의도가 어느 쪽인지 주석이나 설계 문서로 한 번 명시해 두면 이후 유지보수 시 혼동을 줄일 수 있을 것 같습니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc0ae1e and 25095ad.

📒 Files selected for processing (107)
  • src/common/command.rs (1 hunks)
  • src/common/fs.rs (0 hunks)
  • src/common/mod.rs (1 hunks)
  • src/config/launch_config.rs (3 hunks)
  • src/config/mod.rs (1 hunks)
  • src/engine/actions/ddl/alter_database.rs (3 hunks)
  • src/engine/actions/ddl/alter_table.rs (5 hunks)
  • src/engine/actions/ddl/create_database.rs (3 hunks)
  • src/engine/actions/ddl/create_table.rs (2 hunks)
  • src/engine/actions/ddl/drop_database.rs (1 hunks)
  • src/engine/actions/ddl/drop_table.rs (1 hunks)
  • src/engine/actions/dml/delete.rs (1 hunks)
  • src/engine/actions/dml/insert.rs (4 hunks)
  • src/engine/actions/dml/scan.rs (1 hunks)
  • src/engine/actions/dml/select.rs (2 hunks)
  • src/engine/actions/dml/update.rs (1 hunks)
  • src/engine/actions/etc.rs (1 hunks)
  • src/engine/actions/mod.rs (1 hunks)
  • src/engine/ast/ddl/alter_database.rs (1 hunks)
  • src/engine/ast/ddl/alter_table.rs (1 hunks)
  • src/engine/ast/ddl/create_database.rs (1 hunks)
  • src/engine/ast/ddl/create_index.rs (2 hunks)
  • src/engine/ast/ddl/create_table.rs (2 hunks)
  • src/engine/ast/ddl/drop_database.rs (1 hunks)
  • src/engine/ast/ddl/drop_table.rs (1 hunks)
  • src/engine/ast/dml/delete.rs (2 hunks)
  • src/engine/ast/dml/expressions/between.rs (2 hunks)
  • src/engine/ast/dml/expressions/binary.rs (2 hunks)
  • src/engine/ast/dml/expressions/call.rs (1 hunks)
  • src/engine/ast/dml/expressions/list.rs (1 hunks)
  • src/engine/ast/dml/expressions/not_between.rs (2 hunks)
  • src/engine/ast/dml/expressions/parentheses.rs (1 hunks)
  • src/engine/ast/dml/expressions/subquery.rs (1 hunks)
  • src/engine/ast/dml/expressions/unary.rs (2 hunks)
  • src/engine/ast/dml/insert.rs (2 hunks)
  • src/engine/ast/dml/parts/from.rs (1 hunks)
  • src/engine/ast/dml/parts/group_by.rs (1 hunks)
  • src/engine/ast/dml/parts/having.rs (1 hunks)
  • src/engine/ast/dml/parts/insert_values.rs (1 hunks)
  • src/engine/ast/dml/parts/join.rs (1 hunks)
  • src/engine/ast/dml/parts/order_by.rs (1 hunks)
  • src/engine/ast/dml/parts/select_item.rs (1 hunks)
  • src/engine/ast/dml/parts/target.rs (1 hunks)
  • src/engine/ast/dml/parts/update_item.rs (1 hunks)
  • src/engine/ast/dml/parts/where.rs (1 hunks)
  • src/engine/ast/dml/plan/delete/delete_plan.rs (2 hunks)
  • src/engine/ast/dml/plan/delete/from.rs (1 hunks)
  • src/engine/ast/dml/plan/select/filter.rs (1 hunks)
  • src/engine/ast/dml/plan/select/from.rs (1 hunks)
  • src/engine/ast/dml/plan/select/join.rs (1 hunks)
  • src/engine/ast/dml/plan/select/no_from.rs (1 hunks)
  • src/engine/ast/dml/plan/select/scan.rs (1 hunks)
  • src/engine/ast/dml/plan/select/select_plan.rs (2 hunks)
  • src/engine/ast/dml/plan/select/subquery.rs (1 hunks)
  • src/engine/ast/dml/plan/update/from.rs (1 hunks)
  • src/engine/ast/dml/plan/update/update_plan.rs (2 hunks)
  • src/engine/ast/dml/select.rs (2 hunks)
  • src/engine/ast/dml/update.rs (2 hunks)
  • src/engine/ast/mod.rs (1 hunks)
  • src/engine/ast/other/desc_table.rs (1 hunks)
  • src/engine/ast/other/show_databases.rs (1 hunks)
  • src/engine/ast/other/show_tables.rs (1 hunks)
  • src/engine/ast/other/use_database.rs (1 hunks)
  • src/engine/ast/tcl/begin_transaction.rs (1 hunks)
  • src/engine/ast/tcl/commit.rs (1 hunks)
  • src/engine/ast/tcl/rollback.rs (1 hunks)
  • src/engine/ast/types/column.rs (1 hunks)
  • src/engine/ast/types/expression.rs (5 hunks)
  • src/engine/ast/types/foreign_key.rs (1 hunks)
  • src/engine/ast/types/select_column.rs (1 hunks)
  • src/engine/ast/types/table.rs (1 hunks)
  • src/engine/encoder/mod.rs (1 hunks)
  • src/engine/expression.rs (6 hunks)
  • src/engine/initialize.rs (16 hunks)
  • src/engine/lexer/operator_token.rs (1 hunks)
  • src/engine/lexer/test/comment.rs (1 hunks)
  • src/engine/lexer/test/select.rs (1 hunks)
  • src/engine/lexer/tokenizer.rs (1 hunks)
  • src/engine/lexer/tokens.rs (2 hunks)
  • src/engine/mod.rs (2 hunks)
  • src/engine/optimizer/optimizer.rs (1 hunks)
  • src/engine/parser/implements/common.rs (1 hunks)
  • src/engine/parser/implements/ddl/database.rs (1 hunks)
  • src/engine/parser/implements/ddl/table.rs (1 hunks)
  • src/engine/parser/implements/ddl/top_level.rs (1 hunks)
  • src/engine/parser/implements/debug.rs (1 hunks)
  • src/engine/parser/implements/dml/delete.rs (1 hunks)
  • src/engine/parser/implements/dml/expression.rs (1 hunks)
  • src/engine/parser/implements/dml/insert.rs (1 hunks)
  • src/engine/parser/implements/dml/select.rs (1 hunks)
  • src/engine/parser/implements/dml/update.rs (1 hunks)
  • src/engine/parser/implements/other/backslash_command.rs (1 hunks)
  • src/engine/parser/implements/other/desc.rs (1 hunks)
  • src/engine/parser/implements/other/show.rs (1 hunks)
  • src/engine/parser/implements/other/use.rs (1 hunks)
  • src/engine/parser/implements/tcl/begin.rs (1 hunks)
  • src/engine/parser/implements/tcl/commit.rs (1 hunks)
  • src/engine/parser/implements/tcl/rollback.rs (1 hunks)
  • src/engine/parser/implements/utils.rs (1 hunks)
  • src/engine/parser/parser.rs (1 hunks)
  • src/engine/parser/test/alter_database.rs (1 hunks)
  • src/engine/parser/test/alter_table.rs (1 hunks)
  • src/engine/parser/test/common.rs (1 hunks)
  • src/engine/parser/test/create_database.rs (1 hunks)
  • src/engine/parser/test/create_table.rs (1 hunks)
  • src/engine/parser/test/ddl.rs (1 hunks)
  • src/engine/parser/test/delete.rs (1 hunks)
⛔ Files not processed due to max files limit (37)
  • src/engine/parser/test/drop_database.rs
  • src/engine/parser/test/drop_table.rs
  • src/engine/parser/test/expressions.rs
  • src/engine/parser/test/insert.rs
  • src/engine/parser/test/other.rs
  • src/engine/parser/test/select.rs
  • src/engine/parser/test/tcl.rs
  • src/engine/parser/test/update.rs
  • src/engine/schema/database.rs
  • src/engine/schema/mod.rs
  • src/engine/schema/row.rs
  • src/engine/schema/table.rs
  • src/engine/server/channel.rs
  • src/engine/server/mod.rs
  • src/engine/types.rs
  • src/engine/wal/endec/implements/bitcode.rs
  • src/engine/wal/manager/builder.rs
  • src/engine/wal/manager/mod.rs
  • src/executor/README.md
  • src/executor/common.rs
  • src/executor/encoder/mod.rs
  • src/executor/implements/other/desc_table.rs
  • src/executor/implements/other/mod.rs
  • src/executor/implements/other/show_databases.rs
  • src/executor/implements/other/show_tables.rs
  • src/executor/implements/other/use_database.rs
  • src/executor/mod.rs
  • src/executor/predule.rs
  • src/executor/util.rs
  • src/main.rs
  • src/pgwire/connection/connection.rs
  • src/pgwire/connection/prepared_statement.rs
  • src/pgwire/engine/engine.rs
  • src/pgwire/engine/rrdb.rs
  • src/server/README.md
  • src/server/mod.rs
  • src/server/predule.rs
💤 Files with no reviewable changes (1)
  • src/common/fs.rs
🔇 Additional comments (105)
src/engine/ast/dml/parts/having.rs (1)

1-1: 임포트 경로 업데이트가 모듈 재조직과 일치합니다.

SQLExpression 임포트 경로가 새로운 engine::ast::types 네임스페이스로 올바르게 업데이트되었습니다. 이는 PR의 모듈 구조 재조직 목표와 완벽하게 부합합니다.

src/engine/ast/dml/plan/select/no_from.rs (1)

1-1: LGTM! 모듈 경로 업데이트가 올바릅니다.

프로젝트 레이아웃 재구성에 따라 import 경로가 crate::ast::predule에서 crate::engine::ast::predule로 올바르게 업데이트되었습니다. PR의 목표인 AST 모듈을 engine 네임스페이스 하위로 이동하는 작업과 일치합니다.

src/engine/ast/dml/expressions/subquery.rs (1)

1-1: LGTM!

import 경로를 engine:: 네임스페이스로 이동한 변경사항이 프로젝트 리팩토링 목표와 일치하며, 올바르게 적용되었습니다.

src/engine/ast/dml/plan/select/subquery.rs (1)

1-1: 임포트 경로 업데이트가 올바르게 적용되었습니다.

프로젝트 구조 재편성에 따라 임포트 경로가 crate::ast::types에서 crate::engine::ast::types로 정확하게 변경되었습니다. 변경 사항이 명확하고 PR의 목적과 일치합니다.

src/common/mod.rs (1)

1-2: LGTM! 모듈 구조가 명확합니다.

새로운 commandfs 모듈을 명확하게 노출하여 프로젝트 레이아웃 개선 목표에 부합합니다.

src/common/command.rs (2)

6-9: LGTM! 테스트 가능한 커맨드 추상화입니다.

mockall::automock 속성을 사용하여 테스트에서 모킹이 가능한 깔끔한 trait 설계입니다. 단일 책임 원칙을 잘 따르고 있습니다.


11-17: LGTM! 효율적인 구현입니다.

Zero-sized type인 RealCommandRunner를 사용하여 런타임 오버헤드 없이 추상화를 제공합니다. Command::output()을 올바르게 위임하고 있습니다.

src/engine/ast/dml/expressions/call.rs (1)

1-1: 임포트 경로 업데이트 확인 완료

crate::ast::types에서 crate::engine::ast::types로의 임포트 경로 변경이 프로젝트 레이아웃 재구성 목표와 일치합니다.

src/engine/ast/dml/plan/select/scan.rs (1)

1-1: 임포트 경로 변경 적절함

엔진 네임스페이스로의 일관된 마이그레이션입니다.

src/engine/ast/dml/plan/delete/from.rs (1)

1-1: 네임스페이스 재구성 확인

AST 관련 타입들의 엔진 네임스페이스 이동이 올바르게 반영되었습니다.

src/engine/ast/ddl/alter_table.rs (1)

1-5: 임포트 경로 업데이트 완료

엔진 네임스페이스로의 임포트 경로 변경이 적절합니다. Line 1의 주석 처리된 임포트는 이후 정리가 필요할 수 있습니다.

src/engine/ast/dml/parts/insert_values.rs (1)

1-1: 임포트 경로 변경 확인

엔진 네임스페이스로의 일관된 마이그레이션입니다.

src/engine/ast/types/column.rs (1)

1-1: 임포트 경로 리팩토링 적절

DataType 임포트 경로가 새로운 엔진 네임스페이스 구조에 맞게 업데이트되었습니다.

src/engine/ast/tcl/commit.rs (1)

1-1: TCL 모듈 임포트 경로 업데이트 확인

엔진 네임스페이스로의 경로 변경이 올바릅니다.

src/engine/ast/other/desc_table.rs (1)

1-1: 네임스페이스 마이그레이션 완료 확인됨

검색 결과 src/test.rs:9에서만 use crate::ast::가 발견되었으나, 이는 주석 처리된 코드입니다. 활성 코드에서는 이전 임포트 경로가 남아있지 않으므로 네임스페이스 마이그레이션이 일관되고 완벽하게 적용되었습니다.

src/engine/ast/dml/parts/where.rs (1)

1-1: 네임스페이스 리팩토링 변경사항 확인됨.

SQLExpression 임포트 경로가 engine 네임스페이스로 올바르게 업데이트되었습니다. 로직 변경이 없으며 프로젝트 구조 개선에 부합합니다.

src/engine/ast/dml/parts/order_by.rs (1)

1-1: 네임스페이스 업데이트 승인.

임포트 경로가 engine::ast 네임스페이스로 일관되게 마이그레이션되었습니다.

src/engine/ast/dml/parts/from.rs (1)

1-1: 임포트 경로 업데이트 확인.

SubqueryExpressionTableName의 임포트 경로가 engine::ast 네임스페이스로 정확하게 업데이트되었습니다.

src/engine/optimizer/optimizer.rs (1)

1-14: 임포트 구조 개선 승인.

그룹화된 임포트에서 명시적인 개별 임포트 문으로 변경되었으며, 모든 경로가 engine::ast 네임스페이스로 일관되게 업데이트되었습니다. 이는 가독성을 향상시키고 옵티마이저 로직에는 영향을 주지 않습니다.

src/engine/ast/ddl/create_table.rs (2)

1-4: DDL 타입 임포트 경로 업데이트 승인.

CreateTableQuery 관련 모든 타입들의 임포트 경로가 engine::ast 네임스페이스로 올바르게 마이그레이션되었습니다. 퍼블릭 API 및 기능에는 변경이 없습니다.


80-80: 테스트 임포트 경로 업데이트 확인.

테스트 모듈의 DataType 임포트도 engine::ast 경로로 일관되게 업데이트되었습니다.

src/engine/ast/types/table.rs (1)

3-3: 타입 임포트 네임스페이스 마이그레이션 승인.

FromClauseFromTarget의 임포트 경로가 engine::ast 네임스페이스로 정확하게 업데이트되었으며, TableName의 변환 로직은 그대로 유지됩니다.

src/engine/parser/implements/dml/expression.rs (1)

1-14: 파서 임포트 네임스페이스 전면 마이그레이션 승인.

표현식 파서의 모든 임포트 경로가 engine::ast, engine::lexer, engine::parser 네임스페이스로 일관되게 업데이트되었습니다. 파싱 로직 및 알고리즘은 변경되지 않았으며, 네임스페이스 재구성만 반영되었습니다.

src/engine/parser/implements/other/desc.rs (1)

1-5: 네임스페이스 리팩토링 승인 완료.

코드 검사를 통해 다음을 확인했습니다:

  • src/engine/parser/implements/other/desc.rs의 모든 임포트가 올바르게 업데이트됨
  • crate::engine::parser::predule 패턴이 다른 모든 파서 구현 파일(14개 이상)과 일관됨
  • parse_desc_query 메서드가 src/engine/parser/parser.rs에서 올바르게 호출되고 있음
  • 테스트 파일 src/engine/parser/test/other.rs도 새 네임스페이스 임포트를 사용 중
  • 깨진 임포트나 충돌하는 참조 없음

모든 변경사항이 일관되게 적용되었으며 컴파일 오류는 발생하지 않을 것으로 예상됩니다.

src/engine/actions/dml/scan.rs (1)

6-18: DBEngine 및 engine 네임스페이스로의 이전이 일관적으로 잘 정리되었습니다.

DBEngine의 메서드로 옮기면서 TableName, StorageEncoder, TableDataRow, ExecuteError 모두 crate::engine::* 네임스페이스를 사용하도록 맞춘 부분이 전체 엔진 구조 리팩터링 방향과 잘 맞습니다. 내부 로직 자체는 기존 full_scan 동작을 그대로 유지하는 것으로 보이며, 에러 처리와 디코딩 흐름도 자연스럽습니다.

Also applies to: 32-85

src/engine/ast/types/expression.rs (1)

1-12: AST/스키마 타입을 engine 네임스페이스로 통합한 부분이 잘 정리되었습니다.

Binary/Unary/Between/NotBetween/Call/List/Parentheses/SubqueryExpression, WhereClause, TableDataFieldType 모두 crate::engine::... 경로를 사용하도록 바뀌어서, AST/스키마 타입이 엔진 모듈 아래로 일관되게 모인 것이 좋습니다. From<TableDataFieldType> for SQLExpression 구현도 기존 매핑(정수/실수/불리언/문자열/배열/NULL)을 그대로 유지하고 있어 동작 변경 없이 경로만 재배치된 것으로 보입니다. 테스트 모듈도 동일한 네임스페이스를 참조하도록 맞춰져 있어 후속 유지보수에 유리할 것 같습니다.

Also applies to: 231-247, 258-274

src/engine/ast/dml/parts/update_item.rs (1)

1-7: UpdateItem이 engine AST 타입을 사용하도록 정리된 부분 좋습니다.

SQLExpressioncrate::engine::ast::types에서 가져오도록 바꿔서, DML 파트 정의가 전반적인 엔진 네임스페이스 구조와 일관되게 맞춰졌습니다. 구조체 자체의 의미나 동작 변화는 없어서 리팩터링 목적에 잘 부합합니다.

src/engine/ast/dml/expressions/list.rs (1)

1-20: ListExpression이 engine AST 네임스페이스와 잘 맞춰졌습니다.

SQLExpression import 경로만 crate::engine::ast::types로 이동했고, ListExpressionSQLExpression::List 간 변환 로직은 그대로 유지되어 있습니다. 리스트 표현식 관련 기능에는 영향을 주지 않으면서 모듈 구조만 깔끔하게 정리된 것으로 보입니다.

src/engine/ast/ddl/drop_table.rs (1)

1-32: DropTableQuery가 engine AST 네임스페이스를 사용하도록 일관되게 정리되었습니다.

TableName, DDLStatement, SQLStatement를 모두 crate::engine::ast에서 가져오도록 바뀌어 DDL 쿼리 타입이 엔진 모듈 아래로 자연스럽게 편입되었습니다. builder/set_table/set_if_exists/build 체인 API는 변경되지 않아 기존 사용 코드는 그대로 동작할 것으로 보입니다.

src/engine/ast/types/foreign_key.rs (1)

1-11: ForeignKey가 engine AST의 TableName을 참조하도록 정리된 점 좋습니다.

외래키 정의에서 사용하는 TableNamecrate::engine::ast::types로 이동해, 다른 AST 타입들과 동일한 네임스페이스를 공유하게 된 점이 구조적으로 자연스럽습니다. 필드 구성과 직렬화/비교 동작에는 변화가 없어 보입니다.

src/engine/ast/tcl/begin_transaction.rs (1)

1-10: BeginTransactionQuery가 engine AST 네임스페이스로 편입된 부분이 자연스럽습니다.

SQLStatement, TCLStatementcrate::engine::ast에서 가져오도록 바뀌어 TCL 쿼리도 다른 AST들과 동일한 계층 구조를 따르게 되었습니다. From<BeginTransactionQuery> for SQLStatement 구현은 그대로라 기존 트랜잭션 시작 흐름에 영향은 없을 것으로 보입니다.

src/engine/ast/types/select_column.rs (1)

1-25: SelectColumn이 engine AST 타입으로 정리되어 일관성이 좋아졌습니다.

SQLExpressioncrate::engine::ast::types에서 가져오도록 변경해, SelectColumnSQLExpression::SelectColumn 변환이 엔진 AST 타입 체계 안에서 완결되도록 한 점이 좋습니다. 구조체와 생성자(new) 자체는 바뀐 부분이 없어 기존 SELECT 컬럼 처리 동작도 그대로 유지될 것으로 보입니다.

src/engine/lexer/tokenizer.rs (1)

3-3: 임포트 경로 업데이트 확인 완료

네임스페이스 재구성에 따라 crate::lexer::predule에서 crate::engine::lexer::predule로 임포트 경로가 올바르게 업데이트되었습니다.

src/engine/ast/dml/plan/select/filter.rs (1)

1-1: 임포트 경로 변경 승인

SQLExpression 타입의 임포트 경로가 engine::ast 네임스페이스로 일관되게 업데이트되었습니다.

src/engine/ast/other/show_databases.rs (1)

1-1: 네임스페이스 이동 확인

AST 관련 타입들이 engine::ast 네임스페이스로 올바르게 이동되었습니다.

src/engine/ast/dml/parts/group_by.rs (1)

1-1: 임포트 경로 업데이트 승인

SelectColumn 타입의 임포트 경로가 리팩토링 방향에 맞게 업데이트되었습니다.

src/engine/ast/dml/plan/update/from.rs (1)

1-1: 임포트 경로 정리 확인

DML 플랜 관련 타입들이 engine::ast 네임스페이스로 일관되게 이동되었습니다.

src/engine/ast/dml/parts/select_item.rs (1)

1-1: 임포트 변경 승인

SQLExpression 임포트가 엔진 네임스페이스로 올바르게 업데이트되었습니다.

src/engine/ast/dml/expressions/between.rs (1)

3-3: 메인 코드 및 테스트 임포트 일관성 확인

SQLExpression 임포트가 메인 코드와 테스트 코드 모두에서 engine::ast::types로 일관되게 업데이트되었습니다.

Also applies to: 49-49

src/engine/parser/test/ddl.rs (1)

3-12: 테스트 파일 임포트 경로 업데이트 완료

DDL 테스트 파일의 모든 임포트가 engine:: 네임스페이스로 체계적으로 업데이트되었습니다. 테스트 로직은 변경되지 않았으며, 임포트 경로만 리팩토링 방향에 맞게 수정되었습니다.

src/engine/ast/dml/plan/select/from.rs (1)

1-1: 임포트 경로 업데이트가 올바르게 적용되었습니다.

crate::ast에서 crate::engine::ast로의 네임스페이스 마이그레이션이 정확합니다.

src/engine/ast/mod.rs (1)

9-21: 자체 참조 임포트가 올바르게 구성되었습니다.

engine::ast 모듈에서 자신의 하위 모듈들을 crate::engine::ast로 임포트하는 것은 새로운 구조에서 올바른 접근입니다.

src/engine/ast/other/show_tables.rs (1)

1-1: 임포트 경로가 일관되게 업데이트되었습니다.

OtherStatementSQLStatement의 임포트 경로가 새로운 engine::ast 네임스페이스로 올바르게 변경되었습니다.

src/engine/ast/ddl/alter_database.rs (1)

1-1: DDL 관련 임포트가 정확하게 업데이트되었습니다.

DDLStatementSQLStatement의 경로가 engine::ast로 올바르게 마이그레이션되었습니다.

src/engine/ast/dml/insert.rs (1)

1-1: 프로덕션 코드와 테스트 코드의 임포트가 일관되게 업데이트되었습니다.

메인 코드(Line 1)와 테스트 코드(Line 68) 모두에서 engine::ast 경로로의 변경이 일관성 있게 적용되었습니다.

Also applies to: 68-68

src/engine/ast/other/use_database.rs (1)

1-1: 임포트 경로 변경이 적절합니다.

OtherStatementSQLStatement의 임포트가 새로운 모듈 구조에 맞게 업데이트되었습니다.

src/engine/ast/dml/delete.rs (1)

1-1: DML 삭제 쿼리의 임포트가 체계적으로 업데이트되었습니다.

프로덕션 코드와 테스트 코드의 임포트가 모두 engine::ast 네임스페이스로 일관되게 마이그레이션되었습니다.

Also applies to: 53-53

src/config/mod.rs (1)

1-1: 리팩토링 완료 확인 - 모든 GlobalConfig 참조가 성공적으로 LaunchConfig로 업데이트되었습니다.

검증 결과:

  • GlobalConfig 참조: 0건 (전체 제거됨)
  • LaunchConfig 정의: src/config/launch_config.rs:11에서 확인
  • launch_config 모듈 사용: 8개 파일에서 올바르게 import됨

코드베이스 전체에서 리팩토링이 완전히 진행되었습니다.

src/engine/ast/tcl/rollback.rs (1)

1-1: engine 네임스페이스로 AST import 경로를 옮긴 부분 문제 없어 보입니다.

동작을 바꾸지 않고 RollbackQuery -> SQLStatement 변환 로직은 그대로 유지한 채 경로만 crate::engine::ast로 맞춰서, 전체 엔진 레이아웃 리팩토링과 잘 정합되는 변경입니다.

src/engine/ast/dml/expressions/parentheses.rs (1)

1-1: SQLExpression import를 engine AST 타입 네임스페이스로 이동한 부분 적절합니다.

ParenthesesExpression 구조와 From<ParenthesesExpression> for SQLExpression 구현은 그대로이고, 참조 경로만 새 crate::engine::ast::types로 정리되어 리팩토링 의도에 잘 맞습니다.

src/engine/ast/dml/parts/target.rs (1)

1-1: UpdateTarget에서 TableName import 경로 변경이 일관성 있게 적용되었습니다.

UpdateTargetFrom<TableName> for UpdateTarget의 동작은 유지하면서, TableNamecrate::engine::ast::types에서 가져오도록만 수정되어 엔진 하위 AST 타입 구조와 잘 맞습니다.

src/engine/ast/dml/expressions/not_between.rs (1)

1-1: NotBetweenExpression 본문과 테스트 모두 engine AST 타입 네임스페이스로 정리된 점 좋습니다.

프로덕션 코드와 테스트 모두 SQLExpressioncrate::engine::ast::types에서 가져오도록 통일해, 네임스페이스 리팩토링 이후에도 타입 일관성이 유지됩니다. 표현식 타입과 From 구현은 변함없어 회귀 위험도 낮아 보입니다.

Also applies to: 29-29

src/engine/lexer/test/comment.rs (1)

2-2: lexer 코멘트 토큰 테스트가 engine 네임스페이스를 사용하도록 잘 정리되었습니다.

TokenTokenizercrate::engine::lexer::predule에서 가져오도록만 바뀌었고, 실제 토큰 시퀀스와 기대값(assert) 로직은 그대로라 리팩토링 후에도 동일한 동작을 검증합니다.

src/engine/parser/implements/utils.rs (1)

1-1: Parser 유틸에서 Parser/Token import를 engine 모듈로 옮긴 변경이 깔끔합니다.

Parser 확장 메서드들의 시그니처와 구현은 그대로 유지하면서, 의존 경로만 crate::engine::parser::predulecrate::engine::lexer::predule로 옮겨져 새 엔진 중심 구조와 잘 맞습니다.

Also applies to: 3-3

src/engine/parser/test/delete.rs (1)

3-10: DELETE 파서 테스트의 AST/lexer/parser import들을 engine 네임스페이스로 일괄 변경한 부분이 잘 정리되었습니다.

DeleteQuery, 표현식 관련 타입들, 토큰, Parser 모두를 crate::engine::... 경로로 가져오도록 통일해, 새 엔진 모듈 구조에 맞추면서 테스트 로직과 기대값 구성은 그대로 유지되고 있습니다.

src/engine/ast/dml/parts/join.rs (1)

1-1: JoinClause에서 사용하는 AST 타입 import를 engine::ast::types로 옮긴 변경이 적절합니다.

JoinClauseJoinType 정의는 그대로이고, SQLExpression, TableName 참조 경로만 새 엔진 AST 타입 모듈로 이동해, 직렬화/파생 설정과도 충돌 없이 구조 리팩토링 목적에 부합합니다.

src/engine/ast/dml/select.rs (1)

3-7: LGTM! 임포트 경로 업데이트가 올바르게 적용되었습니다.

crate::ast에서 crate::engine::ast로의 임포트 경로 변경이 일관되게 적용되었으며, 테스트 모듈의 임포트도 함께 업데이트되었습니다.

Also applies to: 233-236

src/engine/parser/test/create_database.rs (1)

2-5: LGTM! 테스트 임포트 경로가 올바르게 업데이트되었습니다.

모든 테스트 의존성이 engine:: 네임스페이스로 일관되게 마이그레이션되었습니다.

src/engine/parser/test/common.rs (1)

2-9: LGTM! 공통 테스트 유틸리티 임포트가 올바르게 업데이트되었습니다.

AST, lexer, parser 모듈에 대한 모든 임포트가 engine:: 네임스페이스로 일관되게 변경되었습니다.

src/engine/parser/implements/other/show.rs (1)

1-3: LGTM! Parser 구현 임포트가 올바르게 업데이트되었습니다.

SHOW 쿼리 파서의 모든 의존성이 engine:: 네임스페이스로 정확하게 마이그레이션되었습니다.

Also applies to: 6-7

src/engine/parser/implements/dml/delete.rs (1)

1-1: LGTM! DELETE 파서 임포트가 올바르게 업데이트되었습니다.

DML DELETE 쿼리 파서의 모든 임포트가 engine:: 네임스페이스로 정확하게 변경되었습니다.

Also applies to: 3-3, 6-6

src/engine/ast/dml/plan/delete/delete_plan.rs (1)

1-1: LGTM! DELETE 플랜 임포트가 올바르게 업데이트되었습니다.

FilterPlan 임포트와 테스트 모듈의 임포트가 모두 engine::ast 경로로 일관되게 변경되었습니다.

Also applies to: 31-34

src/engine/ast/dml/plan/select/join.rs (1)

1-4: LGTM! JOIN 플랜 임포트가 올바르게 업데이트되었습니다.

조인 관련 타입들의 임포트가 engine::ast 네임스페이스로 정확하게 마이그레이션되었습니다.

src/engine/ast/ddl/create_index.rs (1)

1-4: CREATE INDEX 임포트 경로 마이그레이션 완료 및 검증됨

검증 결과 src/engine/ast/ddl/create_index.rs의 모든 임포트가 crate::engine::ast:: 네임스페이스로 올바르게 업데이트되었습니다. 프로젝트 전체에서 332개의 활성 engine:: 임포트문이 일관되게 적용되었으며, 기존의 낡은 스타일 임포트는 찾아지지 않았습니다(src/test.rs의 주석 처리된 코드 제외). 메인 코드와 테스트 코드 모두 새로운 네임스페이스를 사용하고 있어 마이그레이션이 완전히 이루어졌습니다.

src/engine/parser/implements/tcl/commit.rs (1)

1-4: LGTM! 네임스페이스 마이그레이션이 정확합니다.

crate::ast에서 crate::engine::ast로, crate::parser에서 crate::engine::parser로의 임포트 경로 업데이트가 올바르게 적용되었습니다. 로직 변경 없이 구조적 리팩토링만 수행되었습니다.

src/engine/encoder/mod.rs (1)

1-1: LGTM! 모듈 노출이 적절합니다.

schema_encoder 모듈을 공개적으로 노출하여 engine::encoder 네임스페이스 하에서 접근 가능하게 했습니다.

src/engine/parser/implements/other/backslash_command.rs (1)

1-6: LGTM! 임포트 경로가 올바르게 업데이트되었습니다.

AST, 렉서, 파서 모듈의 임포트 경로가 모두 engine:: 네임스페이스로 일관되게 마이그레이션되었습니다.

src/engine/parser/implements/tcl/rollback.rs (1)

1-4: LGTM! 네임스페이스 마이그레이션이 정확합니다.

TCL 관련 AST 및 파서 임포트가 engine:: 네임스페이스로 올바르게 업데이트되었습니다.

src/engine/lexer/test/select.rs (1)

2-4: LGTM! 테스트 임포트가 올바르게 업데이트되었습니다.

렉서 테스트의 임포트 경로가 engine::lexer::predule로 일관되게 업데이트되었으며, 테스트 로직에는 변경사항이 없습니다.

src/engine/parser/implements/common.rs (1)

1-7: LGTM! 모든 임포트 경로가 일관되게 업데이트되었습니다.

AST 타입, 렉서, 파서 모듈의 임포트가 모두 engine:: 네임스페이스로 올바르게 마이그레이션되었습니다. 파싱 로직에는 변경사항이 없습니다.

src/engine/parser/implements/ddl/database.rs (1)

1-9: LGTM! DDL 파서 임포트가 올바르게 업데이트되었습니다.

데이터베이스 DDL 관련 AST, 렉서, 파서 임포트 경로가 모두 engine:: 네임스페이스로 일관되게 마이그레이션되었습니다.

src/engine/actions/mod.rs (1)

3-3: 모듈 이름 변경 확인 완료 - 모든 참조가 올바르게 업데이트됨

검증 결과 모듈 이름 변경이 완전하게 처리되었습니다:

  • pub mod etc; - src/engine/actions/mod.rs의 3번 라인에서 새 모듈명 적용됨
  • actions::other 참조 - 코드베이스 전체에서 발견되지 않음
  • ✓ 이전 other 디렉토리 - 제거됨
  • ✓ 새 etc.rs 모듈 파일 - 정상 위치에 존재
src/engine/ast/dml/update.rs (2)

1-1: AST 임포트 경로를 engine 네임스페이스로 옮긴 부분 확인했습니다

TableName, DMLStatement, SQLStatement 모두 crate::engine::ast 아래로 정리되어, PR 목적(엔진 중심 레이아웃)과 잘 맞고, 타입 일관성도 유지됩니다.


57-76: 테스트에서 SQLExpression 경로 정렬이 잘 되어 있습니다

테스트 모듈도 crate::engine::ast::types::SQLExpression을 사용하도록 맞춰서, 프로덕션 코드와 네임스페이스가 일치합니다. 리팩토링 이후에도 테스트가 같은 타입을 바라보도록 잘 조정된 것 같습니다.

src/engine/ast/dml/plan/select/select_plan.rs (2)

1-1: Group/Order 절 관련 임포트 경로 변경이 일관적입니다

GroupByClause, OrderByClausecrate::engine::ast::dml::parts 에서 가져오도록 바꾼 것은, 다른 DML AST 모듈과도 정합성이 있어서 구조적으로 자연스럽습니다.


70-76: SelectPlan 테스트 임포트가 새 엔진 구조와 잘 맞습니다

테스트에서 사용하는 JoinType, SelectFromPlan, JoinScanType, ScanType, SQLExpression, TableName 모두 crate::engine::ast 트리로 이동하여, 실제 모듈 구조와 어긋나는 부분이 없습니다. 리네임/이동에 따른 테스트 정리도 잘 되어 있습니다.

src/engine/parser/parser.rs (1)

3-6: 파서 상단 의존성을 engine 네임스페이스로 모은 방향이 적절합니다

SQLStatement, Token/Tokenizer, ParserContext를 모두 crate::engine 아래에서 가져오도록 통일해 둔 점이 좋습니다. 파서 구현부에는 추가 변경이 없어, 동작을 건드리지 않고 레이아웃만 재구성한 것으로 보입니다.

src/engine/ast/dml/expressions/unary.rs (2)

1-1: Unary 표현식에서 사용하는 SQLExpression 임포트 변경 확인했습니다

SQLExpressioncrate::engine::ast::types 에서 가져오도록 변경해 엔진 쪽 AST 트리에 자연스럽게 합류시켰습니다. 타입 사용처와도 일관적입니다.


27-30: UnaryOperator 테스트 임포트도 새 AST 위치와 잘 맞습니다

테스트에서 UnaryOperatorSQLExpression 을 각각 crate::engine::ast::dml::expressions::operatorscrate::engine::ast::types 에서 임포트하도록 바꾼 부분이 실제 구조와 정합적으로 보입니다. 리팩토링 후에도 테스트가 동일 타입을 참조하도록 잘 정리되어 있습니다.

src/engine/ast/ddl/drop_database.rs (1)

1-1: DDL re-export 경로를 engine::ast 로 옮긴 부분이 자연스럽습니다

DropDatabaseQuery::build 가 여전히 SQLStatement::DDL(DDLStatement::DropDatabaseQuery(...)) 를 생성하는 구조와 잘 맞고, 이제 이 파일이 엔진 쪽 AST 타입을 re-export 하는 관문 역할을 명확히 합니다.

src/engine/parser/test/alter_table.rs (1)

3-9: AST/파서 테스트 import 경로 리팩토링은 문제 없어 보입니다.

AlterTable*, Column/DataType/SQLExpression/TableName, Parser/ParserContext 를 모두 crate::engine::... 아래에서 가져오도록 바꾼 부분이 현재 엔진 모듈 구조와 잘 맞고, 테스트 본문 로직은 그대로라 동작 변화는 없을 것으로 보입니다.

src/engine/parser/test/alter_database.rs (1)

2-7: 엔진 네임스페이스로의 테스트 import 이관이 잘 정리되었습니다.

AlterDatabase*, SQLStatement, Token, Parsercrate::engine::... 아래로 옮긴 부분이 다른 테스트들과 일관적이고, 테스트 케이스 구성 및 검증 로직은 그대로 유지되어 있어 기능 변화 없이 구조만 정리된 것으로 보입니다.

src/engine/lexer/operator_token.rs (1)

1-3: 연산자/에러 타입 경로 변경은 안전해 보입니다.

BinaryOperator/UnaryOperatorIntoError/RRDBErrorcrate::engine::... 경로로 옮긴 것은 전체 AST/에러 모듈 리팩토링 방향과 잘 맞고, 아래 TryInto 구현이나 테스트 코드에는 영향이 없습니다. 이 파일은 경로 재배치만 이뤄진 것으로 판단됩니다.

src/engine/ast/dml/expressions/binary.rs (1)

1-1: Binary 연산식 AST의 엔진 경로 이관이 잘 되어 있습니다.

SQLExpressioncrate::engine::ast::types 로, 테스트 쪽 BinaryOperatorExpression/SQLExpression import 를 crate::engine::ast::dml::... 경로로 옮긴 부분이 전체 AST 재구성 방향과 일관적입니다. From 구현 및 테스트의 기대값 구성은 그대로 유지되어 있어서, 동작에는 변화 없이 네임스페이스만 정리된 것으로 보입니다.

Also applies to: 46-52

src/engine/parser/implements/dml/select.rs (1)

3-13: SELECT 파서의 엔진 AST/파서/렉서 경로 이관은 적절합니다.

WhereClause, GroupByItem, HavingClause, JoinClause/JoinType, OrderBy*, SelectItem/SelectWildCard, SelectQueryOperatorToken/Token, Parser/ParserContext 를 모두 crate::engine::... 경로로 옮긴 부분이 DML 쿼리 관련 모듈들을 엔진 네임스페이스 아래로 모으는 목적과 잘 맞습니다. 구현부는 그대로여서 기능적인 변화 없이 레이아웃만 정리된 것으로 보입니다.

src/engine/parser/implements/dml/insert.rs (1)

1-6: LGTM! 네임스페이스 재구성이 일관되게 적용되었습니다.

import 경로가 crate::engine:: 네임스페이스로 올바르게 업데이트되었으며, 로직 변경은 없습니다.

src/engine/lexer/tokens.rs (2)

2-4: LGTM! Import 경로가 올바르게 업데이트되었습니다.

BinaryOperator와 관련 타입들의 경로가 crate::engine::ast 네임스페이스로 일관되게 변경되었습니다.


189-192: LGTM! 테스트 import도 일관되게 업데이트되었습니다.

테스트 모듈의 import 경로가 engine:: 네임스페이스를 올바르게 사용하고 있습니다.

src/engine/ast/dml/plan/update/update_plan.rs (2)

1-1: LGTM! FilterPlan import 경로가 올바르게 업데이트되었습니다.

네임스페이스 변경이 정확하게 반영되었습니다.


31-34: LGTM! 테스트 import도 일관성 있게 변경되었습니다.

테스트 코드의 import 경로가 engine:: 네임스페이스를 올바르게 사용합니다.

src/engine/ast/ddl/create_database.rs (1)

1-1: LGTM! Public API 경로가 올바르게 재구성되었습니다.

DDLStatementSQLStatementcrate::engine::ast 네임스페이스를 통해 올바르게 노출되고 있습니다.

src/config/launch_config.rs (2)

11-11: LGTM! GlobalConfig에서 LaunchConfig로의 리네이밍이 명확합니다.

새로운 이름이 설정의 용도(launch configuration)를 더 명확하게 표현합니다.


53-63: LGTM! 설정 파일 로딩 기능이 적절히 추가되었습니다.

load_from_path 메서드가 TOML 파일로부터 설정을 로드하는 기능을 제공하며, 기본 경로 사용을 지원합니다.

src/engine/parser/test/create_table.rs (1)

3-6: LGTM! 테스트 파일의 import가 일관되게 업데이트되었습니다.

모든 import 경로가 engine:: 네임스페이스를 올바르게 사용하고 있으며, 테스트 로직은 변경되지 않았습니다.

src/engine/parser/implements/dml/update.rs (1)

1-7: LGTM! Parser import가 일관되게 업데이트되었습니다.

DML update 관련 타입들의 import 경로가 engine:: 네임스페이스로 올바르게 변경되었으며, 파싱 로직은 변경되지 않았습니다.

src/engine/expression.rs (3)

1-15: LGTM! Import 경로가 일관되게 업데이트되었습니다.

모든 타입과 모듈이 engine:: 네임스페이스로 올바르게 이동되었습니다.


25-26: LGTM! Executor에서 DBEngine으로의 전환과 가시성 축소가 적절합니다.

impl DBEngine 변경은 PR의 리팩토링 목표에 부합하며, reduce_expression의 가시성을 pub(crate)로 제한하는 것은 API surface area를 줄이는 좋은 개선입니다.


389-396: LGTM! 로직 변경 없이 포맷팅만 조정되었습니다.

이진 연산자 처리 로직은 동일하게 유지되고 있습니다.

src/engine/actions/dml/select.rs (2)

6-21: DBEngine 및 engine 네임스페이스 기반으로의 리팩터링 일관성이 좋습니다.

DBEngine 을 대상으로 하는 implcrate::engine::... 경로로의 import 정리가 전체 엔진 레이아웃 개편 방향과 잘 맞고, 함수 시그니처/반환 타입(ExecuteResult, RRDBError)도 기존 실행 흐름과 자연스럽게 이어집니다.


120-133: 리뷰 코멘트는 부분적으로만 정확합니다. 컴파일 에러는 발생하지 않지만, 논리적 오류는 존재합니다.

코드 검증 결과:

문법 및 타입 검증:

  • if let Some(table_name) = table_alias_reverse_map.get(table_name) && table_name == &field.table_name.table_name 구문은 Rust 2021+ 표준 문법이며 타입도 정상입니다.
  • table_alias_reverse_mapHashMap<String, String> 타입이고, .get() 반환값 Option<&String>과 비교 &String == &String은 모두 타입이 맞습니다.
  • 따라서 컴파일 에러는 발생하지 않습니다.

논리적 오류:

  • 51줄: table_alias_reverse_map.insert(table_name.clone().table_name, alias);로 맵을 생성할 때, 키는 실제 테이블명, 값은 별칭입니다.
  • 128-130줄: 이 맵의 값(별칭)과 field.table_name.table_name(테이블명)을 비교하고 있어, 실제로는 절대 일치할 수 없습니다.
  • 맵의 키-값 관계가 의도와 맞지 않습니다.

권장사항:
제안하신 리팩토링은 정확합니다. 중첩된 if로 분리하고 변수명을 명확히 하면 가독성과 유지보수성이 개선됩니다:

} else if let Some(alias) = table_alias_reverse_map.get(table_name) {
    if alias == &field.table_name.table_name {
        table_name_matched = true;
    }
}

Likely an incorrect or invalid review comment.

src/engine/parser/implements/ddl/top_level.rs (1)

1-6: 파서 관련 타입을 engine 네임스페이스로 옮긴 변경이 구조적으로 자연스럽습니다.

SQLStatement, Token, ParserContext, Parser 를 모두 crate::engine::... 경로로 모은 덕분에 파싱 계층이 엔진 하위로 명확히 묶여서 이후 모듈 구조 이해에 도움이 될 것 같습니다.

src/engine/actions/ddl/create_database.rs (1)

3-91: DBEngine/engine 네임스페이스 기반으로의 create_database 리팩터링이 안정적으로 보입니다.

  • CreateDatabaseQuery, StorageEncoder, DatabaseSchema, Execute* 타입을 모두 crate::engine::... 으로 모으고
  • impl DBEngine 에서 데이터 디렉터리 경로 계산 → DB 디렉터리/tables 서브디렉터리 생성 → database.configDatabaseSchema 를 encode 해서 기록하는 흐름이 자연스럽게 이어집니다.

기존 동작을 크게 바꾸지 않으면서 타입과 레이아웃만 정리된 형태라, 아키텍처 측면에서 무난하게 잘 정리된 것 같습니다.

src/engine/actions/ddl/alter_database.rs (1)

3-10: DBEngine 및 engine 스키마/인코더 타입으로의 전환이 create_database 와 잘 대칭을 이룹니다.

AlterDatabaseQuery/Action, StorageEncoder, DatabaseSchema, Execute* 타입을 모두 crate::engine::... 하위로 가져오고 impl DBEngine 에서 처리하게 만든 구조가 create_database 와도 자연스럽게 짝을 이루어서, DDL 액션들이 엔진 레이어에 일관되게 모인 느낌입니다.

Also applies to: 14-18

src/engine/initialize.rs (1)

16-23: DBEngine::initialize로 초기화 플로우를 묶은 설계는 좋습니다.

init_configinit_database 순으로 한 번만 공개 API에서 호출하게 한 점이 명확하고, 외부에서는 DBEngine::initialize().await만 알면 되어서 사용성이 좋아졌습니다. 나머지 헬퍼들을 비공개 메서드로 숨긴 것도 방향성이 괜찮습니다.

src/engine/mod.rs (1)

1-15: 엔진 모듈 네임스페이스 정리가 명확합니다

engine 아래로 ast/encoder/lexer/parser/schema/server/wal 및 DB 엔진 전용 actions/expression/initialize/types를 정리한 구조가 역할별로 잘 나뉘어 있어서, 이후 유지보수와 탐색성이 좋아질 것 같습니다. 이 방향성은 전체 PR 목표(레이아웃 재구성)에 잘 부합합니다.

Comment thread src/engine/actions/etc.rs
Comment thread src/engine/actions/etc.rs
Comment on lines +100 to +117
let futures = read_dir_result.map(|e| async {
match e {
Ok(entry) => match entry.file_type() {
Ok(file_type) => {
if file_type.is_dir() {
let mut path = entry.path();
path.push("database.config");

match tokio::fs::read(path).await {
Ok(result) => {
let database_config: DatabaseSchema =
encoder.decode(result.as_slice()).unwrap();

Some(database_config.database_name)
}
Err(_) => None,
}
} else {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

show_databases에서 encoder.decode(...).unwrap()은 설정 파일 손상 시 패닉을 유발합니다

match tokio::fs::read(path).await {
    Ok(result) => {
        let database_config: DatabaseSchema =
            encoder.decode(result.as_slice()).unwrap();

        Some(database_config.database_name)
    }
    Err(_) => None,
}

여기서 decodeNone을 반환하면 unwrap()이 패닉을 일으켜 엔진 전체가 종료됩니다. 같은 파일의 다른 코드에서는 디코드 실패를 안전하게 처리하고 있어(예: desc_tableok_or_else, show_tablesmatch encoder.decode(...) { Some(decoded) => ..., None => return None }), 이곳도 일관되게 방어적으로 처리하는 것이 좋아 보입니다.

예시:

-                                    match tokio::fs::read(path).await {
-                                        Ok(result) => {
-                                            let database_config: DatabaseSchema =
-                                                encoder.decode(result.as_slice()).unwrap();
-
-                                            Some(database_config.database_name)
-                                        }
-                                        Err(_) => None,
-                                    }
+                                    match tokio::fs::read(path).await {
+                                        Ok(result) => {
+                                            let database_config: Option<DatabaseSchema> =
+                                                encoder.decode(result.as_slice());
+
+                                            match database_config {
+                                                Some(config) => Some(config.database_name),
+                                                None => None, // 부정확한 config는 조용히 스킵
+                                            }
+                                        }
+                                        Err(_) => None,
+                                    }

이렇게 하면 잘못된 database.config 하나 때문에 전체 쿼리 처리가 중단되는 일을 피할 수 있습니다.


I need to verify this review comment by examining the actual code. Let me search the repository to confirm the issue.


---

🏁 Script executed:

```shell
#!/bin/bash
# Read the specific file and lines to verify the unwrap() usage
cat "src/engine/actions/etc.rs" | sed -n '90,130p'

Length of output: 1687


🏁 Script executed:

#!/bin/bash
# Search for encoder.decode patterns in the file to verify inconsistent handling
rg -n "encoder\.decode" "src/engine/actions/etc.rs" -C 5

Length of output: 1317


🏁 Script executed:

#!/bin/bash
# Search for the functions mentioned: desc_table and show_tables
rg -n "fn desc_table|fn show_tables" "src/engine/actions/etc.rs" -A 15

Length of output: 1540


더 자세히 desc_table 함수의 전체 구현을 확인하겠습니다.


---

🏁 Script executed:

```shell
#!/bin/bash
# Get the full desc_table function implementation to see error handling
rg -n "fn desc_table" "src/engine/actions/etc.rs" -A 40

Length of output: 1878


🏁 Script executed:

#!/bin/bash
# Search for all ok_or_else patterns mentioned in review to find error handling examples
rg -n "ok_or_else|match encoder\.decode" "src/engine/actions/etc.rs" -B 2 -A 2

Length of output: 632


show_databases의 설정 파일 디코드 시 unwrap() 사용으로 인한 패닉 위험 해결 필요

검증 결과 리뷰 의견의 지적이 정확합니다. 같은 파일 내에서 encoder.decode() 호출 시 다음과 같은 일관되지 않은 오류 처리 패턴이 확인됩니다:

  • desc_table (36-38줄): .ok_or_else(|| ExecuteError::wrap("config decode error"))?; - 안전한 에러 전파
  • show_tables (182-184줄): match encoder.decode(result.as_slice()) { Some(decoded) => decoded, None => return None } - 안전한 처리
  • show_databases (111줄): encoder.decode(result.as_slice()).unwrap() - 패닉 유발

111줄의 unwrap()은 손상된 database.config 파일 하나로 인해 전체 엔진을 중단시킵니다. 제안된 수정안(match 패턴 사용 또는 ok_or_else)을 적용하여 일관된 오류 처리로 변경하세요.

🤖 Prompt for AI Agents
In src/engine/actions/etc.rs around lines 100 to 117, the code uses
encoder.decode(...).unwrap() which can panic if the config is corrupted; replace
the unwrap with safe error handling consistent with the rest of the module
(e.g., match encoder.decode(result.as_slice()) { Some(decoded) => decoded, None
=> return None } or map the error to an ExecuteError via ok_or_else and
propagate), so a malformed database.config yields a controlled None/error
instead of crashing the process.

Comment thread src/engine/expression.rs
Comment on lines +74 to +78
_ => {
return Err(TypeError::wrap(
"unary '!' operator is valid only for integer and float types.",
));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

에러 메시지가 부정확합니다.

UnaryOperator::Neg 브랜치에서 배열 요소 처리 중 발생하는 에러 메시지가 "unary '!' operator"라고 표시되어 있지만, 실제로는 "unary '-' operator"여야 합니다. Line 83-85의 에러 메시지가 올바른 표현입니다.

                                    _ => {
                                        return Err(TypeError::wrap(
-                                            "unary '!' operator is valid only for integer and float types.",
+                                            "unary '-' operator is valid only for integer and float types.",
                                        ));
                                    }
🤖 Prompt for AI Agents
In src/engine/expression.rs around lines 74 to 78, the error message in the
fallback arm incorrectly references the unary '!' operator while this branch is
for UnaryOperator::Neg; update the TypeError::wrap string to mention the unary
'-' operator (matching the message used at lines 83-85) so the error correctly
reads that the unary '-' operator is valid only for integer and float types.

Comment thread src/engine/initialize.rs
Comment on lines 241 to 247
let test_cases = vec![
TestCase {
name: "init 정상 동작 (linux)",
want_error: false,
mock_config: Box::new(|| {
let config = GlobalConfig::default();
let config = LaunchConfig::default();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

테스트에서 test_cases[..5]만 순회하여 마지막 두 케이스가 실행되지 않습니다.

test_init_config에서:

for test_case in test_cases[..5].iter() {
    ...
}

로 슬라이스를 잘라 사용하고 있어서, 정의된 7개의 TestCase 중 앞의 5개만 실행되고 마지막 두 케이스(“전역 설정파일 생성 실패”, “최상위 디렉터리 생성 실패”)는 아예 검증되지 않습니다.

전체 케이스를 모두 돌리려면 단순히:

-        for test_case in test_cases[..5].iter() {
+        for test_case in &test_cases {

처럼 변경하는 편이 의도에도 더 잘 맞고, 새로 추가된 실패 시나리오에 대한 회귀도 막을 수 있습니다.

Also applies to: 313-314, 370-371, 420-421, 480-481, 522-523, 556-557, 579-597

🤖 Prompt for AI Agents
In src/engine/initialize.rs around lines 241-247 (and similarly at 313-314,
370-371, 420-421, 480-481, 522-523, 556-557, 579-597), the tests iterate over a
sliced subset of test_cases (e.g., test_cases[..5]) which skips the last two
defined cases; change the iteration to cover the entire vector (e.g., iterate
over test_cases.iter()) so all defined TestCase entries are executed and
validated, updating each occurrence noted to remove the hardcoded slice bounds.

Comment thread src/engine/mod.rs
Comment on lines +101 to +138
pub async fn get_table_config(&self, table_name: TableName) -> Result<TableSchema, RRDBError> {
let encoder = StorageEncoder::new();

let base_path = self.get_data_directory();

let TableName {
database_name,
table_name,
} = table_name;

let database_name = database_name.unwrap();

let database_path = base_path.clone().join(&database_name);
let table_path = database_path.clone().join("tables").join(&table_name);

// config data 파일 내용 변경
let config_path = table_path.clone().join("table.config");

match tokio::fs::read(&config_path).await {
Ok(data) => {
let table_config: Option<TableSchema> = encoder.decode(data.as_slice());

match table_config {
Some(table_config) => Ok(table_config),
None => Err(ExecuteError::wrap("invalid config data")),
}
}
Err(error) => match error.kind() {
ErrorKind::NotFound => Err(ExecuteError::wrap("table not found")),
_ => Err(ExecuteError::wrap(format!("{:?}", error))),
},
}
}

// 데이터 저장 경로를 반환합니다..
pub fn get_data_directory(&self) -> PathBuf {
PathBuf::from(self.config.data_directory.clone())
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

get_table_config에서 database_name.unwrap() 사용은 패닉 위험이 있습니다

let TableName {
    database_name,
    table_name,
} = table_name;

let database_name = database_name.unwrap();

위 코드에서 database_nameNone인 경우(예: USE dbDELETE FROM table처럼 현재 DB 컨텍스트를 이용하려는 경우) 런타임 패닉이 발생할 수 있습니다.

이 레이어에 도달하는 TableName이 항상 Some이라는 불변식을 100% 보장하지 않는다면, 다음과 같이 명시적으로 에러를 반환하는 편이 안전합니다:

-        let TableName {
-            database_name,
-            table_name,
-        } = table_name;
-
-        let database_name = database_name.unwrap();
+        let TableName {
+            database_name,
+            table_name,
+        } = table_name;
+
+        let database_name = match database_name {
+            Some(name) => name,
+            None => {
+                return Err(ExecuteError::wrap("database is not selected"));
+            }
+        };

이렇게 하면 DB 미선택 상태에서의 접근을 명시적인 에러로 처리할 수 있고, 패닉 없이 상위 계층에서 적절히 대응할 수 있습니다.


I'll verify the review comment by examining the codebase for the TableName struct definition and how get_table_config is called.


---

🏁 Script executed:

```shell
#!/bin/bash
# Find TableName struct definition
rg -n "struct\s+TableName" --type rust

Length of output: 54


🏁 Script executed:

#!/bin/bash
# Search for get_table_config call sites
rg -n "get_table_config" --type rust -B2 -A2

Length of output: 3561


🏁 Script executed:

#!/bin/bash
# Search for where database_name is set in TableName construction
rg -n "TableName\s*\{" --type rust -B3 -A3

Length of output: 34737



---

🏁 Script executed:

```shell
#!/bin/bash
# Check select.rs handler context around get_table_config call
cat src/engine/actions/dml/select.rs | head -60 | tail -30

Length of output: 1089


🏁 Script executed:

#!/bin/bash
# Check delete.rs handler context around get_table_config call
cat src/engine/actions/dml/delete.rs | head -45 | tail -25

Length of output: 786


🏁 Script executed:

#!/bin/bash
# Check update.rs handler context around get_table_config call
cat src/engine/actions/dml/update.rs | head -50 | tail -30

Length of output: 1009


🏁 Script executed:

#!/bin/bash
# Search for any database context or validation before these calls
rg -n "database.*context\|current.*database\|USE\s+database" --type rust -i src/engine/actions/dml/ -B2 -A2

Length of output: 0



---

🏁 Script executed:

```shell
#!/bin/bash
# Search optimizer for any database_name validation/normalization
rg -n "database_name" src/engine/optimizer/ --type rust -B2 -A2

Length of output: 0


get_table_config에서 database_name.unwrap() 호출 시 런타임 패닉 위험

src/engine/ast/types/table.rs의 TableName 구조체에서 database_nameOption<String>이며, 파서 테스트 코드(src/engine/parser/test/select.rs:234, 306, 380 등)가 database_name: None인 경우를 명시적으로 구성합니다. DML 핸들러들(src/engine/actions/dml/select.rs:45, delete.rs:37, update.rs:43)이 이러한 테이블명을 검증 없이 get_table_config에 전달하므로, src/engine/mod.rs:111의 database_name.unwrap()은 패닉을 발생시킬 수 있습니다.

let table_name = from.table_name.clone();
let table_config = self.get_table_config(table_name.clone()).await?;

위와 같은 호출에서 table_name.database_nameNone이면 패닉이 발생합니다. 명시적인 에러 처리로 변경하세요:

-        let database_name = database_name.unwrap();
+        let database_name = match database_name {
+            Some(name) => name,
+            None => {
+                return Err(ExecuteError::wrap("database is not selected"));
+            }
+        };
🤖 Prompt for AI Agents
In src/engine/mod.rs around lines 101 to 138, replace the direct
database_name.unwrap() with explicit Option handling to avoid a runtime panic:
match or if-let on table_name.database_name, and if it's None return an
appropriate Err(RRDBError) (e.g. Err(ExecuteError::wrap("missing database
name"))), otherwise use the unwrapped value; keep the rest of the function
unchanged and ensure the error type matches the function's Result so callers
receive a clear, handled error instead of panicking.

Comment on lines +1 to +13
use crate::engine::ast::ddl::alter_table::{
AlterColumnDropDefault, AlterColumnDropNotNull, AlterColumnSetDefault, AlterColumnSetNotNull,
AlterColumnSetType, AlterTableAddColumn, AlterTableAlterColumn, AlterTableDropColumn,
AlterTableQuery, AlterTableRenameColumn, AlterTableRenameTo,
};
use crate::ast::ddl::create_table::CreateTableQuery;
use crate::ast::ddl::drop_database::SQLStatement;
use crate::ast::ddl::drop_table::DropTableQuery;
use crate::engine::ast::ddl::create_table::CreateTableQuery;
use crate::engine::ast::ddl::drop_database::SQLStatement;
use crate::engine::ast::ddl::drop_table::DropTableQuery;
use crate::errors::predule::ParsingError;
use crate::errors::RRDBError;
use crate::lexer::predule::Token;
use crate::parser::context::ParserContext;
use crate::parser::predule::Parser;
use crate::engine::lexer::predule::Token;
use crate::engine::parser::context::ParserContext;
use crate::engine::parser::predule::Parser;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

SQLStatement import 경로가 잘못되었을 가능성이 큽니다.

현재 이 파일에서는 다음과 같이 SQLStatement 를 가져오고 있습니다.

use crate::engine::ast::ddl::drop_database::SQLStatement;

하지만 다른 파서/테스트 코드에서는 일관되게 crate::engine::ast::SQLStatement 를 사용하고 있고, drop_database 모듈이 SQLStatement 를 정의하거나 재export 하는 구조는 이름상으로도 자연스럽지 않습니다. 이 상태라면:

  • drop_database 모듈에 SQLStatement 가 없으면 컴파일 에러가 발생하거나,
  • 같은 이름의 전혀 다른 타입을 잘못 import 하게 될 위험이 있습니다.

이 파일에서도 아래와 같이 루트 AST에서 직접 가져오는 쪽이 의도에 더 맞고, 다른 코드들과도 일관적일 것 같습니다.

-use crate::engine::ast::ddl::drop_database::SQLStatement;
+use crate::engine::ast::SQLStatement;

또한 ParserContext 를 이 파일만 parser::context::ParserContext 에서 직접 가져오고, 다른 구현은 parser::predule 경유로 쓰고 있어서, 나중에 정리하실 때는 prelude 경로로 통일하는 것도 고려해 보시면 좋겠습니다.

🤖 Prompt for AI Agents
In src/engine/parser/implements/ddl/table.rs around lines 1 to 13, the file
incorrectly imports SQLStatement from
crate::engine::ast::ddl::drop_database::SQLStatement which likely points to the
wrong module; change the import to use the canonical
crate::engine::ast::SQLStatement so the parser uses the root AST type
consistently with other modules, and while here also change the ParserContext
import to come from crate::engine::parser::prelude (or the same prelude path
used elsewhere) to keep imports consistent.

Copy link
Copy Markdown
Collaborator

@wHoIsDReAmer wHoIsDReAmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGBTM

@myyrakle myyrakle merged commit adeb88a into master Nov 19, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

리팩토링: 코드 구조 개선

2 participants