<%#
 Copyright 2013-2024 the original author or authors from the JHipster project.

 This file is part of the JHipster project, see https://www.jhipster.tech/
 for more information.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      https://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-%>
package <%= entityAbsolutePackage %>.repository.base;

import <%= entityAbsolutePackage %>.domain.<%= persistClass %>;

<%_ if (implementsEagerLoadApis && ormTool === 'hibernate') { _%>
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
<%_ } _%>
<%_ if (ormTool === 'hibernate') { _%>
import org.springframework.data.jpa.repository.*;
  <%_ if (implementsEagerLoadApis || softDelete) { _%>
import org.springframework.data.repository.query.Param;
  <%_ } _%>
<%_ } _%>
<%_ if (ormTool === 'hibernate') { _%>
  <%_ if (softDelete || implementsEagerLoadApis || relationships.some(r => r.relationshipManyToOne && r.otherEntityUser)) { _%>
import java.util.List;
  <%_ } _%>
  <%_ if (implementsEagerLoadApis || softDelete) { _%>
import java.util.Optional;
  <%_ } _%>
<%_ } _%>
<%_ if (primaryKey.typeUUID) { _%>

import java.util.UUID;
<%_ } _%>
<%# add by begcode start %>
<%_ if (serviceNo && ormTool === 'mybatis') { _%>
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.base.CaseFormat;
<%_ } _%>
<%_ if (databaseTypeSql || databaseTypeMongodb || databaseTypeCouchbase) {
    let importSecurityUtils = false;
    for (r of relationships) {
        if (r.relationshipManyToOne && r.otherEntityUser) {
            importSecurityUtils = true;
        }
    }
_%>
    <%_ if (importSecurityUtils && databaseTypeSql) { %>
import <%= packageName %>.security.SecurityUtils;
    <%_ } _%>
<%_ } _%>
import org.springframework.data.repository.NoRepositoryBean;
<%_ if (databaseTypeSql && ormTool === 'mybatis') { _%>
import com.diboot.core.mapper.BaseCrudMapper;
  <%_ if (fieldsContainParentAndChildren || databaseTypeSql && relationships.some(relationship => relationship.relationshipManyToOne && relationship.otherEntityUser)) { _%>
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  <%_ } _%>
  <%_ if (fieldsContainParentAndChildren) { _%>
import com.baomidou.mybatisplus.core.metadata.IPage;
  <%_ } _%>
  <%_ if (relationships && relationships.length) { _%>
import com.diboot.core.binding.Binder;
  <%_ } _%>
import org.apache.ibatis.annotations.*;
import java.util.List;
import java.util.Objects;
  <%_ if (relationships.some(relationship => relationship.relationshipManyToOne && relationship.otherEntityUser) && databaseTypeSql) { _%>
import java.util.ArrayList;
  <%_ } _%>
import java.util.Optional;
<%_ } _%>
<%_ if (addCustomMethod.indexOf('repository') !== -1) { _%>
<%- include(`../../_entityCustom_/${entityClass}.repository.ejs`, {position: 'import'}); -%>
<%_ } _%>
// jhipster-needle-add-import - JHipster will add getters and setters here, do not remove
<%# add by begcode end %>

/**
 * <%= springDataDescription %> repository for the <%= persistClass %> entity.
<%_ if (containsBagRelationships) { _%>
 *
 * When extending this class, extend <%= entityClass %>RepositoryWithBagRelationships too.
 * For more information refer to https://github.com/jhipster/generator-jhipster/issues/17990.
<%_ } _%>
 */
<%_ if (!implementsEagerLoadApis) { _%>
@SuppressWarnings("unused")
<%_ } _%>
@NoRepositoryBean
public interface <%= entityClass %>BaseRepository<% if (ormTool === 'mybatis') { %><E extends <%= persistClass %>><% } %> extends <% if (ormTool === 'hibernate') { %><% if (containsBagRelationships) { %><%= entityClass %>RepositoryWithBagRelationships, <% } %>JpaRepository<<%= persistClass %>, <%= primaryKey.type %>><% if (jpaMetamodelFiltering) { %>, JpaSpecificationExecutor<<%= persistClass %>><% } %><% } else { %>BaseCrudMapper<<%= persistClass %>><% } %> {
<%_ if (addCustomMethod.indexOf('repository') !== -1) { _%>
<%- include(`../../_entityCustom_/${entityClass}.repository.ejs`, {position: 'field'}); -%>
<%_ } _%>
<%_ if (ormTool === 'hibernate') { _%>
<%_ for (const relationship of relationships) { _%>
  <%_ if (relationship.relationshipManyToOne && relationship.otherEntityUser) { _%>

    @Query("select <%= entityInstanceDbSafe %> from <%= persistClass %> <%= entityInstanceDbSafe %> where <%= entityInstanceDbSafe %>.<%= relationship.relationshipFieldName %>.login = ?#{authentication.name}")
    List<<%= persistClass %>> findBy<%= relationship.relationshipNameCapitalized %>IsCurrentUser();
  <%_ } _%>
<%_ } _%>
<%_ if (implementsEagerLoadApis) { _%>

  <%_ const containsToOneEagerRelationship = relationships.some(relationship => relationship.relationshipEagerLoad && !relationship.bagRelationship); _%>
    default Optional<<%= persistClass %>> findOneWithEagerRelationships(<%= primaryKey.type %> <%= primaryKey.name %>) {
        return <% if (containsBagRelationships) { %>this.fetchBagRelationships(<% } %>
            this.<% if (containsToOneEagerRelationship) { %>findOneWithToOneRelationships<% } else { %>findById<% } %>(<%= primaryKey.name %>)
        <%  if (containsBagRelationships) { %>)<% } %>;
    }

    default List<<%= persistClass %>> findAllWithEagerRelationships() {
        return <% if (containsBagRelationships) { %>this.fetchBagRelationships(<% } %>
            this.<% if (containsToOneEagerRelationship) { %>findAllWithToOneRelationships<% } else { %>findAll<% } %>()
        <%  if (containsBagRelationships) { %>)<% } %>;
    }

    default Page<<%= persistClass %>> findAllWithEagerRelationships(Pageable pageable) {
        return <% if (containsBagRelationships) { %>this.fetchBagRelationships(<% } %>
            this.<% if (containsToOneEagerRelationship) { %>findAllWithToOneRelationships<% } else { %>findAll<% } %>(pageable)
        <%  if (containsBagRelationships) { %>)<% } %>;
    }
  <%_ if (containsToOneEagerRelationship) { _%>

    @Query(value = "select <%= entityInstanceDbSafe %> from <%= persistClass %> <%= entityInstanceDbSafe %><%
      for (const relationship of relationships) {
        if (relationship.relationshipEagerLoad && !relationship.bagRelationship) { %> left join fetch <%= entityInstanceDbSafe %>.<%= relationship.reference.name %><% }
      } %>",
        countQuery = "select count(<%= entityInstanceDbSafe %>) from <%= persistClass %> <%= entityInstanceDbSafe %>")
    Page<<%= persistClass %>> findAllWithToOneRelationships(Pageable pageable);

    @Query("select <%= entityInstanceDbSafe %> from <%= persistClass %> <%= entityInstanceDbSafe %><%
      for (const relationship of relationships) {
        if (relationship.relationshipEagerLoad && !relationship.bagRelationship) { %> left join fetch <%= entityInstanceDbSafe %>.<%= relationship.reference.name %><% }
      } %>")
    List<<%= persistClass %>> findAllWithToOneRelationships();

    @Query("select <%= entityInstanceDbSafe %> from <%= persistClass %> <%= entityInstanceDbSafe %><%
      for (const relationship of relationships) {
        if (relationship.relationshipEagerLoad && !relationship.bagRelationship) { %> left join fetch <%= entityInstanceDbSafe %>.<%= relationship.reference.name %><% }
      } %> where <%= entityInstanceDbSafe %>.id =:id")
    Optional<<%= persistClass %>> findOneWithToOneRelationships(@Param("id") <%= primaryKey.type %> id);

    <%_ if (fieldsContainParentAndChildren) { _%>
    Page<<%= persistClass %>> findAllBy<%= this._.upperFirst(parentRelationshipName) %>IsNull(Pageable pageable);

    List<<%= persistClass %>> findAllBy<%= this._.upperFirst(parentRelationshipName) %>Id(<%= primaryKey.type %> id);
    <%_ } _%>
  <%_ } _%>
<%_ } _%>
    <%_ if (softDelete) { _%>
    @Modifying
    @Query("update <%= persistClass %> set deletedTime = null, delFlag = false where delFlag = true and  <%= primaryKey.name %> in :ids")
    void restoreByIdsInRecycleBin(@Param("ids") List<<%= primaryKey.type %>> ids);

    @Modifying
    @Query("delete <%= persistClass %> where delFlag = true and <%= primaryKey.name %> in :ids")
    void deleteInRecycleBin(@Param("ids") List<<%= primaryKey.type %>> ids);

    @Modifying
    @Query("delete <%= persistClass %> where delFlag = true")
    void deleteInRecycleBin();

    Optional<<%= persistClass %>> findOneByDelFlagIsTrueAndId(<%= primaryKey.type %> id);
    <%_ } _%>
<%_ } else { _%>
<%_ if (implementsEagerLoadApis) { _%>
    <%_ if (databaseTypeSql) { _%>
    <%_ const containsToOneEagerRelationship = relationships.some(relationship => relationship.relationshipEagerLoad && !relationship.bagRelationship); _%>
    default Optional<<%= persistClass %>> findOneWithEagerRelationships(<%= primaryKey.type %> <%= primaryKey.name %>) {
      <%_ if (containsBagRelationships) { _%>
        <%_ if (containsToOneEagerRelationship) { _%>
        return Optional.ofNullable(this.selectById(<%= primaryKey.name %>)).map(<%= entityInstance %> -> {
            Binder.bindRelations(<%= entityInstance %>, new String[]{"<%- relationships.map(relationship => relationship.relationshipName).join('", "')%>"});
            return <%= entityInstance %>;
        });
        <%_ } else { _%>
        return this.findById(<%= primaryKey.name %>);
        <%_ } _%>
      <%_ } else { _%>
        <%_ if (containsToOneEagerRelationship) { _%>
        return Optional.ofNullable(this.selectById(<%= primaryKey.name %>)).map(<%= entityInstance %> -> {
            Binder.bindRelations(<%= entityInstance %>, new String[]{"<%- relationships.map(relationship => relationship.relationshipName).join('", "')%>"});
            return <%= entityInstance %>;
        });
        <%_ } else { _%>
        return this.findById(<%= primaryKey.name %>);
        <%_ } _%>
      <%_ } _%>
    }
    <%_ } _%>
  <%_ } _%>

    default List<<%= entityClass %>> findAll() {
        return this.selectList(null);
    }

    default Optional<<%= entityClass %>> findById(<%= primaryKey.type %> id) {
        return Optional.ofNullable(this.selectById(id));
    }
<%_ if (anyFieldIsOwner && ormTool === 'mybatis') { _%>
    @Select("delete from <%= entityTableName %> <%= entityTableName %> where <%= entityTableName %>.owner_entity_name = #{ownerEntityName} and <%= entityTableName %>.owner_entity_id = #{ownerEntityId}")
    void deleteAllByIdEntity(@Param("ownerEntityName") String ownerEntityName, @Param("ownerEntityId") Long ownerEntityId);
<%_ } _%>
<%_ for (const relationship of relationships) {
    if ((relationship.relationshipManyToOne || relationship.relationshipOneToOne && relationship.ownerSide) && databaseTypeSql && ormTool === 'mybatis') { _%>
    @Select("delete from <%= entityTableName %> <%= entityTableName %> where <%= entityTableName %>.<%= relationship.columnName %>_<%=  relationship.otherEntity.primaryKey.fields[0].columnName%> = #{<%= relationship.relationshipName %><%= relationship.otherEntity.primaryKey.nameCapitalized%>}")
    void deleteAllBy<%= relationship.relationshipNameCapitalized %><%= relationship.otherEntity.primaryKey.nameCapitalized%>(@Param("<%= relationship.relationshipName %><%= relationship.otherEntity.primaryKey.nameCapitalized%>") <%= relationship.otherEntity.primaryKey.type%> <%= relationship.relationshipName %><%= relationship.otherEntity.primaryKey.nameCapitalized%>);
    <%_ } _%>
    <%_ if (relationship.relationshipManyToOne && relationship.otherEntityUser && databaseTypeSql) { _%>

    default List<<%= persistClass %>> findBy<%= relationship.relationshipNameCapitalized %>IsCurrentUser() {
        List<<%= persistClass %>> result = new ArrayList<>();
        SecurityUtils.getCurrentUserId().ifPresent(userid ->result.addAll(this.selectList(new QueryWrapper<<%= persistClass %>>().eq("<%= relationship.columnName %>_<%= relationship.otherEntity.primaryKey.fields[0].columnName %>", userid))));
        return result;
    }
    <%_ }
        if (relationship.relationshipOneToOne && relationship.otherEntityUser && databaseTypeSql) { _%>

    @Select("select <%= entityTableName %>.* from <%= entityTableName %> <%= entityTableName %> where <%= entityTableName %>.login = #{login}")
    Optional<<%= persistClass %>> getBy<%= relationship.relationshipNameCapitalized %>IsCurrentUser(@Param("login") String login);
    <%_ }
} _%>
    <%_ if (fieldsContainParentAndChildren) { _%>
    default IPage<<%= persistClass %>> findAllBy<%= this._.upperFirst(parentRelationshipName) %>IsNull(IPage<<%= persistClass %>> pageable) {
        return this.selectPage(pageable, new QueryWrapper<<%= persistClass %>>().isNull("<%= parentRelationshipName %>_id"));
    }
    <%_ } _%>
    <%_ if (extensibleData) { _%>

    int insertByMap(@Param("fieldsMap") Map<String, Object> fieldsMap);

    Map<String, Object> selectMapByIdAndColumns(@Param(value = "id") Long id, @Param("fieldsMap") Map<String, String> fieldsMap);

    int updateToManyRelationById(@Param(value = "tableName") String tableName, @Param(value = "id") Long id, @Param("fieldsMap") Map<String, String> fieldsMap);

    int insertToManyRelation(@Param(value = "tableName") String tableName, @Param("fieldsMap") Map<String, String> fieldsMap);

    Map<String, Object> selectMapByTableAndIdAndColumns(
        @Param("table") String table,
        @Param("id") Long id,
        @Param("fieldsMap") Map<String, String> fieldsMap,
        @Param("joinTable") String joinTable,
        @Param("relationIdName") String relationIdName
    );

    List<Map<String, Object>> selectMapsByTableAndIdAndColumns(
        @Param("id") Long id,
        @Param("fieldsMap") Map<String, String> fieldsMap,
        @Param("joinTable") String joinTable,
        @Param("otherTable") String otherTable,
        @Param("relationIdName") String relationIdName,
        @Param("otherIdName") String otherIdName
    );
    <%_ } _%>

    default <%= persistClass %> saveAndGet(<%= persistClass %> <%= entityInstance %>) {
        if (Objects.nonNull(<%= entityInstance %>.get<%= primaryKey.nameCapitalized %>())) {
            this.updateById(<%= entityInstance %>);
        } else {
            this.insert(<%= entityInstance %>);
        }
        return this.selectById(<%= entityInstance %>.get<%= primaryKey.nameCapitalized %>());
    }
    <%_ if (serviceNo) { _%>

    default <%= persistClass %> updateBySpecifiedField(<%= persistClass %> <%= entityInstance %>, String fieldName) {
        UpdateWrapper<<%= persistClass %>> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fieldName), BeanUtil.getFieldValue(<%= entityInstance %>, fieldName));
        updateWrapper.eq("<%= primaryKey.name %>", <%= entityInstance %>.get<%= primaryKey.nameCapitalized %>());
        update(null, updateWrapper);
        return selectById(<%= entityInstance %>.get<%= primaryKey.nameCapitalized %>());
    }

    default <%= persistClass %> updateBySpecifiedFields(<%= persistClass %> <%= entityInstance %>, Set<String> fieldNames) {
        UpdateWrapper<<%= persistClass %>> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("<%= primaryKey.name %>", <%= entityInstance %>.get<%= primaryKey.nameCapitalized %>());
        fieldNames.forEach(fieldName ->
            updateWrapper.set(
                CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fieldName),
                BeanUtil.getFieldValue(<%= entityInstance %>, fieldName)
            )
        );
        this.update(null, updateWrapper);
        return selectById(<%= entityInstance %>.get<%= primaryKey.nameCapitalized %>());
    }
    <%_ } _%>
<%_ } _%>
<%# add by begcode start %>
<%_ if (addCustomMethod.indexOf('repository') !== -1) { _%>
<%- include(`../../_entityCustom_/${entityClass}.repository.ejs`, {position: 'method'}); -%>
<%_ } _%>

    // jhipster-needle-repository-add-method - JHipster will add getters and setters here, do not remove
<%# add by begcode end %>
}
