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

fr.ird.observe.toolkit.templates.entity.ToolkitEntityHibernateMappingTransformer Maven / Gradle / Ivy

There is a newer version: 10.0.1
Show newest version
package fr.ird.observe.toolkit.templates.entity;

/*-
 * #%L
 * Toolkit :: Templates
 * %%
 * Copyright (C) 2017 - 2024 Ultreia.io
 * %%
 * 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, see
 * .
 * #L%
 */

import fr.ird.observe.toolkit.templates.ToolkitTagValues;
import fr.ird.observe.toolkit.templates.entity.query.SqlQueryDefinition;
import org.codehaus.plexus.component.annotations.Component;
import org.nuiton.eugene.Template;
import org.nuiton.eugene.models.object.ObjectModel;
import org.nuiton.eugene.models.object.ObjectModelAttribute;
import org.nuiton.eugene.models.object.ObjectModelClass;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataAssociation;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataEntity;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataEntityPath;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataLink;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataModel;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataModelPaths;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataOneToOneComposition;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataReverseAssociation;
import org.nuiton.topia.templates.EntityHibernateMappingTransformer;
import org.nuiton.topia.templates.hibernate.HibernateClassContext;
import org.nuiton.topia.templates.sql.TopiaMetadataEntityPathsBuilder;
import org.nuiton.topia.templates.sql.TopiaMetadataModelBuilder;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;




/**
 * Created on 27/04/2021.
 *
 * @author Tony Chemit - [email protected]
 * @since 5.0.19
 */
@Component(role = Template.class, hint = "fr.ird.observe.toolkit.templates.entity.ToolkitEntityHibernateMappingTransformer")
public class ToolkitEntityHibernateMappingTransformer extends EntityHibernateMappingTransformer {

    private final ToolkitTagValues toolkitTagValues = new ToolkitTagValues();
    private TopiaMetadataModel metadataModel;
    private TopiaMetadataModelPaths allPaths;
    private GroupBySqlHelper groupBySqlHelper;

    public static String getReferenceQuery(TopiaMetadataEntity table, String referencesTagValue) {
        List realReferences = new LinkedList<>();
        realReferences.add("topiaId");
        realReferences.add("topiaCreateDate");
        realReferences.add("topiaVersion");
        realReferences.addAll(List.of(referencesTagValue.split("\\s*,\\s*")));
        return String.format("SELECT %1$s FROM %2$s.%3$s main",
                             realReferences.stream().map(s -> "main." + s).collect(Collectors.joining(", ")),
                             table.getDbSchemaName(),
                             table.getDbTableName());
    }

    @Override
    public void generateFromModel(Writer output, ObjectModel input) throws IOException {
        metadataModel = TopiaMetadataModelBuilder.buildFull(isVerbose(), input, getTemplateHelper());
        allPaths = TopiaMetadataEntityPathsBuilder.create(metadataModel);
        groupBySqlHelper = new GroupBySqlHelper(topiaHibernateTagValues, metadataModel, model, getTemplateHelper(), this);
        super.generateFromModel(output, input);
    }

    @Override
    protected void generateSqlQueries(Writer output, HibernateClassContext classContext) throws IOException {

        ObjectModelClass input = classContext.getInput();
        Set userQueries = getTemplateHelper().queriesForType(input.getQualifiedName(),classContext.getMetadataEntity().getDbSchemaName(),classContext.getMetadataEntity().getDbTableName());
        addUserQueries(output, userQueries);
        addEntityToIdsProjection(output, input);
        addEntityToIdEqualsProjection(output, input);
        addEntityToIdInProjection(output, input);
        addEntityToIdBeforeProjection(output, input);
        addEntityToIdAfterProjection(output, input);

        TopiaMetadataEntity entity = metadataModel.getEntity(getTemplateHelper().getEntityEnumLiteralName(input));
        String inputClassName = entity.getFullyQualifiedName();
        if (inputClassName.contains(".referential.")) {
            return;
        }
        String referencesTagValue = toolkitTagValues.getReferencesTagValue(input);
        if (referencesTagValue != null) {
            addReferenceQuery(output, input.getQualifiedName(), entity, referencesTagValue);
        }

        String[] navigationParentTagValues = topiaExtensionTagValues.getGroupBy(input);
        if (navigationParentTagValues != null) {
            for (String groupByPattern : navigationParentTagValues) {
                if (isVerbose()) {
                    getLog().info(String.format("Add entry point parent query on %s::%s", inputClassName, groupByPattern));
                }
                String groupBy = groupByPattern;
                String groupByPredicate = null;
                String groupBySecond = null;
                int index = groupByPattern.indexOf(":");
                if (index > -1) {
                    groupBy = groupByPattern.substring(0, index);
                    groupByPredicate = groupByPattern.substring(index + 1);
                } else {
                    index = groupByPattern.indexOf(".");
                    if (index > -1) {
                        groupBy = groupByPattern.substring(0, index);
                        groupBySecond = groupByPattern.substring(index + 1);
                    }
                }
                ObjectModelAttribute attribute = input.getAttribute(groupBy);
                groupBySqlHelper.addRootGetMultipleParentEntity(output,
                                                                classContext.getPackage(),
                                                                input,
                                                                inputClassName,
                                                                entity,
                                                                Objects.requireNonNull(attribute),
                                                                groupBy,
                                                                groupBy,
                                                                groupByPredicate,
                                                                groupBySecond);
            }
            return;
        }
        if (!allPaths.containsKey(entity)) {
            return;
        }

        List paths = new ArrayList<>(allPaths.getEntityPath(entity));
        if (paths.size() == 2) {
            int match = 0;
            for (TopiaMetadataEntityPath path : paths) {
                TopiaMetadataLink lastLink = path.getLastLink();
                if (lastLink instanceof TopiaMetadataAssociation) {
                    match++;
                }
            }
            if (match == 2) {
                // no need two paths
                paths.remove(1);
            } else {
                for (TopiaMetadataEntityPath path : paths) {
                    registerParentQuery(output, input, entity, path);

                }
                return;
            }
        }

        if (paths.size() == 1) {
            for (TopiaMetadataEntityPath path : paths) {
                int linksSize = path.getLinksSize();
                if (linksSize == 0) {
                    continue;
                }
                registerParentQuery(output, input, entity, path);
            }
        } else {
            throw new IllegalStateException("Can't manage three paths to data for " + input.getQualifiedName());
        }
    }

    private void addUserQueries(Writer output, Set userQueries) throws IOException {
        for (SqlQueryDefinition userQuery : userQueries) {
            String queryName = userQuery.getFullyQualifiedName();
            String query = userQuery.getQuery();
            String extraParameters = " read-only=\"true\"";
            if (userQuery.isCallable()) {
                extraParameters += " callable=\"true\"";
            }
            boolean added = addSqlQuery(output, queryName, query, extraParameters, userQuery.getComment(), userQuery.withParameters() ? userQuery.getParameters() : null);
            if (!added) {
                throw new IllegalStateException(String.format("Can't add query: %s", queryName));
            }
        }
    }

    private void registerParentQuery(Writer output, ObjectModelClass input, TopiaMetadataEntity entity, TopiaMetadataEntityPath path) throws IOException {
        TopiaMetadataLink lastLink = path.getLastLink();
        String property = lastLink.getTargetPropertyName();
        TopiaMetadataEntity owner = lastLink.getOwner();
        String key = owner.getFullyQualifiedName() + "-" + lastLink.getTargetPropertyName();
        if (lastLink instanceof TopiaMetadataReverseAssociation) {
            if (isVerbose()) {
                getLog().info(String.format("Add single parent query on %s", lastLink));
            }
            addGetSingleParentEntity(output, input.getQualifiedName(), key, lastLink.getOwner(), property);
        } else if (lastLink instanceof TopiaMetadataOneToOneComposition) {
            if (isVerbose()) {
                getLog().info(String.format("Add single parent query on %s", lastLink));
            }
            addGetMultipleParentEntity(output, input.getQualifiedName(), key, entity, owner, ((TopiaMetadataOneToOneComposition) lastLink).getSourceDbName());
        } else {
            if (isVerbose()) {
                getLog().info(String.format("Add multiple parent query on %s", lastLink));
            }
            addGetMultipleParentEntity(output, input.getQualifiedName(), key, entity, owner, owner.getDbTableName());
        }
    }

    private void addReferenceQuery(Writer output, String input, TopiaMetadataEntity table, String referencesTagValue) throws IOException {
        String queryName = input + "::reference";
        String query = getReferenceQuery(table, referencesTagValue);
        boolean added = addSqlQuery(output, queryName, query, " read-only=\"true\"");
        if (!added) {
            throw new IllegalStateException(String.format("Can't add query: %s", queryName));
        }
    }


    private void addGetMultipleParentEntity(Writer output, String input, String key, TopiaMetadataEntity table, TopiaMetadataEntity parentTable, String property) throws IOException {
        {
            String query = String.format("select p.topiaId, p.lastUpdateDate from %s.%s p inner join %s.%s e on e.%s = p.topiaId where e.topiaId = ?", parentTable.getDbSchemaName(), parentTable.getDbTableName(), table.getDbSchemaName(), table.getDbTableName(), property);
            String queryName = String.format("%s::getParentId::%s", input, key);
            boolean added = addSqlQuery(output, queryName, query, " read-only=\"true\"");
            if (!added) {
                throw new IllegalStateException(String.format("Can't add query: %s", queryName));
            }
        }
        {
            String query = String.format("select distinct(e.topiaId) from %s.%s e where e.%s in ( ?1 )", table.getDbSchemaName(), table.getDbTableName(), property);
            String queryName = String.format("%s::byParentId::%s", input, key);
            boolean added = addSqlQuery(output, queryName, query, " read-only=\"true\"");
            if (!added) {
                throw new IllegalStateException(String.format("Can't add query: %s", queryName));
            }
        }
    }

    private void addGetSingleParentEntity(Writer output, String input, String key, TopiaMetadataEntity table, String property) throws IOException {
        {
            String query = String.format("select p.topiaId, p.lastUpdateDate from %s.%s as p where p.%s = ?", table.getDbSchemaName(), table.getDbTableName(), property);
            String queryName = String.format("%s::getParentId::%s", input, key);
            boolean added = addSqlQuery(output, queryName, query, " read-only=\"true\"");
            if (!added) {
                throw new IllegalStateException(String.format("Can't add query: %s", queryName));
            }
        }
        {
            String query = String.format("select distinct(e.%3$s) from %1$s.%2$s e where e.topiaId in ( ?1 )", table.getDbSchemaName(), table.getDbTableName(), property);
            String queryName = String.format("%s::byParentId::%s", input, key);
            boolean added = addSqlQuery(output, queryName, query, " read-only=\"true\"");
            if (!added) {
                throw new IllegalStateException(String.format("Can't add query: %s", queryName));
            }
        }
    }

    private void addEntityToIdsProjection(Writer output, ObjectModelClass input) throws IOException {
        String query = String.format("select new fr.ird.observe.dto.ToolkitIdBean(id, lastUpdateDate)\n" +
                                             "    from %s as e", input.getQualifiedName() + "Impl");
        addQuery(output, input.getQualifiedName() + "::id::all", query, " read-only=\"true\"");
    }

    private void addEntityToIdEqualsProjection(Writer output, ObjectModelClass input) throws IOException {
        String query = String.format("select new fr.ird.observe.dto.ToolkitIdBean(id, lastUpdateDate)\n" +
                                             "    from %s as e\n" +
                                             "    where e.id = ?1", input.getQualifiedName() + "Impl");
        addQuery(output, input.getQualifiedName() + "::id::equals", query, " read-only=\"true\"");
    }

    private void addEntityToIdInProjection(Writer output, ObjectModelClass input) throws IOException {
        String query = String.format("select new fr.ird.observe.dto.ToolkitIdBean(id, lastUpdateDate)\n" +
                                             "    from %s as e\n" +
                                             "    where e.id in ( ?1 )", input.getQualifiedName() + "Impl");
        addQuery(output, input.getQualifiedName() + "::id::in", query, " read-only=\"true\"");
    }

    private void addEntityToIdBeforeProjection(Writer output, ObjectModelClass input) throws IOException {
        String query = String.format("select new fr.ird.observe.dto.ToolkitIdBean(id, lastUpdateDate)\n" +
                                             "    from %s as e\n" +
                                             "    where e.lastUpdateDate <= ?1", input.getQualifiedName() + "Impl");
        addQuery(output, input.getQualifiedName() + "::id::before", query, " read-only=\"true\"");
    }

    private void addEntityToIdAfterProjection(Writer output, ObjectModelClass input) throws IOException {
        String query = String.format("select new fr.ird.observe.dto.ToolkitIdBean(id, lastUpdateDate)\n" +
                                             "    from %s as e\n" +
                                             "    where e.lastUpdateDate > ?1", input.getQualifiedName() + "Impl");
        addQuery(output, input.getQualifiedName() + "::id::after", query, " read-only=\"true\"");
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy