in hollow/src/main/java/com/netflix/hollow/core/index/FieldPaths.java [116:230]
static FieldPath<FieldSegment> createFieldPath(
HollowDataset dataset, String type, String path,
boolean autoExpand, boolean requireFullPath, boolean traverseSequences) {
Objects.requireNonNull(dataset);
Objects.requireNonNull(type);
Objects.requireNonNull(path);
String[] segments = path.isEmpty() ? new String[0] : path.split("\\.");
List<FieldSegment> fieldSegments = new ArrayList<>();
String segmentType = type;
for (int i = 0; i < segments.length; i++) {
HollowSchema schema = dataset.getSchema(segmentType);
// @@@ Can this only occur for anything other than the root `type`?
if (schema == null) {
LOG.log(Level.WARNING, FieldPathException.message(FieldPathException.ErrorKind.NOT_BINDABLE, dataset,
type, segments, fieldSegments, null, i));
throw new FieldPathException(FieldPathException.ErrorKind.NOT_BINDABLE, dataset, type, segments, fieldSegments, null, i);
}
String segment = segments[i];
HollowSchema.SchemaType schemaType = schema.getSchemaType();
if (schemaType == HollowSchema.SchemaType.OBJECT) {
HollowObjectSchema objectSchema = (HollowObjectSchema) schema;
int index = objectSchema.getPosition(segment);
if (index == -1) {
throw new FieldPathException(FieldPathException.ErrorKind.NOT_FOUND, dataset, type, segments,
fieldSegments, schema, i);
}
segmentType = objectSchema.getReferencedType(index);
fieldSegments.add(new ObjectFieldSegment(objectSchema, segment, segmentType, index));
} else if (traverseSequences && (schemaType == HollowSchema.SchemaType.SET
|| schemaType == HollowSchema.SchemaType.LIST)) {
HollowCollectionSchema collectionSchema = (HollowCollectionSchema) schema;
if (!segment.equals("element")) {
throw new FieldPathException(FieldPathException.ErrorKind.NOT_FOUND, dataset, type, segments,
fieldSegments, schema, i);
}
segmentType = collectionSchema.getElementType();
fieldSegments.add(new FieldSegment(collectionSchema, segment, segmentType));
} else if (traverseSequences && schemaType == HollowSchema.SchemaType.MAP) {
HollowMapSchema mapSchema = (HollowMapSchema) schema;
if (segment.equals("key")) {
segmentType = mapSchema.getKeyType();
} else if (segment.equals("value")) {
segmentType = mapSchema.getValueType();
} else {
throw new FieldPathException(FieldPathException.ErrorKind.NOT_FOUND, dataset, type, segments,
fieldSegments, schema, i);
}
fieldSegments.add(new FieldSegment(mapSchema, segment, segmentType));
} else if (!traverseSequences) {
throw new FieldPathException(FieldPathException.ErrorKind.NOT_TRAVERSABLE, dataset, type, segments,
fieldSegments, schema, i);
}
if (i < segments.length - 1 && segmentType == null) {
throw new FieldPathException(FieldPathException.ErrorKind.NOT_TRAVERSABLE, dataset, type, segments,
fieldSegments, schema, i);
}
}
if (autoExpand) {
while (segmentType != null) {
HollowSchema schema = dataset.getSchema(segmentType);
if (schema.getSchemaType() == HollowSchema.SchemaType.OBJECT) {
HollowObjectSchema objectSchema = (HollowObjectSchema) schema;
if (objectSchema.numFields() == 1) {
segmentType = objectSchema.getReferencedType(0);
fieldSegments.add(
new ObjectFieldSegment(objectSchema, objectSchema.getFieldName(0), segmentType,
0));
} else if (objectSchema.getPrimaryKey() != null && objectSchema.getPrimaryKey().numFields() == 1) {
PrimaryKey key = objectSchema.getPrimaryKey();
FieldPath<ObjectFieldSegment> expandedFieldSegments;
try {
expandedFieldSegments =
createFieldPathForPrimaryKey(dataset, key.getType(), key.getFieldPaths()[0]);
} catch (FieldPathException cause) {
FieldPathException e = new FieldPathException(FieldPathException.ErrorKind.NOT_EXPANDABLE,
dataset, type, segments,
fieldSegments, objectSchema);
e.initCause(cause);
throw e;
}
fieldSegments.addAll(expandedFieldSegments.segments);
break;
} else {
throw new FieldPathException(FieldPathException.ErrorKind.NOT_EXPANDABLE, dataset, type,
segments,
fieldSegments, objectSchema);
}
} else {
throw new FieldPathException(FieldPathException.ErrorKind.NOT_EXPANDABLE, dataset, type, segments,
fieldSegments, schema);
}
}
} else if (requireFullPath && segmentType != null) {
throw new FieldPathException(FieldPathException.ErrorKind.NOT_FULL, dataset, type, segments,
fieldSegments);
}
return new FieldPath<>(type, fieldSegments, !autoExpand);
}