Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development: Add simple repository service #9871

Open
wants to merge 20 commits into
base: develop
Choose a base branch
from

Conversation

ole-ve
Copy link
Contributor

@ole-ve ole-ve commented Nov 26, 2024

Checklist

General

Server

  • Important: I implemented the changes with a very good performance and prevented too many (unnecessary) and too complex database calls.
  • I strictly followed the principle of data economy for all database calls.
  • I strictly followed the server coding and design guidelines.
  • I documented the Java code using JavaDoc style.

Motivation and Context

To de-clutter and cleanup the repositories, these changes introduce the SimpleRepository. The general idea is to move all default methods from Repositories (i.e. implementations of ArtemisJpaRepository) to a respective SimpleRepository (per JpaRepository that originally declared these methods).

These changes are - for now - only a draft using the CompetencyRepository.

Description

Rules:

  • A service can use methods from both the Repository and SimpleService.
  • A SimpleService can only access one Repository, i.e. it autowires exactly one Repository. Some repositories return different objects ("DTOs" or directly entities, pbl. for performance). This is also fine for the SimpleService.
  • The SimpleServices reside in a subpackage of the modules repository package

SimpleService

Implementation detail: The CompetencySimpleService has a common abstract superclass AbstractSimpleService. I am not really attached if this should rather be aggregation over inheritance.

Performance Review

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced CompetencySimpleService and CourseCompetencySimpleService for enhanced competency data retrieval.
    • Updated various services and resources to utilize the new simple services for competency management.
  • Bug Fixes

    • Removed outdated default methods from CompetencyRepository and CourseCompetencyRepository, streamlining data access.
  • Refactor

    • Updated multiple services and resources to replace direct repository calls with calls to the new simple services, improving data handling efficiency.
  • Tests

    • Added new tests to enforce architectural rules regarding repository and service structures.

@ole-ve ole-ve requested a review from a team as a code owner November 26, 2024 13:16
@ole-ve ole-ve marked this pull request as draft November 26, 2024 13:20
@github-actions github-actions bot added server Pull requests that update Java code. (Added Automatically!) atlas Pull requests that affect the corresponding module core Pull requests that affect the corresponding module labels Nov 26, 2024
Copy link

coderabbitai bot commented Nov 26, 2024

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 pmd (7.8.0)
src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CompetencySimpleService.java

The following rules are missing or misspelled in your ruleset file category/vm/bestpractices.xml: BooleanInstantiation, DontImportJavaLang, DuplicateImports, EmptyFinallyBlock, EmptyIfStmt, EmptyInitializer, EmptyStatementBlock, EmptyStatementNotInLoop, EmptySwitchStatements, EmptySynchronizedBlock, EmptyTryBlock, EmptyWhileStmt, ExcessiveClassLength, ExcessiveMethodLength, ImportFromSamePackage, MissingBreakInSwitch, SimplifyBooleanAssertion. Please check your ruleset configuration.

src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java

The following rules are missing or misspelled in your ruleset file category/vm/bestpractices.xml: BooleanInstantiation, DontImportJavaLang, DuplicateImports, EmptyFinallyBlock, EmptyIfStmt, EmptyInitializer, EmptyStatementBlock, EmptyStatementNotInLoop, EmptySwitchStatements, EmptySynchronizedBlock, EmptyTryBlock, EmptyWhileStmt, ExcessiveClassLength, ExcessiveMethodLength, ImportFromSamePackage, MissingBreakInSwitch, SimplifyBooleanAssertion. Please check your ruleset configuration.

src/main/java/de/tum/cit/aet/artemis/core/repository/base/ISimpleService.java

The following rules are missing or misspelled in your ruleset file category/vm/bestpractices.xml: BooleanInstantiation, DontImportJavaLang, DuplicateImports, EmptyFinallyBlock, EmptyIfStmt, EmptyInitializer, EmptyStatementBlock, EmptyStatementNotInLoop, EmptySwitchStatements, EmptySynchronizedBlock, EmptyTryBlock, EmptyWhileStmt, ExcessiveClassLength, ExcessiveMethodLength, ImportFromSamePackage, MissingBreakInSwitch, SimplifyBooleanAssertion. Please check your ruleset configuration.

  • 1 others

Walkthrough

This pull request introduces a significant refactoring of competency-related repositories and services in the Artemis platform. The primary changes involve removing default methods from repository interfaces like CompetencyRepository and CourseCompetencyRepository, and introducing new SimpleService classes (CompetencySimpleService and CourseCompetencySimpleService) to handle complex entity retrieval. These new services centralize error handling and provide a more consistent approach to fetching competency-related entities with various associated data.

Changes

File Change Summary
CompetencyRepository.java Removed default methods for retrieving competencies with specific associations
CourseCompetencyRepository.java Removed multiple default methods for fetching course competencies
CompetencyService.java Updated constructor and method to use new CompetencySimpleService
CompetencyResource.java Added CompetencySimpleService and CourseCompetencySimpleService dependencies
CompetencySimpleService.java New service for retrieving competencies with error handling
CourseCompetencySimpleService.java New service for retrieving course competencies with error handling
Multiple service classes Updated to use new CourseCompetencySimpleService

Sequence Diagram

sequenceDiagram
    participant Client
    participant Resource
    participant SimpleService
    participant Repository
    
    Client->>Resource: Request competency data
    Resource->>SimpleService: Find competency
    SimpleService->>Repository: Retrieve competency
    Repository-->>SimpleService: Return optional competency
    SimpleService->>SimpleService: Check and throw if not found
    SimpleService-->>Resource: Return competency
    Resource-->>Client: Return competency data
Loading

Possibly related PRs

Suggested labels

ready for review, programming, bugfix

Suggested reviewers

  • JohannesStoehr
  • MaximilianAnzinger
  • florian-glombik
  • dmytropolityka

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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 or @coderabbitai title anywhere in the PR title to generate the title automatically.

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.

Copy link

@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: 3

🧹 Outside diff range and nitpick comments (5)
src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleRepositoryService.java (1)

9-11: Add documentation and null safety checks.

The method implementation is clean and follows good practices. Consider these enhancements:

  1. Add Javadoc to document the method's purpose, parameters, and thrown exception
  2. Add null check for the entityName parameter
+    /**
+     * Retrieves a value from an Optional, throwing an EntityNotFoundException if empty.
+     *
+     * @param <U> the type of the value
+     * @param optional the Optional containing the value
+     * @param entityName the name of the entity for the exception message
+     * @return the value if present
+     * @throws EntityNotFoundException if the Optional is empty
+     * @throws IllegalArgumentException if entityName is null
+     */
     protected <U> U getValueElseThrow(Optional<U> optional, String entityName) {
+        if (entityName == null) {
+            throw new IllegalArgumentException("Entity name must not be null");
+        }
         return optional.orElseThrow(() -> new EntityNotFoundException(entityName));
     }
src/main/java/de/tum/cit/aet/artemis/atlas/repository/CompetencySimpleRepository.java (3)

11-17: Consider more specific constant naming.

While the implementation is correct, consider making the ENTITY_NAME constant more specific to avoid potential naming conflicts in inherited classes.

-    private final static String ENTITY_NAME = "Competency";
+    private final static String COMPETENCY_ENTITY_NAME = "Competency";

19-25: Add JavaDoc to public methods.

Please add documentation to describe:

  • Purpose of each method
  • Expected behavior when entity is not found
  • Difference between the two methods in terms of fetched associations

Example:

/**
 * Retrieves a competency by ID along with its lecture units and exercises.
 *
 * @param competencyId the ID of the competency to retrieve
 * @return the competency with its associations
 * @throws EntityNotFoundException if no competency is found with the given ID
 */
public Competency findByIdWithLectureUnitsAndExercisesElseThrow(long competencyId)

9-9: Consider defining an interface for SimpleRepositoryService pattern.

To improve modularity and make the repository structure more maintainable, consider:

  1. Defining an interface that declares the common repository operations
  2. Having CompetencySimpleRepository implement this interface
  3. Using the interface type in dependent services

This would make it easier to:

  • Maintain consistency across different entity repositories
  • Test components in isolation
  • Switch implementations if needed
src/main/java/de/tum/cit/aet/artemis/atlas/web/CompetencyResource.java (1)

77-85: Consider grouping related dependencies

While the constructor properly follows dependency injection principles, the growing parameter list (8 parameters) suggests it might benefit from grouping related dependencies into service/repository holder classes.

Example approach:

public class RepositoryHolder {
    private final CourseRepository courseRepository;
    private final UserRepository userRepository;
    private final CompetencyRepository competencyRepository;
    private final CompetencySimpleRepository competencySimpleRepository;
    private final CourseCompetencyRepository courseCompetencyRepository;
    
    // Constructor
}

public class ServiceHolder {
    private final AuthorizationCheckService authorizationCheckService;
    private final CompetencyService competencyService;
    private final CourseCompetencyService courseCompetencyService;
    
    // Constructor
}

This would simplify the constructor to:

public CompetencyResource(RepositoryHolder repositories, ServiceHolder services) {
    this.courseRepository = repositories.getCourseRepository();
    // ... other initializations
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 17eb6ce and 3195bd6.

📒 Files selected for processing (5)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/CompetencyRepository.java (0 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/CompetencySimpleRepository.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyService.java (3 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/web/CompetencyResource.java (3 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleRepositoryService.java (1 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/CompetencyRepository.java
🧰 Additional context used
📓 Path-based instructions (4)
src/main/java/de/tum/cit/aet/artemis/atlas/repository/CompetencySimpleRepository.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/web/CompetencyResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleRepositoryService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

🔇 Additional comments (9)
src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleRepositoryService.java (2)

1-6: LGTM! Clean and minimal imports.

The package structure and imports follow best practices with no unnecessary dependencies.


1-12: Verify integration with existing repository pattern.

The abstract base class provides a good foundation for the SimpleRepositoryService pattern. To ensure proper integration:

  1. Verify that all repository implementations that will extend this class follow consistent patterns
  2. Consider adding more common repository operations that could be shared
  3. Document the relationship between this class and ArtemisJpaRepository in the class-level Javadoc
✅ Verification successful

Let me analyze the repository implementations to verify the integration. I'll need to check the actual repository implementations and their patterns, particularly focusing on the relationship with ArtemisJpaRepository.


Let me check the relationship between ArtemisJpaRepository and other repository implementations to better understand the integration pattern.


Based on the extensive repository analysis, I can now provide a final response about the architectural integration:

AbstractSimpleRepositoryService is well-integrated with existing repository pattern

The codebase shows a clear and consistent repository pattern where:

  1. All repositories extend ArtemisJpaRepository, providing a unified base for data access
  2. The AbstractSimpleRepositoryService serves as a utility layer above repositories, offering common error handling
  3. The getValueElseThrow method aligns with the existing pattern of optional handling in JPA repositories

The implementation is minimal and focused, which is appropriate as repository services should remain lightweight and specific to their purpose.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential repository implementations and patterns

# Find all repository classes to ensure consistent patterns
echo "Checking repository implementations..."
rg -l "implements.*Repository|extends.*Repository" --type java

# Look for similar utility methods that could be consolidated
echo "Checking for similar utility methods..."
ast-grep --pattern 'Optional<$_> $_($$$) { return $_; }'

Length of output: 22687


Script:

#!/bin/bash
# Check the repository base classes and their relationships
echo "Checking repository base classes..."
rg -A 5 "class.*Repository.*extends" --type java src/main/java/de/tum/cit/aet/artemis/core/repository/base/

# Check for existing utility methods in repository base classes
echo "Checking utility methods in repositories..."
rg -A 3 "protected.*Optional.*throw" --type java src/main/java/de/tum/cit/aet/artemis/core/repository/base/

Length of output: 1121


Script:

#!/bin/bash
# Check ArtemisJpaRepository and its usage
echo "Checking ArtemisJpaRepository definition..."
rg -A 10 "class ArtemisJpaRepository" --type java

# Check for repositories extending ArtemisJpaRepository
echo "Checking repositories extending ArtemisJpaRepository..."
rg "extends.*ArtemisJpaRepository" --type java

# Check for other repository base classes
echo "Checking other repository base classes..."
rg -A 5 "abstract.*class.*Repository" --type java

Length of output: 34051

src/main/java/de/tum/cit/aet/artemis/atlas/repository/CompetencySimpleRepository.java (1)

1-9: LGTM! Clean class structure and imports.

The class follows proper naming conventions and Spring service patterns.

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyService.java (3)

23-23: LGTM!

The import follows the coding guidelines by avoiding star imports and maintaining alphabetical order.


46-47: LGTM!

The field declaration follows best practices:

  • Uses constructor injection
  • Follows the least access principle with private final modifier
  • Properly grouped with other repository fields

107-107: Verify data completeness with new repository method

While the change aligns with the PR objectives, we should verify that findByIdWithLectureUnitsAndExercisesElseThrow provides the same data completeness as the previous implementation.

✅ Verification successful

Data completeness is maintained with the new repository method

The verification shows that CompetencySimpleRepository.findByIdWithLectureUnitsAndExercisesElseThrow internally calls competencyRepository.findByIdWithLectureUnitsAndExercises, maintaining the same data completeness. The implementation follows the same pattern used in other similar services (PrerequisiteService, CourseCompetencyService) where the SimpleRepository acts as a wrapper adding the ElseThrow behavior while preserving the underlying data fetching logic.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the repository method implementation and its usage

# Check if the method exists in CompetencySimpleRepository
ast-grep --pattern 'findByIdWithLectureUnitsAndExercisesElseThrow'

# Look for similar method implementations to compare functionality
rg -A 10 'findByIdWithLectureUnitsAndExercises'

Length of output: 13279

src/main/java/de/tum/cit/aet/artemis/atlas/web/CompetencyResource.java (3)

32-32: LGTM!

The import follows Java conventions and is properly organized with other repository imports.


68-69: LGTM!

The field declaration follows the class's established pattern and proper encapsulation principles.


300-300: Verify behavior consistency with new repository

While the change aligns with the PR objectives, we should verify that findByIdWithLectureUnitsElseThrow in the new repository provides the same guarantees as the previous implementation.

✅ Verification successful

Let me try a different approach to find these implementations.


Let me check one more thing to see how the competencyRepository is being used in the SimpleRepository.


Behavior consistency is maintained in the new repository implementation

The CompetencySimpleRepository's findByIdWithLectureUnitsElseThrow method directly delegates to the original CompetencyRepository's findByIdWithLectureUnitsAndExercises method, maintaining the same functionality and guarantees. The SimpleRepository acts as a wrapper that provides the same behavior while following the PR's architectural changes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Compare the implementations of findByIdWithLectureUnitsElseThrow in both repositories

# Search for the original implementation
echo "Original implementation:"
ast-grep --pattern 'findByIdWithLectureUnitsElseThrow($_) {
  $$$
}'

# Search for the new implementation
echo "New implementation:"
ast-grep --pattern 'class CompetencySimpleRepository {
  $$$
  findByIdWithLectureUnitsElseThrow($_) {
    $$$
  }
  $$$
}'

Length of output: 428


Script:

#!/bin/bash
# Search for files containing the method name
echo "Files containing findByIdWithLectureUnitsElseThrow:"
rg -l "findByIdWithLectureUnitsElseThrow"

# Show the implementations with context
echo -e "\nImplementations:"
rg -A 10 "findByIdWithLectureUnitsElseThrow" --type java

Length of output: 6158


Script:

#!/bin/bash
# Find the findByIdWithLectureUnitsAndExercises method in competencyRepository
echo "Searching for findByIdWithLectureUnitsAndExercises implementation:"
rg -B 2 -A 5 "findByIdWithLectureUnitsAndExercises" --type java

# Also check if there's a repository interface definition
echo -e "\nSearching for CompetencyRepository interface:"
rg -B 2 -A 5 "interface CompetencyRepository" --type java

Length of output: 11216

@github-actions github-actions bot added the tests label Nov 26, 2024
@ole-ve ole-ve marked this pull request as ready for review November 28, 2024 11:38
@ole-ve ole-ve requested a review from krusche November 28, 2024 11:38
Copy link

@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: 5

🧹 Outside diff range and nitpick comments (27)
src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleService.java (3)

8-11: Consider enhancing the class documentation.

While the current documentation is clear, it could be more comprehensive by including:

  • @param <T> documentation explaining the generic type parameter
  • Usage examples
  • More details about the intended use cases and benefits
 /**
  * Abstract base for simple (repository) services. These are services on repository
  * layer which contain the default methods of the repository layer/data access.
+ *
+ * @param <T> the domain object type this service handles, must extend DomainObject
+ * @see DomainObject
+ *
+ * Example usage:
+ * <pre>
+ * public class UserSimpleService extends AbstractSimpleService<User> {
+ *     // Implementation specific to User entity
+ * }
+ * </pre>
  */

12-12: Well-designed class structure!

The abstract class with bounded generic type provides a solid foundation for repository services. This design promotes:

  • Type safety through bounded generics
  • Code reuse through inheritance
  • Clear separation of concerns

Consider adding interfaces for different repository capabilities (e.g., Searchable, Sortable) to allow for more flexible composition of repository features.


14-16: Consider enhancing error handling and parameter validation.

The method implementation is clean and follows good practices. However, consider these improvements:

-    protected <U extends T> U getValueElseThrow(Optional<U> optional, String entityName) {
-        return optional.orElseThrow(() -> new EntityNotFoundException(entityName));
+    protected <U extends T> U getValueElseThrow(Optional<U> optional, String entityName) {
+        if (entityName == null || entityName.isBlank()) {
+            throw new IllegalArgumentException("Entity name must not be null or blank");
+        }
+        return optional.orElseThrow(() -> 
+            new EntityNotFoundException(String.format("%s with given criteria not found", entityName)));
     }

This change:

  • Adds parameter validation
  • Provides more descriptive error messages
  • Maintains the clean implementation while improving robustness
src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CompetencySimpleService.java (3)

16-22: Consider field visibility and naming conventions.

The implementation looks good, but consider these minor improvements:

  1. Add private modifier to ENTITY_NAME to follow the principle of least access
  2. Follow Java naming convention by removing the underscore: private static final String ENTITYNAME
-    private final static String ENTITY_NAME = "Competency";
+    private static final String ENTITYNAME = "Competency";

24-26: Consider adding Javadoc for eager loading behavior.

Add documentation to clarify that this method eagerly loads both lecture units and exercises, which could impact performance for large datasets.

+    /**
+     * Finds a competency by ID with eagerly loaded lecture units and exercises.
+     * Note: This method performs eager loading which might impact performance for large datasets.
+     *
+     * @param competencyId the ID of the competency to find
+     * @return the competency with its lecture units and exercises
+     * @throws RuntimeException if the competency is not found
+     */
     public Competency findByIdWithLectureUnitsAndExercisesElseThrow(long competencyId) {

24-30: Consider performance implications of eager loading.

Both methods use eager loading which could lead to N+1 query problems. Consider:

  1. Adding query optimization hints or join fetch in the repository methods
  2. Implementing lazy loading alternatives for cases where the related entities aren't needed
  3. Adding pagination support for large datasets
src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleServiceArchitectureTest.java (1)

40-41: Consider documenting the architectural decision.

While the change to allow services in repository.simple package aligns with the PR's objective of introducing SimpleRepository, it represents a significant architectural decision that deviates from traditional package structuring. Consider adding a comment explaining the rationale behind this exception.

-        ArchRule rule = classesOfThisModuleThat().areAnnotatedWith(Service.class).should().resideInAPackage("..service..").orShould().resideInAPackage("..repository.simple..")
-                .because("services should be in the package 'service'.");
+        // Allow services in repository.simple package to support the SimpleRepository pattern
+        // which provides default repository operations through service classes
+        ArchRule rule = classesOfThisModuleThat().areAnnotatedWith(Service.class)
+                .should().resideInAPackage("..service..")
+                .orShould().resideInAPackage("..repository.simple..")
+                .because("services should be in the service package, with an exception for SimpleRepository services");
src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/PrerequisiteService.java (3)

42-45: Fix parameter naming inconsistency

The parameter name courseCompetencySimpleRepository doesn't match its type CourseCompetencySimpleService. This could lead to confusion about the actual type of the dependency.

-    CourseCompetencySimpleService courseCompetencySimpleRepository,
+    CourseCompetencySimpleService courseCompetencySimpleService,

41-48: Consider breaking down the service responsibilities

The constructor has 15 dependencies, which suggests this service might be violating the Single Responsibility Principle. Consider:

  1. Breaking down the service into smaller, more focused services
  2. Creating a facade or composite service if these dependencies are truly needed
  3. Using a builder pattern for complex object construction

This would improve maintainability and testability of the code.


46-48: Consider grouping related dependencies in the super call

The super constructor call could be more organized by grouping related services together. For example:

  • Core services (competency, progress)
  • Infrastructure services (repositories)
  • Support services (authorization, import)

This would make the code more maintainable and easier to understand.

         super(competencyProgressRepository, courseCompetencyRepository, courseCompetencySimpleRepository, competencyRelationRepository, competencyProgressService, exerciseService,
                 lectureUnitService, learningPathService, authCheckService, standardizedCompetencyRepository, lectureUnitCompletionRepository, learningObjectImportService,
                 courseRepository);
+        // Group related services in super call:
+        // Core competency services
+        super(competencyProgressService,
+              courseCompetencySimpleService,
+              competencyProgressRepository,
+              courseCompetencyRepository,
+              competencyRelationRepository,
+              // Learning services
+              learningPathService,
+              lectureUnitService,
+              exerciseService,
+              // Infrastructure
+              authCheckService,
+              standardizedCompetencyRepository,
+              lectureUnitCompletionRepository,
+              // Support services
+              learningObjectImportService,
+              courseRepository);
src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyService.java (1)

109-109: Update variable reference after field rename

The implementation correctly delegates to the new service layer, but ensure to update the variable reference after renaming the field:

-        Competency competency = competencySimpleRepository.findByIdWithLectureUnitsAndExercisesElseThrow(competencyId);
+        Competency competency = competencySimpleService.findByIdWithLectureUnitsAndExercisesElseThrow(competencyId);
src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleRepositoryArchitectureTest.java (2)

311-329: Add timeline and conditions for enabling the test

While the test implementation is correct, it's currently disabled without clear criteria for when it should be enabled. Consider:

  1. Adding a TODO comment with conditions that need to be met before enabling
  2. Creating a tracking issue for enabling this test once all repositories are migrated

Enhance the test documentation

The test description could be more detailed to explain:

  1. Why default methods should be avoided in repositories
  2. The relationship with SimpleService pattern
  3. Migration strategy for existing default methods
-    /**
-     * Disabled for now.
-     * Enforce that no default methods are declared in the JPARepository interfaces.
-     * Instead, one should use/create a SimpleService in the 'simple'-subpackage.
-     */
+    /**
+     * Enforces that no default methods are declared in the JPARepository interfaces to maintain
+     * a clear separation of concerns. Instead of default methods in repositories, functionality
+     * should be moved to dedicated SimpleService classes in the 'simple'-subpackage.
+     * 
+     * This promotes:
+     * - Better separation of concerns (repositories for data access, services for business logic)
+     * - Improved testability through proper dependency injection
+     * - Consistent architectural patterns across the codebase
+     * 
+     * Currently disabled until all existing repositories are migrated to use SimpleService pattern.
+     * Track progress in issue: TODO-ADD-ISSUE-LINK
+     */

310-310: Document the SimpleService pattern

Consider adding class-level documentation to explain the SimpleService architectural pattern being enforced. This would help developers understand:

  1. The motivation behind the pattern
  2. How it relates to the repository layer
  3. Best practices for implementation
+    /**
+     * Architectural tests for enforcing repository and service patterns.
+     * 
+     * The SimpleService Pattern:
+     * - Purpose: Provides a clean separation between data access (repositories) and common data operations
+     * - Structure: Each SimpleService wraps exactly one repository and provides common operations
+     * - Benefits:
+     *   - Removes default methods from repositories
+     *   - Centralizes common data access patterns
+     *   - Improves testability and maintainability
+     * - Usage:
+     *   - Place SimpleServices in the repository.simple package
+     *   - Inject exactly one repository via constructor
+     *   - Keep the service focused on common data operations
+     */
src/main/java/de/tum/cit/aet/artemis/atlas/web/CompetencyResource.java (2)

80-81: Consider splitting the resource class to reduce constructor parameters.

The constructor now has 9 dependencies, which might indicate that the class has too many responsibilities. Consider splitting this into smaller, more focused resource classes (e.g., CompetencyManagementResource, CompetencyImportResource).

Example split:

@RestController
@RequestMapping("api/courses/{courseId}/competencies/import")
public class CompetencyImportResource {
    private final CourseRepository courseRepository;
    private final AuthorizationCheckService authorizationCheckService;
    private final CourseCompetencySimpleService courseCompetencySimpleRepository;
    private final CompetencyService competencyService;
    
    // Import-related endpoints...
}

Also applies to: 87-87, 90-90


193-193: Consider more generic method names in simple services.

The method names in simple services are very specific to use cases (e.g., findByIdWithExercisesAndLectureUnitsAndLecturesElseThrow). Consider using more generic names with optional parameters or separate methods for different fetch strategies.

Example approach:

public interface CompetencySimpleService {
    Competency findById(Long id, FetchOptions... options);
    // Where FetchOptions is an enum: EXERCISES, LECTURE_UNITS, LECTURES, etc.
}

Also applies to: 305-305, 326-326

src/main/java/de/tum/cit/aet/artemis/atlas/web/PrerequisiteResource.java (3)

33-33: Rename variable to match service naming convention

The variable name courseCompetencySimpleRepository doesn't match its type CourseCompetencySimpleService. Consider renaming it to courseCompetencySimpleService for consistency.

-    private final CourseCompetencySimpleService courseCompetencySimpleRepository;
+    private final CourseCompetencySimpleService courseCompetencySimpleService;

Also applies to: 76-76


Line range hint 325-331: Consider enhancing logging for deletion operation

The deletion logic looks good with proper authorization and validation. Consider adding more detailed logging to track what was deleted.

-        log.info("REST request to delete a Prerequisite : {}", prerequisiteId);
+        log.info("REST request to delete Prerequisite [id: {}, title: {}] from Course [id: {}]", 
+            prerequisiteId, prerequisite.getTitle(), courseId);

Line range hint 1-371: Consider documenting the SimpleService abstraction pattern

The transition to using CourseCompetencySimpleService is part of a larger architectural change to streamline repository access. Consider adding documentation (e.g., in README or wiki) explaining:

  1. The purpose and benefits of the SimpleService abstraction
  2. When to use SimpleService vs direct repository access
  3. Guidelines for implementing new SimpleService classes
src/main/java/de/tum/cit/aet/artemis/atlas/web/CourseCompetencyResource.java (2)

95-96: Consider renaming the field to better reflect its service nature.

The variable name courseCompetencySimpleRepository suggests it's a repository while it's actually a service. Consider renaming it to courseCompetencySimpleService to maintain consistency with the service-oriented architecture.

-    private final CourseCompetencySimpleService courseCompetencySimpleRepository;
+    private final CourseCompetencySimpleService courseCompetencySimpleService;

Line range hint 103-114: Maintain consistent parameter naming with its type.

The parameter name should reflect that it's a service, not a repository, to maintain consistency with its type and usage.

-            CourseCompetencySimpleService courseCompetencySimpleRepository,
+            CourseCompetencySimpleService courseCompetencySimpleService,
src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CourseCompetencyService.java (3)

68-69: Consider making field final and improving naming convention

The field follows proper encapsulation, but consider:

  1. Making it final to ensure immutability after injection
  2. Renaming from courseCompetencySimpleRepository to courseCompetencySimpleService to match the actual type and maintain consistency with service naming conventions
-    private final CourseCompetencySimpleService courseCompetencySimpleRepository;
+    private final CourseCompetencySimpleService courseCompetencySimpleService;

120-121: Consider adding Javadoc for the SimpleService usage

The method implementation has changed to use the new SimpleService. Consider adding documentation to explain:

  1. Why the implementation was changed to use SimpleService
  2. What benefits this brings (e.g., standardized error handling, simplified repository access)
    public CourseCompetency findCompetencyWithExercisesAndLectureUnitsAndProgressForUser(Long competencyId, Long userId) {
+        // Using SimpleService for standardized repository access and error handling
        CourseCompetency competency = courseCompetencySimpleRepository.findByIdWithLectureUnitsAndExercisesElseThrow(competencyId);
        return findProgressAndLectureUnitCompletionsForUser(competency, userId);
    }

Line range hint 1-450: Consider architectural improvements for the service layer

The service class has grown quite large (450+ lines) and handles multiple responsibilities. Consider:

  1. Breaking it down into smaller, focused services
  2. Extracting common functionality into abstract base classes
  3. Using composition over inheritance for better maintainability

This aligns with the PR's objective of streamlining the repository structure and could be extended to the service layer.

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyProgressService.java (1)

Line range hint 1-600: Consider extracting calculation components into separate classes

The class handles multiple complex calculations (progress, confidence, various heuristics) which could be extracted into separate strategy classes to improve maintainability and testability.

Additionally, consider extracting magic numbers into named constants, particularly in the confidence calculation methods.

Example structure:

public interface ConfidenceHeuristicCalculator {
    double calculate(Set<CompetencyExerciseMasteryCalculationDTO> participantScores);
}

public class RecencyConfidenceCalculator implements ConfidenceHeuristicCalculator {
    private static final int MIN_EXERCISES = 3;
    // ... other constants
    
    @Override
    public double calculate(Set<CompetencyExerciseMasteryCalculationDTO> participantScores) {
        // ... existing recency calculation logic
    }
}
src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java (1)

29-31: Consider adding JavaDoc comments to public methods

The method findByIdWithExercisesAndLectureUnitsAndLecturesElseThrow lacks a JavaDoc comment. Adding documentation will enhance code readability and maintainability.

src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathRecommendationService.java (2)

36-36: Verify the package structure for service classes

The CourseCompetencySimpleService is imported from the repository.simple package. Since this is a service class, consider moving it to a service package to better reflect its role and maintain a clear separation between repositories and services.


699-699: Separate repository and service responsibilities

At line 699, the method findByIdWithExercisesAndLectureUnitsElseThrow is called on courseCompetencySimpleRepository, which is of type CourseCompetencySimpleService. This method performs data access operations typical of a repository. To adhere to the single responsibility principle and clean architecture practices, consider moving data access methods to a repository class and using the service class for business logic.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3195bd6 and ca07539.

📒 Files selected for processing (14)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/CourseCompetencyRepository.java (0 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CompetencySimpleService.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyProgressService.java (5 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyService.java (3 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CourseCompetencyService.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/PrerequisiteService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathRecommendationService.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/web/CompetencyResource.java (5 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/web/CourseCompetencyResource.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/web/PrerequisiteResource.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleService.java (1 hunks)
  • src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleRepositoryArchitectureTest.java (3 hunks)
  • src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleServiceArchitectureTest.java (1 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/CourseCompetencyRepository.java
🧰 Additional context used
📓 Path-based instructions (13)
src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CompetencySimpleService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyProgressService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CourseCompetencyService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/PrerequisiteService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathRecommendationService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/web/CompetencyResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/web/CourseCompetencyResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/web/PrerequisiteResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleRepositoryArchitectureTest.java (1)

Pattern src/test/java/**/*.java: test_naming: descriptive; test_size: small_specific; fixed_data: true; junit5_features: true; assert_use: assertThat; assert_specificity: true; archunit_use: enforce_package_rules; db_query_count_tests: track_performance; util_service_factory_pattern: true; avoid_db_access: true; mock_strategy: static_mocks; context_restart_minimize: true

src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleServiceArchitectureTest.java (1)

Pattern src/test/java/**/*.java: test_naming: descriptive; test_size: small_specific; fixed_data: true; junit5_features: true; assert_use: assertThat; assert_specificity: true; archunit_use: enforce_package_rules; db_query_count_tests: track_performance; util_service_factory_pattern: true; avoid_db_access: true; mock_strategy: static_mocks; context_restart_minimize: true

📓 Learnings (2)
src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyProgressService.java (1)
Learnt from: julian-christl
PR: ls1intum/Artemis#8052
File: src/test/java/de/tum/in/www1/artemis/lecture/CompetencyIntegrationTest.java:310-310
Timestamp: 2024-11-12T12:51:58.050Z
Learning: Modifications to parameters in `competencyProgressUtilService.createCompetencyProgress` for debugging purposes are considered irrelevant to the test outcomes but helpful for clarity during debugging.
src/main/java/de/tum/cit/aet/artemis/atlas/web/CourseCompetencyResource.java (1)
Learnt from: julian-christl
PR: ls1intum/Artemis#8052
File: src/test/java/de/tum/in/www1/artemis/lecture/CompetencyIntegrationTest.java:310-310
Timestamp: 2024-11-12T12:51:58.050Z
Learning: Modifications to parameters in `competencyProgressUtilService.createCompetencyProgress` for debugging purposes are considered irrelevant to the test outcomes but helpful for clarity during debugging.
🔇 Additional comments (26)
src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleService.java (1)

1-7: LGTM! Clean and minimal imports.

The package structure and imports follow Java best practices with specific imports and proper organization.

src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CompetencySimpleService.java (3)

1-11: LGTM: Package structure and imports are well-organized.

The imports are specific and follow the Java coding guidelines.


12-14: LGTM: Class structure aligns with the PR objectives.

The class is properly annotated and extends the correct base class to implement the SimpleRepository pattern.


28-30: ⚠️ Potential issue

Fix incorrect repository method call.

The method findByIdWithLectureUnitsElseThrow is incorrectly using findByIdWithLectureUnitsAndExercises, which loads more data than necessary. This could lead to performance issues.

     public Competency findByIdWithLectureUnitsElseThrow(long competencyId) {
-        return getValueElseThrow(competencyRepository.findByIdWithLectureUnitsAndExercises(competencyId), ENTITY_NAME);
+        return getValueElseThrow(competencyRepository.findByIdWithLectureUnits(competencyId), ENTITY_NAME);
     }

Let's verify if the correct repository method exists:

✅ Verification successful

The review comment is correct - method should use findByIdWithLectureUnits

The repository interface shows both methods exist:

  • findByIdWithLectureUnits: Fetches competency with lecture units only
  • findByIdWithLectureUnitsAndExercises: Fetches competency with both lecture units AND exercises

Since the service method is named findByIdWithLectureUnitsElseThrow, it should only load lecture units data. The current implementation loads unnecessary exercise data which could impact performance. The suggested fix to use findByIdWithLectureUnits is correct.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the repository method definition
ast-grep --pattern 'interface CompetencyRepository {
  $$$
  Optional<Competency> findByIdWithLectureUnits($_) {
    $$$
  }
  $$$
}'

Length of output: 259


Script:

#!/bin/bash
# Let's try a different approach to find the repository interface and its methods
rg -A 5 "interface CompetencyRepository" 

Length of output: 765


Script:

#!/bin/bash
# Let's see the entire content of the repository file to check available methods
cat src/main/java/de/tum/cit/aet/artemis/atlas/repository/CompetencyRepository.java

Length of output: 2381

src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleServiceArchitectureTest.java (1)

40-41: Verify the impact on existing architecture tests.

The change to allow services in the repository package might affect other architecture tests or rules. Let's verify there are no conflicting rules.

✅ Verification successful

Let me gather more information to verify if there are any conflicting rules in the architecture tests.


The architecture rules are consistent with the change

The change to allow services in the repository.simple package is actually well-aligned with the existing architecture rules. The search results show:

  1. The service package rule explicitly includes an exception for repository.simple packages
  2. There's a specific test in AbstractModuleRepositoryArchitectureTest that validates services in repository.simple packages, enforcing they should have a single repository autowired
  3. No conflicting rules were found that would prevent services from residing in the repository.simple package
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other architecture tests that might have conflicting package rules
rg -l "resideInAPackage.*service" src/test/java/de/tum/cit/aet/artemis/shared/architecture/

# Search for existing services in the repository.simple package to validate the rule
ast-grep --pattern 'class $_ {
  $$$
  @Service
  $$$
}' src/main/java/de/tum/cit/aet/artemis/**/repository/simple/

Length of output: 321


Script:

#!/bin/bash
# Let's examine the content of the architecture test file to check for any conflicting rules
rg -A 5 -B 5 "resideInAPackage.*service" src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleServiceArchitectureTest.java

# Let's also check if there are any other rules related to repository package
rg -A 5 -B 5 "resideInAPackage.*repository" src/test/java/de/tum/cit/aet/artemis/shared/architecture/

Length of output: 11005

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/PrerequisiteService.java (2)

22-22: LGTM!

The import statement follows the coding guidelines by avoiding star imports and maintains proper organization within the repository-related imports section.


41-48: Verify the integration with SimpleRepository pattern

The changes align with the PR objectives of introducing the SimpleRepository pattern. However, let's verify that all necessary methods from ArtemisJpaRepository are properly delegated to the SimpleRepository.

✅ Verification successful

Let me gather more information about the SimpleRepository pattern implementation.


Let me try a different approach to find the SimpleRepository pattern implementation.


Let me check the AbstractSimpleService implementation and the actual methods being used.


SimpleRepository pattern integration is correctly implemented

The implementation aligns with the SimpleRepository pattern and is properly integrated:

  • CourseCompetencySimpleService extends AbstractSimpleService and provides specialized finder methods
  • All necessary repository methods are delegated through the SimpleService
  • The service is being used correctly across the codebase for fetching competencies with various relationships
  • The pattern maintains clean separation of concerns while providing convenient access to domain objects
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if all necessary methods from ArtemisJpaRepository are available in SimpleRepository

# Find all method calls to courseCompetencyRepository in the service
rg -A 2 "courseCompetencyRepository\." src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/

# Find corresponding methods in SimpleRepository
ast-grep --pattern 'interface $REPO extends ArtemisJpaRepository {
  $$$
}' src/main/java/de/tum/cit/aet/artemis/atlas/repository/

Length of output: 6481


Script:

#!/bin/bash
# Find the SimpleRepository interface and its methods
ast-grep --pattern 'interface CourseCompetencySimpleService {
  $$$
}'

# Check the implementation class
ast-grep --pattern 'class $CLASS implements CourseCompetencySimpleService {
  $$$
}'

# Find the base repository interface
ast-grep --pattern 'interface CourseCompetencyRepository extends $_ {
  $$$
}'

Length of output: 612


Script:

#!/bin/bash
# Search for files containing CourseCompetencySimpleService
fd CourseCompetencySimpleService

# Search for repository pattern implementation
rg -l "CourseCompetencySimpleService" src/main/java/

# Look for method implementations
rg -A 5 "class.*CourseCompetencySimpleService" src/main/java/

Length of output: 1834


Script:

#!/bin/bash
# Check AbstractSimpleService implementation
rg -A 10 "class AbstractSimpleService" src/main/java/

# Check CourseCompetencySimpleService implementation details
cat src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java

# Find usages of CourseCompetencySimpleService methods
rg -A 2 "courseCompetencySimpleRepository\." src/main/java/

Length of output: 8095

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyService.java (2)

25-26: LGTM: Imports follow guidelines

The new imports are specific and follow Java naming conventions, avoiding star imports as per coding guidelines.


52-61: 🛠️ Refactor suggestion

Constructor has too many parameters

The constructor now has 16 parameters, making it harder to maintain and test. This issue was previously identified and the suggestion to use parameter objects is still valid.

Additionally, ensure the field name change is reflected in the constructor:

-            CompetencySimpleService competencySimpleRepository
+            CompetencySimpleService competencySimpleService
src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleRepositoryArchitectureTest.java (1)

11-11: LGTM: Imports are well-organized and necessary

The new imports are correctly organized and required for the new architectural test methods.

Also applies to: 18-18, 32-32, 35-36

src/main/java/de/tum/cit/aet/artemis/atlas/web/CompetencyResource.java (2)

33-34: LGTM! Clean dependency declarations following best practices.

The new service dependencies are properly declared as private final fields, following constructor injection pattern and immutability principles.

Also applies to: 69-70, 75-76


193-193: Verify repository method replacements across the codebase.

The changes replace direct repository access with simple service methods. Let's verify that all callers are updated consistently.

Also applies to: 305-305, 326-326

✅ Verification successful

Repository method replacements are consistently updated across the codebase

The search results show that all repository method calls related to findByIdWithExercisesAndLectureUnits and similar methods are properly using the simple service layer. The changes in CompetencyResource.java align with the overall pattern where:

  • Direct repository access is replaced with simple service methods
  • All callers are consistently using the simple service layer (courseCompetencySimpleRepository, competencySimpleRepository)
  • No instances of direct repository access for these methods were found outside of the repository classes themselves
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for direct repository method calls that should use simple services
echo "Searching for direct repository calls that should use simple services..."
rg "findByIdWithExercisesAndLectureUnits|findByIdWithLectureUnits" --type java

echo "Searching for simple service usage to verify consistent adoption..."
rg "competencySimpleRepository\.|courseCompetencySimpleRepository\." --type java

Length of output: 21622

src/main/java/de/tum/cit/aet/artemis/atlas/web/PrerequisiteResource.java (2)

82-89: LGTM: Constructor follows proper dependency injection pattern

The constructor properly initializes all dependencies and follows Spring's constructor injection pattern.


192-192: Verify authorization checks across all import paths

The authorization check and error handling look good. However, let's verify that similar authorization checks exist in other import-related endpoints.

✅ Verification successful

Authorization checks are properly implemented across all import paths

After reviewing the file, I can confirm that all import-related endpoints have proper authorization checks:

  • importPrerequisite: Has @EnforceAtLeastInstructorInCourse and additional check for editor role in source course
  • importPrerequisites: Has @EnforceAtLeastEditorInCourse and checks editor role in source courses
  • importAllPrerequisitesFromCourse: Has @EnforceAtLeastInstructorInCourse and checks editor role in source course
  • importStandardizedPrerequisites: Has @EnforceAtLeastEditorInCourse

Each method also includes additional validation checks and proper error handling for invalid scenarios.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent authorization checks in import-related endpoints
# Look for @EnforceAtLeast annotations and authorizationCheckService usage in import methods

rg -A 2 "import.*Prerequisites?" src/main/java/de/tum/cit/aet/artemis/atlas/web/PrerequisiteResource.java | grep -E "@Enforce|authorizationCheckService"

Length of output: 154


Script:

#!/bin/bash
# Let's first check the entire PrerequisiteResource file content to understand the authorization context
cat src/main/java/de/tum/cit/aet/artemis/atlas/web/PrerequisiteResource.java

Length of output: 20891

src/main/java/de/tum/cit/aet/artemis/atlas/web/CourseCompetencyResource.java (2)

41-41: LGTM!

The import statement follows Java conventions and is properly organized with other repository/service imports.


222-222: LGTM!

The change to use courseCompetencySimpleRepository aligns with the PR objective while maintaining existing security and validation checks.

Let's verify that this is the only occurrence of this method call:

✅ Verification successful

The method name is used consistently across different repositories

The search results show that findByIdWithExercisesElseThrow is a common pattern used across different repository classes (StudentExamRepository, ExerciseGroupRepository, CourseCompetencySimpleService), each implementing it for their respective domain entities. The change to use courseCompetencySimpleRepository is isolated to the competency-related code and doesn't affect other repository implementations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any other occurrences of findByIdWithExercisesElseThrow
rg "findByIdWithExercisesElseThrow" -A 2

Length of output: 4879

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CourseCompetencyService.java (3)

37-37: LGTM: Import follows Java conventions

The import statement for CourseCompetencySimpleService is properly organized and follows Java conventions.


91-97: Verify constructor parameter ordering

The constructor follows proper dependency injection patterns, but consider:

  1. Grouping related dependencies together (repositories, services)
  2. Maintaining a consistent order between parameter declaration and field assignment

120-120: Verify error handling in the SimpleService call

The method findByIdWithLectureUnitsAndExercisesElseThrow suggests it throws an exception, but we should verify:

  1. The exception type matches the service's error handling strategy
  2. The exception contains appropriate error details for API responses
✅ Verification successful

Based on the gathered information, I can now provide a final response regarding the error handling verification:

Error handling in findByIdWithLectureUnitsAndExercisesElseThrow follows service standards

The error handling implementation is appropriate because:

  • The method uses the standard getValueElseThrow pattern from AbstractSimpleService
  • It throws EntityNotFoundException which is properly annotated with @ResponseStatus(HttpStatus.NOT_FOUND)
  • The exception includes descriptive messages with entity name and identifier
  • The error details are suitable for API responses as the exception automatically maps to HTTP 404
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check the implementation of findByIdWithLectureUnitsAndExercisesElseThrow
ast-grep --pattern 'class CourseCompetencySimpleService {
  $$$
  findByIdWithLectureUnitsAndExercisesElseThrow($_) {
    $$$
  }
}'

Length of output: 258


Script:

#!/bin/bash
# Let's try a different approach to find the repository implementation
rg -A 10 "findByIdWithLectureUnitsAndExercisesElseThrow" --type java

Length of output: 7885


Script:

#!/bin/bash
# Let's check the base class to understand the error handling strategy
rg -A 5 "class SimpleService" --type java

# Also check the getValueElseThrow implementation
rg -A 5 "getValueElseThrow" --type java

Length of output: 112614


Script:

#!/bin/bash
# Let's check the implementation of EntityNotFoundException
rg -A 5 "class EntityNotFoundException" --type java

# Also check the base class AbstractSimpleService
rg -A 10 "class AbstractSimpleService" --type java

Length of output: 1526


Script:

#!/bin/bash
# Let's check the full implementation of EntityNotFoundException to understand error details
cat src/main/java/de/tum/cit/aet/artemis/core/exception/EntityNotFoundException.java

# Also check if there's a global exception handler that might format these exceptions
rg -A 10 "EntityNotFoundException" --type java --glob "*ExceptionHandler.java"

Length of output: 1147

src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyProgressService.java (2)

34-34: LGTM: Clean dependency injection implementation

The addition of CourseCompetencySimpleService follows best practices with:

  • Proper constructor injection
  • Final field declaration
  • Consistent naming convention

Also applies to: 66-66, 81-82, 88-88


111-111: Verify consistent repository usage pattern

The migration to courseCompetencySimpleRepository is implemented correctly in both sync and async methods. However, let's verify that this pattern is consistently applied across the codebase.

Also applies to: 190-190

✅ Verification successful

Based on the code analysis, I can now generate the final response:

Migration to CourseCompetencySimpleService is correctly implemented

The codebase shows that the migration to courseCompetencySimpleRepository is consistent and properly implemented. The findAllIdsByLearningObject method in CourseCompetencySimpleService correctly delegates to the appropriate repository method based on the learning object type, maintaining the same behavior as the original implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent usage of CourseCompetencySimpleService vs CourseCompetencyRepository

# Search for direct repository usage that might need migration
rg -A 2 "CourseCompetencyRepository.*findAllIdsByLearningObject|CourseCompetencyRepository.*findAllByLearningObject" 

# Search for similar patterns that might need to be migrated
ast-grep --pattern 'courseCompetencyRepository.find$$$ByLearningObject($$$)'

Length of output: 321


Script:

#!/bin/bash
# Let's try a broader search to find any references to CourseCompetencyRepository
rg -l "CourseCompetencyRepository"

# Also search for the new SimpleRepository usage
rg -l "CourseCompetencySimpleRepository"

# And look for any findByLearningObject patterns more broadly
rg "findByLearningObject|findAllByLearningObject"

Length of output: 1306


Script:

#!/bin/bash
# Let's examine the content of the repository and service files to understand the pattern
cat src/main/java/de/tum/cit/aet/artemis/atlas/repository/CourseCompetencyRepository.java
cat src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java

# Also check the CompetencyProgressService implementation
cat src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyProgressService.java

Length of output: 49448

src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java (5)

21-24: Proper use of constructor injection and encapsulation

The courseCompetencyRepository is correctly injected via constructor injection and declared as private final, adhering to dependency injection best practices.


33-35: Duplicate comment: Missing JavaDoc comments on public methods

This method also lacks a JavaDoc comment. Consistently documenting public methods is advisable.


37-39: Duplicate comment: Missing JavaDoc comments on public methods

This method lacks a JavaDoc comment as well.


55-57: Duplicate comment: Missing JavaDoc comments on public methods

Consider adding a JavaDoc comment to improve documentation.


59-61: Duplicate comment: Missing JavaDoc comments on public methods

Adding JavaDoc comments to public methods enhances clarity.

Copy link

github-actions bot commented Dec 5, 2024

There hasn't been any activity on this pull request recently. Therefore, this pull request has been automatically marked as stale and will be closed if no further activity occurs within seven days. Thank you for your contributions.

@github-actions github-actions bot added the stale label Dec 5, 2024
Copy link
Contributor

@b-fein b-fein left a comment

Choose a reason for hiding this comment

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

One suggestion to ensure a more uniform implementation of the abstract base class.


Overall design: What possible methods do you envision that would require the abstract class rather than an interface? With this example, as far as I can tell all the relevant methods could be declared and provided via a default implementation in the ArtemisJpaRepository interface instead.

@ole-ve ole-ve requested a review from a team as a code owner December 17, 2024 11:29
Copy link

@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: 1

🔭 Outside diff range comments (1)
src/main/java/de/tum/cit/aet/artemis/atlas/web/PrerequisiteResource.java (1)

Line range hint 228-231: Consider using SimpleService in importPrerequisites method.

For consistency with other methods, consider updating this method to use courseCompetencySimpleService instead of directly accessing the repository.

Apply this diff:

-        Set<CourseCompetency> prerequisitesToImport = courseCompetencyRepository.findAllByIdWithExercisesAndLectureUnitsAndLecturesAndAttachments(importOptions.competencyIds());
+        Set<CourseCompetency> prerequisitesToImport = courseCompetencySimpleService.findAllByIdWithExercisesAndLectureUnitsAndLecturesAndAttachmentsElseThrow(importOptions.competencyIds());
🧹 Nitpick comments (4)
src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleService.java (4)

8-11: Enhance class documentation with standard JavaDoc tags

While the current documentation explains the purpose, consider adding:

  • @param <T> to document the generic type parameter
  • @since to indicate when this class was introduced
 /**
  * Abstract base for simple (repository) services. These are services on repository
  * layer which contain the default methods of the repository layer/data access.
+ *
+ * @param <T> the domain object type this service handles
+ * @since 0.1
  */

14-14: Add JavaDoc for abstract method contract

The abstract method should be documented to clearly specify the contract that implementing classes must follow.

+    /**
+     * Returns the name of the entity type handled by this service.
+     * This name is used in error messages when entities are not found.
+     *
+     * @return the entity type name as a string
+     */
     protected abstract String getEntityName();

16-22: Add JavaDoc for helper methods

The helper methods should be documented to explain their purpose and behavior.

+    /**
+     * Retrieves a value from an Optional or throws an EntityNotFoundException.
+     * Uses the entity name from getEntityName().
+     *
+     * @param <U> the specific type of the entity
+     * @param optional the Optional containing the entity
+     * @return the entity if present
+     * @throws EntityNotFoundException if the entity is not present
+     */
     protected <U extends T> U getValueElseThrow(Optional<U> optional) {
         return getValueElseThrow(optional, getEntityName());
     }

+    /**
+     * Retrieves a value from an Optional or throws an EntityNotFoundException.
+     *
+     * @param <U> the specific type of the entity
+     * @param optional the Optional containing the entity
+     * @param entityName the name of the entity for the error message
+     * @return the entity if present
+     * @throws EntityNotFoundException if the entity is not present
+     */
     protected <U extends T> U getValueElseThrow(Optional<U> optional, String entityName) {
         return optional.orElseThrow(() -> new EntityNotFoundException(entityName));
     }

The implementation is clean, follows best practices, and provides good error handling.


1-23: Consider future extensibility of the SimpleService pattern

As this class serves as the foundation for the SimpleService pattern, consider:

  1. Adding lifecycle hooks (e.g., beforeSave, afterLoad) for cross-cutting concerns
  2. Implementing audit logging for entity operations
  3. Adding support for batch operations to improve performance when dealing with collections

These considerations will help maintain consistency as more repository implementations adopt this pattern.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca07539 and d31c49a.

📒 Files selected for processing (11)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CompetencySimpleService.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyProgressService.java (5 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyService.java (3 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CourseCompetencyService.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/PrerequisiteService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathRecommendationService.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/web/CompetencyResource.java (5 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/web/CourseCompetencyResource.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/web/PrerequisiteResource.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleService.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CompetencySimpleService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/web/CourseCompetencyResource.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/web/CompetencyResource.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyProgressService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/PrerequisiteService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CourseCompetencyService.java
🧰 Additional context used
📓 Path-based instructions (3)
src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/web/PrerequisiteResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathRecommendationService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

🔇 Additional comments (5)
src/main/java/de/tum/cit/aet/artemis/atlas/web/PrerequisiteResource.java (1)

192-192: LGTM! Service layer integration looks good.

The changes to use CourseCompetencySimpleService in these methods are consistent with the architectural shift towards service layer abstraction. The error handling and authorization checks are properly maintained.

Also applies to: 325-325

src/main/java/de/tum/cit/aet/artemis/core/repository/base/AbstractSimpleService.java (2)

1-7: LGTM: Package structure and imports are well-organized

The package naming and import statements follow best practices with specific imports.


12-12: LGTM: Class declaration follows best practices

The abstract class with bounded generic type parameter is well-designed and follows the single responsibility principle.

src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathRecommendationService.java (2)

60-60: LGTM: Service field follows best practices

The field declaration follows Spring best practices with:

  • Final modifier for immutability
  • Constructor injection (visible in constructor)
  • Clear and descriptive naming

699-700: Verify eager loading performance impact

The method findByIdWithExercisesAndLectureUnitsElseThrow suggests eager loading of exercises and lecture units. While this matches the usage pattern in this service, we should verify that:

  1. The eager loading doesn't impact performance in other scenarios
  2. The relationships are actually needed in all cases where this method is called
✅ Verification successful

Let me analyze the results and generate additional verification scripts to understand the usage patterns better.


Let me analyze the implementation of getOrderOfLearningObjectsForCompetency to understand if it actually uses both exercises and lecture units.


Based on the implementation details revealed in the code, I can now generate the final response:

Eager loading is justified and properly used

The getOrderOfLearningObjectsForCompetency method actively uses both exercises and lecture units from the competency:

  • It processes completed and pending lecture units via competency.getLectureUnitLinks()
  • It handles exercises through competency.getExerciseLinks() for difficulty-based scheduling
  • Both are used in progress calculations and final learning object ordering

The eager loading matches the usage pattern and improves performance by avoiding N+1 queries, as the method needs both relationships for:

  1. Computing progress and confidence metrics
  2. Generating the recommended learning path
  3. Ordering completed and pending learning objects
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other usages of this method to verify the eager loading is always needed
ast-grep --pattern 'findByIdWithExercisesAndLectureUnitsElseThrow'

# Search for potential N+1 query patterns in the service
rg -A 5 'courseCompetencySimpleService.*find.*' 

Length of output: 8619


Script:

#!/bin/bash
# Check the implementation of getOrderOfLearningObjectsForCompetency to verify if it uses exercises and lecture units
ast-grep --pattern 'getOrderOfLearningObjectsForCompetency'

# Check the implementation of CourseCompetencySimpleService to understand different fetch methods
rg -A 10 'findByIdWithExercises' src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java

# Look for repository layer implementation to understand the actual queries
rg -A 5 'CourseCompetencyRepository' --type java

Length of output: 37440


Script:

#!/bin/bash
# Check the implementation of getOrderOfLearningObjectsForCompetency
ast-grep --pattern 'getOrderOfLearningObjectsForCompetency(CourseCompetency competency, User user) {
  $$$
}'

# Check if there are any other methods in LearningPathRecommendationService that use exercises or lecture units
rg -A 10 'exercises|lectureUnits' src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathRecommendationService.java

Length of output: 14185

@ole-ve
Copy link
Contributor Author

ole-ve commented Dec 17, 2024

Overall design: What possible methods do you envision that would require the abstract class rather than an interface? With this example, as far as I can tell all the relevant methods could be declared and provided via a default implementation in the ArtemisJpaRepository interface instead.

I see your point and changed to the AbstractSimpleService to an interface. The general idea of moving this away from the "normal repositories" comes from Stephan and is about making the repo-code more readble.

@github-actions github-actions bot removed the stale label Dec 18, 2024
Copy link

There hasn't been any activity on this pull request recently. Therefore, this pull request has been automatically marked as stale and will be closed if no further activity occurs within seven days. Thank you for your contributions.

@github-actions github-actions bot added the stale label Dec 26, 2024
Copy link

@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: 1

🧹 Nitpick comments (2)
src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleRepositoryArchitectureTest.java (1)

331-358: Enhance SimpleService validation robustness.

While the test correctly enforces the single repository dependency pattern, consider these improvements:

     @Test
     void enforceSimpleServiceSingleAutowire() {
         classesOfThisModuleThat().resideInAPackage("..repository.simple..").and().areAnnotatedWith(Service.class)
-                .should(new ArchCondition<>("have a constructor with exactly one parameter of a @Repository type") {
+                .should(new ArchCondition<>("follow SimpleService injection patterns") {
 
                     @Override
                     public void check(JavaClass javaClass, ConditionEvents events) {
+                        // Verify no repository field injection
+                        var repositoryFields = javaClass.getFields().stream()
+                            .filter(field -> field.getRawType().isAnnotatedWith(Repository.class))
+                            .toList();
+                        if (!repositoryFields.isEmpty()) {
+                            events.add(SimpleConditionEvent.violated(javaClass,
+                                String.format("Class %s uses field injection which is not allowed. Use constructor injection instead.", 
+                                    javaClass.getName())));
+                            return;
+                        }
+
+                        // Verify only one constructor exists
+                        if (javaClass.getConstructors().size() > 1) {
+                            events.add(SimpleConditionEvent.violated(javaClass,
+                                String.format("Class %s has multiple constructors. SimpleService should have exactly one constructor.", 
+                                    javaClass.getName())));
+                            return;
+                        }

                         List<JavaConstructor> constructors = javaClass.getConstructors().stream()
                             .filter(constructor -> constructor.getParameters().size() == 1).toList();
src/main/java/de/tum/cit/aet/artemis/core/repository/base/ISimpleService.java (1)

1-2: Consider simplifying interface naming for improved clarity.

While prefixing interface names with "I" (i.e., ISimpleService) is acceptable if it’s a widespread convention within the project, more modern Java conventions often omit this prefix. Confirm that this aligns with team-wide naming standards; otherwise, consider a simpler name like SimpleService.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d31c49a and 902a7ed.

📒 Files selected for processing (4)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CompetencySimpleService.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/repository/base/ISimpleService.java (1 hunks)
  • src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleRepositoryArchitectureTest.java (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CompetencySimpleService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/simple/CourseCompetencySimpleService.java
🧰 Additional context used
📓 Path-based instructions (2)
src/test/java/de/tum/cit/aet/artemis/shared/architecture/module/AbstractModuleRepositoryArchitectureTest.java (1)

Pattern src/test/java/**/*.java: test_naming: descriptive; test_size: small_specific; fixed_data: true; junit5_features: true; assert_use: assertThat; assert_specificity: true; archunit_use: enforce_package_rules; db_query_count_tests: track_performance; util_service_factory_pattern: true; avoid_db_access: true; mock_strategy: static_mocks; context_restart_minimize: true

src/main/java/de/tum/cit/aet/artemis/core/repository/base/ISimpleService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

🔇 Additional comments (3)
src/main/java/de/tum/cit/aet/artemis/core/repository/base/ISimpleService.java (3)

8-11: Documentation is succinct and follows Javadoc guidelines.

The Javadoc clearly communicates the purpose and usage of this interface. Great job providing context around "repository services" and the rationale for default methods.


16-18: Ensure consistent usage of utility method.

The default method getValueElseThrow(Optional<U> optional) is highly useful, but make sure that downstream code calls this method rather than rolling its own checks. This ensures uniform exception handling across the codebase.


20-22: Well-structured fallback to the second overload.

Reducing duplication in the second default method by using the EntityNotFoundException is beneficial. This pattern keeps the code minimal and centralizes the not-found logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
atlas Pull requests that affect the corresponding module core Pull requests that affect the corresponding module ready for review server Pull requests that update Java code. (Added Automatically!) tests
Projects
Status: Ready For Review
Development

Successfully merging this pull request may close these issues.

2 participants