public int Compare(DocumentSnapshot x, DocumentSnapshot y) { GaxPreconditions.CheckArgument(x.Exists, nameof(x), "Document snapshot comparer for a query cannot be used with snapshots of missing documents"); GaxPreconditions.CheckArgument(y.Exists, nameof(y), "Document snapshot comparer for a query cannot be used with snapshots of missing documents"); var orderings = _query._orderings; Direction lastDirection = Direction.Ascending; foreach (var ordering in _query._orderings) { lastDirection = ordering.Direction; int fieldResult; if (Equals(ordering.Field, FieldPath.DocumentId)) { fieldResult = x.Reference.CompareTo(y.Reference); } else { var xValue = x.ExtractValue(ordering.Field); var yValue = y.ExtractValue(ordering.Field); if (xValue == null || yValue == null) { throw new InvalidOperationException("Can only compare fields that exist in the DocumentSnapshot." + " Please include the fields you are ordering on in your Select() call."); } fieldResult = ValueComparer.Instance.Compare(xValue, yValue); } if (fieldResult != 0) { return(lastDirection == Direction.Ascending ? fieldResult : -Math.Sign(fieldResult)); } } // Everything is equal in the specified orderings. // Compare by name, using the last-specified ordering, defaulting to ascending. int result = x.Reference.CompareTo(y.Reference); if (lastDirection == Direction.Descending) { result = -Math.Sign(result); } return(result); }
private Cursor CreateCursorFromSnapshot(DocumentSnapshot snapshot, bool before, out IReadOnlyList <InternalOrdering> newOrderings) { GaxPreconditions.CheckArgument(Equals(snapshot.Reference.Parent, Collection), nameof(snapshot), "Snapshot was from incorrect collection"); GaxPreconditions.CheckNotNull(snapshot, nameof(snapshot)); var cursor = new Cursor { Before = before }; bool hasDocumentId = false; // We may or may not need to add some orderings; this is communicated through the out parameter. newOrderings = _orderings; // Only used when we need to add orderings; set newOrderings to this at the same time. List <InternalOrdering> modifiedOrderings = null; if (_orderings.Count == 0 && _filters != null) { // If no explicit ordering is specified, use the first inequality to define an implicit order. foreach (var filter in _filters) { if (!filter.IsEqualityFilter()) { modifiedOrderings = new List <InternalOrdering>(newOrderings) { new InternalOrdering(filter.Field, Direction.Ascending) }; newOrderings = modifiedOrderings; } } } else { hasDocumentId = _orderings.Any(order => Equals(order.Field, FieldPath.DocumentId)); } if (!hasDocumentId) { // Add implicit sorting by name, using the last specified direction. Direction lastDirection = _orderings.Count == 0 ? Direction.Ascending : _orderings.Last().Direction; // Clone iff this is the first new ordering. if (modifiedOrderings == null) { modifiedOrderings = new List <InternalOrdering>(newOrderings); newOrderings = modifiedOrderings; } modifiedOrderings.Add(new InternalOrdering(FieldPath.DocumentId, lastDirection)); } foreach (var ordering in newOrderings) { var field = ordering.Field; var value = Equals(field, FieldPath.DocumentId) ? ValueSerializer.Serialize(snapshot.Reference) : snapshot.ExtractValue(field); if (value == null) { throw new ArgumentException($"Snapshot does not contain field {field}", nameof(snapshot)); } cursor.Values.Add(ValueSerializer.Serialize(value)); } return(cursor); }