de.sainth.recipe.backend.db.repositories.CookbookRepository.java Source code

Java tutorial

Introduction

Here is the source code for de.sainth.recipe.backend.db.repositories.CookbookRepository.java

Source

/*
 * 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());
    }

}