11@file:JvmName(" Evaluation" )
2+
23package com.google.firebase.firestore.pipeline
34
45import com.google.common.math.LongMath
@@ -10,6 +11,8 @@ import com.google.firebase.firestore.model.MutableDocument
1011import com.google.firebase.firestore.model.Values
1112import com.google.firebase.firestore.model.Values.encodeValue
1213import com.google.firebase.firestore.model.Values.isNanValue
14+ import com.google.firebase.firestore.model.Values.strictCompare
15+ import com.google.firebase.firestore.model.Values.strictEquals
1316import com.google.firebase.firestore.util.Assert
1417import com.google.firestore.v1.Value
1518import com.google.protobuf.ByteString
@@ -76,17 +79,37 @@ internal val evaluateXor: EvaluateFunction = variadicFunction { values: BooleanA
7679
7780// === Comparison Functions ===
7881
79- internal val evaluateEq: EvaluateFunction = comparison(Values ::strictEquals)
82+ internal val evaluateEq: EvaluateFunction = binaryFunction { p1: Value , p2: Value ->
83+ EvaluateResult .boolean(strictEquals(p1, p2))
84+ }
8085
81- internal val evaluateNeq: EvaluateFunction = comparison { v1, v2 -> ! Values .strictEquals(v1, v2) }
86+ internal val evaluateNeq: EvaluateFunction = binaryFunction { p1: Value , p2: Value ->
87+ EvaluateResult .boolean(strictEquals(p1, p2)?.not ())
88+ }
8289
83- internal val evaluateGt: EvaluateFunction = comparison { v1, v2 -> Values .compare(v1, v2) > 0 }
90+ internal val evaluateGt: EvaluateFunction = comparison { v1, v2 ->
91+ (strictCompare(v1, v2) ? : return @comparison false ) > 0
92+ }
8493
85- internal val evaluateGte: EvaluateFunction = comparison { v1, v2 -> Values .compare(v1, v2) >= 0 }
94+ internal val evaluateGte: EvaluateFunction = comparison { v1, v2 ->
95+ when (strictEquals(v1, v2)) {
96+ true -> true
97+ false -> (strictCompare(v1, v2) ? : return @comparison false ) > 0
98+ null -> null
99+ }
100+ }
86101
87- internal val evaluateLt: EvaluateFunction = comparison { v1, v2 -> Values .compare(v1, v2) < 0 }
102+ internal val evaluateLt: EvaluateFunction = comparison { v1, v2 ->
103+ (strictCompare(v1, v2) ? : return @comparison false ) < 0
104+ }
88105
89- internal val evaluateLte: EvaluateFunction = comparison { v1, v2 -> Values .compare(v1, v2) <= 0 }
106+ internal val evaluateLte: EvaluateFunction = comparison { v1, v2 ->
107+ when (strictEquals(v1, v2)) {
108+ true -> true
109+ false -> (strictCompare(v1, v2) ? : return @comparison false ) < 0
110+ null -> null
111+ }
112+ }
90113
91114internal val evaluateNot: EvaluateFunction = unaryFunction { b: Boolean ->
92115 EvaluateResult .boolean(b.not ())
@@ -297,52 +320,48 @@ internal fun plus(t: Timestamp, seconds: Long, nanos: Long): Timestamp =
297320 }
298321
299322private fun plus (t : Timestamp , seconds : Long ): Timestamp =
300- if (seconds == 0L ) t
301- else Values .timestamp(checkedAdd(t.seconds, seconds), t.nanos)
323+ if (seconds == 0L ) t else Values .timestamp(checkedAdd(t.seconds, seconds), t.nanos)
302324
303325internal fun minus (t : Timestamp , seconds : Long , nanos : Long ): Timestamp =
304326 if (nanos == 0L ) {
305327 minus(t, seconds)
306328 } else {
307329 val nanoSum = t.nanos - nanos // Overflow not possible since nanos is 0 to 1 000 000.
308- val secondsSum: Long = checkedSubtract(t.seconds, checkedSubtract(seconds, nanoSum / L_NANOS_PER_SECOND ))
330+ val secondsSum: Long =
331+ checkedSubtract(t.seconds, checkedSubtract(seconds, nanoSum / L_NANOS_PER_SECOND ))
309332 Values .timestamp(secondsSum, (nanoSum % I_NANOS_PER_SECOND ).toInt())
310333 }
311334
312335private fun minus (t : Timestamp , seconds : Long ): Timestamp =
313- if (seconds == 0L ) t
314- else Values .timestamp(checkedSubtract(t.seconds, seconds), t.nanos)
315-
316-
317- internal val evaluateTimestampAdd =
318- ternaryTimestampFunction { t: Timestamp , u: String , n: Long ->
319- EvaluateResult .timestamp(
320- when (u) {
321- " microsecond" -> plus(t, n / L_MICROS_PER_SECOND , (n % L_MICROS_PER_SECOND ) * 1000 )
322- " millisecond" -> plus(t, n / L_MILLIS_PER_SECOND , (n % L_MILLIS_PER_SECOND ) * 1000_000 )
323- " second" -> plus(t, n)
324- " minute" -> plus(t, checkedMultiply(n, 60 ))
325- " hour" -> plus(t, checkedMultiply(n, 3600 ))
326- " day" -> plus(t, checkedMultiply(n, 86400 ))
327- else -> return @ternaryTimestampFunction EvaluateResultError
328- }
329- )
330- }
336+ if (seconds == 0L ) t else Values .timestamp(checkedSubtract(t.seconds, seconds), t.nanos)
331337
332- internal val evaluateTimestampSub =
333- ternaryTimestampFunction { t: Timestamp , u: String , n: Long ->
334- EvaluateResult .timestamp(
335- when (u) {
336- " microsecond" -> minus(t, n / L_MICROS_PER_SECOND , (n % L_MICROS_PER_SECOND ) * 1000 )
337- " millisecond" -> minus(t, n / L_MILLIS_PER_SECOND , (n % L_MILLIS_PER_SECOND ) * 1000_000 )
338- " second" -> minus(t, n)
339- " minute" -> minus(t, checkedMultiply(n, 60 ))
340- " hour" -> minus(t, checkedMultiply(n, 3600 ))
341- " day" -> minus(t, checkedMultiply(n, 86400 ))
342- else -> return @ternaryTimestampFunction EvaluateResultError
343- }
344- )
345- }
338+ internal val evaluateTimestampAdd = ternaryTimestampFunction { t: Timestamp , u: String , n: Long ->
339+ EvaluateResult .timestamp(
340+ when (u) {
341+ " microsecond" -> plus(t, n / L_MICROS_PER_SECOND , (n % L_MICROS_PER_SECOND ) * 1000 )
342+ " millisecond" -> plus(t, n / L_MILLIS_PER_SECOND , (n % L_MILLIS_PER_SECOND ) * 1000_000 )
343+ " second" -> plus(t, n)
344+ " minute" -> plus(t, checkedMultiply(n, 60 ))
345+ " hour" -> plus(t, checkedMultiply(n, 3600 ))
346+ " day" -> plus(t, checkedMultiply(n, 86400 ))
347+ else -> return @ternaryTimestampFunction EvaluateResultError
348+ }
349+ )
350+ }
351+
352+ internal val evaluateTimestampSub = ternaryTimestampFunction { t: Timestamp , u: String , n: Long ->
353+ EvaluateResult .timestamp(
354+ when (u) {
355+ " microsecond" -> minus(t, n / L_MICROS_PER_SECOND , (n % L_MICROS_PER_SECOND ) * 1000 )
356+ " millisecond" -> minus(t, n / L_MILLIS_PER_SECOND , (n % L_MILLIS_PER_SECOND ) * 1000_000 )
357+ " second" -> minus(t, n)
358+ " minute" -> minus(t, checkedMultiply(n, 60 ))
359+ " hour" -> minus(t, checkedMultiply(n, 3600 ))
360+ " day" -> minus(t, checkedMultiply(n, 86400 ))
361+ else -> return @ternaryTimestampFunction EvaluateResultError
362+ }
363+ )
364+ }
346365
347366internal val evaluateTimestampTrunc = notImplemented // TODO: Does not exist in expressions.kt yet.
348367
@@ -402,17 +421,18 @@ internal val evaluateUnixSecondsToTimestamp = unaryFunction { seconds: Long ->
402421internal val evaluateMap: EvaluateFunction = { params ->
403422 if (params.size % 2 != 0 )
404423 throw Assert .fail(" Function should have even number of params, but %d were given." , params.size)
405- else block@{ input: MutableDocument ->
406- val map: MutableMap <String , Value > = HashMap (params.size / 2 )
407- for (i in params.indices step 2 ) {
408- val k = params[i](input).value ? : return @block EvaluateResultError
409- if (! k.hasStringValue()) return @block EvaluateResultError
410- val v = params[i + 1 ](input).value ? : return @block EvaluateResultError
411- // It is against the API contract to include a key more than once.
412- if (map.put(k.stringValue, v) != null ) return @block EvaluateResultError
424+ else
425+ block@{ input: MutableDocument ->
426+ val map: MutableMap <String , Value > = HashMap (params.size / 2 )
427+ for (i in params.indices step 2 ) {
428+ val k = params[i](input).value ? : return @block EvaluateResultError
429+ if (! k.hasStringValue()) return @block EvaluateResultError
430+ val v = params[i + 1 ](input).value ? : return @block EvaluateResultError
431+ // It is against the API contract to include a key more than once.
432+ if (map.put(k.stringValue, v) != null ) return @block EvaluateResultError
433+ }
434+ EvaluateResultValue (encodeValue(map))
413435 }
414- EvaluateResultValue (encodeValue(map))
415- }
416436}
417437
418438// === Helper Functions ===
@@ -688,10 +708,10 @@ private inline fun variadicFunction(
688708 }
689709}
690710
691- private inline fun comparison (crossinline predicate : (Value , Value ) -> Boolean ): EvaluateFunction =
711+ private inline fun comparison (crossinline f : (Value , Value ) -> Boolean? ): EvaluateFunction =
692712 binaryFunction { p1: Value , p2: Value ->
693713 if (isNanValue(p1) or isNanValue(p2)) EvaluateResult .FALSE
694- else catch { EvaluateResult .boolean(predicate (p1, p2)) }
714+ else EvaluateResult .boolean(f (p1, p2))
695715 }
696716
697717private inline fun arithmeticPrimitive (
0 commit comments