Skip to content

Commit

Permalink
Add SaveTo action to save to the database
Browse files Browse the repository at this point in the history
This allows for easy testing (compared to actions like
interacting with Spotify) and may be useful in the future
  • Loading branch information
Migwel authored and Migwel committed Dec 28, 2023
1 parent ff564a0 commit b07846d
Show file tree
Hide file tree
Showing 14 changed files with 271 additions and 1 deletion.
1 change: 1 addition & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* I'm not happy about the database package name, I should find a better one
7 changes: 7 additions & 0 deletions db/tables/Song.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
create sequence song_seq;
CREATE TABLE Song (
id BIGINT NOT NULL DEFAULT nextval('song_seq'),
artist VARCHAR,
title VARCHAR,
raw_data VARCHAR
);
15 changes: 15 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>dev.migwel.icyreader</groupId>
<artifactId>IcyReader</artifactId>
Expand All @@ -46,6 +50,17 @@
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>

<build>
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/dev/migwel/sts/database/DatabaseSaveService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package dev.migwel.sts.database;

import dev.migwel.sts.database.entities.Converter;
import dev.migwel.sts.exception.SaveToException;
import dev.migwel.sts.model.Song;
import dev.migwel.sts.service.SaveService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;

import javax.annotation.ParametersAreNonnullByDefault;

@ParametersAreNonnullByDefault
@Service
public class DatabaseSaveService implements SaveService {
private static final Logger log = LogManager.getLogger(DatabaseSaveService.class);

private final Converter converter;
private final SongRepository songRepository;

public DatabaseSaveService(Converter converter, SongRepository songRepository) {
this.converter = converter;
this.songRepository = songRepository;
}

@Override
public void save(Song song) {
dev.migwel.sts.database.entities.Song entitySong = converter.convert(song);
try {
songRepository.save(entitySong);
} catch (DataAccessException e) {
log.warn("Could not persist song", e);
throw new SaveToException("Cold not persist song: " + e.getMessage());
}
}
}
12 changes: 12 additions & 0 deletions src/main/java/dev/migwel/sts/database/SongRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dev.migwel.sts.database;

import dev.migwel.sts.database.entities.Song;
import org.springframework.data.repository.Repository;

import java.util.Optional;

public interface SongRepository extends Repository<Song, Long> {
Song save(Song song);

Optional<Song> findByArtistAndTitle(String artist, String title);
}
18 changes: 18 additions & 0 deletions src/main/java/dev/migwel/sts/database/entities/Converter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package dev.migwel.sts.database.entities;

import org.springframework.stereotype.Component;

import javax.annotation.ParametersAreNonnullByDefault;

@Component
@ParametersAreNonnullByDefault
public class Converter {
public Song convert(dev.migwel.sts.model.Song model) {
return new Song(model.artist(), model.title(), model.rawData());
}

public dev.migwel.sts.model.Song convert(Song entity) {
return new dev.migwel.sts.model.Song(
entity.getArtist(), entity.getTitle(), entity.getRawData());
}
}
68 changes: 68 additions & 0 deletions src/main/java/dev/migwel/sts/database/entities/Song.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package dev.migwel.sts.database.entities;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;

@Entity
public class Song {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "song_generator")
@SequenceGenerator(name = "song_generator", sequenceName = "song_seq", allocationSize = 1)
private Long id;

private String artist;
private String title;
private String rawData;

public Song() {
// Needed for Spring JPA
}

public Song(Long id, String artist, String title, String rawData) {
this.id = id;
this.artist = artist;
this.title = title;
this.rawData = rawData;
}

public Song(String artist, String title, String rawData) {
this.artist = artist;
this.title = title;
this.rawData = rawData;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getArtist() {
return artist;
}

public void setArtist(String artist) {
this.artist = artist;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getRawData() {
return rawData;
}

public void setRawData(String rawData) {
this.rawData = rawData;
}
}
11 changes: 11 additions & 0 deletions src/main/java/dev/migwel/sts/exception/SaveFromException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.migwel.sts.exception;

public class SaveFromException extends RuntimeException {
public SaveFromException(String message) {
super(message);
}

public SaveFromException(String message, Throwable cause) {
super(message, cause);
}
}
11 changes: 11 additions & 0 deletions src/main/java/dev/migwel/sts/exception/SaveToException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.migwel.sts.exception;

public class SaveToException extends RuntimeException {
public SaveToException(String message) {
super(message);
}

public SaveToException(String message, Throwable cause) {
super(message, cause);
}
}
7 changes: 7 additions & 0 deletions src/main/java/dev/migwel/sts/service/SaveService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package dev.migwel.sts.service;

import dev.migwel.sts.model.Song;

public interface SaveService {
void save(Song song);
}
5 changes: 4 additions & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@

spring.datasource.url=jdbc:postgresql://localhost:5432/savethatsong
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=org.postgresql.Driver
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package dev.migwel.sts.database;

import dev.migwel.sts.model.Song;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Optional;

@SpringBootTest
class DatabaseSaveServiceManualTest {

private final SongRepository songRepository;
private final DatabaseSaveService saveService;

@Autowired
DatabaseSaveServiceManualTest(SongRepository songRepository, DatabaseSaveService saveService) {
this.songRepository = songRepository;
this.saveService = saveService;
}

@Test
void save_success() {
Song song = new Song("artist", "title", "artist - title");
saveService.save(song);
Optional<dev.migwel.sts.database.entities.Song> persistedSong =
songRepository.findByArtistAndTitle("artist", "title");
Assertions.assertTrue(persistedSong.isPresent());
}
}
43 changes: 43 additions & 0 deletions src/test/java/dev/migwel/sts/database/DatabaseSaveServiceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package dev.migwel.sts.database;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

import dev.migwel.sts.database.entities.Converter;
import dev.migwel.sts.exception.SaveToException;
import dev.migwel.sts.model.Song;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.dao.InvalidDataAccessResourceUsageException;

@ExtendWith(MockitoExtension.class)
class DatabaseSaveServiceTest {

@Mock private SongRepository songRepository;
@Spy private Converter converter;
@InjectMocks private DatabaseSaveService saveService;

@Test
void save_success() {
Song song = new Song("artist", "title", "artist - title");
dev.migwel.sts.database.entities.Song entitySong =
new dev.migwel.sts.database.entities.Song(1L, "artist", "title", "artist - title");
doReturn(entitySong).when(songRepository).save(any());
saveService.save(song);
}

@Test
void save_persistFailure() {
doThrow(new InvalidDataAccessResourceUsageException("Could not write song"))
.when(songRepository)
.save(any());
Song song = new Song("artist", "title", "artist - title");
assertThrows(SaveToException.class, () -> saveService.save(song));
}
}
5 changes: 5 additions & 0 deletions src/test/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=username
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

0 comments on commit b07846d

Please sign in to comment.