package com.google.sitebricks.persist; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author dhanji@gmail.com (Dhanji R. Prasanna) */ public class TypesafeEntityQuery<T> implements EntityQuery<T>, EntityQuery.Clause<T> { private final T topic; private final List<FieldMatcher<?>> matchers = new ArrayList<FieldMatcher<?>>(); private final EntityStore store; public TypesafeEntityQuery(T topic, EntityStore store) { this.topic = topic; this.store = store; } @Override public <E> Clause<T> where(E field, FieldMatcher<E> matcher) { matchers.add(matcher); return this; } @Override public <E> Clause and(E field, FieldMatcher<E> matcher) { matchers.add(matcher); return this; } @Override public EntityQuery<T> or() { throw new AssertionError("not yet impl"); } @Override public List<T> list() { return list(0, Integer.MAX_VALUE); } @Override public List<T> list(int limit) { return list(0, limit); } @Override public List<T> list(int offset, int limit) { // Gather into a query model. Map<String, FieldMatcher<?>> matcherMap = toMatcherMap(); return store.execute(type, matcherMap, offset, limit); } private transient Class<T> type; private transient Map<String, FieldMatcher<?>> matcherMap; @SuppressWarnings("unchecked") private Map<String, FieldMatcher<?>> toMatcherMap() { if (matcherMap != null) return matcherMap; List<String> calledFields; try { Class<?> proxyClass = topic.getClass(); type = (Class<T>) proxyClass.getMethod(TopicProxy.TYPE) .invoke(topic); // Must appear last as it freezes the object. calledFields = (List<String>) proxyClass.getMethod(TopicProxy.CALLED_FIELDS) .invoke(topic); } catch (NoSuchMethodException e) { throw new IllegalStateException("Unknown topic used in entity query. You MUST create the topic object" + " using EntityStore.topic()", e); } catch (InvocationTargetException e) { throw new IllegalStateException("Unknown topic used in entity query. You MUST create the topic object" + " using EntityStore.topic()", e); } catch (IllegalAccessException e) { throw new IllegalStateException("Unknown topic used in entity query. You MUST create the topic object" + " using EntityStore.topic()", e); } matcherMap = new HashMap<String, FieldMatcher<?>>(); for (int i = 0, calledFieldsSize = calledFields.size(); i < calledFieldsSize; i++) { String calledField = calledFields.get(i); matcherMap.put(calledField, matchers.get(i)); } return matcherMap; } @Override public <T> void remove() { Map<String, FieldMatcher<?>> query = toMatcherMap(); store.executeDelete(type, query); } }