Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,12 @@ server/src/main/resources/transport/defined/manifest.txt

# JEnv
.java-version

# Claude Flow and Swarm directories
.claude-flow/
.swarm/

# Temporary test files
test-*.java
bug-*.json
*-bug-analysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
---
setup:
- requires:
cluster_features: "gte_v8.2.0"
reason: Field type filters were added in 8.2
- do:
indices.create:
index: test_types_filter
body:
mappings:
properties:
product:
type: object
properties:
name:
type: text
price:
type: float
tags:
type: keyword
category:
type: object
properties:
title:
type: text
id:
type: integer
description:
type: text
nested_comments:
type: nested
properties:
text:
type: text
rating:
type: integer

---
"Types filter excludes object fields when not requested":
- do:
field_caps:
index: 'test_types_filter'
fields: '*'
types: 'text'

# Should include text fields
- is_true: fields.product\\.name
- is_true: fields.category\\.title
- is_true: fields.description
- is_true: fields.nested_comments\\.text

# Should NOT include object or nested fields
- is_false: fields.product
- is_false: fields.category
- is_false: fields.nested_comments

# Should NOT include non-text fields
- is_false: fields.product\\.price
- is_false: fields.product\\.tags
- is_false: fields.category\\.id
- is_false: fields.nested_comments\\.rating

---
"Types filter includes object fields when explicitly requested":
- do:
field_caps:
index: 'test_types_filter'
fields: '*'
types: 'text,object'

# Should include text fields
- is_true: fields.product\\.name
- is_true: fields.category\\.title
- is_true: fields.description

# Should include object fields (but not nested)
- is_true: fields.product
- is_true: fields.category

# Should NOT include nested fields (not in types filter)
- is_false: fields.nested_comments

# Should NOT include other types
- is_false: fields.product\\.price
- is_false: fields.product\\.tags

---
"Types filter includes nested fields when explicitly requested":
- do:
field_caps:
index: 'test_types_filter'
fields: '*'
types: 'nested,text'

# Should include text fields
- is_true: fields.product\\.name
- is_true: fields.nested_comments\\.text

# Should include nested fields
- is_true: fields.nested_comments

# Should NOT include object fields (not in types filter)
- is_false: fields.product
- is_false: fields.category

---
"Types filter with keyword type only":
- do:
field_caps:
index: 'test_types_filter'
fields: '*'
types: 'keyword'

# Should include keyword field
- is_true: fields.product\\.tags

# Should NOT include any object/nested fields
- is_false: fields.product
- is_false: fields.category
- is_false: fields.nested_comments

# Should NOT include other types
- is_false: fields.product\\.name
- is_false: fields.product\\.price
- is_false: fields.description

---
"No types filter includes all fields":
- do:
field_caps:
index: 'test_types_filter'
fields: '*'

# Should include all fields
- is_true: fields.product
- is_true: fields.product\\.name
- is_true: fields.product\\.price
- is_true: fields.product\\.tags
- is_true: fields.category
- is_true: fields.category\\.title
- is_true: fields.category\\.id
- is_true: fields.description
- is_true: fields.nested_comments
- is_true: fields.nested_comments\\.text
- is_true: fields.nested_comments\\.rating

---
"Types filter combined with -parent filter":
- do:
field_caps:
index: 'test_types_filter'
fields: '*'
types: 'text,object'
filters: '-parent'

# Should include text fields
- is_true: fields.product\\.name
- is_true: fields.category\\.title
- is_true: fields.description

# Should NOT include parent objects even though object is in types filter
# because -parent filter takes precedence
- is_false: fields.product
- is_false: fields.category
- is_false: fields.nested_comments
Original file line number Diff line number Diff line change
Expand Up @@ -206,17 +206,27 @@ static Map<String, IndexFieldCapabilities> retrieveFieldCaps(
if (context.getFieldType(parentField) == null) {
// no field type, it must be an object field
String type = context.nestedLookup().getNestedMappers().get(parentField) != null ? "nested" : "object";
IndexFieldCapabilities fieldCap = new IndexFieldCapabilities(
parentField,
type,
false,
false,
false,
false,
null,
Map.of()
);
responseMap.put(parentField, fieldCap);

// Apply types filter to parent object fields
boolean shouldInclude = true;
if (types != null && types.length > 0) {
Set<String> acceptedTypes = Set.of(types);
shouldInclude = acceptedTypes.contains(type);
}

if (shouldInclude) {
IndexFieldCapabilities fieldCap = new IndexFieldCapabilities(
parentField,
type,
false,
false,
false,
false,
null,
Map.of()
);
responseMap.put(parentField, fieldCap);
}
}
dotIndex = parentField.lastIndexOf('.');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,10 @@ public final void validate(MappingLookup mappers) {
throw new IllegalArgumentException("[copy_to] may not be used to copy from a multi-field: [" + this.fullPath() + "]");
}

// Check if dynamic mappings are disabled
ObjectMapper.Dynamic rootDynamic = ObjectMapper.Dynamic.getRootDynamic(mappers);
boolean isDynamicDisabled = rootDynamic == ObjectMapper.Dynamic.FALSE;

final String sourceScope = mappers.nestedLookup().getNestedParent(this.fullPath());
for (String copyTo : this.copyTo().copyToFields()) {
if (mappers.isMultiField(copyTo)) {
Expand All @@ -341,6 +345,13 @@ public final void validate(MappingLookup mappers) {
throw new IllegalArgumentException("Cannot copy to field [" + copyTo + "] since it is mapped as an object");
}

// When dynamic is false, check if the target field exists
if (isDynamicDisabled && mappers.getMapper(copyTo) == null) {
throw new IllegalArgumentException(
"Cannot copy to field [" + copyTo + "] because it does not exist and dynamic mappings are disabled"
);
}

final String targetScope = mappers.nestedLookup().getNestedParent(copyTo);
checkNestedScopeCompatibility(sourceScope, targetScope);
}
Expand Down
Loading