001package org.itsallcode.jdbc.metadata;
002
003import java.sql.*;
004
005import org.itsallcode.jdbc.Context;
006import org.itsallcode.jdbc.UncheckedSQLException;
007import org.itsallcode.jdbc.resultset.*;
008
009/**
010 * A simple wrapper for {@link DatabaseMetaData}.
011 */
012public class DbMetaData {
013
014    private final DatabaseMetaData metaData;
015    private final Context context;
016
017    /**
018     * Create a new instance.
019     * 
020     * @param context  DB context.
021     * @param metaData metaData object.
022     */
023    public DbMetaData(final Context context, final DatabaseMetaData metaData) {
024        this.context = context;
025        this.metaData = metaData;
026    }
027
028    /**
029     * Retrieves a description of the tables available in the given catalog. Only
030     * table descriptions matching the catalog, schema, table name and type criteria
031     * are returned. They are ordered by {@code TABLE_TYPE}, {@code TABLE_CAT},
032     * {@code TABLE_SCHEM} and {@code TABLE_NAME}.
033     * 
034     * @param catalog          a catalog name; must match the catalog name as it is
035     *                         stored in the database; "" retrieves those without a
036     *                         catalog; {@code null} means that the catalog name
037     *                         should not be used to narrow the search
038     * @param schemaPattern    a schema name pattern; must match the schema name as
039     *                         it is stored in the database; "" retrieves those
040     *                         without a schema; {@code null} means that the schema
041     *                         name should not be used to narrow the search
042     * @param tableNamePattern a table name pattern; must match the table name as it
043     *                         is stored in the database
044     * @param types            a list of table types, which must be from the list of
045     *                         table types returned from
046     *                         {@link DatabaseMetaData#getTableTypes()},to include;
047     *                         {@code null} returns all types
048     * @return table descriptions
049     * @see DatabaseMetaData#getTables(String, String, String, String[])
050     */
051    public SimpleResultSet<TableMetaData> getTables(final String catalog, final String schemaPattern,
052            final String tableNamePattern, final String[] types) {
053        return wrapResultSet(getTablesInternal(catalog, schemaPattern, tableNamePattern, types),
054                TableMetaData::create);
055    }
056
057    private ResultSet getTablesInternal(final String catalog, final String schemaPattern, final String tableNamePattern,
058            final String[] types) {
059        try {
060            return metaData.getTables(catalog, schemaPattern, tableNamePattern, types);
061        } catch (final SQLException e) {
062            throw new UncheckedSQLException("Error getting tables", e);
063        }
064    }
065
066    /**
067     * Retrieves a description of table columns available in the specified catalog.
068     * <P>
069     * Only column descriptions matching the catalog, schema, table and column name
070     * criteria are returned. They are ordered by
071     * {@code TABLE_CAT},{@code TABLE_SCHEM}, {@code TABLE_NAME}, and
072     * {@code ORDINAL_POSITION}.
073     * 
074     * @param catalog           a catalog name; must match the catalog name as it is
075     *                          stored in the database; "" retrieves those without a
076     *                          catalog; {@code null} means that the catalog name
077     *                          should not be used to narrow the search
078     * @param schemaPattern     a schema name pattern; must match the schema name as
079     *                          it is stored in the database; "" retrieves those
080     *                          without a schema; {@code null} means that the schema
081     *                          name should not be used to narrow the search
082     * @param tableNamePattern  a table name pattern; must match the table name as
083     *                          it is stored in the database
084     * @param columnNamePattern a column name pattern; must match the column name as
085     *                          it is stored in the database
086     * @return column descriptions
087     * @see DatabaseMetaData#getColumns(String, String, String, String)
088     */
089    public SimpleResultSet<ColumnMetaData> getColumns(final String catalog, final String schemaPattern,
090            final String tableNamePattern, final String columnNamePattern) {
091        return wrapResultSet(getColumnsInternal(catalog, schemaPattern, tableNamePattern, columnNamePattern),
092                ColumnMetaData::create);
093    }
094
095    private ResultSet getColumnsInternal(final String catalog, final String schemaPattern,
096            final String tableNamePattern, final String columnNamePattern) {
097        try {
098            return metaData.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern);
099        } catch (final SQLException e) {
100            throw new UncheckedSQLException("Error getting columns", e);
101        }
102    }
103
104    private <T> SimpleResultSet<T> wrapResultSet(final ResultSet resultSet, final SimpleRowMapper<T> rowMapper) {
105        return new SimpleResultSet<>(context, resultSet, ContextRowMapper.create(rowMapper), () -> {
106        });
107    }
108}