001package io.ebeanservice.docstore.api.mapping;
002
003import io.ebean.annotation.DocMapping;
004import io.ebean.annotation.DocStore;
005import io.ebean.text.PathProperties;
006import io.ebean.util.SplitName;
007
008import java.util.LinkedHashMap;
009import java.util.Map;
010import java.util.Stack;
011
012/**
013 * Builds the DocumentMapping for a given bean type.
014 */
015public class DocMappingBuilder {
016
017  private final PathProperties paths;
018
019  private final DocStore docStore;
020
021  private final Stack<DocPropertyMapping> properties = new Stack<>();
022
023  private final Map<String, DocPropertyMapping> map = new LinkedHashMap<>();
024
025  /**
026   * Create with the document structure paths and docStore deployment annotation.
027   */
028  public DocMappingBuilder(PathProperties paths, DocStore docStore) {
029    this.paths = paths;
030    this.docStore = docStore;
031    this.properties.push(new DocPropertyMapping());
032  }
033
034  /**
035   * Return true if the property is included in the document.
036   */
037  public boolean includesProperty(String prefix, String name) {
038    return paths.includesProperty(prefix, name);
039  }
040
041  /**
042   * Return true if the path is included in the document.
043   */
044  public boolean includesPath(String prefix, String name) {
045    return paths.includesProperty(prefix, name);
046  }
047
048  /**
049   * Add the property mapping.
050   */
051  public void add(DocPropertyMapping docMapping) {
052
053    DocPropertyMapping currentParent = properties.peek();
054    currentParent.addChild(docMapping);
055
056    String parentName = currentParent.getName();
057    String fullName = SplitName.add(parentName, docMapping.getName());
058    map.put(fullName, docMapping);
059  }
060
061  /**
062   * Push the nested object or list onto the properties stack.
063   */
064  public void push(DocPropertyMapping nested) {
065    properties.push(nested);
066  }
067
068  /**
069   * Pop the nested object or list off the properties stack.
070   */
071  public void pop() {
072    properties.pop();
073  }
074
075  /**
076   * Apply any override mappings from the top level docStore annotation.
077   */
078  public void applyMapping() {
079    for (DocMapping docMapping : docStore.mapping()) {
080      applyFieldMapping(docMapping);
081    }
082  }
083
084  private void applyFieldMapping(DocMapping docMapping) {
085
086    DocPropertyMapping mapping = map.get(docMapping.name());
087    if (mapping == null) {
088      throw new IllegalStateException("DocMapping for [" + docMapping.name() + "] but property not included in document?");
089    }
090    mapping.apply(docMapping);
091  }
092
093  /**
094   * Collect the mapping of properties to 'raw' properties for those marked as sortable.
095   */
096  public Map<String, String> collectSortable() {
097
098    DocPropertyMapping peek = properties.peek();
099    SortableVisitor visitor = new SortableVisitor();
100    peek.visit(visitor);
101
102    return visitor.getSortableMap();
103  }
104
105  /**
106   * Create the document mapping.
107   */
108  public DocumentMapping create(String queueId, String indexName, String indexType) {
109
110    int shards = docStore.shards();
111    int replicas = docStore.replicas();
112    DocPropertyMapping root = properties.peek();
113    return new DocumentMapping(queueId, indexName, indexType, paths, root, shards, replicas);
114  }
115
116
117  /**
118   * Find sortable properties to build the mapping to 'raw' properties.
119   */
120  private static class SortableVisitor extends DocPropertyAdapter {
121
122    private Map<String, String> sortableMap = new LinkedHashMap<>();
123
124    @Override
125    public void visitProperty(DocPropertyMapping property) {
126
127      DocPropertyOptions options = property.getOptions();
128      if (options != null && options.isSortable()) {
129        String fullPath = pathStack.peekFullPath(property.getName());
130        sortableMap.put(fullPath, fullPath + ".raw");
131      }
132    }
133
134    private Map<String, String> getSortableMap() {
135      return sortableMap;
136    }
137  }
138}