feat: add resource entity, repository, and service

This commit is contained in:
dualfroz committed 2026-08-24 16:38:57 +02:00
1 parent 567219134a
commit f00085ba22
3 files changed
+205

No files matched your search

@@ -0,0 +1,112 @@
package com.slotline.resource;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
import java.time.Instant;
@Entity
@Table(name = "resource")
public class Resource {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "organization_id", nullable = false)
private Long organizationId;
@Column(name = "group_id")
private Long groupId;
@Column(nullable = false, length = 128)
private String name;
@Column(length = 512)
private String description;
@Column(name = "zone_id", nullable = false, length = 64)
private String zoneId;
@Column(name = "buffer_minutes", nullable = false)
private int bufferMinutes;
@Column(name = "created_at", nullable = false)
private Instant createdAt;
@Version
private Long version;
protected Resource() {
}
public Resource(Long organizationId, String name, String description, Instant createdAt) {
this.organizationId = organizationId;
this.name = name;
this.description = description;
this.zoneId = "UTC";
this.bufferMinutes = 0;
this.createdAt = createdAt;
}
public Long getId() {
return id;
}
public Long getOrganizationId() {
return organizationId;
}
public Long getGroupId() {
return groupId;
}
public void setGroupId(Long groupId) {
this.groupId = groupId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getZoneId() {
return zoneId;
}
public void setZoneId(String zoneId) {
this.zoneId = zoneId;
}
public int getBufferMinutes() {
return bufferMinutes;
}
public void setBufferMinutes(int bufferMinutes) {
this.bufferMinutes = bufferMinutes;
}
public Instant getCreatedAt() {
return createdAt;
}
public Long getVersion() {
return version;
}
}
@@ -0,0 +1,25 @@
package com.slotline.resource;
import jakarta.persistence.LockModeType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;
public interface ResourceRepository extends JpaRepository<Resource, Long> {
List<Resource> findAllByOrderByCreatedAtDesc();
List<Resource> findByOrganizationIdOrderByCreatedAtDesc(Long organizationId);
List<Resource> findByGroupIdOrderByCreatedAtDesc(Long groupId);
Optional<Resource> findByIdAndOrganizationId(Long id, Long organizationId);
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select r from Resource r where r.id = :id")
Optional<Resource> findByIdForBooking(@Param("id") Long id);
}
@@ -0,0 +1,68 @@
package com.slotline.resource;
import com.slotline.common.NotFoundException;
import com.slotline.resource.dto.ResourceRequest;
import com.slotline.resource.dto.ResourceResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.List;
@Service
public class ResourceService {
private final ResourceRepository resources;
public ResourceService(ResourceRepository resources) {
this.resources = resources;
}
@Transactional
public ResourceResponse create(Long organizationId, ResourceRequest request) {
Resource resource = new Resource(organizationId, request.name(), request.description(), Instant.now());
applyPolicy(resource, request);
return ResourceResponse.from(resources.save(resource));
}
@Transactional(readOnly = true)
public List<ResourceResponse> findAll(Long organizationId) {
return resources.findByOrganizationIdOrderByCreatedAtDesc(organizationId).stream()
.map(ResourceResponse::from)
.toList();
}
@Transactional(readOnly = true)
public ResourceResponse findById(Long organizationId, Long id) {
return ResourceResponse.from(require(organizationId, id));
}
@Transactional
public ResourceResponse update(Long organizationId, Long id, ResourceRequest request) {
Resource resource = require(organizationId, id);
resource.setName(request.name());
resource.setDescription(request.description());
applyPolicy(resource, request);
return ResourceResponse.from(resource);
}
private void applyPolicy(Resource resource, ResourceRequest request) {
if (request.zoneId() != null && !request.zoneId().isBlank()) {
resource.setZoneId(request.zoneId());
}
if (request.bufferMinutes() != null) {
resource.setBufferMinutes(request.bufferMinutes());
}
}
@Transactional
public void delete(Long organizationId, Long id) {
resources.delete(require(organizationId, id));
}
@Transactional(readOnly = true)
public Resource require(Long organizationId, Long id) {
return resources.findByIdAndOrganizationId(id, organizationId)
.orElseThrow(() -> new NotFoundException("Resource " + id + " not found"));
}
}