All Downloads are FREE. Search and download functionalities are using the official Maven repository.

win.doyto.query.jdbc.JdbcDataQueryClient Maven / Gradle / Ivy

The newest version!
// Generated by delombok at Wed Nov 06 09:48:29 UTC 2024
/*
 * Copyright © 2019-2024 Forb Yuan
 *
 * 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
 *
 *     http://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 win.doyto.query.jdbc;

import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;
import win.doyto.query.core.DataQueryClient;
import win.doyto.query.core.DoytoQuery;
import win.doyto.query.entity.Persistable;
import win.doyto.query.jdbc.rowmapper.BeanPropertyRowMapper;
import win.doyto.query.jdbc.rowmapper.JoinRowMapperResultSetExtractor;
import win.doyto.query.jdbc.rowmapper.RowMapper;
import win.doyto.query.sql.EntityMetadata;
import win.doyto.query.sql.SqlAndArgs;
import win.doyto.query.util.CommonUtil;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static win.doyto.query.sql.RelationalQueryBuilder.*;

/**
 * JdbcDataQueryClient
 * 

An JDBC implementation for {@link DataQueryClient} * *

History names: *

    *
  • JoinQueryExecutor *
  • JoinQueryService *
  • ComplexQueryService *
  • JdbcComplexQueryService *
  • JdbcComplexDataQuery *
  • JdbcDataQuery *
* * @author f0rb on 2019-06-09 * @since 0.1.3 */ public class JdbcDataQueryClient implements DataQueryClient { private static final Map, RowMapper> holder = new ConcurrentHashMap<>(); private final DatabaseOperations databaseOperations; @SuppressWarnings("unchecked") @Override public , I extends Serializable, Q extends DoytoQuery> List query(Q query, @NonNull Class viewClass) { if (viewClass == null) { throw new java.lang.NullPointerException("viewClass is marked non-null but is null"); } RowMapper rowMapper = (RowMapper) holder.computeIfAbsent(viewClass, BeanPropertyRowMapper::new); EntityMetadata entityMetadata = EntityMetadata.build(viewClass); SqlAndArgs sqlAndArgs = buildSelectAndArgs(query, entityMetadata); List mainEntities = databaseOperations.query(sqlAndArgs, rowMapper); querySubEntities(mainEntities, query, EntityMetadata.build(viewClass)); return mainEntities; } @Override public , I extends Serializable, Q extends DoytoQuery> long count(Q query, Class viewClass) { SqlAndArgs sqlAndArgs = buildCountAndArgs(query, viewClass); return databaseOperations.count(sqlAndArgs); } , I extends Serializable, Q> void querySubEntities(List mainEntities, Q query, EntityMetadata entityMetadata) { if (mainEntities.isEmpty()) { return; } // used for every subdomain query Class mainIdClass = resolveKeyClass(mainEntities.get(0)); List mainIds = mainEntities.stream().map(Persistable::getId).toList(); entityMetadata.getDomainPathFields().forEach(joinField -> { // The name of query field for subdomain should follow this format `with` String queryFieldName = buildQueryFieldName(joinField); if (CommonUtil.readField(query, queryFieldName) instanceof DoytoQuery subQuery) { boolean isList = Collection.class.isAssignableFrom(joinField.getType()); Class joinEntityClass = resolveSubEntityClass(joinField, isList); SqlAndArgs sqlAndArgs = buildSqlAndArgsForSubDomain(subQuery, joinEntityClass, joinField, mainIds); Map> subDomainMap = queryIntoMainEntity(mainIdClass, joinEntityClass, sqlAndArgs); mainEntities.forEach(e -> writeResultToMainDomain(e, joinField, isList, subDomainMap)); } }); } protected String buildQueryFieldName(Field joinField) { return "with" + StringUtils.capitalize(joinField.getName()); } @SuppressWarnings("unchecked") private , I extends Serializable> Class resolveKeyClass(E e) { return (Class) e.getId().getClass(); } @SuppressWarnings("unchecked") private static Class resolveSubEntityClass(Field joinField, boolean isList) { return isList ? CommonUtil.resolveActualReturnClass(joinField) : (Class) joinField.getType(); } @SuppressWarnings("unchecked") private Map> queryIntoMainEntity(Class keyClass, Class joinEntityClass, SqlAndArgs sqlAndArgs) { RowMapper joinRowMapper = (RowMapper) holder.computeIfAbsent(joinEntityClass, BeanPropertyRowMapper::new); JoinRowMapperResultSetExtractor resultSetExtractor = new JoinRowMapperResultSetExtractor<>(KEY_COLUMN, keyClass, joinRowMapper); return databaseOperations.query(sqlAndArgs, resultSetExtractor); } private , I extends Serializable, R> void writeResultToMainDomain(E e, Field joinField, boolean isList, Map> map) { List list = map.getOrDefault(e.getId(), new ArrayList<>()); if (isList) { CommonUtil.writeField(joinField, e, list); } else if (!list.isEmpty()) { CommonUtil.writeField(joinField, e, list.get(0)); } } @java.lang.SuppressWarnings("all") @lombok.Generated public JdbcDataQueryClient(final DatabaseOperations databaseOperations) { this.databaseOperations = databaseOperations; } }