Package co.jirm.orm.dao

Source Code of co.jirm.orm.dao.JirmDao

/**
* Copyright (C) 2012 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 co.jirm.orm.dao;

import static com.google.common.collect.Iterators.partition;
import static com.google.common.collect.Iterators.peekingIterator;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import co.jirm.core.execute.SqlExecutor;
import static co.jirm.core.util.JirmPrecondition.check;
import co.jirm.core.util.ObjectMapUtils;
import co.jirm.core.util.ObjectMapUtils.NestedKeyValue;
import co.jirm.mapper.SqlObjectConfig;
import co.jirm.mapper.copy.CopyBuilder;
import co.jirm.mapper.definition.SqlObjectDefinition;
import co.jirm.mapper.definition.SqlParameterDefinition;
import co.jirm.orm.OrmConfig;
import co.jirm.orm.builder.delete.DeleteBuilderFactory;
import co.jirm.orm.builder.delete.DeleteRootClauseBuilder;
import co.jirm.orm.builder.select.SelectBuilderFactory;
import co.jirm.orm.builder.select.SelectBuilderFactory.CountBuilder;
import co.jirm.orm.builder.select.SelectBuilderFactory.SelectObjectBuilder;
import co.jirm.orm.builder.select.SelectRootClauseBuilder;
import co.jirm.orm.builder.update.UpdateBuilderFactory;
import co.jirm.orm.builder.update.UpdateObjectBuilder;
import co.jirm.orm.builder.update.UpdateRootClauseBuilder;
import co.jirm.orm.writer.SqlWriterStrategy;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.PeekingIterator;


public final class JirmDao<T> {

  private final SqlExecutor sqlExecutor;
  private final SqlObjectConfig config;
  private final SqlObjectDefinition<T> definition;
  private final SelectBuilderFactory<T> selectBuilderFactory;
  private final UpdateBuilderFactory<T> updateBuilderFactory;
  private final DeleteBuilderFactory<T> deleteBuilderFactory;
  private final SqlWriterStrategy writerStrategy;
 
  private JirmDao(
      SqlExecutor sqlExecutor,
      SqlObjectConfig config,
      SqlObjectDefinition<T> definition,
      SqlWriterStrategy writerStrategy,
      SelectBuilderFactory<T> selectBuilderFactory,
      UpdateBuilderFactory<T> updateBuilderFactory,
      DeleteBuilderFactory<T> deleteBuilderFactory) {
    super();
    this.sqlExecutor = sqlExecutor;
    this.config = config;
    this.definition = definition;
    this.writerStrategy = writerStrategy;
    this.selectBuilderFactory = selectBuilderFactory;
    this.updateBuilderFactory = updateBuilderFactory;
    this.deleteBuilderFactory = deleteBuilderFactory;
  }
 
  public static <T> JirmDao<T> newInstance(Class<T> type, OrmConfig config) {
    SqlObjectDefinition<T> definition = config.getSqlObjectConfig().resolveObjectDefinition(type);
    SelectBuilderFactory<T> selectBuilderFactory = SelectBuilderFactory.newInstance(definition, config);
    UpdateBuilderFactory<T> updateBuilderFactory = UpdateBuilderFactory.newInstance(definition, config);
    DeleteBuilderFactory<T> deleteBuilderFactory = DeleteBuilderFactory.newInstance(definition, config);
   
    return new JirmDao<T>(
        config.getSqlExecutor(),
        config.getSqlObjectConfig(),
        definition, config.getSqlWriterStrategy(),
        selectBuilderFactory, updateBuilderFactory, deleteBuilderFactory);
  }

  private LinkedHashMap<String, Object> toLinkedHashMap(T t, boolean bulkInsert) {
    LinkedHashMap<String, Object> m = config.getObjectMapper().convertObjectToSqlMap(t);
    /*
     * Replace the complex objects with there ids.
     */
    for(SqlParameterDefinition pd : definition.getManyToOneParameters().values()) {
      if (pd.getObjectDefinition().isPresent()
          && pd.getObjectDefinition().get().getObjectDefintion().idParameter().isPresent()) {
        SqlParameterDefinition idDef =
            pd.getObjectDefinition().get().getObjectDefintion().idParameter().get();
        NestedKeyValue<Object> nkv =  ObjectMapUtils.getNestedKeyValue(m, pd.getParameterName(), idDef.getParameterName());
        if (nkv.isPresent()) {
          /*
           * TODO: We only set it if the object is actually present. ie do you really want to set null?
           */
          m.put(pd.getParameterName(), idDef.convertToSql(nkv.object));
        }
        else if (bulkInsert) {
          //TODO default annotation perhaps here?
          //http://stackoverflow.com/questions/197045/setting-default-values-for-columns-in-jpa
          m.put(pd.getParameterName(), null);
        }
      }
    }
    for(Entry<String,Object> e : m.entrySet()) {
      Optional<SqlParameterDefinition> d = definition.resolveParameter(e.getKey());
      if (d.isPresent()) {
        e.setValue(d.get().convertToSql(e.getValue()));
      }
    }
    if (bulkInsert) {
      LinkedHashMap<String, Object> copy = new LinkedHashMap<String, Object>(definition.getIdParameters().size());
      /*
       * Order and the number of parameters is really important for bulk insert.
       */
      for(SqlParameterDefinition pd : definition.getParameters().values()) {
        check.state(m.containsKey(pd.getParameterName()),
            "Missing parameter for bulk insert: {}", pd.getParameterName());
        Object o = m.get(pd.getParameterName());
        copy.put(pd.getParameterName(), o);
      }
      m = copy;
    }
    return m;
       
  }
 
  public CopyBuilder<T> copyBuilder() {
    return CopyBuilder.newInstance(definition.getObjectType(), config.getObjectMapper());
  }
 
  protected SqlParameterDefinition idParameter() {
    check.state(definition.idParameter().isPresent(), "No id parameter for : {}",
        definition.getObjectType());
    return this.definition.idParameter().get();
  }
 
  public SelectRootClauseBuilder<SelectObjectBuilder<T>> select() {
    return selectBuilderFactory.select();
  }
 
  public SelectRootClauseBuilder<CountBuilder<T>> count() {
    return selectBuilderFactory.count();
  }
 
  public UpdateRootClauseBuilder<Integer> update() {
    return updateBuilderFactory.update();
  }
 
  public DeleteRootClauseBuilder<Integer> delete() {
    return deleteBuilderFactory.delete();
  }
 
  public Optional<T> findOptionalById(Object id) {
    return select().where()
        .property(idParameter().getParameterName()).eq(id)
        .query()
        .forOptional();
  }
 
  public T findById(Object id) {
    return select().where()
        .property(idParameter().getParameterName()).eq(id)
        .query()
        .forObject();
  }
 
  public void insert(T t) {
    LinkedHashMap<String, Object> m = toLinkedHashMap(t, false);
    Iterator<Entry<String, Object>> it = m.entrySet().iterator();
    /*
     * Remove the null values that are to be generated.
     */
    while(it.hasNext()) {
      Entry<String, Object> e = it.next();
      Optional<SqlParameterDefinition> p = definition.resolveParameter(e.getKey());
      if (p.isPresent() && p.get().isGenerated() && e.getValue() == null) {
        it.remove();
      }
      else if (p.isPresent() && p.get().isVersion() && e.getValue() == null) {
        e.setValue(0);
      }
    }
    insert(m);
  }
 
  public int deleteById(Object id) {
    return deleteBuilderFactory
      .delete()
      .where().property(idParameter().getParameterName()).eq(id)
      .execute();
  }
 
  public UpdateObjectBuilder<T> update(T t) {
    LinkedHashMap<String, Object> m = toLinkedHashMap(t, false);
    return updateBuilderFactory.update(m);
  }

  public T reload(T t) {
    LinkedHashMap<String, Object> m = toLinkedHashMap(t, false);
    Optional<SqlParameterDefinition> id = definition.idParameter();
    check.state(id.isPresent(), "No id definition");
    Optional<Object> o = id.get().valueFrom(m);
    return findById(o.get());
  }
 
  public void insert(Map<String,Object> values) {
    StringBuilder qb = new StringBuilder();
    writerStrategy.insertStatement(qb, definition, values);
    sqlExecutor.update(qb.toString(), writerStrategy.fillValues(definition, values).toArray());
  }
 
  public void insert(Iterator<T> values, int batchSize) {
    Iterator<Map<String,Object>> t = Iterators.transform(values, new Function<T, Map<String,Object>>() {
      @Override
      public Map<String, Object> apply(T input) {
        return toLinkedHashMap(input, true);
      }
    });
    insertMaps(t, batchSize);
  }
 
  public void insertMaps(Iterator<Map<String,Object>> values, int batchSize) {
    if (! values.hasNext() ) return;
    PeekingIterator<Map<String,Object>> vs = peekingIterator(values);
    Map<String,Object> first = vs.peek();
    final String sql = writerStrategy.insertStatement(new StringBuilder(), definition, first).toString();
    ImmutableList<String> keys = ImmutableList.copyOf(vs.peek().keySet());
    Iterator<List<Map<String,Object>>> it = partition(vs, batchSize);

    while (it.hasNext()) {
      List<Map<String,Object>> batch = it.next();
      final List<Object[]> batchValues = Lists.newArrayListWithExpectedSize(batch.size());
      for (Map<String,Object> b : batch) {
        ImmutableList<String> actualKeys = ImmutableList.copyOf(b.keySet());
        check.state(actualKeys.equals(keys), "Keys don't match up to {} for {}", keys, actualKeys);
        batchValues.add(writerStrategy.fillValues(definition, b).toArray());
      }
      /*
       * TODO this will keep making a prepared statementS.
       * Hopefully the JDBC driver has some caching for this.
       */
      sqlExecutor.batchUpdate(sql, batchValues);
    }
   
  }
 
 
  public SelectBuilderFactory<T> getSelectBuilderFactory() {
    return selectBuilderFactory;
  }
 
  public UpdateBuilderFactory<T> getUpdateBuilderFactory() {
    return updateBuilderFactory;
  }
}
TOP

Related Classes of co.jirm.orm.dao.JirmDao

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.