Package com.rapleaf.jack

Source Code of com.rapleaf.jack.AbstractMockDatabaseModel$JavaScriptRecordSelector

package com.rapleaf.jack;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.rapleaf.jack.queries.ModelQuery;
import com.rapleaf.jack.queries.WhereConstraint;
import com.rapleaf.jack.queries.where_operators.IWhereOperator;
import com.rapleaf.jack.util.MysqlToJavaScriptTranslator;

public abstract class AbstractMockDatabaseModel<T extends ModelWithId<T, D>, D extends GenericDatabases>
    implements IModelPersistence<T> {

  private final D databases;
  protected final Map<Long, T> records = new HashMap<Long, T>();

  private static class JavaScriptRecordSelector<T extends ModelWithId>
      implements RecordSelector<T> {

    private final String condition;
    private static final ScriptEngine engine = new ScriptEngineManager()
        .getEngineByName("javascript");

    public JavaScriptRecordSelector(String condition) {
      this.condition = condition;
    }

    @Override
    public boolean selectRecord(T record) {
      try {
        Set<String> referencedFields = new HashSet<String>();
        String conditionJS = MysqlToJavaScriptTranslator.translate(condition,
            referencedFields);
        StringBuilder query = new StringBuilder();
        for (String field : referencedFields) {
          Object fieldValue = record.getField(field);
          query.append("var ");
          query.append(field);
          query.append("=");
          if (fieldValue instanceof String) {
            query.append('"');
            query.append(((String)fieldValue).replaceAll("\"", "\\\\\""));
            query.append('"');
          } else {
            query.append(fieldValue);
          }
          query.append(";");
        }
        query.append(conditionJS);
        Object result = engine.eval(query.toString(), engine.createBindings());
        if (result instanceof Boolean) {
          return (Boolean)result;
        } else {
          throw new RuntimeException(
              "Failed to translate condition from MySQL to JavaScript.  Unsupported or erroneous SQL syntax is likely. Where clause: " + condition);
        }
      } catch (IOException e) {
        throw new RuntimeException(
            "Failed to translate condition from MySQL to JavaScript.  Unsupported or erroneous SQL syntax is likely. Where clause: " + condition,
            e);
      } catch (ScriptException e) {
        throw new RuntimeException(
            "Failed to translate condition from MySQL to JavaScript.  Unsupported or erroneous SQL syntax is likely. Where clause: " + condition,
            e);
      }
    }

  }

  public AbstractMockDatabaseModel(D databases) {
    this.databases = databases;
  }

  protected Set<T> realFind(Map<Enum, Object> fieldsMap) throws IOException {
    return realFind(null, fieldsMap);
  }

  protected Set<T> realFind(Set<Long> ids, Map<Enum, Object> fieldsMap) throws IOException {
    Set<T> foundSet = new HashSet<T>();
    if (fieldsMap == null || fieldsMap.isEmpty()) {
      return foundSet;
    }

    for (T record : records.values()) {
      boolean allMatch = true;
      for (Map.Entry<Enum, Object> e : fieldsMap.entrySet()) {
        Object searchedForValue = e.getValue();
        Object existingValue = record.getField(e.getKey().name());
        if (ids != null && !ids.contains(record.getId())) {
          allMatch = false;
        }
        if (existingValue == null) {
          if (searchedForValue != null) {
            allMatch = false;
          }
        } else if (!existingValue.equals(searchedForValue)) {
          allMatch = false;
        }
      }
      if (allMatch) {
        foundSet.add(record);
      }
    }

    return foundSet;
  }

  protected Set<T> realFind(ModelQuery query) throws IOException {

    if (!query.getSelectedFields().isEmpty()) {
      throw new UnsupportedOperationException("SELECT operator is not supported in mock database queries.");
    }

    if (!query.getGroupByClause().isEmpty()) {
      throw new UnsupportedOperationException("GROUP BY clause is not supported in mock database queries.");
    }

    Set<T> foundSet = new HashSet<T>();

    List<WhereConstraint> constraints = query.getWhereConstraints();
    Set<Long> ids = query.getIdSet();
    if (constraints == null || constraints.isEmpty()) {
      if (ids != null && !ids.isEmpty()) {
        return find(ids);
      }
      return foundSet;
    }
    for (T record : records.values()) {
      boolean allMatch = true;
      for (WhereConstraint constraint : constraints) {

        Enum field = constraint.getField();
        IWhereOperator operator = constraint.getOperator();
        allMatch = allMatch && operator.apply(record.getField(field.name()));
      }
      if (ids != null && !ids.isEmpty() && !ids.contains(record.getId())) {
        allMatch = false;
      }
      T newRecord = record.getCopy();
      if (allMatch) {
        foundSet.add(newRecord);
      }
    }
    return foundSet;
  }

  @Override
  public boolean save(T model) throws IOException {
    records.put(model.getId(), model);
    clearForeignKeyCache();
    return true;
  }

  @Override
  public T find(long id) throws IOException {
    final T tmp = records.get(id);
    if (tmp == null) {
      return null;
    }
    return tmp.getCopy(databases);
  }

  @Override
  public Set<T> find(Set<Long> ids) throws IOException {
    Set<T> results = new HashSet<T>();
    for (Long id : ids) {
      T result = records.get(id);
      if (results != null) {
        results.add(result);
      }
    }
    return results;
  }

  @Override
  public void clearCacheById(long id) throws IOException {
    // No-op
  }

  @Override
  public Set<T> findAllByForeignKey(String foreignKey, long id)
      throws IOException {
    Set<T> ret = new HashSet<T>();
    for (T record : records.values()) {
      Object foreignKeyValue = record.getField(foreignKey);
      if (foreignKeyValue instanceof Long) {
        if (foreignKeyValue.equals(id)) {
          ret.add(record.getCopy(databases));
        }
      } else if (foreignKeyValue instanceof Integer) {
        if (((Integer)foreignKeyValue).longValue() == id) {
          ret.add(record.getCopy(databases));
        }
      } else {
        throw new IllegalArgumentException("Foreign key is not a long or int: "
            + foreignKey);
      }
    }
    return ret;
  }

  @Override
  public Set<T> findAllByForeignKey(String foreignKey, Set<Long> ids)
      throws IOException {
    Set<T> foundSet = new HashSet<T>();
    for (T record : records.values()) {
      Object foreignKeyValue = record.getField(foreignKey);
      if (foreignKeyValue instanceof Long) {
        if (ids.contains(foreignKeyValue)) {
          foundSet.add(record.getCopy(databases));
        }
      } else if (foreignKeyValue instanceof Integer) {
        if (ids.contains(((Integer)foreignKeyValue).longValue())) {
          foundSet.add(record.getCopy(databases));
        }
      } else {
        throw new IllegalArgumentException("Foreign key is not a long or int: "
            + foreignKey);
      }
    }
    return foundSet;
  }

  @Override
  public void clearCacheByForeignKey(String foreignKey, long id) {
    // no-op
  }

  @Override
  public void clearForeignKeyCache() {
    // no-op
  }

  @Override
  public boolean delete(T model) throws IOException {
    return delete(model.getId());
  }

  @Override
  public boolean delete(long id) throws IOException {
    records.remove(id);
    return true;
  }

  @Override
  public boolean deleteAll() throws IOException {
    records.clear();
    return true;
  }

  @Override
  public Set<T> findAll() throws IOException {
    Set<T> ts = new HashSet<T>();
    for (T t : records.values()) {
      ts.add(t.getCopy(databases));
    }
    return ts;
  }

  @Override
  public Set<T> findAll(String conditions) throws IOException {
    return findAll(conditions, getRecordSelector(conditions));
  }

  @Override
  public Set<T> findAll(String conditions, RecordSelector<T> selector) {
    Set<T> results = new HashSet<T>();
    for (T record : records.values()) {
      if (selector.selectRecord(record)) {
        results.add(record.getCopy(databases));
      }
    }
    return results;
  }

  protected RecordSelector<T> getRecordSelector(String conditions)
      throws IOException {
    return new JavaScriptRecordSelector<T>(conditions);
  }

  private boolean useCache = true;

  public boolean isCaching() {
    return useCache;
  }

  public void enableCaching() {
    useCache = true;
  }

  public void disableCaching() {
    useCache = false;
  }
}
TOP

Related Classes of com.rapleaf.jack.AbstractMockDatabaseModel$JavaScriptRecordSelector

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.