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

io.nflow.engine.internal.dao.TableMetadataChecker Maven / Gradle / Ivy

There is a newer version: 10.0.0
Show newest version
package io.nflow.engine.internal.dao;

import static java.lang.String.format;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.inject.Inject;
import javax.inject.Named;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.nflow.engine.config.NFlow;
import io.nflow.engine.model.ModelObject;

@Named
public class TableMetadataChecker {
  private JdbcTemplate jdbc;

  public void ensureCopyingPossible(String sourceTable, String destinationTable) {
    Map sourceMetadataMap = getMetadata(sourceTable);
    Map destMetadataMap = getMetadata(destinationTable);
    if (destMetadataMap.size() < sourceMetadataMap.size()) {
      throw new IllegalArgumentException(format("Source table %s has more columns than destination table %s", sourceTable,
          destinationTable));
    }
    Set sourceKeySet = sourceMetadataMap.keySet();
    Set destKeySet = destMetadataMap.keySet();
    if (!destKeySet.containsAll(sourceKeySet)) {
      Set missingColumns = new LinkedHashSet<>(sourceKeySet);
      missingColumns.removeAll(destKeySet);
      throw new IllegalArgumentException(format("Destination table %s is missing columns %s that are present in source table %s",
          destinationTable, missingColumns, sourceTable));
    }
    for (Entry entry : sourceMetadataMap.entrySet()) {
      ColumnMetadata sourceMetadata = entry.getValue();
      ColumnMetadata destMetadata = destMetadataMap.get(entry.getKey());
      if (!sourceMetadata.typeName.equals(destMetadata.typeName)) {
        throw new IllegalArgumentException(format(
            "Source column %s.%s has type %s and destination column %s.%s has mismatching type %s", sourceTable,
            sourceMetadata.columnName, sourceMetadata.typeName, destinationTable, destMetadata.columnName, destMetadata.typeName));
      }
      if (sourceMetadata.size > destMetadata.size) {
        throw new IllegalArgumentException(format("Source column %s.%s has size %s and destination column %s.%s smaller size %s",
            sourceTable, sourceMetadata.columnName, sourceMetadata.size, destinationTable, destMetadata.columnName,
            destMetadata.size));
      }
    }
  }

  @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "jdbc is injected")
  private Map getMetadata(String tableName) {
    return jdbc.query("select * from " + tableName + " where 1 = 0", new MetadataExtractor());
  }

  static class MetadataExtractor implements ResultSetExtractor> {
    private final Map typeAliases = typeAliases();

    @Override
    public Map extractData(ResultSet rs) throws SQLException {
      ResultSetMetaData metadata = rs.getMetaData();
      Map metadataMap = new LinkedHashMap<>();
      for (int col = 1; col <= metadata.getColumnCount(); col++) {
        String columnName = metadata.getColumnName(col);
        String typeName = metadata.getColumnTypeName(col);
        int size = metadata.getColumnDisplaySize(col);
        metadataMap.put(columnName, new ColumnMetadata(columnName, resolveTypeAlias(typeName), size));
      }
      return metadataMap;
    }

    private String resolveTypeAlias(String type) {
      String resolvedType = typeAliases.get(type);
      if (resolvedType != null) {
        return resolvedType;
      }
      return type;
    }

    private Map typeAliases() {
      Map map = new LinkedHashMap<>();
      map.put("serial", "int4");
      return map;
    }
  }

  private static class ColumnMetadata extends ModelObject {
    public final String columnName;
    public final String typeName;
    public final int size;

    public ColumnMetadata(String columnName, String typeName, int size) {
      this.columnName = columnName;
      this.typeName = typeName;
      this.size = size;
    }
  }

  @Inject
  public void setJdbcTemplate(@NFlow JdbcTemplate jdbcTemplate) {
    this.jdbc = jdbcTemplate;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy