Skip to content

Commit 79abcf5

Browse files
evil159jush
andauthored
Support expressions in PromoteId (#2975)
* Support expressions in `PromoteId` * lint * add missing docs * Update CHANGELOG.md Co-authored-by: Ramon <[email protected]> * Improve documentation * Clarify docs, remove extra constructors * Add missing parameter to PromoteIdValue expression constructor * Revert to old naming * Add expression support on top of existing field * lint * Add JvmOverloads for compatibility * Support expressions without source layer id --------- Co-authored-by: Ramon <[email protected]>
1 parent 5dc9bdf commit 79abcf5

File tree

9 files changed

+114
-16
lines changed

9 files changed

+114
-16
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
Mapbox welcomes participation and contributions from everyone.
44

55
# main
6-
6+
## Features ✨ and improvements 🏁
7+
* Support expression input for `PromoteId`.
78

89
# 11.10.2 February 25, 2025
910
## Bug fixes 🐞

extension-compose/api/Release/metalava.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4299,6 +4299,7 @@ package com.mapbox.maps.extension.compose.style.sources {
42994299
@androidx.compose.runtime.Immutable public final class PromoteIdValue {
43004300
ctor public PromoteIdValue(com.mapbox.bindgen.Value value);
43014301
ctor public PromoteIdValue(String propertyName, String? sourceId = null);
4302+
ctor public PromoteIdValue(com.mapbox.maps.extension.style.expressions.generated.Expression expression, String? sourceId = null);
43024303
ctor public PromoteIdValue(com.mapbox.maps.extension.style.expressions.generated.Expression expression);
43034304
method public com.mapbox.bindgen.Value component1();
43044305
method public com.mapbox.maps.extension.compose.style.sources.PromoteIdValue copy(com.mapbox.bindgen.Value value);

extension-compose/api/extension-compose.api

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3669,6 +3669,8 @@ public final class com/mapbox/maps/extension/compose/style/sources/PromoteIdValu
36693669
public static final field DEFAULT Lcom/mapbox/maps/extension/compose/style/sources/PromoteIdValue;
36703670
public fun <init> (Lcom/mapbox/bindgen/Value;)V
36713671
public fun <init> (Lcom/mapbox/maps/extension/style/expressions/generated/Expression;)V
3672+
public fun <init> (Lcom/mapbox/maps/extension/style/expressions/generated/Expression;Ljava/lang/String;)V
3673+
public synthetic fun <init> (Lcom/mapbox/maps/extension/style/expressions/generated/Expression;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
36723674
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
36733675
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
36743676
public final fun component1 ()Lcom/mapbox/bindgen/Value;

extension-compose/src/main/java/com/mapbox/maps/extension/compose/style/internal/ComposeTypeUtils.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ internal object ComposeTypeUtils {
3333
)
3434
)
3535
is PromoteId -> with(value) {
36-
val propertyNameValue = Value(propertyName)
36+
val promoteIdValue = Value.fromJson(propertyName).getValueOrElse { Value.valueOf(propertyName) }
3737
sourceId?.let {
38-
Value(hashMapOf(sourceId to propertyNameValue))
39-
} ?: propertyNameValue
38+
Value(hashMapOf(sourceId to promoteIdValue))
39+
}
40+
promoteIdValue
4041
}
4142
is TextWritingMode -> {
4243
value.value

extension-compose/src/main/java/com/mapbox/maps/extension/compose/style/sources/PropertyTypes.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,12 @@ public data class PromoteIdValue(public val value: Value) {
190190
/**
191191
* Construct the PromoteId with [Mapbox Expression](https://docs.mapbox.com/style-spec/reference/expressions/).
192192
*/
193-
public constructor(expression: Expression) : this(expression as Value)
193+
@JvmOverloads
194+
public constructor(expression: Expression, sourceId: String? = null) : this(
195+
ComposeTypeUtils.wrapToValue(
196+
com.mapbox.maps.extension.style.types.PromoteId(expression, sourceId)
197+
)
198+
)
194199

195200
/**
196201
* True if the this value is not [INITIAL]

extension-style/api/Release/metalava.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7696,11 +7696,15 @@ package com.mapbox.maps.extension.style.types {
76967696
@Keep public final class PromoteId {
76977697
ctor public PromoteId(String propertyName, String? sourceId = null);
76987698
ctor public PromoteId(String propertyName);
7699+
ctor public PromoteId(com.mapbox.maps.extension.style.expressions.generated.Expression expression, String? sourceId = null);
7700+
ctor public PromoteId(com.mapbox.maps.extension.style.expressions.generated.Expression expression);
76997701
method public String component1();
77007702
method public String? component2();
77017703
method public com.mapbox.maps.extension.style.types.PromoteId copy(String propertyName, String? sourceId);
7704+
method public com.mapbox.maps.extension.style.expressions.generated.Expression? getExpression();
77027705
method public String getPropertyName();
77037706
method public String? getSourceId();
7707+
property public final com.mapbox.maps.extension.style.expressions.generated.Expression? expression;
77047708
property public final String propertyName;
77057709
property public final String? sourceId;
77067710
field public static final com.mapbox.maps.extension.style.types.PromoteId.Companion Companion;

extension-style/api/extension-style.api

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6566,6 +6566,9 @@ public abstract interface annotation class com/mapbox/maps/extension/style/types
65666566

65676567
public final class com/mapbox/maps/extension/style/types/PromoteId {
65686568
public static final field Companion Lcom/mapbox/maps/extension/style/types/PromoteId$Companion;
6569+
public fun <init> (Lcom/mapbox/maps/extension/style/expressions/generated/Expression;)V
6570+
public fun <init> (Lcom/mapbox/maps/extension/style/expressions/generated/Expression;Ljava/lang/String;)V
6571+
public synthetic fun <init> (Lcom/mapbox/maps/extension/style/expressions/generated/Expression;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
65696572
public fun <init> (Ljava/lang/String;)V
65706573
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
65716574
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
@@ -6574,6 +6577,7 @@ public final class com/mapbox/maps/extension/style/types/PromoteId {
65746577
public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lcom/mapbox/maps/extension/style/types/PromoteId;
65756578
public static synthetic fun copy$default (Lcom/mapbox/maps/extension/style/types/PromoteId;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/mapbox/maps/extension/style/types/PromoteId;
65766579
public fun equals (Ljava/lang/Object;)Z
6580+
public final fun getExpression ()Lcom/mapbox/maps/extension/style/expressions/generated/Expression;
65776581
public final fun getPropertyName ()Ljava/lang/String;
65786582
public final fun getSourceId ()Ljava/lang/String;
65796583
public fun hashCode ()I

extension-style/src/main/java/com/mapbox/maps/extension/style/types/PromoteId.kt

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,65 @@ package com.mapbox.maps.extension.style.types
22

33
import androidx.annotation.Keep
44
import com.mapbox.bindgen.Value
5-
import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource
5+
import com.mapbox.maps.extension.style.expressions.generated.Expression
66
import com.mapbox.maps.extension.style.sources.generated.VectorSource
7+
import com.mapbox.maps.extension.style.utils.TypeUtils
8+
import com.mapbox.maps.extension.style.utils.unwrapToExpression
79

810
/**
911
* Holds a property type to promote a specific feature for feature state API.
1012
*
11-
* @param sourceId source layer id of the feature, either source [GeoJsonSource] or [VectorSource].
12-
* @param propertyName feature property name.
13+
* @param propertyName promote id value.
14+
* @param sourceId source layer in [VectorSource] to which the feature ID override applies.
15+
*
16+
* If not provided the override will be applied to all layers of the source.
1317
*
1418
* For more information see [The online documentation](https://docs.mapbox.com/mapbox-gl-js/style-spec/types/#promoteId).
1519
*/
1620
@Keep
1721
data class PromoteId @JvmOverloads constructor(
22+
/*
23+
* Feature property name.
24+
*/
1825
val propertyName: String,
26+
27+
/*
28+
* The source layer in [VectorSource] to which the feature ID override applies.
29+
*
30+
* If not provided the override will be applied to all layers of the source.
31+
*/
1932
val sourceId: String? = null
2033
) {
34+
35+
/**
36+
* Expression to promote.
37+
*/
38+
val expression: Expression? = try {
39+
Value.fromJson(propertyName).value?.unwrapToExpression()
40+
} catch (_: Throwable) {
41+
null
42+
}
43+
44+
/**
45+
* Construct a [PromoteId] object from an [Expression].
46+
*
47+
* @param expression expression to promote.
48+
* @param sourceId source layer in [VectorSource] to which the feature ID override applies.
49+
*
50+
* If not provided the override will be applied to all layers of the source.
51+
*/
52+
@JvmOverloads
53+
constructor(expression: Expression, sourceId: String? = null) : this(
54+
expression.toJson(),
55+
sourceId
56+
)
57+
2158
internal fun toValue(): Value {
59+
val promoteIdValue = Value.fromJson(propertyName).getValueOrElse { Value.valueOf(propertyName) }
2260
sourceId?.let {
23-
return Value(hashMapOf(sourceId to Value(propertyName)))
61+
return Value(hashMapOf(sourceId to promoteIdValue))
2462
}
25-
return Value(propertyName)
63+
return promoteIdValue
2664
}
2765

2866
/**
@@ -37,23 +75,27 @@ data class PromoteId @JvmOverloads constructor(
3775
* Throws [RuntimeException] exception if couldn't construct to [PromoteId].
3876
*/
3977
internal fun fromProperty(propertyName: Any) = when (propertyName) {
40-
is String -> {
41-
PromoteId(propertyName)
42-
}
78+
is String -> PromoteId(propertyName)
79+
is List<*> -> PromoteId(TypeUtils.wrapToValue(propertyName).unwrapToExpression())
4380
is HashMap<*, *> -> {
4481
@Suppress("UNCHECKED_CAST")
4582
try {
46-
val propertyMap = propertyName as HashMap<String, String>
83+
val propertyMap = propertyName as HashMap<String, *>
4784
if (propertyMap.keys.isNotEmpty()) {
4885
val key = propertyMap.keys.iterator().next()
49-
PromoteId(propertyMap[key] ?: "", key)
86+
when (val value = propertyMap[key]) {
87+
is String? -> PromoteId(value ?: "", key)
88+
is List<*> -> PromoteId(TypeUtils.wrapToValue(value).unwrapToExpression(), key)
89+
else -> throw RuntimeException("PromoteId value should be either String or Expression")
90+
}
5091
} else {
5192
PromoteId("")
5293
}
5394
} catch (e: RuntimeException) {
54-
throw IllegalArgumentException("$propertyName must be in the format HashMap<String,String>")
95+
throw IllegalArgumentException("$propertyName must be in the format HashMap<String,String> or HashMap<String,Expression>")
5596
}
5697
}
98+
5799
else -> throw UnsupportedOperationException("Wrapping ${propertyName::class.java.simpleName} to PromoteId is not supported.")
58100
}
59101
}

extension-style/src/test/java/com/mapbox/maps/extension/style/utils/PromoteIdTest.kt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.mapbox.maps.extension.style.utils
22

3+
import com.mapbox.maps.extension.style.expressions.dsl.generated.coalesce
34
import com.mapbox.maps.extension.style.types.PromoteId
45
import org.junit.Assert.assertEquals
56
import org.junit.Test
@@ -60,5 +61,42 @@ class PromoteIdTest {
6061
PromoteId.fromProperty(hashMapOf(1 to 2))
6162
}
6263

64+
@Test
65+
fun fromProperty_Expression() {
66+
val expected = PromoteId(
67+
coalesce {
68+
get { literal("building_id") }
69+
id()
70+
},
71+
"building"
72+
)
73+
val actual = PromoteId.fromProperty(
74+
hashMapOf(
75+
"building" to listOf(
76+
"coalesce", listOf("get", "building_id"), listOf("id")
77+
)
78+
)
79+
)
80+
81+
assertEquals(expected, actual)
82+
}
83+
84+
@Test
85+
fun fromProperty_ExpressionNullSource() {
86+
val expected = PromoteId(
87+
coalesce {
88+
get { literal("building_id") }
89+
id()
90+
},
91+
)
92+
val actual = PromoteId.fromProperty(
93+
listOf(
94+
"coalesce", listOf("get", "building_id"), listOf("id")
95+
)
96+
)
97+
98+
assertEquals(expected, actual)
99+
}
100+
63101
private data class MockType(val a: String, val b: String)
64102
}

0 commit comments

Comments
 (0)