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

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

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 com.google.gson.Gson;
import org.nuiton.eugene.models.object.ObjectModel;
import org.nuiton.eugene.models.object.ObjectModelClass;
import org.nuiton.eugene.models.object.ObjectModelType;
import org.nuiton.topia.persistence.TopiaEntity;
import org.nuiton.topia.service.sql.internal.TopiaEntitySqlModelResourceImpl;
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.TopiaMetadataReverseAssociation;
import org.nuiton.topia.service.sql.script.DeleteReferentialScript;
import org.nuiton.topia.service.sql.script.DisableReferentialScript;
import org.nuiton.topia.service.sql.script.ReplaceReferentialInDataScript;
import org.nuiton.topia.service.sql.script.ReplaceReferentialInReferentialScript;
import org.nuiton.topia.service.sql.script.TopiaEntitySqlScript;
import org.nuiton.topia.service.sql.script.TopiaEntitySqlScriptModel;
import org.nuiton.topia.service.sql.script.UpdateLastUpdateDateFieldScript;
import org.nuiton.topia.service.sql.script.UpdateLastUpdateDateTableScript;
import org.nuiton.topia.templates.TopiaTemplateHelper;
import org.nuiton.topia.templates.sql.TopiaMetadataModelBuilder;
import org.nuiton.topia.templates.sql.TopiaMetadataModelGeneratorSupport;

import java.io.File;
import java.io.Writer;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;

/**
 * Created on 13/09/2020.
 *
 * @author Tony Chemit - [email protected]
 * @since 1.27
 */
public class ToolkitEntityScriptModelGenerator extends TopiaMetadataModelGeneratorSupport {

    private static final String UPDATE_LAST_UPDATE_DATE_FIELD_SQL_START = "UPDATE %s.%s SET lastUpdateDate = '%%1$s'::timestamp, topiaVersion = topiaVersion + 1";
    private static final String UPDATE_LAST_UPDATE_DATE_FIELD_SQL_WHERE_EQUALS = " WHERE %s = '%%2$s'";
    private static final String UPDATE_LAST_UPDATE_DATE_FIELD_SQL_WHERE_SELECT = " WHERE topiaId = ( %s )";
    private static final String UPDATE_LAST_UPDATE_DATA_FIELD_SQL_SELECT_START = "SELECT %3$s FROM %1$s.%2$s %2$s";
    private static final String UPDATE_LAST_UPDATE_DATA_FIELD_SQL_INNER_JOIN_REVERSE = " INNER JOIN %1$s.%2$s %2$s ON %2$s.%3$s = %4$s.%5$s";
    private static final String UPDATE_LAST_UPDATE_DATA_FIELD_SQL_INNER_JOIN_SIMPLE = " INNER JOIN %1$s.%2$s %2$s ON %2$s.%3$s = %4$s.topiaId";
    private static final String UPDATE_LAST_UPDATE_DATE_TABLE_SQL = "UPDATE common.lastUpdateDate SET lastUpdateDate = '%%1$s'::timestamp WHERE type ='%s'";
    private final Gson gson = TopiaEntitySqlModelResourceImpl.getGsonBuilder().create();

    @Override
    public String getFilenameForModel(ObjectModel model) {
        return TopiaEntitySqlModelResourceImpl.toScriptModelLocation(super.getFilenameForModel(model));
    }

    @Override
    protected File getDestinationFile(File destDir, String filename) {
        return destDir.toPath().resolve(filename).toFile();
    }

    @Override
    protected void generateFromElement(Object element, File destDir, String filename, ObjectModelType type) {
        if (ObjectModelType.OBJECT_MODEL != type) {
            // only generate on model
            return;
        }
        super.generateFromElement(element, destDir, filename, type);
    }

    @Override
    public void generateFromModel(Writer output, ObjectModel input) {

        TopiaTemplateHelper templateHelper = getTemplateHelper();
        metadataModel = TopiaMetadataModelBuilder.buildFull(isVerbose(), model, templateHelper);
        allPaths = getAllPaths();

        Map queries = new TreeMap<>();
        List entityClasses = templateHelper.getEntityClasses(model, true);
        for (ObjectModelClass entityClass : entityClasses) {
            if (entityClass.isAbstract()) {
                continue;
            }
            boolean referential = entityClass.getPackageName().contains(".referential");
            TopiaMetadataEntity entity = getEntityEnumName(entityClass);
            UpdateLastUpdateDateFieldScript fieldRequests = new UpdateLastUpdateDateFieldScript(generateLastUpdateDateFieldRequests(entity));
            UpdateLastUpdateDateTableScript tableRequests = new UpdateLastUpdateDateTableScript(generateLastUpdateDateTableRequests(entity));
            ReplaceReferentialInDataScript replaceReferentialInDataScript = null;
            ReplaceReferentialInReferentialScript replaceReferentialInReferentialScript = null;
            DeleteReferentialScript deleteReferentialScript = null;
            DisableReferentialScript disableReferentialScript = null;
            if (referential) {
                List replaceInDataScriptRequests = new ReplaceReferentialScriptGenerator(metadataModel, entity).generateSql("%2$s", "%3$s", "%1$s", true);
                List replaceInReferentialScriptRequests = new ReplaceReferentialScriptGenerator(metadataModel, entity).generateSql("%2$s", "%3$s", "%1$s", false);
                List deleteScriptRequests = new DeleteReferentialScriptGenerator(metadataModel, entity).generateSql("%1$s");
                List disableScriptRequests = List.of(new DisableReferentialScriptGenerator(entity).generateSql());
                replaceReferentialInDataScript = replaceInDataScriptRequests.isEmpty() ? null : new ReplaceReferentialInDataScript(replaceInDataScriptRequests);
                replaceReferentialInReferentialScript = replaceInReferentialScriptRequests.isEmpty() ? null : new ReplaceReferentialInReferentialScript(replaceInReferentialScriptRequests);
                deleteReferentialScript = new DeleteReferentialScript(deleteScriptRequests);
                disableReferentialScript = new DisableReferentialScript(disableScriptRequests);
            }
            TopiaEntitySqlScript entityQueries = new TopiaEntitySqlScript(fieldRequests, tableRequests, replaceReferentialInDataScript, replaceReferentialInReferentialScript, deleteReferentialScript, disableReferentialScript);
            queries.put(entity.getFullyQualifiedName(), entityQueries);
        }
        TopiaEntitySqlScriptModel scriptModel = new TopiaEntitySqlScriptModel(queries);
        gson.toJson(scriptModel, output);
    }

    protected List generateLastUpdateDateFieldRequests(TopiaMetadataEntity entity) {
        List types;
        List links;
        Optional optionalPath = getAllPaths().getEntityPathsForEntryPoint(entity);
        if (optionalPath.isPresent()) {
            TopiaMetadataEntityPath path = optionalPath.get();
            links = new LinkedList<>(path.getLinks());
            types = new LinkedList<>(path.getTypes());
        } else {
            // limit case, only one type
            types = List.of(entity);
            // and no link
            links = List.of();
        }
        return generateLastUpdateDateFieldRequests(types, links);
    }

    protected List generateLastUpdateDateTableRequests(TopiaMetadataEntity entity) {
        List types;
        Optional optionalPath = getAllPaths().getEntityPathsForEntryPoint(entity);
        if (optionalPath.isPresent()) {
            TopiaMetadataEntityPath path = optionalPath.get();
            types = new LinkedList<>(path.getTypes());
        } else {
            // limit case, only one type
            types = List.of(entity);
            // and no link
        }
        return generateLastUpdateDateTableRequests(types);
    }

    private List generateLastUpdateDateTableRequests(List types) {
        List result = new LinkedList<>();
        List tmp = new LinkedList<>(types);
        Collections.reverse(tmp);
        for (TopiaMetadataEntity type : tmp) {
            String tableSql = String.format(UPDATE_LAST_UPDATE_DATE_TABLE_SQL, type.getFullyQualifiedName());
            result.add(tableSql + ";");
        }
        return result;
    }

    private List generateLastUpdateDateFieldRequests(List types, List links) {
        List builder = new LinkedList<>();
        // take types in reverse order
        Collections.reverse(types);
        // take links in reverse order
        Collections.reverse(links);
        List inProcess = null;
        Iterator linksIterator = links.iterator();
        for (TopiaMetadataEntity type : types) {
            String fieldSql = generateLastUpdateDateFieldRequest(type, inProcess);
            builder.add(fieldSql + ";");
            if (inProcess == null) {
                // first round
                inProcess = new LinkedList<>();
            }
            if (linksIterator.hasNext()) {
                inProcess.add(linksIterator.next());
            }
        }
        return builder;
    }

    private String generateLastUpdateDateFieldRequest(TopiaMetadataEntity type, List inProcess) {
        String sql = String.format(UPDATE_LAST_UPDATE_DATE_FIELD_SQL_START, type.getDbSchemaName(), type.getDbTableName());
        if (inProcess == null) {
            sql += finalizeRequest(TopiaEntity.PROPERTY_TOPIA_ID);
            return sql;
        }
        // Needs links from root to type
        List tmp = new LinkedList<>(inProcess);
        Collections.reverse(tmp);
        Iterator inOderLinks = tmp.iterator();

        TopiaMetadataLink firstLink = inOderLinks.next();
        if (!inOderLinks.hasNext() && firstLink instanceof TopiaMetadataReverseAssociation) {
            sql += finalizeRequest(firstLink.getTargetDbName());
            return sql;
        }
        StringBuilder selectSql = new StringBuilder();
        selectSql.append(prepareSubSelect(firstLink));
        TopiaMetadataLink lastLink = firstLink;
        while (inOderLinks.hasNext()) {
            TopiaMetadataLink nextLink = inOderLinks.next();
            if (!(nextLink instanceof TopiaMetadataReverseAssociation)) {
                selectSql.append(appendInnerJoin(lastLink, nextLink));
            }
            lastLink = nextLink;
        }
        selectSql.append(finalizeSubSelect(lastLink));
        sql += String.format(UPDATE_LAST_UPDATE_DATE_FIELD_SQL_WHERE_SELECT, selectSql);
        return sql;
    }

    private String finalizeRequest(String column) {
        return String.format(UPDATE_LAST_UPDATE_DATE_FIELD_SQL_WHERE_EQUALS, column);
    }

    private String prepareSubSelect(TopiaMetadataLink firstLink) {
        String selectColumn;
        TopiaMetadataEntity tableOwner;
        if (firstLink instanceof TopiaMetadataReverseAssociation) {
            tableOwner = firstLink.getOwner();
            selectColumn = TopiaEntity.PROPERTY_TOPIA_ID;
        } else {
            tableOwner = firstLink.getTarget();
            selectColumn = firstLink.getTarget().getDbColumnName(firstLink.getOwner().getDbTableName());
        }
        return String.format(UPDATE_LAST_UPDATE_DATA_FIELD_SQL_SELECT_START, tableOwner.getDbSchemaName(), tableOwner.getDbTableName(), tableOwner.getDbTableName() + "." + selectColumn);
    }

    private String appendInnerJoin(TopiaMetadataLink lastLink, TopiaMetadataLink nextLink) {
        TopiaMetadataEntity tableOwner = nextLink.getTarget();
        if (lastLink instanceof TopiaMetadataReverseAssociation) {
            String columnName = lastLink.getTargetDbName();
            return String.format(UPDATE_LAST_UPDATE_DATA_FIELD_SQL_INNER_JOIN_REVERSE, tableOwner.getDbSchemaName(), tableOwner.getDbTableName(), columnName, lastLink.getOwner().getDbTableName(), lastLink.getTargetDbName());
        }
        String columnName = tableOwner.getDbColumnName(nextLink.getOwner().getDbTableName());
        return String.format(UPDATE_LAST_UPDATE_DATA_FIELD_SQL_INNER_JOIN_SIMPLE, tableOwner.getDbSchemaName(), tableOwner.getDbTableName(), columnName, lastLink.getTarget().getDbTableName());
    }

    private String finalizeSubSelect(TopiaMetadataLink lastLink) {
        String targetColumn;
        if (lastLink instanceof TopiaMetadataReverseAssociation) {
            targetColumn = lastLink.getTableName() + "." + lastLink.getTargetDbName();
        } else {
            targetColumn = lastLink.getTarget().getDbTableName() + "." + TopiaEntity.PROPERTY_TOPIA_ID;
        }
        return finalizeRequest(targetColumn);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy