// Path: src/main/java/net/nextpulse/jadmin/ColumnDefinition.java
// public class ColumnDefinition {
// 
//   /**
//    * Column name, case sensitive
//    */
//   private String name;
//   /**
//    * JAdmin-type of this column.
//    */
//   private ColumnType type;
// 
//   /**
//    * True if this column is part of the key identifying a row of the datasource containing this column.
//    */
//   private boolean keyColumn;
//   private boolean editable;
//   private List<InputValidationRule> validationRules = new ArrayList<>();
//   private InputTransformer inputTransformer;
//   private ColumnValueTransformer columnValueTransformer;
// 
//   public ColumnDefinition() {
//   }
// 
//   public ColumnDefinition(String name, ColumnType type) {
//     this.name = name;
//     this.type = type;
//   }
// 
//   public ColumnDefinition(String name, ColumnType type, boolean keyColumn, boolean editable) {
//     this.name = name;
//     this.type = type;
//     this.keyColumn = keyColumn;
//     this.editable = editable;
//   }
// 
//   public String getName() {
//     return name;
//   }
// 
//   public ColumnDefinition setName(String name) {
//     this.name = name;
//     return this;
//   }
// 
//   public ColumnType getType() {
//     return type;
//   }
// 
//   public void setType(ColumnType type) {
//     this.type = type;
//   }
// 
//   public boolean isKeyColumn() {
//     return keyColumn;
//   }
// 
//   public ColumnDefinition setKeyColumn(boolean keyColumn) {
//     this.keyColumn = keyColumn;
//     return this;
//   }
// 
//   public boolean isEditable() {
//     return editable;
//   }
// 
//   public ColumnDefinition setEditable(boolean editable) {
//     this.editable = editable;
//     return this;
//   }
// 
//   /**
//    * Adds the provided input validation rule to the list of rules.
//    *
//    * @param inputValidationRules  rule(s) that should be active for this column
//    */
//   public ColumnDefinition addValidationRules(InputValidationRule... inputValidationRules) {
//     validationRules.addAll(Arrays.asList(inputValidationRules));
//     return this;
//   }
//   
//   /**
//    * @return the configured validation rules
//    */
//   public List<InputValidationRule> getValidationRules() {
//     return validationRules;
//   }
//   
//   public InputTransformer getInputTransformer() {
//     return inputTransformer;
//   }
//   
//   public ColumnDefinition setInputTransformer(InputTransformer inputTransformer) {
//     this.inputTransformer = inputTransformer;
//     return this;
//   }
// 
//   public ColumnValueTransformer getColumnValueTransformer() {
//     return columnValueTransformer;
//   }
// 
//   public ColumnDefinition setColumnValueTransformer(ColumnValueTransformer columnValueTransformer) {
//     this.columnValueTransformer = columnValueTransformer;
//     return this;
//   }
// }
// 
// Path: src/main/java/net/nextpulse/jadmin/ColumnType.java
// public enum ColumnType {
//   string,
//   text,
//   integer,
//   bool,
//   datetime;
// 
// }
// 
// Path: src/main/java/net/nextpulse/jadmin/dao/DataAccessException.java
// public class DataAccessException extends Exception {
//   public DataAccessException(Exception cause) {
//     super(cause);
//   }
// 
//   public DataAccessException(String message) {
//     super(message);
//   }
// 
//   public DataAccessException(String message, Exception cause) {
//     super(message, cause);
//   }
// }


import net.nextpulse.jadmin.ColumnDefinition;
import net.nextpulse.jadmin.ColumnType;
import net.nextpulse.jadmin.dao.DataAccessException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
package net.nextpulse.jadmin.schema;



/**
 * Generic implementation of the ResourceSchemaProvider interface, providing schema retrieval logic for SQL backed resources.
 *
 * @author yholkamp
 */
public class GenericSQLSchemaProvider implements ResourceSchemaProvider {

  private static final Logger logger = LogManager.getLogger();
  private static final String COLUMN_NAME = "COLUMN_NAME";
  private static final String TYPE_NAME = "TYPE_NAME";

  private final DataSource dataSource;
  private final String tableName;
  private List<ColumnDefinition> keyColumns = null;
  private List<ColumnDefinition> columnDefinitions = null;

  public GenericSQLSchemaProvider(DataSource dataSource, String tableName) {
    this.dataSource = dataSource;
    this.tableName = tableName;
  }

  @Override
  public List<ColumnDefinition> getKeyColumns() throws DataAccessException {
    if(keyColumns == null) {
      logger.trace("Retrieving key columns for {}", tableName);
      keyColumns = getColumnDefinitions().stream().filter(ColumnDefinition::isKeyColumn).collect(Collectors.toList());
    }
    return keyColumns;
  }

  @Override
// Path: src/main/java/net/nextpulse/jadmin/ColumnDefinition.java
// public class ColumnDefinition {
// 
//   /**
//    * Column name, case sensitive
//    */
//   private String name;
//   /**
//    * JAdmin-type of this column.
//    */
//   private ColumnType type;
// 
//   /**
//    * True if this column is part of the key identifying a row of the datasource containing this column.
//    */
//   private boolean keyColumn;
//   private boolean editable;
//   private List<InputValidationRule> validationRules = new ArrayList<>();
//   private InputTransformer inputTransformer;
//   private ColumnValueTransformer columnValueTransformer;
// 
//   public ColumnDefinition() {
//   }
// 
//   public ColumnDefinition(String name, ColumnType type) {
//     this.name = name;
//     this.type = type;
//   }
// 
//   public ColumnDefinition(String name, ColumnType type, boolean keyColumn, boolean editable) {
//     this.name = name;
//     this.type = type;
//     this.keyColumn = keyColumn;
//     this.editable = editable;
//   }
// 
//   public String getName() {
//     return name;
//   }
// 
//   public ColumnDefinition setName(String name) {
//     this.name = name;
//     return this;
//   }
// 
//   public ColumnType getType() {
//     return type;
//   }
// 
//   public void setType(ColumnType type) {
//     this.type = type;
//   }
// 
//   public boolean isKeyColumn() {
//     return keyColumn;
//   }
// 
//   public ColumnDefinition setKeyColumn(boolean keyColumn) {
//     this.keyColumn = keyColumn;
//     return this;
//   }
// 
//   public boolean isEditable() {
//     return editable;
//   }
// 
//   public ColumnDefinition setEditable(boolean editable) {
//     this.editable = editable;
//     return this;
//   }
// 
//   /**
//    * Adds the provided input validation rule to the list of rules.
//    *
//    * @param inputValidationRules  rule(s) that should be active for this column
//    */
//   public ColumnDefinition addValidationRules(InputValidationRule... inputValidationRules) {
//     validationRules.addAll(Arrays.asList(inputValidationRules));
//     return this;
//   }
//   
//   /**
//    * @return the configured validation rules
//    */
//   public List<InputValidationRule> getValidationRules() {
//     return validationRules;
//   }
//   
//   public InputTransformer getInputTransformer() {
//     return inputTransformer;
//   }
//   
//   public ColumnDefinition setInputTransformer(InputTransformer inputTransformer) {
//     this.inputTransformer = inputTransformer;
//     return this;
//   }
// 
//   public ColumnValueTransformer getColumnValueTransformer() {
//     return columnValueTransformer;
//   }
// 
//   public ColumnDefinition setColumnValueTransformer(ColumnValueTransformer columnValueTransformer) {
//     this.columnValueTransformer = columnValueTransformer;
//     return this;
//   }
// }
// 
// Path: src/main/java/net/nextpulse/jadmin/ColumnType.java
// public enum ColumnType {
//   string,
//   text,
//   integer,
//   bool,
//   datetime;
// 
// }
// 
// Path: src/main/java/net/nextpulse/jadmin/dao/DataAccessException.java
// public class DataAccessException extends Exception {
//   public DataAccessException(Exception cause) {
//     super(cause);
//   }
// 
//   public DataAccessException(String message) {
//     super(message);
//   }
// 
//   public DataAccessException(String message, Exception cause) {
//     super(message, cause);
//   }
// }


// Path: src/main/java/net/nextpulse/jadmin/schema/GenericSQLSchemaProvider.java
import net.nextpulse.jadmin.ColumnDefinition;
import net.nextpulse.jadmin.ColumnType;
import net.nextpulse.jadmin.dao.DataAccessException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

package net.nextpulse.jadmin.schema;



/**
 * Generic implementation of the ResourceSchemaProvider interface, providing schema retrieval logic for SQL backed resources.
 *
 * @author yholkamp
 */
public class GenericSQLSchemaProvider implements ResourceSchemaProvider {

  private static final Logger logger = LogManager.getLogger();
  private static final String COLUMN_NAME = "COLUMN_NAME";
  private static final String TYPE_NAME = "TYPE_NAME";

  private final DataSource dataSource;
  private final String tableName;
  private List<ColumnDefinition> keyColumns = null;
  private List<ColumnDefinition> columnDefinitions = null;

  public GenericSQLSchemaProvider(DataSource dataSource, String tableName) {
    this.dataSource = dataSource;
    this.tableName = tableName;
  }

  @Override
  public List<ColumnDefinition> getKeyColumns() throws DataAccessException {
    if(keyColumns == null) {
      logger.trace("Retrieving key columns for {}", tableName);
      keyColumns = getColumnDefinitions().stream().filter(ColumnDefinition::isKeyColumn).collect(Collectors.toList());
    }
    return keyColumns;
  }

  @Override
  public List<ColumnDefinition> getColumnDefinitions() throws DataAccessException {