|  | @@ -20,13 +20,17 @@
 | 
	
		
			
				|  |  |  package org.elasticsearch.index.mapper.copyto;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import com.google.common.collect.ImmutableList;
 | 
	
		
			
				|  |  | +import org.apache.lucene.index.IndexableField;
 | 
	
		
			
				|  |  |  import org.elasticsearch.common.bytes.BytesReference;
 | 
	
		
			
				|  |  |  import org.elasticsearch.common.xcontent.ToXContent;
 | 
	
		
			
				|  |  |  import org.elasticsearch.common.xcontent.XContentBuilder;
 | 
	
		
			
				|  |  | +import org.elasticsearch.common.xcontent.XContentFactory;
 | 
	
		
			
				|  |  |  import org.elasticsearch.common.xcontent.json.JsonXContent;
 | 
	
		
			
				|  |  |  import org.elasticsearch.index.mapper.*;
 | 
	
		
			
				|  |  | +import org.elasticsearch.index.mapper.ParseContext.Document;
 | 
	
		
			
				|  |  |  import org.elasticsearch.index.mapper.core.LongFieldMapper;
 | 
	
		
			
				|  |  |  import org.elasticsearch.index.mapper.core.StringFieldMapper;
 | 
	
		
			
				|  |  | +import org.elasticsearch.index.service.IndexService;
 | 
	
		
			
				|  |  |  import org.elasticsearch.test.ElasticsearchSingleNodeTest;
 | 
	
		
			
				|  |  |  import org.junit.Test;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -223,4 +227,105 @@ public class CopyToMapperTests extends ElasticsearchSingleNodeTest {
 | 
	
		
			
				|  |  |          assertThat(fields.get(1), equalTo("bar"));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    public void testCopyToNestedField() throws Exception {
 | 
	
		
			
				|  |  | +        IndexService indexService = createIndex("test");
 | 
	
		
			
				|  |  | +        DocumentMapperParser parser = indexService.mapperService().documentMapperParser();
 | 
	
		
			
				|  |  | +        for (boolean mapped : new boolean[] {true, false}) {
 | 
	
		
			
				|  |  | +            XContentBuilder mapping = jsonBuilder().startObject()
 | 
	
		
			
				|  |  | +                    .startObject("type")
 | 
	
		
			
				|  |  | +                        .startObject("properties")
 | 
	
		
			
				|  |  | +                            .startObject("n1")
 | 
	
		
			
				|  |  | +                                .field("type", "nested")
 | 
	
		
			
				|  |  | +                                .startObject("properties")
 | 
	
		
			
				|  |  | +                                    .startObject("n2")
 | 
	
		
			
				|  |  | +                                        .field("type", "nested")
 | 
	
		
			
				|  |  | +                                        .startObject("properties")
 | 
	
		
			
				|  |  | +                                            .startObject("source")
 | 
	
		
			
				|  |  | +                                                .field("type", "long")
 | 
	
		
			
				|  |  | +                                                .startArray("copy_to")
 | 
	
		
			
				|  |  | +                                                    .value("target") // should go to the root doc
 | 
	
		
			
				|  |  | +                                                    .value("n1.target") // should go to the parent doc
 | 
	
		
			
				|  |  | +                                                    .value("n1.n2.target") // should go to the current doc
 | 
	
		
			
				|  |  | +                                                .endArray()
 | 
	
		
			
				|  |  | +                                            .endObject();
 | 
	
		
			
				|  |  | +            for (int i = 0; i < 3; ++i) {
 | 
	
		
			
				|  |  | +                if (mapped) {
 | 
	
		
			
				|  |  | +                    mapping = mapping.startObject("target").field("type", "long").endObject();
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                mapping = mapping.endObject().endObject();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            mapping = mapping.endObject();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            DocumentMapper mapper = parser.parse(mapping.string());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            XContentBuilder jsonDoc = XContentFactory.jsonBuilder()
 | 
	
		
			
				|  |  | +                    .startObject()
 | 
	
		
			
				|  |  | +                        .startArray("n1")
 | 
	
		
			
				|  |  | +                            .startObject()
 | 
	
		
			
				|  |  | +                                .startArray("n2")
 | 
	
		
			
				|  |  | +                                    .startObject()
 | 
	
		
			
				|  |  | +                                        .field("source", 3)
 | 
	
		
			
				|  |  | +                                    .endObject()
 | 
	
		
			
				|  |  | +                                    .startObject()
 | 
	
		
			
				|  |  | +                                        .field("source", 5)
 | 
	
		
			
				|  |  | +                                    .endObject()
 | 
	
		
			
				|  |  | +                                .endArray()
 | 
	
		
			
				|  |  | +                            .endObject()
 | 
	
		
			
				|  |  | +                            .startObject()
 | 
	
		
			
				|  |  | +                                .startArray("n2")
 | 
	
		
			
				|  |  | +                                    .startObject()
 | 
	
		
			
				|  |  | +                                        .field("source", 7)
 | 
	
		
			
				|  |  | +                                    .endObject()
 | 
	
		
			
				|  |  | +                                .endArray()
 | 
	
		
			
				|  |  | +                            .endObject()
 | 
	
		
			
				|  |  | +                        .endArray()
 | 
	
		
			
				|  |  | +                    .endObject();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            ParsedDocument doc = mapper.parse("type", "1", jsonDoc.bytes());
 | 
	
		
			
				|  |  | +            assertEquals(6, doc.docs().size());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            Document nested = doc.docs().get(0);
 | 
	
		
			
				|  |  | +            assertFieldValue(nested, "n1.n2.target", 7L);
 | 
	
		
			
				|  |  | +            assertFieldValue(nested, "n1.target");
 | 
	
		
			
				|  |  | +            assertFieldValue(nested, "target");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            nested = doc.docs().get(2);
 | 
	
		
			
				|  |  | +            assertFieldValue(nested, "n1.n2.target", 5L);
 | 
	
		
			
				|  |  | +            assertFieldValue(nested, "n1.target");
 | 
	
		
			
				|  |  | +            assertFieldValue(nested, "target");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            nested = doc.docs().get(3);
 | 
	
		
			
				|  |  | +            assertFieldValue(nested, "n1.n2.target", 3L);
 | 
	
		
			
				|  |  | +            assertFieldValue(nested, "n1.target");
 | 
	
		
			
				|  |  | +            assertFieldValue(nested, "target");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            Document parent = doc.docs().get(1);
 | 
	
		
			
				|  |  | +            assertFieldValue(parent, "target");
 | 
	
		
			
				|  |  | +            assertFieldValue(parent, "n1.target", 7L);
 | 
	
		
			
				|  |  | +            assertFieldValue(parent, "n1.n2.target");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            parent = doc.docs().get(4);
 | 
	
		
			
				|  |  | +            assertFieldValue(parent, "target");
 | 
	
		
			
				|  |  | +            assertFieldValue(parent, "n1.target", 3L, 5L);
 | 
	
		
			
				|  |  | +            assertFieldValue(parent, "n1.n2.target");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            Document root = doc.docs().get(5);
 | 
	
		
			
				|  |  | +            assertFieldValue(root, "target", 3L, 5L, 7L);
 | 
	
		
			
				|  |  | +            assertFieldValue(root, "n1.target");
 | 
	
		
			
				|  |  | +            assertFieldValue(root, "n1.n2.target");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private void assertFieldValue(Document doc, String field, Number... expected) {
 | 
	
		
			
				|  |  | +        IndexableField[] values = doc.getFields(field);
 | 
	
		
			
				|  |  | +        if (values == null) {
 | 
	
		
			
				|  |  | +            values = new IndexableField[0];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        Number[] actual = new Number[values.length];
 | 
	
		
			
				|  |  | +        for (int i = 0; i < values.length; ++i) {
 | 
	
		
			
				|  |  | +            actual[i] = values[i].numericValue();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        assertArrayEquals(expected, actual);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  }
 |