Skip to content

[UNI-216] fix : 길 찾기 오류 해결#126

Merged
thdgustjd1 merged 2 commits intobefrom
fix/UNI-216
Feb 13, 2025
Merged

[UNI-216] fix : 길 찾기 오류 해결#126
thdgustjd1 merged 2 commits intobefrom
fix/UNI-216

Conversation

@thdgustjd1
Copy link
Copy Markdown
Collaborator

@thdgustjd1 thdgustjd1 commented Feb 13, 2025

📝 PR 타입

  • 기능 구현
  • 기능 수정
  • 버그 수정
  • 리팩토링
  • 인프라, 의존성, 환경 변수, 빌드 관련 코드 업데이트

🚀 변경 사항

길 찾기 로직에서 발생하던 오류를 해결하였습니다.

  • 리팩토링 과정에서 누락된 케이스를 처리하였습니다.

Summary by CodeRabbit

  • New Features

    • Added administrative revision rollback and new endpoints for creating building nodes and routes.
    • Enhanced map functionality with improved fastest route calculation and risk management.
  • Improvements

    • Updated CI/CD to run tests during builds, increasing overall reliability.
    • Enhanced auditing with automatic timestamp tracking and selective audit control.
  • Refactors

    • Reorganized domain APIs to better reflect building and map responsibilities, streamlining the overall structure.

@thdgustjd1 thdgustjd1 added 🔧 fix 수정사항 및 버그관련 등 🫀 be 백엔드 task labels Feb 13, 2025
@thdgustjd1 thdgustjd1 requested a review from mikekks February 13, 2025 07:42
@thdgustjd1 thdgustjd1 self-assigned this Feb 13, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 13, 2025

Walkthrough

The pull request introduces extensive refactoring and new functionalities throughout the codebase. It modifies CI/CD workflows and build dependencies, restructures packages by consolidating node‐related code into building and map modules, and adds new endpoints and service methods for route and revision management. Auditing, exception handling, logging, and utility classes have been updated, and database configurations now favor MySQL Testcontainers over H2. Additionally, several test classes and supporting repositories have been added or re‐organized to accommodate the new design.

Changes

File(s) Summary of Changes
.github/workflows/be-ci.yml, uniro_backend/.gitignore, uniro_backend/build.gradle Updated CI workflow to run tests; added ignore and tracking rules for SQL files; added testcontainer dependencies.
UniroBackendApplication.java, CustomPostUpdateListener.java, DisableEnversAspect.java, RevisionContext.java, RevisionType.java Enabled JPA auditing by adding @EnableJpaAuditing; introduced custom listeners/aspects and thread-local revision type management.
AdminApi.java, AdminController.java, RevisionOperationAspect.java, AdminService.java, CustomReversionListener.java, RevInfoRepository.java, NodeAuditRepository.java, RouteAuditRepository.java Modified admin endpoints (including rollbackRev), added revision-specific operations and new repository methods for audit record management.
Files under building and map packages (e.g. BuildingApi.java, BuildingController.java, various DTOs, BuildingService.java, MapApi.java, MapController.java, MapService.java, RouteCalculator.java, etc.) Reorganized controllers, services, DTOs, and repositories from node-centric to building/map-centric; added new endpoints for building route creation and enhanced route calculation logic.
EnversConfig.java, ErrorCode.java, GlobalExceptionHandler.java, various custom exception classes (AdminException, BuildingException, NodeException, UnivException) and logging classes (ExecutionLoggingAop.java) Updated exception handling and logging; added new error codes and a custom logging AOP to improve diagnostics.
GeoUtils.java, RouteUtils.java, MapClient.java, MapClientImpl.java Modified coordinate conversion order in GeoUtils; added a utility (RouteUtils) to identify building routes; updated import paths and batch size in MapClientImpl.
Configuration files (application-dev.yml, application-local.yml, application-test.yml, data.sql, h2gis-setting.sql) Switched DB configuration from H2 to MySQL Testcontainers; updated dialect settings; removed H2 spatial initialization and unused SQL schema setup.
Numerous test classes and new repository interfaces (e.g. AdminServiceTest.java, BuildingServiceTest.java, MapServiceTest.java, RevInfoTestRepository.java, NodeTestRepository.java, RouteTestRepository.java, etc.) Added comprehensive tests for admin, building, and map services; restructured test repositories and fixtures to align with new package organization.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant MapController
  participant MapService
  participant MapClient
  participant NodeRepository
  participant BuildingRepository
  
  Client->>MapController: POST /{univId}/building-route
  MapController->>MapService: createBuildingRoute(univId, reqDTO)
  MapService->>MapClient: Retrieve building node info (height, etc.)
  MapService->>NodeRepository: Save new Node
  MapService->>BuildingRepository: Save new Building
  MapService-->>MapController: Return success
  MapController-->>Client: HTTP 200 OK
Loading
sequenceDiagram
  participant AdminClient
  participant AdminController
  participant AdminService
  participant RevInfoRepository
  participant NodeAuditRepository

  AdminClient->>AdminController: PATCH /{univId}/revisions/{versionId} (rollback)
  AdminController->>AdminService: rollbackRev(univId, versionId)
  AdminService->>RevInfoRepository: Fetch revision info
  AdminService->>NodeAuditRepository: Delete nodes/routes after version
  AdminService-->>AdminController: Confirmation of rollback
  AdminController-->>AdminClient: HTTP 200 OK
Loading

Poem

I’m a little rabbit with code in my paws,
Hopping through revisions without a pause.
New endpoints and tests make me jump with delight,
As changes unfold in the morning light.
With nibbling bytes and gentle cheers,
I celebrate progress with bunny ears!

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@thdgustjd1 thdgustjd1 changed the base branch from main to be February 13, 2025 07:42
Copy link
Copy Markdown
Collaborator

@mikekks mikekks left a comment

Choose a reason for hiding this comment

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

고생하셨습니다 ~!

@thdgustjd1 thdgustjd1 merged commit b3319d2 into be Feb 13, 2025
@thdgustjd1 thdgustjd1 deleted the fix/UNI-216 branch February 13, 2025 07:48
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.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

🛑 Comments failed to post (12)
uniro_backend/src/main/java/com/softeer5/uniro_backend/common/exception/GlobalExceptionHandler.java (1)

24-29: 🛠️ Refactor suggestion

Enhance validation error handling.

While the basic structure is good, consider these improvements:

  1. Rename the method to avoid collision (e.g., handleValidationException)
  2. Include field-specific validation errors in the response
  3. Consider using more specific error codes based on validation failure type

Here's a suggested implementation:

 @ExceptionHandler(MethodArgumentNotValidException.class)
-public ResponseEntity<ErrorResponse> handleCustomException(MethodArgumentNotValidException ex) {
+public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {
     log.error(ex.getMessage());
-    ErrorResponse response = new ErrorResponse(INVALID_INPUT_VALUE);
+    List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
+    Map<String, String> validationErrors = fieldErrors.stream()
+        .collect(Collectors.toMap(
+            FieldError::getField,
+            FieldError::getDefaultMessage,
+            (first, second) -> first
+        ));
+    ErrorResponse response = new ErrorResponse(INVALID_INPUT_VALUE, validationErrors);
     return new ResponseEntity<>(response, HttpStatus.valueOf(INVALID_INPUT_VALUE.getHttpStatus()));
 }

Note: This assumes ErrorResponse can handle validation details. If not, you'll need to extend it.

uniro_backend/src/main/java/com/softeer5/uniro_backend/building/dto/request/CreateBuildingNodeReqDTO.java (1)

27-28: 🛠️ Refactor suggestion

Add validation for level field.

The level field is used for map scaling (1-10) but lacks range validation. Add @Min(1) and @Max(10) annotations to ensure valid values.

    @Schema(description = "레벨(지도 축척에 따른 노출정도, 1~10)", example = "3")
+   @Min(value = 1, message = "Level must be at least 1")
+   @Max(value = 10, message = "Level must not exceed 10")
    private final int level;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    @Schema(description = "레벨(지도 축척에 따른 노출정도, 1~10)", example = "3")
    @Min(value = 1, message = "Level must be at least 1")
    @Max(value = 10, message = "Level must not exceed 10")
    private final int level;
uniro_backend/src/main/java/com/softeer5/uniro_backend/building/controller/BuildingApi.java (1)

60-61: 🛠️ Refactor suggestion

Fix incorrect response code in Swagger documentation.

For resource creation, use 201 (Created) instead of 200 (OK).

    @ApiResponses(value = {
-           @ApiResponse(responseCode = "200", description = "건물 노드 생성 성공"),
+           @ApiResponse(responseCode = "201", description = "건물 노드 생성 성공"),
            @ApiResponse(responseCode = "400", description = "EXCEPTION(임시)", content = @Content),
    })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    @ApiResponses(value = {
           @ApiResponse(responseCode = "201", description = "건물 노드 생성 성공"),
           @ApiResponse(responseCode = "400", description = "EXCEPTION(임시)", content = @Content),
    })
uniro_backend/src/main/java/com/softeer5/uniro_backend/common/logging/ArgType.java (1)

26-32: 💡 Verification agent

🛠️ Refactor suggestion

🧩 Analysis chain

Improve robustness of type detection.

The current implementation has several potential issues:

  1. Missing null checks could cause NPE
  2. Case-sensitive string matching might miss variations (e.g., "DTO", "Dto")
  3. Simple substring matching could cause false positives
  4. Performance could be improved with result caching

Consider this more robust implementation:

     private static boolean isCustomDto(Object arg) {
+        if (arg == null) return false;
+        String className = arg.getClass().getName().toLowerCase();
-        return arg.getClass().getName().contains("dto");
+        return className.contains(".dto.") || className.endsWith("dto");
     }

     private static boolean isEntity(Object arg) {
+        if (arg == null) return false;
+        String className = arg.getClass().getName().toLowerCase();
-        return arg.getClass().getName().contains("entity");
+        return className.contains(".entity.") || className.endsWith("entity");
     }

Let's verify the class naming patterns in the codebase:


🏁 Script executed:

#!/bin/bash
# Search for DTO and Entity class patterns
echo "DTO class patterns:"
fd -e java | xargs rg -l "dto" || true
echo -e "\nEntity class patterns:"
fd -e java | xargs rg -l "entity" || true

Length of output: 8970


Robust Type Detection: Address Null Safety & Precise Pattern Matching

The current implementation still poses risks:

  • Null Safety: No null check on the argument can lead to a NullPointerException.
  • Case Sensitivity: Using a case-sensitive substring check might miss valid DTO/Entity naming variations (e.g., "DTO", "dto", "Dto").
  • Overly Broad Matching: Simple substring matching can cause false positives.
  • Performance: Consider caching the computed class name if this check becomes a performance hotspot.

Recommended refactor:

     private static boolean isCustomDto(Object arg) {
+        if (arg == null) return false;
+        String className = arg.getClass().getName().toLowerCase();
-        return arg.getClass().getName().contains("dto");
+        return className.contains(".dto.") || className.endsWith("dto");
     }

     private static boolean isEntity(Object arg) {
+        if (arg == null) return false;
+        String className = arg.getClass().getName().toLowerCase();
-        return arg.getClass().getName().contains("entity");
+        return className.contains(".entity.") || className.endsWith("entity");
     }

We've verified that the codebase consistently uses the .dto. pattern in DTO classes and .entity. for entities. The refined approach should cover common naming variations while mitigating potential NPEs. Please integrate these changes and consider result caching if profiling indicates a performance issue.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	private static boolean isCustomDto(Object arg) {
	    if (arg == null) return false;
	    String className = arg.getClass().getName().toLowerCase();
	    return className.contains(".dto.") || className.endsWith("dto");
	}

	private static boolean isEntity(Object arg) {
	    if (arg == null) return false;
	    String className = arg.getClass().getName().toLowerCase();
	    return className.contains(".entity.") || className.endsWith("entity");
	}
uniro_backend/src/main/java/com/softeer5/uniro_backend/common/logging/ExecutionLoggingAop.java (1)

99-140: 🛠️ Refactor suggestion

Consider adding depth limit for recursive logging.

The logDetail method recursively traverses object fields which could cause performance issues with deeply nested objects.

 private void logDetail(Object arg, String requestType, StringBuilder logMessage, int depth) {
+    if (depth > 3) { // Limit recursion depth
+        logMessage.append("  ".repeat(depth)).append("[Max depth reached]\n");
+        return;
+    }
     String indent = "  ".repeat(depth);
     ArgType argType = ArgType.getArgType(arg);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	private void logDetail(Object arg, String requestType, StringBuilder logMessage, int depth) {
	    if (depth > 3) { // Limit recursion depth
	        logMessage.append("  ".repeat(depth)).append("[Max depth reached]\n");
	        return;
	    }
		String indent = "  ".repeat(depth); // depth 수준에 따른 들여쓰기
		ArgType argType = ArgType.getArgType(arg);

		switch (argType) {
			case NULL -> logMessage.append(indent).append(requestType).append(" null\n");
			case LIST -> {
				logMessage.append(indent)
					.append(requestType)
					.append(" ")
					.append(arg.getClass().getSimpleName())
					.append("\n");
				List<?> list = (List<?>) arg;
				for (int i = 0; i < list.size(); i++) {
					logDetail(list.get(i), "[List Element " + i + "] ", logMessage, depth + 1);
				}
			}
			case CUSTOM_DTO -> {
				logMessage.append(indent)
					.append(requestType)
					.append("DTO: ")
					.append(arg.getClass().getSimpleName())
					.append("\n");
				logObjectFields(arg, logMessage, depth + 1);
			}
			case ENTITY -> {
				logMessage.append(indent)
					.append(requestType)
					.append(arg.getClass().getSimpleName())
					.append(" : ")
					.append("\n");
				logObjectFields(arg, logMessage, depth + 1);
			}
			default -> logMessage.append(indent)
				.append(requestType)
				.append(" ")
				.append(arg.getClass().getSimpleName())
				.append(": ")
				.append(arg)
				.append("\n");
		}
	}
uniro_backend/src/main/java/com/softeer5/uniro_backend/map/entity/Route.java (1)

101-108: 🛠️ Refactor suggestion

Equality check excludes path and nodes.
isEqualRoute checks ID, cost, caution, and danger factors. If node equality or path geometry matter, consider including them here or rename the method to clarify partial equality.

uniro_backend/src/main/java/com/softeer5/uniro_backend/admin/setting/RevisionContext.java (2)

32-34: ⚠️ Potential issue

Fix potential memory leak in clear() method.

The clear() method should remove all ThreadLocal variables to prevent memory leaks.

Apply this diff to fix the clear() method:

 public static void clear() {
     univIdHolder.remove();
+    actionHolder.remove();
+    REVISION_TYPE_THREAD_LOCAL.remove();
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    public static void clear() {
        univIdHolder.remove();
        actionHolder.remove();
        REVISION_TYPE_THREAD_LOCAL.remove();
    }

32-34: ⚠️ Potential issue

Prevent memory leaks by clearing all ThreadLocal variables.

The clear() method only removes univIdHolder, but leaves actionHolder and REVISION_TYPE_THREAD_LOCAL in memory. This can lead to memory leaks, especially in thread pools where threads are reused.

Apply this diff to clear all ThreadLocal variables:

 public static void clear() {
     univIdHolder.remove();
+    actionHolder.remove();
+    REVISION_TYPE_THREAD_LOCAL.remove();
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    public static void clear() {
        univIdHolder.remove();
        actionHolder.remove();
        REVISION_TYPE_THREAD_LOCAL.remove();
    }
uniro_backend/src/main/java/com/softeer5/uniro_backend/admin/repository/NodeAuditRepository.java (2)

30-35: ⚠️ Potential issue

Replace native query with JPQL to prevent SQL injection.

While the current implementation uses parameter binding, it's safer to use JPQL or @query annotation.

Apply this diff to fix the SQL injection vulnerability:

-    public void deleteAllAfterVersionId(Long univId, Long versionId) {
-        entityManager.createNativeQuery("DELETE FROM node_aud WHERE univ_id = :univId AND rev > :versionId")
-            .setParameter("univId", univId)
-            .setParameter("versionId", versionId)
-            .executeUpdate();
-    }
+    @Query("DELETE FROM NodeAud n WHERE n.univId = :univId AND n.rev > :versionId")
+    @Modifying
+    public void deleteAllAfterVersionId(@Param("univId") Long univId, @Param("versionId") Long versionId);

30-35: ⚠️ Potential issue

Add input validation and error handling for delete operation.

The deleteAllAfterVersionId method has several potential issues:

  1. No validation of input parameters
  2. No error handling for failed queries
  3. Uses native SQL which could be vulnerable to SQL injection

Consider using JPQL or Criteria API instead of native SQL, and add proper validation:

 public void deleteAllAfterVersionId(Long univId, Long versionId) {
+    if (univId == null || versionId == null) {
+        throw new IllegalArgumentException("univId and versionId must not be null");
+    }
+    try {
+        String jpql = "DELETE FROM NodeAud n WHERE n.univId = :univId AND n.rev > :versionId";
+        entityManager.createQuery(jpql)
+            .setParameter("univId", univId)
+            .setParameter("versionId", versionId)
+            .executeUpdate();
+    } catch (Exception e) {
+        throw new RuntimeException("Failed to delete node audit records", e);
+    }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	public void deleteAllAfterVersionId(Long univId, Long versionId) {
	    if (univId == null || versionId == null) {
	        throw new IllegalArgumentException("univId and versionId must not be null");
	    }
	    try {
	        String jpql = "DELETE FROM NodeAud n WHERE n.univId = :univId AND n.rev > :versionId";
	        entityManager.createQuery(jpql)
	            .setParameter("univId", univId)
	            .setParameter("versionId", versionId)
	            .executeUpdate();
	    } catch (Exception e) {
	        throw new RuntimeException("Failed to delete node audit records", e);
	    }
	}
uniro_backend/src/main/java/com/softeer5/uniro_backend/admin/repository/RouteAuditRepository.java (2)

31-36: 🛠️ Refactor suggestion

⚠️ Potential issue

Extract common audit functionality to a base class.

  1. The native query should be replaced with JPQL to prevent SQL injection.
  2. The code is duplicated from NodeAuditRepository and should be extracted to a base class.

Create a base class for audit repositories:

@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class BaseAuditRepository<T> {
    @PersistenceContext
    protected EntityManager entityManager;

    protected abstract Class<T> getEntityClass();

    public List<T> getAllEntitiesAtRevision(Long univId, Long versionId) {
        AuditReader auditReader = AuditReaderFactory.get(entityManager);
        return auditReader.createQuery()
            .forEntitiesAtRevision(getEntityClass(), versionId)
            .add(AuditEntity.property("univId").eq(univId))
            .getResultList();
    }

    @Query("DELETE FROM #{#entityName}Aud e WHERE e.univId = :univId AND e.rev > :versionId")
    @Modifying
    public abstract void deleteAllAfterVersionId(@Param("univId") Long univId, @Param("versionId") Long versionId);
}

Then update RouteAuditRepository:

-@Repository
-@RequiredArgsConstructor
-@Transactional
-public class RouteAuditRepository {
-    private final EntityManager entityManager;
+@Repository
+@Transactional
+public class RouteAuditRepository extends BaseAuditRepository<Route> {
+    @Override
+    protected Class<Route> getEntityClass() {
+        return Route.class;
+    }
-    public List<Route> getAllRoutesAtRevision(Long univId, Long versionId) {
-        AuditReader auditReader = AuditReaderFactory.get(entityManager);
-        return auditReader.createQuery()
-            .forEntitiesAtRevision(Route.class, versionId)
-            .add(AuditEntity.property("univId").eq(univId))
-            .getResultList();
-    }
-
-    public void deleteAllAfterVersionId(Long univId, Long versionId) {
-        entityManager.createNativeQuery("DELETE FROM route_aud WHERE univ_id = :univId AND rev > :versionId")
-            .setParameter("univId", univId)
-            .setParameter("versionId", versionId)
-            .executeUpdate();
-    }
}

19-36: 🛠️ Refactor suggestion

Extract common audit functionality to a base class.

The code is duplicated between NodeAuditRepository and RouteAuditRepository. Consider creating a base class to handle common audit operations.

Create a base class:

@MappedSuperclass
public abstract class BaseAuditRepository<T> {
    protected final EntityManager entityManager;

    protected BaseAuditRepository(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public List<T> getAllAtRevision(Class<T> entityClass, Long univId, Long versionId) {
        AuditReader auditReader = AuditReaderFactory.get(entityManager);
        return auditReader.createQuery()
            .forEntitiesAtRevision(entityClass, versionId)
            .add(AuditEntity.property("univId").eq(univId))
            .getResultList();
    }

    public void deleteAllAfterVersionId(String tableName, Long univId, Long versionId) {
        if (univId == null || versionId == null) {
            throw new IllegalArgumentException("univId and versionId must not be null");
        }
        try {
            String jpql = String.format("DELETE FROM %s WHERE univId = :univId AND rev > :versionId", tableName);
            entityManager.createQuery(jpql)
                .setParameter("univId", univId)
                .setParameter("versionId", versionId)
                .executeUpdate();
        } catch (Exception e) {
            throw new RuntimeException("Failed to delete audit records", e);
        }
    }
}

Then simplify the repositories:

@Repository
@RequiredArgsConstructor
@Transactional
public class RouteAuditRepository extends BaseAuditRepository<Route> {
    public RouteAuditRepository(EntityManager entityManager) {
        super(entityManager);
    }

    public List<Route> getAllRoutesAtRevision(Long univId, Long versionId) {
        return getAllAtRevision(Route.class, univId, versionId);
    }

    public void deleteAllAfterVersionId(Long univId, Long versionId) {
        super.deleteAllAfterVersionId("RouteAud", univId, versionId);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🫀 be 백엔드 task 🔧 fix 수정사항 및 버그관련 등

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants