org.chaston.oakfunds.storage.mgmt.SchemaBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.chaston.oakfunds.storage.mgmt.SchemaBuilder.java

Source

/*
 * Copyright 2014 Miles Chaston
 *
 * 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 org.chaston.oakfunds.storage.mgmt;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import com.google.inject.Inject;
import org.chaston.oakfunds.jdbc.ColumnDef;
import org.chaston.oakfunds.jdbc.FunctionDef;
import org.chaston.oakfunds.jdbc.TableDef;
import org.chaston.oakfunds.storage.AttributeType;
import org.chaston.oakfunds.storage.Identifiable;
import org.chaston.oakfunds.storage.RecordType;
import org.chaston.oakfunds.storage.SystemColumnDefs;
import org.joda.time.Instant;

import java.math.BigDecimal;
import java.sql.Types;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

/**
 * TODO(mchaston): write JavaDocs
 */
public class SchemaBuilder {
    private final ImmutableMap<String, TableDef> tableDefs;
    private final ImmutableMap<String, FunctionDef> functionDefs;

    @Inject
    SchemaBuilder(Set<RecordType> recordTypes, Set<FunctionDef> functionDefs) {
        Multimap<RecordType, RecordType> typesBySuperType = groupBySuperType(recordTypes);
        Map<String, TableDef.Builder> tableDefBuilders = createBaseTables(typesBySuperType);
        tableDefs = ImmutableMap
                .copyOf(Maps.transformValues(tableDefBuilders, new Function<TableDef.Builder, TableDef>() {
                    @Override
                    public TableDef apply(TableDef.Builder builder) {
                        return builder.build();
                    }
                }));
        ImmutableMap.Builder<String, FunctionDef> functionDefsBuilder = ImmutableMap.builder();
        for (FunctionDef functionDef : functionDefs) {
            functionDefsBuilder.put(functionDef.getName(), functionDef);
        }
        this.functionDefs = functionDefsBuilder.build();
    }

    private Multimap<RecordType, RecordType> groupBySuperType(Set<? extends RecordType> recordTypes) {
        Multimap<RecordType, RecordType> typesBySuperType = MultimapBuilder.hashKeys().arrayListValues().build();
        for (RecordType recordType : recordTypes) {
            typesBySuperType.put(recordType.getRootType(), recordType);
        }
        return typesBySuperType;
    }

    private Map<String, TableDef.Builder> createBaseTables(Multimap<RecordType, RecordType> typesBySuperType) {
        ImmutableMap.Builder<String, TableDef.Builder> baseTables = ImmutableMap.builder();
        for (Map.Entry<RecordType, Collection<RecordType>> entry : typesBySuperType.asMap().entrySet()) {
            RecordType rootType = entry.getKey();
            TableDef.Builder tableDefBuilder = TableDef.builder(SystemColumnDefs.SCHEMA, rootType.getName());
            tableDefBuilder.addColumnDef(
                    rootType.isAutoIncrementId() ? SystemColumnDefs.AUTO_NUMBERED_ID : SystemColumnDefs.MANUAL_ID);
            tableDefBuilder.addColumnDef(SystemColumnDefs.TYPE);

            switch (rootType.getTemporalType()) {
            case NONE:
                // Nothing more to add.
                break;
            case INSTANT:
                tableDefBuilder.addColumnDef(SystemColumnDefs.INSTANT);
                break;
            case INTERVAL:
                tableDefBuilder.addColumnDef(SystemColumnDefs.START_TIME);
                tableDefBuilder.addColumnDef(SystemColumnDefs.END_TIME);
                break;
            default:
                throw new UnsupportedOperationException(
                        "Temporal type " + rootType.getTemporalType() + " is not supported.");
            }

            if (rootType.getContainingType() != null) {
                tableDefBuilder.addColumnDef(SystemColumnDefs.CONTAINER_ID);
            }

            Collection<RecordType> subTypes = entry.getValue();
            for (RecordType<?> subType : subTypes) {
                for (AttributeType attributeType : subType.getAttributes().values()) {
                    tableDefBuilder.addColumnDef(new ColumnDef(attributeType.getColumnName(),
                            toSqlType(attributeType.getType()), false)); // Never make user defined types required.
                }
            }
            baseTables.put(rootType.getName(), tableDefBuilder);
        }
        return baseTables.build();
    }

    private int toSqlType(Class<?> attributeType) {
        if (String.class.equals(attributeType)) {
            return Types.VARCHAR;
        }
        if (Integer.class.equals(attributeType) || Integer.TYPE.equals(attributeType)) {
            return Types.INTEGER;
        }
        if (Boolean.class.equals(attributeType) || Boolean.TYPE.equals(attributeType)) {
            return Types.BOOLEAN;
        }
        if (BigDecimal.class.equals(attributeType)) {
            return Types.BIGINT;
        }
        if (Instant.class.equals(attributeType)) {
            return Types.TIMESTAMP;
        }
        if (Identifiable.class.isAssignableFrom(attributeType)) {
            return Types.SMALLINT;
        }
        throw new UnsupportedOperationException("Type " + attributeType + " is not supported.");
    }

    public ImmutableMap<String, TableDef> getTableDefs() {
        return tableDefs;
    }

    public ImmutableMap<String, FunctionDef> getFunctionDefs() {
        return functionDefs;
    }
}