diff --git a/README.md b/README.md
index a4add1a0..bad794cb 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
-
+
@@ -35,8 +35,9 @@ Recommended IntelliJ plugin: [JS GraphQL](https://plugins.jetbrains.com/plugin/8
1. Import as a Gradle project into your favourite IDE
2. Start the MySQL Database or run the docker-compose file `docker-compose up -d` (you may need to add `sudo` to this command)
-3. Run `BooksApiApplication.java`
-4. Go to `localhost:8080/graphiql`
+3. Set the active Spring profile to dev (see how to do this in [IntelliJ](https://github.com/Project-Books/books-api/wiki/Change-active-Spring-profile-in-IntelliJ))
+4. Run `BooksApiApplication.java`
+5. Go to `localhost:8080/graphiql`
Sample query:
```graphql
@@ -44,13 +45,11 @@ Sample query:
findAllBooks {
title
authors {
- firstName
- lastName
+ fullName
}
genre
isbn13
yearOfPublication
- publisher
format
}
}
diff --git a/src/main/java/com/karankumar/booksapi/BooksApiApplication.java b/src/main/java/com/karankumar/booksapi/BooksApiApplication.java
index 1241912f..6b09f0d4 100644
--- a/src/main/java/com/karankumar/booksapi/BooksApiApplication.java
+++ b/src/main/java/com/karankumar/booksapi/BooksApiApplication.java
@@ -20,14 +20,18 @@
import com.karankumar.booksapi.model.BookFormat;
import com.karankumar.booksapi.model.BookGenre;
import com.karankumar.booksapi.model.Language;
-import com.karankumar.booksapi.model.PublisherName;
+import com.karankumar.booksapi.model.Publisher;
import com.karankumar.booksapi.repository.AuthorRepository;
import com.karankumar.booksapi.repository.BookRepository;
+import com.karankumar.booksapi.repository.PublisherRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
+import java.util.List;
+import java.util.Set;
+
@SpringBootApplication
public class BooksApiApplication {
public static void main(String[] args) {
@@ -36,53 +40,56 @@ public static void main(String[] args) {
@Bean
public CommandLineRunner populateData(AuthorRepository authorRepository,
- BookRepository bookRepository) {
+ BookRepository bookRepository,
+ PublisherRepository publisherRepository) {
return args -> {
- Author author = new Author("J.K. Rowling");
- author.setAbout("A fantastic author");
- authorRepository.save(author);
+ Publisher publisher = new Publisher("Bloomsbury");
+ publisherRepository.save(publisher);
- Book book1 = new Book(
+ Book book1 = createBook(
"Harry Potter and the Philosopher's stone",
- new Author[] {author},
- Language.ENGLISH,
"Philosopher's stone blurb",
- BookGenre.FANTASY,
- BookFormat.PAPERBACK
+ 1997,
+ "9781408810545"
);
- book1.setYearOfPublication(1997);
- book1.setIsbn13("9781408810545");
- book1.setPublisher(PublisherName.BLOOMSBURY);
bookRepository.save(book1);
+ publisher.addBook(book1);
- Book book2 = new Book(
+ Book book2 = createBook(
"Harry Potter and the Chamber of Secrets",
- new Author[] {author},
- Language.ENGLISH,
"Chamber of secrets blurb",
- BookGenre.FANTASY,
- BookFormat.PAPERBACK
+ 1998,
+ "1234567898765"
);
- book2.setIsbn13("1234567898765");
- book2.setGenre(BookGenre.FANTASY);
- book2.setPublisher(PublisherName.BLOOMSBURY);
- book2.setFormat(BookFormat.PAPERBACK);
bookRepository.save(book2);
- Author author2 = new Author("J.R.R. Tolkien");
- author2.setAbout("Another fantastic author");
- authorRepository.save(author2);
- Book book3 = new Book(
+ Book book3 = createBook(
"The Hobbit",
- new Author[] {author, author2},
- Language.ENGLISH,
"Hobbit blurb",
- BookGenre.FANTASY,
- BookFormat.PAPERBACK
+ 1937,
+ "1234567898761"
);
- book3.setYearOfPublication(1937);
- book3.setPublisher(PublisherName.HARPER_COLLINS);
bookRepository.save(book3);
+ Author author2 = new Author("J.R.R. Tolkien", Set.of(book3));
+ author2.setAbout("Another fantastic author");
+ authorRepository.save(author2);
+
+ Author author = new Author("J.K. Rowling", Set.of(book1, book2, book3));
+ author.setAbout("A fantastic author");
+ authorRepository.save(author);
};
}
+
+ private Book createBook(String title, String blurb, int yearOfPublication, String isbn13) {
+ Book book = new Book(
+ title,
+ Language.ENGLISH,
+ blurb,
+ BookGenre.FANTASY,
+ BookFormat.PAPERBACK
+ );
+ book.setYearOfPublication(yearOfPublication);
+ book.setIsbn13(isbn13);
+ return book;
+ }
}
diff --git a/src/main/java/com/karankumar/booksapi/model/Author.java b/src/main/java/com/karankumar/booksapi/model/Author.java
index e900faaa..7b463ef6 100644
--- a/src/main/java/com/karankumar/booksapi/model/Author.java
+++ b/src/main/java/com/karankumar/booksapi/model/Author.java
@@ -48,7 +48,18 @@ public class Author {
private String about;
- public Author(@NonNull String fullName) {
+ public Author(@NonNull String fullName, @NonNull Set books) {
this.fullName = fullName;
+ books.forEach(this::addBook);
+ }
+
+ public void addBook(@NonNull Book book) {
+ books.add(book);
+ book.getAuthors().add(this);
+ }
+
+ public void removeBook(@NonNull Book book) {
+ books.remove(book);
+ book.getAuthors().remove(this);
}
}
diff --git a/src/main/java/com/karankumar/booksapi/model/Book.java b/src/main/java/com/karankumar/booksapi/model/Book.java
index 1a723fc4..e0a8c410 100644
--- a/src/main/java/com/karankumar/booksapi/model/Book.java
+++ b/src/main/java/com/karankumar/booksapi/model/Book.java
@@ -30,8 +30,10 @@
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
+import javax.persistence.OneToMany;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
@Entity
@@ -70,23 +72,21 @@ public class Book {
@Column(nullable = false)
private String blurb;
- private PublisherName publisher;
+ @ManyToMany(mappedBy = "books", fetch = FetchType.LAZY)
+ private Set publishers = new HashSet<>();
@Column(nullable = false)
private BookFormat format;
- public Book(@NonNull String title, @NonNull Author[] authors, @NonNull Language language,
- @NonNull String blurb, @NonNull BookGenre genre, @NonNull BookFormat format) {
+ @OneToMany(mappedBy = "book")
+ private List bookSeriesMapping;
+
+ public Book(@NonNull String title, @NonNull Language language, @NonNull String blurb,
+ @NonNull BookGenre genre, @NonNull BookFormat format) {
this.title = title;
- Arrays.stream(authors).forEach(this::addAuthor);
this.language = language;
this.blurb = blurb;
this.genre = genre;
this.format = format;
}
-
- public void addAuthor(@NonNull Author author) {
- authors.add(author);
- author.getBooks().add(this);
- }
}
diff --git a/src/main/java/com/karankumar/booksapi/model/BookSeries.java b/src/main/java/com/karankumar/booksapi/model/BookSeries.java
new file mode 100644
index 00000000..bd0cea9b
--- /dev/null
+++ b/src/main/java/com/karankumar/booksapi/model/BookSeries.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 Karan Kumar
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see .
+ */
+
+package com.karankumar.booksapi.model;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.NonNull;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import java.util.List;
+
+@Entity
+@Getter
+@Setter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class BookSeries {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Setter(AccessLevel.NONE)
+ private Long id;
+
+ @Column(nullable = false, name = "series_name")
+ private String seriesName;
+
+ @OneToMany(mappedBy = "bookSeries")
+ private List bookSeriesMapping;
+
+ public BookSeries(@NonNull String seriesName){
+ this.seriesName = seriesName;
+ }
+}
diff --git a/src/main/java/com/karankumar/booksapi/model/BookSeriesMapping.java b/src/main/java/com/karankumar/booksapi/model/BookSeriesMapping.java
new file mode 100644
index 00000000..0f519f85
--- /dev/null
+++ b/src/main/java/com/karankumar/booksapi/model/BookSeriesMapping.java
@@ -0,0 +1,60 @@
+/*
+The book project lets a user keep track of different books they would like to read, are currently reading, have read or did not finish.
+Copyright (C) 2020 Karan Kumar
+
+This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with this program.
+If not, see .
+*/
+
+package com.karankumar.booksapi.model;
+
+import lombok.*;
+
+import javax.persistence.*;
+
+@Getter
+@Setter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Entity
+@Table(
+ name="Book_To_BookSeries_Mapping",
+ uniqueConstraints = {
+ @UniqueConstraint(
+ name = "UK_bookSeriesId_bookId",
+ columnNames = {"book_series_id","book_id"}
+ ),
+ @UniqueConstraint(
+ name = "UK_bookSeriesId_serialNumber",
+ columnNames = {"book_series_id","serial_number"}
+ )
+ }
+)
+public class BookSeriesMapping {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Setter(AccessLevel.NONE)
+ private Long id;
+
+ @ManyToOne(optional = false)
+ private BookSeries bookSeries;
+
+ @ManyToOne(optional = false)
+ private Book book;
+
+ @Column(nullable = false, name = "serial_number")
+ private Integer seriesPosition;
+
+ public BookSeriesMapping(@NonNull BookSeries bookSeries, @NonNull Book bookInSeries,
+ @NonNull Integer seriesPosition) {
+ this.bookSeries = bookSeries;
+ this.book = bookInSeries;
+ this.seriesPosition = seriesPosition;
+ }
+}
diff --git a/src/main/java/com/karankumar/booksapi/model/Publisher.java b/src/main/java/com/karankumar/booksapi/model/Publisher.java
new file mode 100644
index 00000000..05f38e2b
--- /dev/null
+++ b/src/main/java/com/karankumar/booksapi/model/Publisher.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 Karan Kumar
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see .
+ */
+package com.karankumar.booksapi.model;
+
+import lombok.AccessLevel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+import lombok.Setter;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import java.util.HashSet;
+import java.util.Set;
+
+@Entity
+@Data
+@EqualsAndHashCode()
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class Publisher {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Setter(AccessLevel.NONE)
+ private Long id;
+
+ private String name;
+
+ @ManyToMany(fetch = FetchType.LAZY)
+ @JoinTable(
+ name = "publisher_book",
+ joinColumns = @JoinColumn(name = "publisher_id"),
+ inverseJoinColumns = @JoinColumn(name = "book_id")
+ )
+ private Set books = new HashSet<>();
+
+ public Publisher(@NonNull String name) {
+ this.name = name;
+ }
+
+ public void addBook(@NonNull Book book) {
+ books.add(book);
+ book.getPublishers().add(this);
+ }
+}
diff --git a/src/main/java/com/karankumar/booksapi/model/PublisherName.java b/src/main/java/com/karankumar/booksapi/model/PublisherName.java
deleted file mode 100644
index ab43afa6..00000000
--- a/src/main/java/com/karankumar/booksapi/model/PublisherName.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2021 Karan Kumar
- *
- * This program is free software: you can redistribute it and/or modify it under the terms of the
- * GNU General Public License as published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along with this program.
- * If not, see .
- */
-
-package com.karankumar.booksapi.model;
-
-/**
- * The publisher name represents the name displayed on the book (not necessarily the name of the
- * company). This can also include imprints
- */
-public enum PublisherName {
- // This should be kept in alphabetical order
- ALLEN_LANE("Allen Lane"),
- AMISTAD_PRESS("Amistad Press"),
- BLOOMSBURY("Bloomsbury"),
- CAMBRIDGE_UNIVERSITY_PRESS("Cambridge University Press"),
- DK("DK"),
- GRANTA("Granta"),
- HARLEQUIN_ENTERPRISES("Harlequin Enterprises"),
- HARPER_COLLINS("HarperCollins"),
- HARPER_ONE("HarperOne"),
- LITTLE_BROWN("Little, Brown"),
- MICHAEL_JOSEPH("Michael Joseph"),
- OXFORD_UNIVERSITY_PRESS("Oxford University Press"),
- PELICAN_BOOKS("Pelican Books"),
- PENGUIN_BOOKS("Penguin Books"),
- PRENTICE_HALL("Prentice Hall"),
- VINTAGE("Vintage"),
- WH_ALLEN("WH Allen");
-
- private final String name;
-
- PublisherName(String name) {
- this.name = name;
- }
-
- @Override
- public String toString() {
- return name;
- }
-}
diff --git a/src/main/java/com/karankumar/booksapi/mutations/AuthorMutation.java b/src/main/java/com/karankumar/booksapi/mutations/AuthorMutation.java
index d82a497b..cc4a5f08 100644
--- a/src/main/java/com/karankumar/booksapi/mutations/AuthorMutation.java
+++ b/src/main/java/com/karankumar/booksapi/mutations/AuthorMutation.java
@@ -21,6 +21,8 @@
import com.netflix.graphql.dgs.DgsData;
import graphql.schema.DataFetchingEnvironment;
+import java.util.HashSet;
+
@DgsComponent
public class AuthorMutation {
private final AuthorService authorService;
@@ -32,6 +34,6 @@ public AuthorMutation(AuthorService authorService) {
@DgsData(parentType = "Mutation", field = "addAuthor")
public Author addAuthor(DataFetchingEnvironment dataFetchingEnvironment) {
String fullName = dataFetchingEnvironment.getArgument("fullName");
- return authorService.save(new Author(fullName));
+ return authorService.save(new Author(fullName, new HashSet<>()));
}
}
diff --git a/src/main/java/com/karankumar/booksapi/mutations/BookMutation.java b/src/main/java/com/karankumar/booksapi/mutations/BookMutation.java
index 6e65ae65..08e34bd9 100644
--- a/src/main/java/com/karankumar/booksapi/mutations/BookMutation.java
+++ b/src/main/java/com/karankumar/booksapi/mutations/BookMutation.java
@@ -30,6 +30,7 @@
@DgsComponent
public class BookMutation {
private final BookService bookService;
+ private static final String NOT_FOUND_ERROR_MESSAGE = "Book not found";
public BookMutation(BookService bookService) {
this.bookService = bookService;
@@ -44,7 +45,7 @@ public Book addIsbn13(DataFetchingEnvironment dataFetchingEnvironment)
);
if (optionalBook.isEmpty()) {
- throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Book not found");
+ throw new ResponseStatusException(HttpStatus.NOT_FOUND, NOT_FOUND_ERROR_MESSAGE);
}
String isbn13 = dataFetchingEnvironment.getArgument("isbn13");
@@ -52,4 +53,20 @@ public Book addIsbn13(DataFetchingEnvironment dataFetchingEnvironment)
book.setIsbn13(isbn13);
return bookService.save(optionalBook.get());
}
+
+ @DgsData(parentType = "Mutation", field = "deleteBook")
+ public Book deleteBook(DataFetchingEnvironment dataFetchingEnvironment) {
+ Long id = dataFetchingEnvironment.getArgument("bookId");
+ if (id == null) {
+ throw new ResponseStatusException(HttpStatus.NOT_FOUND, NOT_FOUND_ERROR_MESSAGE);
+ }
+
+ Optional book = bookService.findById(id);
+ if (book.isEmpty()) {
+ throw new ResponseStatusException(HttpStatus.NOT_FOUND, NOT_FOUND_ERROR_MESSAGE);
+ }
+
+ bookService.deleteBook(id);
+ return book.get();
+ }
}
diff --git a/src/main/java/com/karankumar/booksapi/repository/BookRepository.java b/src/main/java/com/karankumar/booksapi/repository/BookRepository.java
index 02538887..1530c5be 100644
--- a/src/main/java/com/karankumar/booksapi/repository/BookRepository.java
+++ b/src/main/java/com/karankumar/booksapi/repository/BookRepository.java
@@ -16,6 +16,8 @@
package com.karankumar.booksapi.repository;
import com.karankumar.booksapi.model.Book;
+import com.karankumar.booksapi.model.BookSeries;
+import com.karankumar.booksapi.model.BookSeriesMapping;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
@@ -32,4 +34,11 @@ public interface BookRepository extends CrudRepository {
Book findBookByIsbn13(String isbn13);
Book findByTitleIgnoreCase(String title);
+
+ @Query("SELECT a.bookSeries FROM BookSeriesMapping a WHERE a.book = ?1")
+ List getAllBookSeriesForBook(Book book);
+
+ @Query("SELECT a.seriesPosition FROM BookSeriesMapping a WHERE a.book = ?1 AND a.bookSeries = ?2")
+ Integer getBookPositionInBookSeries(Book book, BookSeries bookSeries);
+
}
diff --git a/src/main/java/com/karankumar/booksapi/repository/BookSeriesMappingRepository.java b/src/main/java/com/karankumar/booksapi/repository/BookSeriesMappingRepository.java
new file mode 100644
index 00000000..35766441
--- /dev/null
+++ b/src/main/java/com/karankumar/booksapi/repository/BookSeriesMappingRepository.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 Karan Kumar
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see .
+ */
+
+package com.karankumar.booksapi.repository;
+
+import com.karankumar.booksapi.model.Book;
+import com.karankumar.booksapi.model.BookSeries;
+import com.karankumar.booksapi.model.BookSeriesMapping;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+
+import java.util.List;
+
+public interface BookSeriesMappingRepository extends CrudRepository {
+ @Query("SELECT a.book FROM BookSeriesMapping a WHERE a.bookSeries = ?1")
+ List getAllBooksByBookSeries(BookSeries bookSeries);
+}
diff --git a/src/main/java/com/karankumar/booksapi/repository/BookSeriesRepository.java b/src/main/java/com/karankumar/booksapi/repository/BookSeriesRepository.java
new file mode 100644
index 00000000..7a167b33
--- /dev/null
+++ b/src/main/java/com/karankumar/booksapi/repository/BookSeriesRepository.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 Karan Kumar
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see .
+ */
+
+package com.karankumar.booksapi.repository;
+
+import com.karankumar.booksapi.model.BookSeries;
+import org.springframework.data.repository.CrudRepository;
+
+public interface BookSeriesRepository extends CrudRepository {
+}
diff --git a/src/main/java/com/karankumar/booksapi/repository/PublisherRepository.java b/src/main/java/com/karankumar/booksapi/repository/PublisherRepository.java
new file mode 100644
index 00000000..f1d04318
--- /dev/null
+++ b/src/main/java/com/karankumar/booksapi/repository/PublisherRepository.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 Karan Kumar
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see .
+ */
+
+package com.karankumar.booksapi.repository;
+
+import com.karankumar.booksapi.model.Publisher;
+import org.springframework.data.repository.CrudRepository;
+
+public interface PublisherRepository extends CrudRepository {
+}
diff --git a/src/main/java/com/karankumar/booksapi/service/BookService.java b/src/main/java/com/karankumar/booksapi/service/BookService.java
index bb6ea847..435a8065 100644
--- a/src/main/java/com/karankumar/booksapi/service/BookService.java
+++ b/src/main/java/com/karankumar/booksapi/service/BookService.java
@@ -43,6 +43,7 @@ public Book save(@NonNull Book book) throws InvalidISBN10Exception, InvalidISBN1
}
return bookRepository.save(book);
}
+
private boolean isIsbn10Invalid(@NonNull String isbn10) {
return !(new ISBNValidator().isValidISBN10(isbn10));
}
@@ -75,4 +76,8 @@ public Book findBookByIsbn13(@NonNull String isbn13) {
public Book findByTitle(@NonNull String title) {
return bookRepository.findByTitleIgnoreCase(title);
}
+
+ public void deleteBook(@NonNull Long id) {
+ bookRepository.deleteById(id);
+ }
}
diff --git a/src/main/resources/application.properties b/src/main/resources/application-dev.properties
similarity index 65%
rename from src/main/resources/application.properties
rename to src/main/resources/application-dev.properties
index eb331bee..a2448c44 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application-dev.properties
@@ -1,12 +1,10 @@
spring.banner.image.location=banner.txt
spring.jpa.open-in-view=false
-spring.jpa.hibernate.ddl-auto=validate
+spring.jpa.hibernate.ddl-auto=create
spring.datasource.url = jdbc:mysql://localhost:3307/booksapi
spring.datasource.username = dbuser
spring.datasource.password = dbpassword
spring.flyway.enabled = true
-
-#graphql.servlet.maxQueryDepth=3 TODO: raise to a sensible number (this is set too low)
diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties
new file mode 100644
index 00000000..e1bf9781
--- /dev/null
+++ b/src/main/resources/application-prod.properties
@@ -0,0 +1,7 @@
+spring.jpa.open-in-view=false
+
+spring.datasource.url = jdbc:mysql://localhost:3307/booksapi
+spring.datasource.username = dbuser
+spring.datasource.password = dbpassword
+
+spring.flyway.enabled = true
diff --git a/src/main/resources/db/migration/V0010_CREATE_BOOK_TO_BOOK_SERIES_MAPPING.sql b/src/main/resources/db/migration/V0010_CREATE_BOOK_TO_BOOK_SERIES_MAPPING.sql
new file mode 100644
index 00000000..fb8a36d2
--- /dev/null
+++ b/src/main/resources/db/migration/V0010_CREATE_BOOK_TO_BOOK_SERIES_MAPPING.sql
@@ -0,0 +1,15 @@
+CREATE TABLE `book_to_book_series_mapping`
+(
+ `id` bigint NOT NULL AUTO_INCREMENT,
+ `serial_number` int NOT NULL,
+ `book_id` bigint NOT NULL,
+ `book_series_id` bigint NOT NULL,
+
+ PRIMARY KEY (`id`),
+
+ UNIQUE KEY `UK_bookSeriesId_bookId` (`book_series_id`,`book_id`),
+ UNIQUE KEY `UK_bookSeriesId_serialNumber` (`book_series_id`,`serial_number`),
+ CONSTRAINT `FK_book_id` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`),
+ CONSTRAINT `FK_book_series_id` FOREIGN KEY (`book_series_id`) REFERENCES `book_series` (`id`)
+
+) ENGINE=InnoDB
\ No newline at end of file
diff --git a/src/main/resources/db/migration/V008__CREATE_PUBLISHER.sql b/src/main/resources/db/migration/V008__CREATE_PUBLISHER.sql
new file mode 100644
index 00000000..84a38ac6
--- /dev/null
+++ b/src/main/resources/db/migration/V008__CREATE_PUBLISHER.sql
@@ -0,0 +1,5 @@
+CREATE TABLE publisher
+(
+ id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(255) NOT NULL UNIQUE
+) ENGINE = InnoDB
diff --git a/src/main/resources/db/migration/V009_CREATE_BOOKSERIES.sql b/src/main/resources/db/migration/V009_CREATE_BOOKSERIES.sql
new file mode 100644
index 00000000..2c887b28
--- /dev/null
+++ b/src/main/resources/db/migration/V009_CREATE_BOOKSERIES.sql
@@ -0,0 +1,8 @@
+CREATE TABLE `book_series`
+(
+ `id` BIGINT NOT NULL AUTO_INCREMENT,
+ `series_name` varchar(255) NOT NULL,
+
+ PRIMARY KEY (`id`)
+
+) ENGINE=InnoDB
\ No newline at end of file
diff --git a/src/main/resources/db/migration/V009__CREATE_PUBLISHER_BOOK.sql b/src/main/resources/db/migration/V009__CREATE_PUBLISHER_BOOK.sql
new file mode 100644
index 00000000..95a46a93
--- /dev/null
+++ b/src/main/resources/db/migration/V009__CREATE_PUBLISHER_BOOK.sql
@@ -0,0 +1,8 @@
+CREATE TABLE publisher_book
+(
+ publisher_id BIGINT NOT NULL,
+ book_id BIGINT NOT NULL,
+ PRIMARY KEY (publisher_id, book_id),
+ FOREIGN KEY (publisher_id) REFERENCES publisher (id),
+ FOREIGN KEY (book_id) REFERENCES book (id)
+) ENGINE = InnoDB
diff --git a/src/main/resources/db/migration/V010__RENAME_PUBLISHER_BOOK_CONSTRAINTS.sql b/src/main/resources/db/migration/V010__RENAME_PUBLISHER_BOOK_CONSTRAINTS.sql
new file mode 100644
index 00000000..08c3c6b8
--- /dev/null
+++ b/src/main/resources/db/migration/V010__RENAME_PUBLISHER_BOOK_CONSTRAINTS.sql
@@ -0,0 +1,7 @@
+ALTER TABLE publisher_book
+DROP FOREIGN KEY FK6buft2dj1d6ig7hekbx7c0ysp,
+ADD CONSTRAINT publisher_book_publisher_id FOREIGN KEY (publisher_id) REFERENCES publisher (id);
+
+ALTER TABLE publisher_book
+DROP FOREIGN KEY FKnro4ab7u1j42osd4sehbkptrr,
+ADD CONSTRAINT publisher_book_book_id FOREIGN KEY (book_id) REFERENCES book (id);
diff --git a/src/main/resources/schema/book.graphqls b/src/main/resources/schema/book.graphqls
index 9e311109..3a401bce 100644
--- a/src/main/resources/schema/book.graphqls
+++ b/src/main/resources/schema/book.graphqls
@@ -7,7 +7,7 @@ type Book {
genre: Genre
isbn13: String
yearOfPublication: Int
- publisher: PublisherName
+ publisher: Publisher
format: BookFormat
}
diff --git a/src/main/resources/schema/mutation.graphqls b/src/main/resources/schema/mutation.graphqls
index 722e8c60..6e5bc24a 100644
--- a/src/main/resources/schema/mutation.graphqls
+++ b/src/main/resources/schema/mutation.graphqls
@@ -1,6 +1,7 @@
type Mutation {
addIsbn13(bookId: Long!, isbn13: String): Book
addAuthor(fullName: String!): Author
+ deleteBook(bookId: Long!): Book
}
scalar Long
diff --git a/src/main/resources/schema/publisher.graphqls b/src/main/resources/schema/publisher.graphqls
new file mode 100644
index 00000000..dae3a47a
--- /dev/null
+++ b/src/main/resources/schema/publisher.graphqls
@@ -0,0 +1,5 @@
+type Publisher {
+ id: ID!
+ name: String!
+ books: [Book!]
+}
diff --git a/src/main/resources/schema/publishername.graphqls b/src/main/resources/schema/publishername.graphqls
deleted file mode 100644
index d8186bcc..00000000
--- a/src/main/resources/schema/publishername.graphqls
+++ /dev/null
@@ -1,19 +0,0 @@
-enum PublisherName {
- ALLEN_LANE,
- AMISTAD_PRESS,
- BLOOMSBURY,
- CAMBRIDGE_UNIVERSITY_PRESS,
- DK,
- GRANTA,
- HARLEQUIN_ENTERPRISES,
- HARPER_COLLINS,
- HARPER_ONE,
- LITTLE_BROWN,
- MICHAEL_JOSEPH,
- OXFORD_UNIVERSITY_PRESS,
- PELICAN_BOOKS,
- PENGUIN_BOOKS,
- PRENTICE_HALL,
- VINTAGE,
- WH_ALLEN
-}
diff --git a/src/test/java/com/karankumar/booksapi/model/AuthorTest.java b/src/test/java/com/karankumar/booksapi/model/AuthorTest.java
index b3edbc51..d70cac57 100644
--- a/src/test/java/com/karankumar/booksapi/model/AuthorTest.java
+++ b/src/test/java/com/karankumar/booksapi/model/AuthorTest.java
@@ -15,6 +15,7 @@
package com.karankumar.booksapi.model;
+import org.assertj.core.util.Sets;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -24,7 +25,9 @@
class AuthorTest {
@Test
@DisplayName("throw a Null Pointer Exception on an attempt to create with a null name")
- void notAcceptNullFirstName() {
- assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> new Author(null));
+ void notAcceptNullName() {
+ assertThatExceptionOfType(NullPointerException.class).isThrownBy(() ->
+ new Author(null, Sets.newHashSet())
+ );
}
}
diff --git a/src/test/java/com/karankumar/booksapi/model/BookSeriesMappingTest.java b/src/test/java/com/karankumar/booksapi/model/BookSeriesMappingTest.java
new file mode 100644
index 00000000..f63aa466
--- /dev/null
+++ b/src/test/java/com/karankumar/booksapi/model/BookSeriesMappingTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 Karan Kumar
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see .
+ */
+
+package com.karankumar.booksapi.model;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
+@DisplayName("Book Series Mapping should")
+class BookSeriesMappingTest {
+
+ @Test
+ @DisplayName("throw a Null Pointer Exception on an attempt to create with Null Serial Number")
+ void notAcceptNullSerialNumber() {
+ BookSeries bookSeries = new BookSeries("Harry Potter Series");
+ Book book = createBook();
+
+ assertThatExceptionOfType(NullPointerException.class)
+ .isThrownBy(() -> new BookSeriesMapping(bookSeries, book, null));
+ }
+
+ private Book createBook() {
+ Book book = new Book(
+ "Harry Potter and the Philosopher's stone",
+ Language.ENGLISH,
+ "Sample blurb value",
+ BookGenre.FANTASY,
+ BookFormat.PAPERBACK
+ );
+ book.setYearOfPublication(1997);
+ book.setIsbn13("9781408810545");
+ return book;
+ }
+
+ @Test
+ @DisplayName("throw a Null Pointer Exception on an attempt to create with Null Book")
+ void notAcceptNullBook() {
+
+ BookSeries bookSeries = new BookSeries("Harry Potter Series");
+
+ assertThatExceptionOfType(NullPointerException.class)
+ .isThrownBy(() -> new BookSeriesMapping(bookSeries, null, 1));
+ }
+
+ @Test
+ @DisplayName("throw a Null Pointer Exception on an attempt to create with Null Book Series.")
+ void notAcceptNullBookSeries() {
+ Book book = createBook();
+
+ assertThatExceptionOfType(NullPointerException.class)
+ .isThrownBy(() -> new BookSeriesMapping(null, book, 1));
+ }
+}
diff --git a/src/test/java/com/karankumar/booksapi/model/BookSeriesTest.java b/src/test/java/com/karankumar/booksapi/model/BookSeriesTest.java
new file mode 100644
index 00000000..f3f21af9
--- /dev/null
+++ b/src/test/java/com/karankumar/booksapi/model/BookSeriesTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 Karan Kumar
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see .
+ */
+
+package com.karankumar.booksapi.model;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
+@DisplayName("Book series should")
+class BookSeriesTest {
+
+ @Test
+ @DisplayName("throw a null pointer exception on an attempt to create with a null Series Name.")
+ void notAcceptNullSeriesName(){
+ assertThatExceptionOfType(NullPointerException.class)
+ .isThrownBy(() -> new BookSeries(null));
+ }
+}
diff --git a/src/test/java/com/karankumar/booksapi/model/BookTest.java b/src/test/java/com/karankumar/booksapi/model/BookTest.java
index 2b25346c..e985e700 100644
--- a/src/test/java/com/karankumar/booksapi/model/BookTest.java
+++ b/src/test/java/com/karankumar/booksapi/model/BookTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Karan Kumar
+ * Copyright (C) 2021 Karan Kumar
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
@@ -25,41 +25,21 @@ class BookTest {
@Test
@DisplayName("throw a Null Pointer Exception on an attempt to create with a null title")
void notAcceptNullTitle() {
- // given
- Author author = new Author("J.K. Rowling");
-
- // when and then
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> new Book(
null,
- new Author[] { author },
Language.ENGLISH,
"Sample blurb value", BookGenre.FANTASY,
BookFormat.HARDCOVER
));
}
- @Test
- @DisplayName("throw a Null Pointer Exception on an attempt to create with a null Author")
- void notAcceptNullAuthor() {
- assertThatExceptionOfType(NullPointerException.class)
- .isThrownBy(() -> new Book(
- "The Hobbit", null, Language.ARABIC, "Sample blurb value", BookGenre.FANTASY,
- BookFormat.EBOOK
- ));
- }
-
@Test
@DisplayName("throw a Null Pointer Exception on an attempt to create with a null language")
void notAcceptNullLanguage() {
- // given
- Author author = new Author("J.K. Rowling");
-
- // when and then
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> new Book(
"The Hobbit",
- new Author[] {author},
null,
"Sample blurb value",
BookGenre.FANTASY,
diff --git a/src/test/java/com/karankumar/booksapi/repository/AuthorRepositoryTest.java b/src/test/java/com/karankumar/booksapi/repository/AuthorRepositoryTest.java
index 492e2f5e..f6341816 100644
--- a/src/test/java/com/karankumar/booksapi/repository/AuthorRepositoryTest.java
+++ b/src/test/java/com/karankumar/booksapi/repository/AuthorRepositoryTest.java
@@ -22,6 +22,7 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import java.util.HashSet;
import java.util.List;
import static com.karankumar.booksapi.repository.RepositoryTestUtils.createBook;
@@ -33,15 +34,18 @@ class AuthorRepositoryTest {
private final BookRepository bookRepository;
private final AuthorRepository authorRepository;
+ private final BookSeriesMappingRepository bookSeriesMappingRepository;
@Autowired
- AuthorRepositoryTest(BookRepository bookRepository, AuthorRepository authorRepository) {
+ AuthorRepositoryTest(BookRepository bookRepository, AuthorRepository authorRepository, BookSeriesMappingRepository bookSeriesMappingRepository) {
this.bookRepository = bookRepository;
this.authorRepository = authorRepository;
+ this.bookSeriesMappingRepository = bookSeriesMappingRepository;
}
@BeforeEach
void setUp() {
+ bookSeriesMappingRepository.deleteAll();
authorRepository.deleteAll();
bookRepository.deleteAll();
}
@@ -52,7 +56,7 @@ void findSavedAuthors() {
// given
Author author1 = createAndSaveAuthor("Kevlin", "Henney");
Author author2 = createAndSaveAuthor("Trisha", "Gee");
- saveBook(author1, author2);
+ saveBook();
// when
List result = authorRepository.findAllAuthors();
@@ -61,13 +65,13 @@ void findSavedAuthors() {
assertThat(result).containsExactlyInAnyOrder(author1, author2);
}
- private void saveBook(Author author1, Author author2) {
- bookRepository.save(createBook(author1, author2));
+ private void saveBook() {
+ bookRepository.save(createBook());
}
private Author createAndSaveAuthor(String firstName, String lastName) {
String fullName = firstName + " " + lastName;
- Author author = new Author(fullName);
+ Author author = new Author(fullName, new HashSet<>());
authorRepository.save(author);
return author;
}
diff --git a/src/test/java/com/karankumar/booksapi/repository/BookRepositoryTest.java b/src/test/java/com/karankumar/booksapi/repository/BookRepositoryTest.java
index e88b165b..f102bb5b 100644
--- a/src/test/java/com/karankumar/booksapi/repository/BookRepositoryTest.java
+++ b/src/test/java/com/karankumar/booksapi/repository/BookRepositoryTest.java
@@ -20,7 +20,10 @@
import com.karankumar.booksapi.model.Book;
import com.karankumar.booksapi.model.BookFormat;
import com.karankumar.booksapi.model.BookGenre;
+import com.karankumar.booksapi.model.BookSeries;
+import com.karankumar.booksapi.model.BookSeriesMapping;
import com.karankumar.booksapi.model.Language;
+import java.util.HashSet;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -42,27 +45,36 @@ class BookRepositoryTest {
private final BookRepository bookRepository;
private final AuthorRepository authorRepository;
-
+ private final BookSeriesRepository bookSeriesRepository;
+ private final BookSeriesMappingRepository bookSeriesMappingRepository;
+ private final String harryPotter1Title = "Harry Potter and the Philosopher's stone";
+ private final String harryPotterSeriesName = "Harry Potter Series";
+
private Author author1;
private Author author2;
@Autowired
- BookRepositoryTest(BookRepository bookRepository, AuthorRepository authorRepository) {
+ BookRepositoryTest(BookRepository bookRepository, AuthorRepository authorRepository,
+ BookSeriesRepository bookSeriesRepository,
+ BookSeriesMappingRepository bookSeriesMappingRepository) {
this.bookRepository = bookRepository;
this.authorRepository = authorRepository;
+ this.bookSeriesRepository = bookSeriesRepository;
+ this.bookSeriesMappingRepository = bookSeriesMappingRepository;
}
@BeforeEach
void setUp() {
+ bookSeriesMappingRepository.deleteAll();
authorRepository.deleteAll();
bookRepository.deleteAll();
+ bookSeriesRepository.deleteAll();
}
@Test
@DisplayName("find saved books")
void findSavedBooks() {
// given
- createAndSaveAuthors();
- Book book = createBook(author1, author2);
+ Book book = createBook();
bookRepository.save(book);
// when
@@ -79,8 +91,7 @@ void findSavedBooks() {
@DisplayName("find book with isbn")
void findBookByIsbn() {
// given
- createAndSaveAuthors();
- Book book = createBookwithISBN();
+ Book book = createBookWithIsbn13();
bookRepository.save(book);
// when
@@ -90,16 +101,9 @@ void findBookByIsbn() {
assertThat(result).isEqualTo(book);
}
- private void createAndSaveAuthors() {
- author1 = new Author(AUTHOR1_FULL_NAME);
- author2 = new Author("Trisha Gee");
- saveAllAuthors(author1, author2);
- }
-
- private Book createBookwithISBN() {
+ private Book createBookWithIsbn13() {
Book book = new Book(
"Game of APIs",
- new Author[]{author1, author2},
Language.ENGLISH,
"",
BookGenre.SATIRE,
@@ -113,12 +117,15 @@ private Book createBookwithISBN() {
@DisplayName("find by author")
void findByAuthor() {
// given
- createAndSaveAuthors();
- Book book = createBookwithISBN();
+ Book book = createBookWithIsbn13();
bookRepository.save(book);
+ String authorName = "Kevlin Henney";
+ Author author = new Author(authorName, new HashSet<>());
+ author.addBook(book);
+ authorRepository.save(author);
// when
- List result = bookRepository.findByAuthor(AUTHOR1_FULL_NAME);
+ List result = bookRepository.findByAuthor(authorName);
// then
assertSoftly(softly -> {
@@ -130,10 +137,8 @@ void findByAuthor() {
@Test
void findBookByTitle() {
// given
- createAndSaveAuthors();
Book book = new Book(
TITLE,
- new Author[]{author1, author2},
Language.ENGLISH,
"",
BookGenre.ART,
@@ -152,10 +157,8 @@ void findBookByTitle() {
@DisplayName("find book by title case insensitive")
void findBookByTitleCaseInsensitive() {
// given
- createAndSaveAuthors();
Book book = new Book(
TITLE,
- new Author[]{author1, author2},
Language.ENGLISH,
"",
BookGenre.MYSTERY,
@@ -173,4 +176,65 @@ void findBookByTitleCaseInsensitive() {
private void saveAllAuthors(Author... authors) {
Arrays.stream(authors).forEach(authorRepository::save);
}
+
+ @Test
+ @DisplayName("find all Book Series for a Book")
+ void findBookSeriesForBook(){
+ List assertion = addBookToSeries();
+ Book book = bookRepository.findByTitleIgnoreCase(harryPotter1Title);
+
+ List result = bookRepository.getAllBookSeriesForBook(book);
+
+ assertThat(result).containsExactlyInAnyOrderElementsOf(assertion);
+ }
+
+ @Test
+ @DisplayName("find book position in Book Series")
+ void findBookPositionInSeries() {
+ // Get book and book series from repo
+ List allSeries = addBookToSeries();
+ Book book = bookRepository.findByTitleIgnoreCase(harryPotter1Title);
+ BookSeries assertion = null;
+ for (BookSeries series : allSeries) {
+ if (series.getSeriesName().equals(harryPotterSeriesName)) {
+ assertion = series;
+ break;
+ }
+ }
+
+ assertThat(bookRepository.getBookPositionInBookSeries(book, assertion)).isEqualTo(1);
+ }
+
+ private List addBookToSeries() {
+
+ Book book1 = createSeriesBook(harryPotter1Title);
+ bookRepository.save(book1);
+
+ Book book2 = createSeriesBook("Harry Potter and the Chamber of Secrets");
+ bookRepository.save(book2);
+
+ BookSeries bookSeries1 = new BookSeries(harryPotterSeriesName);
+ bookSeriesRepository.save(bookSeries1);
+
+ BookSeries bookSeries2 = new BookSeries("J.K. Rowling Specials");
+ bookSeriesRepository.save(bookSeries2);
+
+ bookSeriesMappingRepository.save(new BookSeriesMapping(bookSeries1, book1, 1));
+ bookSeriesMappingRepository.save(new BookSeriesMapping(bookSeries1, book2, 2));
+
+ bookSeriesMappingRepository.save(new BookSeriesMapping(bookSeries2, book1, 1));
+ bookSeriesMappingRepository.save(new BookSeriesMapping(bookSeries2, book2, 2));
+
+ return List.of(bookSeries1, bookSeries2);
+ }
+
+ private Book createSeriesBook(String title) {
+ return new Book(
+ title,
+ Language.ENGLISH,
+ "Sample blurb value",
+ BookGenre.FANTASY,
+ BookFormat.PAPERBACK
+ );
+ }
}
diff --git a/src/test/java/com/karankumar/booksapi/repository/BookSeriesMappingRepositoryTest.java b/src/test/java/com/karankumar/booksapi/repository/BookSeriesMappingRepositoryTest.java
new file mode 100644
index 00000000..75fc1675
--- /dev/null
+++ b/src/test/java/com/karankumar/booksapi/repository/BookSeriesMappingRepositoryTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 Karan Kumar
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see .
+ */
+
+package com.karankumar.booksapi.repository;
+
+import com.karankumar.booksapi.annotations.DataJpaIntegrationTest;
+import com.karankumar.booksapi.model.Book;
+import com.karankumar.booksapi.model.BookFormat;
+import com.karankumar.booksapi.model.BookGenre;
+import com.karankumar.booksapi.model.BookSeries;
+import com.karankumar.booksapi.model.BookSeriesMapping;
+import com.karankumar.booksapi.model.Language;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@DataJpaIntegrationTest
+@DisplayName("BookSeriesMappingRepository should")
+class BookSeriesMappingRepositoryTest {
+ private final BookRepository bookRepository;
+ private final AuthorRepository authorRepository;
+ private final BookSeriesRepository bookSeriesRepository;
+ private final BookSeriesMappingRepository bookSeriesMappingRepository;
+ private final String book1Title = "Harry Potter and the Philosopher's stone";
+ private final String book2Title = "Harry Potter and the Chamber of Secrets";
+
+ @Autowired
+ BookSeriesMappingRepositoryTest(BookRepository bookRepository,
+ AuthorRepository authorRepository,
+ BookSeriesRepository bookSeriesRepository,
+ BookSeriesMappingRepository bookSeriesMappingRepository) {
+
+ this.bookRepository = bookRepository;
+ this.authorRepository = authorRepository;
+ this.bookSeriesRepository = bookSeriesRepository;
+ this.bookSeriesMappingRepository = bookSeriesMappingRepository;
+ }
+
+ @BeforeEach
+ void setUp() {
+ bookSeriesMappingRepository.deleteAll();
+ authorRepository.deleteAll();
+ bookRepository.deleteAll();
+ bookSeriesRepository.deleteAll();
+ }
+
+ @Test
+ @DisplayName("return all books in a series.")
+ void fetchAllBooksInBookSeries() {
+ BookSeries bs = createBookSeriesMapping();
+ List assertion = bookSeriesMappingRepository.getAllBooksByBookSeries(bs);
+
+ List bookList = new ArrayList<>();
+ bookList.add(bookRepository.findByTitleIgnoreCase(book1Title));
+ bookList.add(bookRepository.findByTitleIgnoreCase(book2Title));
+
+ assertThat(assertion).hasSize(bookList.size()).hasSameElementsAs(bookList);
+ }
+
+ private BookSeries createBookSeriesMapping() {
+
+ Book book1 = createBook(book1Title);
+ bookRepository.save(book1);
+
+ Book book2 = createBook(book2Title);
+ bookRepository.save(book2);
+
+ BookSeries bookSeries = new BookSeries("Harry Potter Series");
+ bookSeriesRepository.save(bookSeries);
+
+ bookSeriesMappingRepository.save(new BookSeriesMapping(bookSeries, book1, 1));
+ bookSeriesMappingRepository.save(new BookSeriesMapping(bookSeries, book2, 2));
+
+ return bookSeries;
+ }
+
+ private Book createBook(String title) {
+ return new Book(
+ title,
+ Language.ENGLISH,
+ "Sample blurb value",
+ BookGenre.FANTASY,
+ BookFormat.PAPERBACK
+ );
+ }
+}
diff --git a/src/test/java/com/karankumar/booksapi/repository/RepositoryTestUtils.java b/src/test/java/com/karankumar/booksapi/repository/RepositoryTestUtils.java
index 5bee7dd3..09384bde 100644
--- a/src/test/java/com/karankumar/booksapi/repository/RepositoryTestUtils.java
+++ b/src/test/java/com/karankumar/booksapi/repository/RepositoryTestUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Karan Kumar
+ * Copyright (C) 2021 Karan Kumar
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
@@ -20,15 +20,13 @@
import com.karankumar.booksapi.model.BookFormat;
import com.karankumar.booksapi.model.BookGenre;
import com.karankumar.booksapi.model.Language;
-import com.karankumar.booksapi.model.PublisherName;
final class RepositoryTestUtils {
private RepositoryTestUtils() { }
- static Book createBook(Author... authors) {
+ static Book createBook() {
Book book = new Book(
"97 Things Every Java Programmer Should Know",
- authors,
Language.ENGLISH,
"Sample blurb value",
BookGenre.CHILDREN,
@@ -37,7 +35,6 @@ static Book createBook(Author... authors) {
book.setGenre(BookGenre.REFERENCE);
book.setYearOfPublication(2019);
book.setIsbn13("9781408670545");
- book.setPublisher(PublisherName.CAMBRIDGE_UNIVERSITY_PRESS);
book.setFormat(BookFormat.PAPERBACK);
return book;
}
diff --git a/stale.yml b/stale.yml
new file mode 100644
index 00000000..98b5ea75
--- /dev/null
+++ b/stale.yml
@@ -0,0 +1,20 @@
+name: Mark stale issues and pull requests
+
+on:
+ schedule:
+ - cron: "30 1 * * *"
+
+jobs:
+ stale:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/stale@v3
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ stale-pr-message: 'How are you getting on with this? If you need a hand, feel free to let us know by creating a new GitHub discussion. We are marking this as stale, but if you are still working on this, please remove the stale label or comment. Otherwise, we will close this PR in 7 days.'
+ stale-pr-label: 'no-pr-activity'
+ days-before-pr-stale: 7
+ exempt-pr-assignees: 'knjk04'
+ days-before-issue-stale: -1