Skip to content

Commit 5b822c7

Browse files
committed
Add realtime tests for mapGet. Fixup implementation.
1 parent f5fdcf6 commit 5b822c7

File tree

3 files changed

+92
-2
lines changed

3 files changed

+92
-2
lines changed

firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/evaluation.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,12 @@ private fun notEqAny(value: Value, list: List<Value>): EvaluateResult {
359359
return if (foundNull) EvaluateResult.NULL else EvaluateResult.TRUE
360360
}
361361

362+
// === Map Functions ===
363+
364+
internal val evaluateMapGet = binaryFunction { map: Map<String, Value>, key: String ->
365+
EvaluateResultValue(map[key] ?: return@binaryFunction EvaluateResultUnset)
366+
}
367+
362368
// === String Functions ===
363369

364370
internal val evaluateStrConcat = variadicFunction { strings: List<String> ->
@@ -741,6 +747,18 @@ private inline fun binaryFunction(
741747
}
742748
}
743749

750+
@JvmName("binaryMapStringFunction")
751+
private inline fun binaryFunction(
752+
crossinline function: (Map<String, Value>, String) -> EvaluateResult
753+
): EvaluateFunction =
754+
binaryFunctionType(
755+
ValueTypeCase.MAP_VALUE,
756+
{ v: Value -> v.mapValue.fieldsMap },
757+
ValueTypeCase.STRING_VALUE,
758+
Value::getStringValue,
759+
function
760+
)
761+
744762
@JvmName("binaryValueArrayFunction")
745763
private inline fun binaryFunction(
746764
crossinline function: (Value, List<Value>) -> EvaluateResult

firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,7 +1821,7 @@ abstract class Expr internal constructor() {
18211821
*/
18221822
@JvmStatic
18231823
fun mapGet(mapExpression: Expr, key: String): Expr =
1824-
FunctionExpr("map_get", notImplemented, mapExpression, key)
1824+
FunctionExpr("map_get", evaluateMapGet, mapExpression, key)
18251825

18261826
/**
18271827
* Accesses a value from a map (object) field using the provided [key].
@@ -1832,7 +1832,29 @@ abstract class Expr internal constructor() {
18321832
*/
18331833
@JvmStatic
18341834
fun mapGet(fieldName: String, key: String): Expr =
1835-
FunctionExpr("map_get", notImplemented, fieldName, key)
1835+
FunctionExpr("map_get", evaluateMapGet, fieldName, key)
1836+
1837+
/**
1838+
* Accesses a value from a map (object) field using the provided [keyExpression].
1839+
*
1840+
* @param mapExpression The expression representing the map.
1841+
* @param keyExpression The key to access in the map.
1842+
* @return A new [Expr] representing the value associated with the given key in the map.
1843+
*/
1844+
@JvmStatic
1845+
fun mapGet(mapExpression: Expr, keyExpression: Expr): Expr =
1846+
FunctionExpr("map_get", evaluateMapGet, mapExpression, keyExpression)
1847+
1848+
/**
1849+
* Accesses a value from a map (object) field using the provided [keyExpression].
1850+
*
1851+
* @param fieldName The field name of the map field.
1852+
* @param keyExpression The key to access in the map.
1853+
* @return A new [Expr] representing the value associated with the given key in the map.
1854+
*/
1855+
@JvmStatic
1856+
fun mapGet(fieldName: String, keyExpression: Expr): Expr =
1857+
FunctionExpr("map_get", evaluateMapGet, fieldName, keyExpression)
18361858

18371859
/**
18381860
* Creates an expression that merges multiple maps into a single map. If multiple maps have the
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.google.firebase.firestore.pipeline
2+
3+
import com.google.firebase.firestore.model.Values.encodeValue
4+
import com.google.firebase.firestore.pipeline.Expr.Companion.constant
5+
import com.google.firebase.firestore.pipeline.Expr.Companion.map
6+
import com.google.firebase.firestore.pipeline.Expr.Companion.mapGet
7+
import org.junit.Test
8+
import org.junit.runner.RunWith
9+
import org.robolectric.RobolectricTestRunner
10+
11+
@RunWith(RobolectricTestRunner::class)
12+
class MapTests {
13+
14+
@Test
15+
fun `mapGet - get existing key returns value`() {
16+
val mapExpr = map(mapOf("a" to 1L, "b" to 2L, "c" to 3L))
17+
val expr = mapGet(mapExpr, constant("b"))
18+
assertEvaluatesTo(evaluate(expr), encodeValue(2L), "mapGet existing key should return value")
19+
}
20+
21+
@Test
22+
fun `mapGet - get missing key returns unset`() {
23+
val mapExpr = map(mapOf("a" to 1L, "b" to 2L, "c" to 3L))
24+
val expr = mapGet(mapExpr, "d")
25+
assertEvaluatesToUnset(evaluate(expr), "mapGet missing key should return unset")
26+
}
27+
28+
@Test
29+
fun `mapGet - get from empty map returns unset`() {
30+
val mapExpr = map(emptyMap())
31+
val expr = mapGet(mapExpr, "d")
32+
assertEvaluatesToUnset(evaluate(expr), "mapGet from empty map should return unset")
33+
}
34+
35+
@Test
36+
fun `mapGet - wrong map type returns error`() {
37+
val mapExpr = constant("not a map") // Pass a string instead of a map
38+
val expr = mapGet(mapExpr, "d")
39+
// This should evaluate to an error because the first argument is not a map.
40+
assertEvaluatesToError(evaluate(expr), "mapGet with wrong map type should return error")
41+
}
42+
43+
@Test
44+
fun `mapGet - wrong key type returns error`() {
45+
val mapExpr = map(emptyMap())
46+
val expr = mapGet(mapExpr, constant(false))
47+
// This should evaluate to an error because the key argument is not a string.
48+
assertEvaluatesToError(evaluate(expr), "mapGet with wrong key type should return error")
49+
}
50+
}

0 commit comments

Comments
 (0)