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
080    DocMapping[] mapping = docStore.mapping();
081    for (DocMapping docMapping : mapping) {
082      applyFieldMapping(null, docMapping);
083    }
084  }
085
086  private void applyFieldMapping(String prefix, DocMapping docMapping) {
087
088    String name = docMapping.name();
089    String fullName = SplitName.add(prefix, name);
090
091    DocPropertyMapping mapping = map.get(fullName);
092    if (mapping == null) {
093      throw new IllegalStateException("DocMapping for [" + fullName + "] but property not included in document?");
094    }
095    mapping.apply(docMapping);
096  }
097
098  /**
099   * Collect the mapping of properties to 'raw' properties for those marked as sortable.
100   */
101  public Map<String, String> collectSortable() {
102
103    DocPropertyMapping peek = properties.peek();
104    SortableVisitor visitor = new SortableVisitor();
105    peek.visit(visitor);
106
107    return visitor.getSortableMap();
108  }
109
110  /**
111   * Create the document mapping.
112   */
113  public DocumentMapping create(String queueId, String indexName, String indexType) {
114
115    int shards = docStore.shards();
116    int replicas = docStore.replicas();
117    DocPropertyMapping root = properties.peek();
118    return new DocumentMapping(queueId, indexName, indexType, paths, root, shards, replicas);
119  }
120
121
122  /**
123   * Find sortable properties to build the mapping to 'raw' properties.
124   */
125  private static class SortableVisitor extends DocPropertyAdapter {
126
127    private Map<String, String> sortableMap = new LinkedHashMap<>();
128
129    @Override
130    public void visitProperty(DocPropertyMapping property) {
131
132      DocPropertyOptions options = property.getOptions();
133      if (options != null && options.isSortable()) {
134        String fullPath = pathStack.peekFullPath(property.getName());
135        sortableMap.put(fullPath, fullPath + ".raw");
136      }
137    }
138
139    private Map<String, String> getSortableMap() {
140      return sortableMap;
141    }
142  }
143}