Skip to content

Commit

Permalink
feat: constraint instances (#101)
Browse files Browse the repository at this point in the history
* feat: constraint instances

* feat: constraint signatures

* WIP

* feat: constraint instances

* feat: constraint signatures

* WIP

* Pushing this because I need the code on another device

* Added a method to the SpecificationBuilder class (It has yet to be tested)
Removed useless test class

* Fixed the constraint arguments filter

* Refactored SpecificationBuilder

* Removed test code from controller

* Fixed the create method of the constraint instance service
Adjusted and added other tests
Added an annotation to suppress warnings in SpecificationBuilder

* Update server/src/main/java/de/uftos/services/ConstraintInstanceService.java

Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>

* Fixed typo
Changed method name
Converted a String[] to List<String>

* Fixed import

* Renamed method
Javadoc

* Suppressing tests javadoc

---------

Co-authored-by: Marco <marcodemartino23@gmail.com>
  • Loading branch information
danieldietzler and SuperMarcomen authored Jul 17, 2024
1 parent 65fd068 commit 103a3e3
Show file tree
Hide file tree
Showing 12 changed files with 399 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import de.uftos.dto.ConstraintInstanceRequestDto;
import de.uftos.entities.ConstraintInstance;
import de.uftos.entities.ConstraintSignature;
import de.uftos.repositories.database.ConstraintInstanceRepository;
import de.uftos.repositories.database.ConstraintSignatureRepository;
import de.uftos.services.ConstraintInstanceService;
import de.uftos.services.ConstraintSignatureService;
import java.util.Optional;
Expand All @@ -26,6 +28,8 @@
public class ConstraintController {
private final ConstraintSignatureService constraintSignatureService;
private final ConstraintInstanceService constraintInstanceService;
private final ConstraintInstanceRepository constraintInstanceRepository;
private final ConstraintSignatureRepository constraintSignatureRepository;

/**
* Creates the constraint controller.
Expand All @@ -35,9 +39,13 @@ public class ConstraintController {
*/
@Autowired
public ConstraintController(ConstraintSignatureService constraintSignatureService,
ConstraintInstanceService constraintInstanceService) {
ConstraintInstanceService constraintInstanceService,
ConstraintInstanceRepository constraintInstanceRepository,
ConstraintSignatureRepository constraintSignatureRepository) {
this.constraintSignatureService = constraintSignatureService;
this.constraintInstanceService = constraintInstanceService;
this.constraintInstanceRepository = constraintInstanceRepository;
this.constraintSignatureRepository = constraintSignatureRepository;
}

/**
Expand Down
14 changes: 13 additions & 1 deletion server/src/main/java/de/uftos/entities/ConstraintArgument.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package de.uftos.entities;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.util.Objects;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* The database table for constraint arguments.
Expand All @@ -14,14 +18,22 @@
*/
@Entity(name = "constraint_argument")
@Data
@NoArgsConstructor
public class ConstraintArgument {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String id;

private String name;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "constraint_parameter_id", nullable = false)
private ConstraintParameter constraintParameter;
private String value;


public ConstraintArgument(String name, String value) {
this.value = value;
}

@Override
public boolean equals(Object other) {
if (this == other) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class ConstraintInstance {
private ConstraintSignature signature;

@NotNull
@OneToMany(cascade = CascadeType.REMOVE)
@OneToMany(cascade = CascadeType.ALL)
private List<ConstraintArgument> arguments;

@NotNull
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package de.uftos.entities;

import com.fasterxml.jackson.annotation.JsonIgnore;
import de.uftos.dto.ResourceType;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import java.util.List;
import java.util.Objects;
import lombok.Data;

Expand All @@ -23,6 +26,10 @@ public class ConstraintParameter {

private String parameterName;

@JsonIgnore
@OneToMany(mappedBy = "constraintParameter")
private List<ConstraintArgument> constraintArguments;

@Enumerated(EnumType.STRING)
private ResourceType parameterType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ public class ConstraintSignature {
private RewardPenalize defaultType;

@NotNull
@OneToMany
@OneToMany(cascade = CascadeType.ALL)
private List<ConstraintParameter> parameters;

@JsonIgnore
@OneToMany(mappedBy = "signature", cascade = CascadeType.REMOVE)
@OneToMany(mappedBy = "signature", cascade = CascadeType.ALL)
private List<ConstraintInstance> instances;

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package de.uftos.repositories.database;

import de.uftos.entities.ConstraintInstance;
import de.uftos.entities.ConstraintSignature;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.ListCrudRepository;
import org.springframework.data.repository.ListPagingAndSortingRepository;

Expand All @@ -9,5 +12,7 @@
*/
public interface ConstraintInstanceRepository
extends ListPagingAndSortingRepository<ConstraintInstance, String>,
ListCrudRepository<ConstraintInstance, String> {
ListCrudRepository<ConstraintInstance, String>, JpaSpecificationExecutor<ConstraintInstance> {

Optional<ConstraintInstance> findBySignatureAndId(ConstraintSignature signature, String id);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.uftos.repositories.database;

import de.uftos.entities.ConstraintSignature;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.ListCrudRepository;
import org.springframework.data.repository.ListPagingAndSortingRepository;

Expand All @@ -9,5 +10,5 @@
*/
public interface ConstraintSignatureRepository
extends ListPagingAndSortingRepository<ConstraintSignature, String>,
ListCrudRepository<ConstraintSignature, String> {
ListCrudRepository<ConstraintSignature, String>, JpaSpecificationExecutor<ConstraintSignature> {
}
131 changes: 126 additions & 5 deletions server/src/main/java/de/uftos/services/ConstraintInstanceService.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
package de.uftos.services;

import de.uftos.dto.ConstraintInstanceRequestDto;
import de.uftos.dto.ResourceType;
import de.uftos.entities.ConstraintArgument;
import de.uftos.entities.ConstraintInstance;
import de.uftos.entities.ConstraintParameter;
import de.uftos.entities.ConstraintSignature;
import de.uftos.repositories.database.ConstraintInstanceRepository;
import de.uftos.repositories.database.ConstraintSignatureRepository;
import de.uftos.repositories.database.GradeRepository;
import de.uftos.repositories.database.LessonRepository;
import de.uftos.repositories.database.RoomRepository;
import de.uftos.repositories.database.StudentGroupRepository;
import de.uftos.repositories.database.StudentRepository;
import de.uftos.repositories.database.SubjectRepository;
import de.uftos.repositories.database.TagRepository;
import de.uftos.repositories.database.TeacherRepository;
import de.uftos.repositories.database.TimeslotRepository;
import de.uftos.utils.SpecificationBuilder;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
Expand All @@ -17,15 +36,46 @@
@Service
public class ConstraintInstanceService {
private final ConstraintInstanceRepository repository;
private final ConstraintSignatureRepository signatureRepository;
private final GradeRepository gradeRepository;
private final LessonRepository lessonRepository;
private final RoomRepository roomRepository;
private final StudentRepository studentRepository;
private final StudentGroupRepository studentGroupRepository;
private final SubjectRepository subjectRepository;
private final TagRepository tagRepository;
private final TeacherRepository teacherRepository;
private final TimeslotRepository timeslotRepository;


/**
* Creates a constraintInstance service.
*
* @param repository the repository for accessing the constraintInstance entity.
*/
@Autowired
public ConstraintInstanceService(ConstraintInstanceRepository repository) {
public ConstraintInstanceService(ConstraintInstanceRepository repository,
ConstraintSignatureRepository signatureRepository,
GradeRepository gradeRepository,
LessonRepository lessonRepository,
RoomRepository roomRepository,
StudentRepository studentRepository,
StudentGroupRepository studentGroupRepository,
SubjectRepository subjectRepository,
TagRepository tagRepository,
TeacherRepository teacherRepository,
TimeslotRepository timeslotRepository) {
this.repository = repository;
this.signatureRepository = signatureRepository;
this.gradeRepository = gradeRepository;
this.lessonRepository = lessonRepository;
this.roomRepository = roomRepository;
this.studentRepository = studentRepository;
this.studentGroupRepository = studentGroupRepository;
this.subjectRepository = subjectRepository;
this.tagRepository = tagRepository;
this.teacherRepository = teacherRepository;
this.timeslotRepository = timeslotRepository;
}

/**
Expand All @@ -36,7 +86,36 @@ public ConstraintInstanceService(ConstraintInstanceRepository repository) {
* @return the newly created constraint instance.
*/
public ConstraintInstance create(String signatureId, ConstraintInstanceRequestDto request) {
return null;
ConstraintSignature signature = this.signatureRepository.findById(signatureId)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));

if (signature.getParameters().size() != request.arguments().size()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
}

for (ConstraintParameter parameter : signature.getParameters()) {
String value = request.arguments().get(parameter.getParameterName());
if (value == null || value.isEmpty()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"Parameter %s could not be found".formatted(parameter.getParameterName()));
}

boolean exists = this.getResourceTypeMapping(value).get(parameter.getParameterType());
if (!exists) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"%s with id %s could not be found".formatted(parameter.getParameterName(),
parameter.getId()));
}
}

ConstraintInstance instance = new ConstraintInstance();
List<ConstraintArgument> arguments = request.arguments().entrySet().stream()
.map(item -> new ConstraintArgument(item.getKey(), item.getValue())).toList();
instance.setArguments(arguments);
instance.setSignature(signature);
instance.setType(request.type());

return this.repository.save(instance);
}

/**
Expand All @@ -48,7 +127,12 @@ public ConstraintInstance create(String signatureId, ConstraintInstanceRequestDt
*/
public Page<ConstraintInstance> get(String signatureId, Pageable pageable,
Optional<String> argument) {
return this.repository.findAll(pageable);
Specification<ConstraintInstance> specification = new SpecificationBuilder<ConstraintInstance>()
.andJoinEquals(signatureId, "signature", "name")
.optionalAndJoinLikeIgnoreCase(argument, "arguments", "value")
.build();

return this.repository.findAll(specification, pageable);
}

/**
Expand All @@ -59,7 +143,10 @@ public Page<ConstraintInstance> get(String signatureId, Pageable pageable,
* @throws ResponseStatusException if the ID doesn't have a corresponding constraintInstance.
*/
public ConstraintInstance getById(String signatureId, String id) {
return this.repository.findById(id)
ConstraintSignature signature = this.signatureRepository.findById(signatureId)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));

return this.repository.findBySignatureAndId(signature, id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
}

Expand All @@ -72,7 +159,15 @@ public ConstraintInstance getById(String signatureId, String id) {
*/
public ConstraintInstance update(String signatureId, String id,
ConstraintInstanceRequestDto request) {
return null;
ConstraintInstance instance = this.getById(signatureId, id);

List<ConstraintArgument> arguments = request.arguments().entrySet().stream()
.map(item -> new ConstraintArgument(item.getKey(), item.getValue())).toList();

instance.setArguments(arguments);
instance.setType(request.type());

return this.repository.save(instance);
}

/**
Expand All @@ -82,6 +177,32 @@ public ConstraintInstance update(String signatureId, String id,
* @param id the ID of the constraintInstance.
*/
public void delete(String signatureId, String id) {
ConstraintInstance instance = this.getById(signatureId, id);

this.repository.delete(instance);
}


private Map<ResourceType, Boolean> getResourceTypeMapping(String id) {
return Map.ofEntries(
new AbstractMap.SimpleEntry<>(ResourceType.GRADE,
this.gradeRepository.findById(id).isPresent()),
new AbstractMap.SimpleEntry<>(ResourceType.LESSON,
this.lessonRepository.findById(id).isPresent()),
new AbstractMap.SimpleEntry<>(ResourceType.ROOM,
this.roomRepository.findById(id).isPresent()),
new AbstractMap.SimpleEntry<>(ResourceType.STUDENT,
this.studentRepository.findById(id).isPresent()),
new AbstractMap.SimpleEntry<>(ResourceType.STUDENT_GROUP,
this.studentGroupRepository.findById(id).isPresent()),
new AbstractMap.SimpleEntry<>(ResourceType.SUBJECT,
this.subjectRepository.findById(id).isPresent()),
new AbstractMap.SimpleEntry<>(ResourceType.TAG,
this.tagRepository.findById(id).isPresent()),
new AbstractMap.SimpleEntry<>(ResourceType.TEACHER,
this.teacherRepository.findById(id).isPresent()),
new AbstractMap.SimpleEntry<>(ResourceType.TIMESLOT,
this.timeslotRepository.findById(id).isPresent())
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
Expand Down Expand Up @@ -35,7 +36,11 @@ public ConstraintSignatureService(ConstraintSignatureRepository repository) {
* @return the page of the entries fitting the parameters.
*/
public Page<ConstraintSignature> get(Pageable pageable, Optional<String> name) {
return this.repository.findAll(pageable);
Specification<ConstraintSignature> specification = Specification.where(
((root, query, cb) -> cb.like(cb.lower(root.get("id")),
"%" + name.orElse("").toLowerCase() + "%")));

return this.repository.findAll(specification, pageable);
}

/**
Expand Down
Loading

0 comments on commit 103a3e3

Please sign in to comment.