io.github.carlomicieli.footballdb.starter.pages.Table.java Source code

Java tutorial

Introduction

Here is the source code for io.github.carlomicieli.footballdb.starter.pages.Table.java

Source

/*
 * Copyright 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.github.carlomicieli.footballdb.starter.pages;

import org.apache.commons.lang3.tuple.ImmutablePair;

import java.util.*;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toMap;

/**
 * It represents an immutable Table, with an optional header.
 *
 * @author Carlo Micieli
 */
public class Table {
    private final List<String> headers;
    private final List<Row> rows;
    private final ImmutablePair<Integer, Integer> size;

    protected Table(TableBuilder tb) {
        this.size = ImmutablePair.of(tb.size.getKey(), tb.size.getValue());
        this.headers = Collections.unmodifiableList(tb.columnHeaders);
        this.rows = tb.values.stream().map(r -> Row.of(r, headers)).collect(Collectors.toList());
    }

    /**
     * Returns a new <em>TableBuilder</em> to build tables
     *
     * @return a new table builder
     */
    public static TableBuilder builder() {
        return new TableBuilder();
    }

    /**
     * Returns the number of table rows.
     *
     * @return the rows count
     */
    public int columnsCount() {
        return size.getRight();
    }

    /**
     * Returns the number of rows in the table.
     *
     * @return the rows count
     */
    public int rowsCount() {
        return size.getLeft();
    }

    /**
     * Returns the table size.
     *
     * @return the table size
     */
    public ImmutablePair<Integer, Integer> size() {
        return size;
    }

    /**
     * Returns the n-th row in the table, or <em>Optional.empty()</em> if the
     * column is not present.
     *
     * @param index the row number (starting from 1)
     * @return a row
     */
    public Optional<Row> row(int index) {
        if (index > size.getLeft()) {
            return Optional.empty();
        }
        return Optional.ofNullable(rows.get(index - 1));
    }

    /**
     * Returns the List of extractValues for the n-th row in the table.
     * @param index the row number (starting from 1)
     * @return
     */
    public Optional<List<String>> rowValues(int index) {
        return row(index).map(r -> r.values);
    }

    /**
     * Returns the table header.
     *
     * @return the header
     */
    public List<String> header() {
        return headers;
    }

    /**
     * Returns the stream for the table rows.
     *
     * @return the rows
     */
    public Stream<Row> rowsStream() {
        return rows.stream();
    }

    public Map<String, String> valuesForRow(int n) {
        if (tableWithoutHeader())
            return Collections.emptyMap();

        return rowValues(n).map(cells -> {
            Map<String, String> m = IntStream.range(0, columnsCount()).mapToObj(bindHeaderWithValue(cells))
                    .collect(toMap(p -> p.getKey(), p -> p.getValue()));
            return m;
        }).orElse(null);
    }

    @Override
    public String toString() {
        return "Table(" + headersToString() + rowsToString() + ")";
    }

    private String rowsToString() {
        return rowsStream().map(Row::toString).collect(Collectors.joining(", "));
    }

    private String headersToString() {
        if (tableWithoutHeader())
            return "";
        return "Header(" + headers.stream().collect(Collectors.joining(", ")) + "), ";
    }

    private IntFunction<ImmutablePair<String, String>> bindHeaderWithValue(List<String> cells) {
        return index -> ImmutablePair.of(headers.get(index), cells.get(index));
    }

    private boolean tableWithoutHeader() {
        return headers.size() == 0;
    }

    public Stream<Row> filter(Predicate<Row> predicate) {
        return rowsStream().filter(predicate);
    }

    public Stream<Row> map(Function<Row, Row> mapper) {
        return rowsStream().map(mapper);
    }

    public static class Row {
        private final List<String> values;
        private final List<String> header;

        private Row(List<String> values, List<String> header) {
            this.values = values;
            this.header = header;
        }

        public static Row of(List<String> values, List<String> header) {
            return new Row(values, header);
        }

        public String value(int column) {
            return get(column - 1);
        }

        public String value(String columnName) {
            if (header.size() == 0)
                throw new UnsupportedOperationException("Table without header");

            int index = header.indexOf(columnName);
            if (index != -1) {
                return get(index);
            }

            return "";
        }

        public Row subset(String... columns) {
            List<String> values = Stream.of(columns).map(this::value).collect(Collectors.toList());
            return new Row(values, Arrays.asList(columns));
        }

        @Override
        public String toString() {
            return "Row(" + values.stream().collect(Collectors.joining(", ")) + ")";
        }

        private String get(int index) {
            return values.get(index);
        }
    }
}