1
1
@file:JvmName(" Evaluation" )
2
+
2
3
package com.google.firebase.firestore.pipeline
3
4
4
5
import com.google.common.math.LongMath
@@ -10,6 +11,8 @@ import com.google.firebase.firestore.model.MutableDocument
10
11
import com.google.firebase.firestore.model.Values
11
12
import com.google.firebase.firestore.model.Values.encodeValue
12
13
import 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
13
16
import com.google.firebase.firestore.util.Assert
14
17
import com.google.firestore.v1.Value
15
18
import com.google.protobuf.ByteString
@@ -76,17 +79,37 @@ internal val evaluateXor: EvaluateFunction = variadicFunction { values: BooleanA
76
79
77
80
// === Comparison Functions ===
78
81
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
+ }
80
85
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
+ }
82
89
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
+ }
84
93
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
+ }
86
101
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
+ }
88
105
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
+ }
90
113
91
114
internal val evaluateNot: EvaluateFunction = unaryFunction { b: Boolean ->
92
115
EvaluateResult .boolean(b.not ())
@@ -297,52 +320,48 @@ internal fun plus(t: Timestamp, seconds: Long, nanos: Long): Timestamp =
297
320
}
298
321
299
322
private 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)
302
324
303
325
internal fun minus (t : Timestamp , seconds : Long , nanos : Long ): Timestamp =
304
326
if (nanos == 0L ) {
305
327
minus(t, seconds)
306
328
} else {
307
329
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 ))
309
332
Values .timestamp(secondsSum, (nanoSum % I_NANOS_PER_SECOND ).toInt())
310
333
}
311
334
312
335
private 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)
331
337
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
+ }
346
365
347
366
internal val evaluateTimestampTrunc = notImplemented // TODO: Does not exist in expressions.kt yet.
348
367
@@ -402,17 +421,18 @@ internal val evaluateUnixSecondsToTimestamp = unaryFunction { seconds: Long ->
402
421
internal val evaluateMap: EvaluateFunction = { params ->
403
422
if (params.size % 2 != 0 )
404
423
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))
413
435
}
414
- EvaluateResultValue (encodeValue(map))
415
- }
416
436
}
417
437
418
438
// === Helper Functions ===
@@ -688,10 +708,10 @@ private inline fun variadicFunction(
688
708
}
689
709
}
690
710
691
- private inline fun comparison (crossinline predicate : (Value , Value ) -> Boolean ): EvaluateFunction =
711
+ private inline fun comparison (crossinline f : (Value , Value ) -> Boolean? ): EvaluateFunction =
692
712
binaryFunction { p1: Value , p2: Value ->
693
713
if (isNanValue(p1) or isNanValue(p2)) EvaluateResult .FALSE
694
- else catch { EvaluateResult .boolean(predicate (p1, p2)) }
714
+ else EvaluateResult .boolean(f (p1, p2))
695
715
}
696
716
697
717
private inline fun arithmeticPrimitive (
0 commit comments