Skip to content

Commit db7c444

Browse files
committed
Additional Realtime Expression Support
1 parent c2d442c commit db7c444

File tree

6 files changed

+948
-381
lines changed

6 files changed

+948
-381
lines changed

firebase-firestore/api.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,7 @@ package com.google.firebase.firestore.pipeline {
10631063
method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, Object right);
10641064
method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(Object value);
10651065
method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr expression);
1066-
method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, Object right);
1066+
method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, Object value);
10671067
method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr other);
10681068
method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right);
10691069
method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, Object right);
@@ -1377,7 +1377,7 @@ package com.google.firebase.firestore.pipeline {
13771377
method public com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right);
13781378
method public com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, Object right);
13791379
method public com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr expression);
1380-
method public com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, Object right);
1380+
method public com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, Object value);
13811381
method public com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right);
13821382
method public com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, Object right);
13831383
method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr expression);

firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ internal object Values {
107107
}
108108
}
109109

110+
fun strictEquals(left: Value, right: Value): Boolean {
111+
val leftType = typeOrder(left)
112+
val rightType = typeOrder(right)
113+
if (leftType != rightType) {
114+
return false
115+
}
116+
117+
return when (leftType) {
118+
TYPE_ORDER_NULL -> false
119+
TYPE_ORDER_NUMBER -> strictNumberEquals(left, right)
120+
TYPE_ORDER_ARRAY -> strictArrayEquals(left, right)
121+
TYPE_ORDER_VECTOR,
122+
TYPE_ORDER_MAP -> strictObjectEquals(left, right)
123+
TYPE_ORDER_SERVER_TIMESTAMP ->
124+
ServerTimestamps.getLocalWriteTime(left) == ServerTimestamps.getLocalWriteTime(right)
125+
TYPE_ORDER_MAX_VALUE -> true
126+
else -> left == right
127+
}
128+
}
129+
110130
@JvmStatic
111131
fun equals(left: Value?, right: Value?): Boolean {
112132
if (left === right) {
@@ -135,6 +155,17 @@ internal object Values {
135155
}
136156
}
137157

158+
private fun strictNumberEquals(left: Value, right: Value): Boolean {
159+
if (left.valueTypeCase != right.valueTypeCase) {
160+
return false
161+
}
162+
return when (left.valueTypeCase) {
163+
ValueTypeCase.INTEGER_VALUE -> left.integerValue == right.integerValue
164+
ValueTypeCase.DOUBLE_VALUE -> left.doubleValue == right.doubleValue
165+
else -> false
166+
}
167+
}
168+
138169
private fun numberEquals(left: Value, right: Value): Boolean {
139170
if (left.valueTypeCase != right.valueTypeCase) {
140171
return false
@@ -147,6 +178,23 @@ internal object Values {
147178
}
148179
}
149180

181+
private fun strictArrayEquals(left: Value, right: Value): Boolean {
182+
val leftArray = left.arrayValue
183+
val rightArray = right.arrayValue
184+
185+
if (leftArray.valuesCount != rightArray.valuesCount) {
186+
return false
187+
}
188+
189+
for (i in 0 until leftArray.valuesCount) {
190+
if (!strictEquals(leftArray.getValues(i), rightArray.getValues(i))) {
191+
return false
192+
}
193+
}
194+
195+
return true
196+
}
197+
150198
private fun arrayEquals(left: Value, right: Value): Boolean {
151199
val leftArray = left.arrayValue
152200
val rightArray = right.arrayValue
@@ -164,6 +212,24 @@ internal object Values {
164212
return true
165213
}
166214

215+
private fun strictObjectEquals(left: Value, right: Value): Boolean {
216+
val leftMap = left.mapValue
217+
val rightMap = right.mapValue
218+
219+
if (leftMap.fieldsCount != rightMap.fieldsCount) {
220+
return false
221+
}
222+
223+
for ((key, value) in leftMap.fieldsMap) {
224+
val otherEntry = rightMap.fieldsMap[key] ?: return false
225+
if (!strictEquals(value, otherEntry)) {
226+
return false
227+
}
228+
}
229+
230+
return true
231+
}
232+
167233
private fun objectEquals(left: Value, right: Value): Boolean {
168234
val leftMap = left.mapValue
169235
val rightMap = right.mapValue
@@ -173,7 +239,7 @@ internal object Values {
173239
}
174240

175241
for ((key, value) in leftMap.fieldsMap) {
176-
val otherEntry = rightMap.fieldsMap[key]
242+
val otherEntry = rightMap.fieldsMap[key] ?: return false
177243
if (!equals(value, otherEntry)) {
178244
return false
179245
}
@@ -592,13 +658,14 @@ internal object Values {
592658
// the backend to do that.
593659
val truncatedNanoseconds: Int = timestamp.nanoseconds / 1000 * 1000
594660

595-
return Value.newBuilder()
596-
.setTimestampValue(
597-
Timestamp.newBuilder().setSeconds(timestamp.seconds).setNanos(truncatedNanoseconds)
598-
)
599-
.build()
661+
return encodeValue(
662+
Timestamp.newBuilder().setSeconds(timestamp.seconds).setNanos(truncatedNanoseconds).build()
663+
)
600664
}
601665

666+
@JvmStatic
667+
fun encodeValue(value: Timestamp): Value = Value.newBuilder().setTimestampValue(value).build()
668+
602669
@JvmField val TRUE_VALUE: Value = Value.newBuilder().setBooleanValue(true).build()
603670

604671
@JvmField val FALSE_VALUE: Value = Value.newBuilder().setBooleanValue(false).build()

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
11
package com.google.firebase.firestore.pipeline
22

33
import com.google.firebase.firestore.model.Values
4+
import com.google.firebase.firestore.model.Values.encodeValue
45
import com.google.firestore.v1.Value
6+
import com.google.protobuf.Timestamp
57

68
internal sealed class EvaluateResult(val value: Value?) {
79
companion object {
810
val TRUE: EvaluateResultValue = EvaluateResultValue(Values.TRUE_VALUE)
911
val FALSE: EvaluateResultValue = EvaluateResultValue(Values.FALSE_VALUE)
1012
val NULL: EvaluateResultValue = EvaluateResultValue(Values.NULL_VALUE)
11-
fun booleanValue(boolean: Boolean) = if (boolean) TRUE else FALSE
13+
val DOUBLE_ZERO: EvaluateResultValue = double(0.0)
14+
val LONG_ZERO: EvaluateResultValue = long(0)
15+
fun boolean(boolean: Boolean) = if (boolean) TRUE else FALSE
16+
fun double(double: Double) = EvaluateResultValue(encodeValue(double))
17+
fun long(long: Long) = EvaluateResultValue(encodeValue(long))
18+
fun long(int: Int) = EvaluateResultValue(encodeValue(int.toLong()))
19+
fun string(string: String) = EvaluateResultValue(encodeValue(string))
20+
fun timestamp(seconds: Long, nanos: Int): EvaluateResult =
21+
if (seconds !in -62_135_596_800 until 253_402_300_800) EvaluateResultError
22+
else
23+
EvaluateResultValue(
24+
encodeValue(Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build())
25+
)
1226
}
27+
internal inline fun evaluateNonNull(f: (Value) -> EvaluateResult): EvaluateResult =
28+
if (value?.hasNullValue() == true) f(value) else this
1329
}
1430

1531
internal object EvaluateResultError : EvaluateResult(null)

0 commit comments

Comments
 (0)