class PropertyMapping {

    public static PropertyMapping fromObject(String propertyKey, Object stringOrMap) {
        if (stringOrMap instanceof String) {
            String neoPropertyKey = (String) stringOrMap;
            return fromObject(
                propertyKey,
                Collections.singletonMap(
                    PROPERTY_KEY,
                    neoPropertyKey
                )
            );
        } else if (stringOrMap instanceof Map) {
            Map<String, Object> relPropertyMap = (Map) stringOrMap;
            Object propertyNameValue = relPropertyMap.getOrDefault(PROPERTY_KEY, propertyKey);
            if (!(propertyNameValue instanceof String)) {
                throw new IllegalArgumentException(formatWithLocale(
                    "Expected the value of '%s' to be of type String, but was '%s'.",
                    PROPERTY_KEY, propertyNameValue.getClass().getSimpleName()
                ));
            }
            String neoPropertyKey = (String) propertyNameValue;

            final Object aggregationValue = relPropertyMap.get(RelationshipProjection.AGGREGATION_KEY);
            Aggregation aggregation;
            if (aggregationValue == null) {
                aggregation = Aggregation.DEFAULT;
            } else if (aggregationValue instanceof String) {
                aggregation = Aggregation.lookup(((String) aggregationValue).toUpperCase(Locale.ENGLISH));
            } else {
                throw new IllegalStateException(formatWithLocale(
                    "Expected the value of '%s' to be of type String, but was '%s'",
                    RelationshipProjection.AGGREGATION_KEY, aggregationValue.getClass().getSimpleName()
                ));
            }

            return PropertyMapping.of(
                propertyKey,
                neoPropertyKey,
                relPropertyMap.get(DEFAULT_VALUE_KEY),
                aggregation
            );
        } else {
            throw new IllegalStateException(formatWithLocale(
                "Expected stringOrMap to be of type String or Map, but got %s",
                stringOrMap.getClass().getSimpleName()
            ));
        }
    }

}