DemoRunner: add sections H-L (Specification family, JpaSort.unsafe, Money value object)
This commit is contained in:
@@ -2,12 +2,15 @@ package com.ankurm.sdjpa4demo;
|
||||
|
||||
import com.ankurm.sdjpa4demo.domain.Author;
|
||||
import com.ankurm.sdjpa4demo.domain.Book;
|
||||
import com.ankurm.sdjpa4demo.domain.BookSummary;
|
||||
import com.ankurm.sdjpa4demo.domain.Money;
|
||||
import com.ankurm.sdjpa4demo.repo.AuthorRepository;
|
||||
import com.ankurm.sdjpa4demo.repo.BookRepository;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.JpaSort;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -16,6 +19,10 @@ import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.ankurm.sdjpa4demo.repo.AuthorSpecifications.byCountryDelete;
|
||||
import static com.ankurm.sdjpa4demo.repo.AuthorSpecifications.hasCountry;
|
||||
import static com.ankurm.sdjpa4demo.repo.AuthorSpecifications.relabelCountry;
|
||||
|
||||
@Component
|
||||
@Profile("!test")
|
||||
public class DemoRunner implements CommandLineRunner {
|
||||
@@ -40,10 +47,12 @@ public class DemoRunner implements CommandLineRunner {
|
||||
Author anon = authors.save(new Author("Anonymous", null)); // null country
|
||||
authors.save(new Author("Martin Fowler", "UK"));
|
||||
authors.save(new Author("Kent Beck", "DE")); // bookless: safe to delete in section G
|
||||
Author wall1 = authors.save(new Author("Grady Booch", "US"));
|
||||
Author wall2 = authors.save(new Author("Robert Martin", "US"));
|
||||
|
||||
books.save(new Book("Design Patterns", new BigDecimal("42.00"), gof));
|
||||
books.save(new Book("Effective Java", new BigDecimal("45.00"), bloch));
|
||||
books.save(new Book("Refactoring", new BigDecimal("45.00"), anon)); // duplicate price 45.00
|
||||
books.save(new Book("Design Patterns", new Money(new BigDecimal("42.00"), "USD"), gof));
|
||||
books.save(new Book("Effective Java", new Money(new BigDecimal("45.00"), "USD"), bloch));
|
||||
books.save(new Book("Refactoring", new Money(new BigDecimal("45.00"), "USD"), anon)); // duplicate price 45.00
|
||||
|
||||
// (A) Optional vs non-null vs @Nullable single-result semantics
|
||||
section("A. Null-handling of single-result query methods");
|
||||
@@ -92,13 +101,13 @@ public class DemoRunner implements CommandLineRunner {
|
||||
System.out.println("badgeFor(gof) -> " + authors.badgeFor(gof.getId()));
|
||||
System.out.println("badgeFor(anon) -> " + authors.badgeFor(anon.getId()));
|
||||
|
||||
// (F) Single-result that matches multiple rows -> non-unique edge case
|
||||
section("F. Non-unique single result edge case");
|
||||
// (F) Single-result that matches multiple rows -> non-unique edge case (embedded-path version)
|
||||
section("F. Non-unique single result edge case (embedded value object path)");
|
||||
try {
|
||||
Book b = books.findByPrice(new BigDecimal("45.00"));
|
||||
System.out.println("findByPrice(45.00) -> " + b);
|
||||
Book b = books.findByPriceAmount(new BigDecimal("45.00"));
|
||||
System.out.println("findByPriceAmount(45.00) -> " + b);
|
||||
} catch (IncorrectResultSizeDataAccessException ex) {
|
||||
System.out.println("findByPrice(45.00) matches 2 rows -> throws "
|
||||
System.out.println("findByPriceAmount(45.00) matches 2 rows -> throws "
|
||||
+ ex.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@@ -107,6 +116,44 @@ public class DemoRunner implements CommandLineRunner {
|
||||
long deleted = authors.deleteByCountry("DE");
|
||||
System.out.println("deleteByCountry('DE') removed -> " + deleted + " row(s)");
|
||||
|
||||
// (H) PredicateSpecification: the SAME instance reused for a read and a bulk delete
|
||||
section("H. PredicateSpecification reused across read and delete");
|
||||
List<Author> usAuthors = authors.findAll(hasCountry("US"));
|
||||
System.out.println("findAll(hasCountry(\"US\")) -> "
|
||||
+ usAuthors.stream().map(Author::getName).toList());
|
||||
|
||||
// (I) DeleteSpecification: explicit CriteriaDelete-typed bulk delete
|
||||
section("I. DeleteSpecification bulk delete");
|
||||
long removedGB = authors.delete(byCountryDelete("GB")); // no GB rows on purpose -> 0
|
||||
System.out.println("delete(byCountryDelete(\"GB\")) removed -> " + removedGB + " row(s)");
|
||||
long removedViaPredicate = authors.delete(hasCountry("US").and((root, cb) ->
|
||||
cb.equal(root.get("name"), "Grady Booch")));
|
||||
System.out.println("delete(hasCountry(\"US\").and(name=\"Grady Booch\")) removed -> "
|
||||
+ removedViaPredicate + " row(s)");
|
||||
|
||||
// (J) UpdateSpecification: CriteriaUpdate-backed bulk update
|
||||
section("J. UpdateSpecification bulk update");
|
||||
long updated = authors.update(relabelCountry("UK", "GB"));
|
||||
System.out.println("update(relabelCountry(\"UK\" -> \"GB\")) updated -> " + updated + " row(s)");
|
||||
System.out.println("findAll(hasCountry(\"GB\")) -> "
|
||||
+ authors.findAll(hasCountry("GB")).stream().map(Author::getName).toList());
|
||||
|
||||
// (K) JpaSort.unsafe(...) with a CASE expression, combined with a plain derived query
|
||||
section("K. JpaSort.unsafe with a CASE expression");
|
||||
Sort usFirst = JpaSort.unsafe(Sort.Direction.ASC,
|
||||
"CASE WHEN country = 'US' THEN 0 ELSE 1 END");
|
||||
List<Author> caseOrdered = authors.findByNameStartingWith("", usFirst);
|
||||
System.out.println("JpaSort.unsafe(CASE WHEN country='US' ...) -> "
|
||||
+ caseOrdered.stream().map(a -> a.getName() + "(" + a.getCountry() + ")").toList());
|
||||
|
||||
// (L) Value-object corner scenarios: embedded-path traversal + record projection
|
||||
section("L. Money value object: embedded-path query and record projection");
|
||||
List<Book> pricey = books.findByPriceAmountGreaterThanEqual(new BigDecimal("45.00"));
|
||||
System.out.println("findByPriceAmountGreaterThanEqual(45.00) -> "
|
||||
+ pricey.stream().map(Book::getTitle).toList());
|
||||
List<BookSummary> summaries = books.findByPriceAmountLessThanEqual(new BigDecimal("42.00"));
|
||||
summaries.forEach(s -> System.out.println("BookSummary projection -> " + s));
|
||||
|
||||
section("DONE");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user