Java tutorial
/* * Copyright (c) 2017 sainth (sainth@sainth.de) * * 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, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package de.sainth.recipe.backend.db.repositories; import de.sainth.recipe.backend.db.generated.tables.records.CookbooksRecord; import de.sainth.recipe.backend.rest.views.Cookbook; import de.sainth.recipe.backend.rest.views.Cookbook.CookbookRecipe; import de.sainth.recipe.backend.rest.views.User; import org.jooq.BatchBindStep; import org.jooq.DSLContext; import org.jooq.Record5; import org.jooq.SelectOnConditionStep; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import static de.sainth.recipe.backend.db.generated.tables.Cookbooks.COOKBOOKS; import static de.sainth.recipe.backend.db.generated.tables.CookbooksRecipes.COOKBOOKS_RECIPES; import static de.sainth.recipe.backend.db.generated.tables.Recipes.RECIPES; import static de.sainth.recipe.backend.db.generated.tables.Users.USERS; import static org.jooq.impl.DSL.using; @Component public class CookbookRepository { private final DSLContext create; @Autowired public CookbookRepository(DSLContext create) { this.create = create; } public List<Cookbook> findAll() { SelectOnConditionStep<Record5<Long, String, String, Long, String>> selectAll = selectAllStatement(); List<Cookbook> cookbooks = selectAll.fetch().stream() .map(c -> new Cookbook(c.value1(), c.value2(), c.value3(), new User(c.value4(), c.value5()))) .collect(Collectors.toList()); for (Cookbook cookbook : cookbooks) { cookbook.setRecipes(selectCookbookRecipes(cookbook.getId())); } return cookbooks; } private SelectOnConditionStep<Record5<Long, String, String, Long, String>> selectAllStatement() { return create.select(COOKBOOKS.ID, COOKBOOKS.NAME, COOKBOOKS.DESCRIPTION, COOKBOOKS.AUTHOR, USERS.NAME) .from(COOKBOOKS).join(USERS).on(USERS.ID.eq(COOKBOOKS.AUTHOR)); } public List<Cookbook> findAllFor(Long userId) { List<Cookbook> cookbooks = selectAllStatement().where(USERS.ID.eq(userId)).fetch().stream() .map(c -> new Cookbook(c.value1(), c.value2(), c.value3(), new User(c.value4(), c.value5()))) .collect(Collectors.toList()); for (Cookbook cookbook : cookbooks) { cookbook.setRecipes(selectCookbookRecipes(cookbook.getId())); } return cookbooks; } public Cookbook findOne(Long id) { Record5<Long, String, String, Long, String> record = selectAllStatement().where(COOKBOOKS.ID.eq(id)) .fetchOne(); if (record == null) { return null; } Cookbook cookbook = new Cookbook(record.value1(), record.value2(), record.value3(), new User(record.value4(), record.value5())); cookbook.setRecipes(selectCookbookRecipes(cookbook.getId())); return cookbook; } public void delete(Long id) { create.transaction(configuration -> { using(configuration).delete(COOKBOOKS_RECIPES).where(COOKBOOKS_RECIPES.COOKBOOK.eq(id)).execute(); using(configuration).delete(COOKBOOKS).where(COOKBOOKS.ID.eq(id)).execute(); }); } public void delete(Long id, Long userId) { if (create.fetchExists(selectAllStatement().where(COOKBOOKS.ID.eq(id)).and(USERS.ID.eq(userId)))) { delete(id); } } public void deleteAll() { create.transaction(configuration -> { using(configuration).delete(COOKBOOKS_RECIPES).execute(); using(configuration).delete(COOKBOOKS).execute(); }); } public Cookbook save(Cookbook cookbook) { AtomicReference<Cookbook> bu = new AtomicReference<>(); create.transaction(configuration -> { Long id = null; if (cookbook.getId() != null) { id = using(configuration).select(COOKBOOKS.ID).from(COOKBOOKS) .where(COOKBOOKS.ID.eq(cookbook.getId())).forUpdate().fetchOneInto(Long.class); } CookbooksRecord cookbooksRecord; if (cookbook.getId() == null || id == null) { cookbooksRecord = using(configuration) .insertInto(COOKBOOKS, COOKBOOKS.NAME, COOKBOOKS.DESCRIPTION, COOKBOOKS.AUTHOR) .values(cookbook.getName(), cookbook.getDescription(), cookbook.getAuthor().getId()) .returning().fetchOne(); } else { cookbooksRecord = using(configuration).update(COOKBOOKS).set(COOKBOOKS.NAME, cookbook.getName()) .set(COOKBOOKS.DESCRIPTION, cookbook.getDescription()).returning().fetchOne(); } List<CookbookRecipe> cookbookRecipes = selectCookbookRecipes( cookbook.getRecipes().stream().map(CookbookRecipe::getId).collect(Collectors.toList()), cookbook.getAuthor().getId()); BatchBindStep batchInsert = using(configuration).batch( create.insertInto(COOKBOOKS_RECIPES, COOKBOOKS_RECIPES.COOKBOOK, COOKBOOKS_RECIPES.RECIPE) .values((Long) null, null)); for (CookbookRecipe r : cookbookRecipes) { batchInsert.bind(cookbooksRecord.getId(), r.getId()); } batchInsert.execute(); bu.set(new Cookbook(cookbooksRecord.getId(), cookbooksRecord.getName(), cookbooksRecord.getDescription(), cookbook.getAuthor(), cookbookRecipes)); }); return bu.get(); } private List<CookbookRecipe> selectCookbookRecipes(long cookbookId) { return create.select(RECIPES.ID, RECIPES.NAME, RECIPES.DIFFICULTY, RECIPES.AUTHOR, USERS.NAME) .from(COOKBOOKS_RECIPES).join(RECIPES).on(RECIPES.ID.eq(COOKBOOKS_RECIPES.RECIPE)).join(USERS) .on(USERS.ID.eq(RECIPES.AUTHOR)).where(COOKBOOKS_RECIPES.COOKBOOK.eq(cookbookId)).fetch().stream() .map(r -> new CookbookRecipe(r.value1(), r.value2(), r.value3(), new User(r.value4(), r.value5()))) .collect(Collectors.toList()); } private List<CookbookRecipe> selectCookbookRecipes(Collection<Long> recipeIds, Long userId) { return create.select(RECIPES.ID, RECIPES.NAME, RECIPES.DIFFICULTY, RECIPES.AUTHOR, USERS.NAME).from(RECIPES) .join(USERS).on(USERS.ID.eq(RECIPES.AUTHOR)).where(RECIPES.ID.in(recipeIds)) .and(RECIPES.AUTHOR.eq(userId).or(RECIPES.PUBLIC_VISIBLE.eq(Boolean.TRUE))).fetch().stream() .map(r -> new CookbookRecipe(r.value1(), r.value2(), r.value3(), new User(r.value4(), r.value5()))) .collect(Collectors.toList()); } }