コード例 #1
0
        public void GetValue_CloneTimestamp()
        {
            var proto = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = "projects/proj/databases/db/documents/col1/doc1/col2/doc2",
                Fields     =
                {
                    { "Timestamp", new Value {
                          TimestampValue = CreateProtoTimestamp(1, 30)
                      } },
                }
            };
            var db       = FirestoreDb.Create("proj", "db", new FakeFirestoreClient());
            var readTime = new Timestamp(10, 2);
            var snapshot = DocumentSnapshot.ForDocument(db, proto, readTime);
            // If we ask for the field twice, the results should be independent. (We clone the value.)
            var fieldValue1 = snapshot.GetValue <wkt::Timestamp>("Timestamp");
            var fieldValue2 = snapshot.GetValue <wkt::Timestamp>("Timestamp");

            Assert.NotSame(fieldValue1, fieldValue2);
            Assert.Equal(fieldValue1, fieldValue2);

            fieldValue1.Nanos = 999;
            Assert.NotEqual(fieldValue1, fieldValue2);
        }
コード例 #2
0
        public void ConvenienceMembers()
        {
            var db       = FirestoreDb.Create("proj", "db", new FakeFirestoreClient());
            var query    = db.Collection("col1");
            var readTime = new Timestamp(10, 2);
            var doc1     = DocumentSnapshot.ForMissingDocument(db, "projects/proj/databases/db/documents/col1/doc1", readTime);
            var proto    = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = "projects/proj/databases/db/documents/col1/doc2"
            };
            var doc2 = DocumentSnapshot.ForDocument(db, proto, readTime);
            var docs = new[] { doc1, doc2 };

            var querySnapshot = new QuerySnapshot(query, docs, readTime);

            Assert.Equal(2, querySnapshot.Count);
            // Indexer
            Assert.Same(doc1, querySnapshot[0]);
            Assert.Same(doc2, querySnapshot[1]);
            Assert.Throws <ArgumentOutOfRangeException>(() => querySnapshot[-1]);
            Assert.Throws <ArgumentOutOfRangeException>(() => querySnapshot[2]);
            // Use IEnumerable<DocumentSnapshot>
            Assert.Equal(docs, querySnapshot);
            // OfType forces the use of non-generic IEnumerable
            Assert.Equal(docs, querySnapshot.OfType <DocumentSnapshot>());
        }
コード例 #3
0
        public void GetValue_CloneLatLng()
        {
            var proto = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = "projects/proj/databases/db/documents/col1/doc1/col2/doc2",
                Fields     =
                {
                    { "GeoPoint", new Value {
                          GeoPointValue = new Type.LatLng{
                              Latitude = 2.5, Longitude = 3.75
                          }
                      } }
                }
            };
            var db       = FirestoreDb.Create("proj", "db", new FakeFirestoreClient());
            var readTime = new Timestamp(10, 2);
            var snapshot = DocumentSnapshot.ForDocument(db, proto, readTime);

            // If we ask for the field twice, the results should be independent. (We clone the value.)
            var fieldValue1 = snapshot.GetValue <Type.LatLng>("GeoPoint");
            var fieldValue2 = snapshot.GetValue <Type.LatLng>("GeoPoint");

            Assert.NotSame(fieldValue1, fieldValue2);
            Assert.Equal(fieldValue1, fieldValue2);

            fieldValue1.Longitude = 4.5;
            Assert.NotEqual(fieldValue1, fieldValue2);
        }
コード例 #4
0
        public void Equality()
        {
            var control = GetSampleSnapshot();
            var equalDb = FirestoreDb.Create("proj", "db", new FakeFirestoreClient());

            // Equal (but distinct) everything
            var doc1   = control.Document.Clone();
            var equal1 = DocumentSnapshot.ForDocument(equalDb, doc1, control.ReadTime);

            var doc2 = control.Document.Clone();

            doc2.CreateTime = null;
            doc2.UpdateTime = null;
            // Different create/update times
            var equal2 = DocumentSnapshot.ForDocument(equalDb, doc2, control.ReadTime);

            // Different read time
            var equal3 = DocumentSnapshot.ForDocument(equalDb, doc2, new Timestamp(10, 3));

            // Different fields
            var doc4 = doc1.Clone();

            doc4.Fields["other"] = new Value {
                StringValue = "different"
            };
            var unequal1 = DocumentSnapshot.ForDocument(equalDb, doc4, control.ReadTime);

            // Different name
            var doc5 = doc1.Clone();

            doc5.Name += "x";
            var unequal2 = DocumentSnapshot.ForDocument(equalDb, doc5, control.ReadTime);

            EqualityTester.AssertEqual(control, new[] { equal1, equal2, equal3 }, new[] { unequal1, unequal2 });
        }
        private static DocumentSnapshot CreateSnapshot(string docId, int value1, int value2)
        {
            var readTime = new Timestamp(10, 2);
            var proto    = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = s_db.Document($"col/{docId}").Path,
                Fields     = { { "value1", CreateValue(value1) }, { "value2", CreateValue(value2) } }
            };

            return(DocumentSnapshot.ForDocument(s_db, proto, readTime));
        }
コード例 #6
0
        private static DocumentSnapshot GetSampleSnapshot(string docId)
        {
            var readTime = new Timestamp(10, 2);
            var proto    = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = $"projects/proj/databases/db/documents/col1/{docId}",
                Fields     = { ValueSerializer.SerializeMap(new { Name = docId }) }
            };

            return(DocumentSnapshot.ForDocument(s_db, proto, readTime));
        }
コード例 #7
0
        internal static DocumentSnapshot GetSampleSnapshot(FirestoreDb db, string docId)
        {
            var readTime = new Timestamp(10, 2);
            var proto    = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = db.Document($"col1/{docId}").Path,
                Fields     = { ValueSerializer.SerializeMap(db.SerializationContext, new { Name = docId }) }
            };

            return(DocumentSnapshot.ForDocument(db, proto, readTime));
        }
コード例 #8
0
        private DocumentSnapshot CreateSnapshot(string path, int value = 0)
        {
            var readTime = new Timestamp(10, 2);
            var proto    = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = s_db.Document(path).Path,
                Fields     = { { "field", CreateValue(value) } }
            };

            return(DocumentSnapshot.ForDocument(s_db, proto, readTime));
        }
コード例 #9
0
        public void Equality_Missing()
        {
            var nonMissing = GetSampleSnapshot();
            var db         = nonMissing.Database;
            var doc        = nonMissing.Document;

            var control  = DocumentSnapshot.ForMissingDocument(db, doc.Name, new Timestamp(1, 2));
            var equal    = DocumentSnapshot.ForMissingDocument(db, doc.Name, new Timestamp(1, 3));
            var unequal1 = DocumentSnapshot.ForMissingDocument(db, doc.Name + "x", new Timestamp(1, 2));
            var unequal2 = DocumentSnapshot.ForDocument(db, doc, new Timestamp(1, 2));

            EqualityTester.AssertEqual(control, new[] { equal }, new[] { unequal1, unequal2 });
        }
コード例 #10
0
        private static DocumentSnapshot GetSampleSnapshot(string docId)
        {
            var db       = FirestoreDb.Create("project", "database", new FakeFirestoreClient());
            var readTime = new Timestamp(10, 2);
            var proto    = new Document
            {
                CreateTime = new Timestamp(1, 10).ToProto(),
                UpdateTime = new Timestamp(2, 20).ToProto(),
                Name       = $"projects/proj/databases/db/documents/col1/{docId}",
                Fields     = { ValueSerializer.SerializeMap(new { Name = docId }) }
            };

            return(DocumentSnapshot.ForDocument(db, proto, readTime));
        }
コード例 #11
0
        public void CollectionGroup_InvalidCursor()
        {
            var db         = FirestoreDb.Create("proj", "db", new FakeFirestoreClient());
            var collection = s_db.Collection("col1");
            var document   = new Document
            {
                CreateTime = CreateProtoTimestamp(0, 0),
                UpdateTime = CreateProtoTimestamp(0, 0),
                Name       = collection.Document("doc").Path,
                Fields     = { { "field", CreateArray(CreateValue(1), CreateValue(2)) } }
            };
            var snapshot = DocumentSnapshot.ForDocument(s_db, document, Timestamp.FromProto(document.CreateTime));

            // Collection group query for a different collection
            var query = db.CollectionGroup("col2");

            Assert.Throws <ArgumentException>(() => query.StartAt(snapshot));
        }
コード例 #12
0
        public void ConvertTo_ValueType()
        {
            var db       = FirestoreDb.Create("proj", "db", new FakeFirestoreClient());
            var readTime = new Timestamp(10, 2);
            var proto    = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = "projects/proj/databases/db/documents/col1/doc1/col2/doc2",
                Fields     =
                {
                    ["Name"]  = ProtoHelpers.CreateValue("text"),
                    ["Value"] = ProtoHelpers.CreateValue(100)
                }
            };
            var document = DocumentSnapshot.ForDocument(db, proto, readTime);
            var value    = document.ConvertTo <SerializationTestData.CustomValueType>();

            Assert.Equal("text", value.Name);
            Assert.Equal(100, value.Value);
        }
コード例 #13
0
        public void ArrayContainsIsEquality()
        {
            var collection = s_db.Collection("col");
            var document   = new Document
            {
                CreateTime = CreateProtoTimestamp(0, 0),
                UpdateTime = CreateProtoTimestamp(0, 0),
                Name       = collection.Document("doc").Path,
                Fields     = { { "field", CreateArray(CreateValue(1), CreateValue(2)) } }
            };
            var snapshot = DocumentSnapshot.ForDocument(s_db, document, Timestamp.FromProto(document.CreateTime));
            // An inequality filter would create an implicit ordering here, but "array contains"
            // is effectively an equality filter, so we should end up with document ID ordering instead.
            var query           = s_db.Collection("col").WhereArrayContains("field", 1).StartAt(snapshot);
            var structured      = query.ToStructuredQuery();
            var documentIdOrder = new Order {
                Direction = Direction.Ascending, Field = FieldPath.DocumentId.ToFieldReference()
            };

            Assert.Equal(new[] { documentIdOrder }, structured.OrderBy);
        }
コード例 #14
0
        private static DocumentSnapshot GetSampleSnapshot()
        {
            var poco = new SampleData
            {
                Name   = "Test",
                Nested = new NestedData {
                    Score = 20
                }
            };
            var db       = FirestoreDb.Create("proj", "db", new FakeFirestoreClient());
            var readTime = new Timestamp(10, 2);
            var proto    = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = "projects/proj/databases/db/documents/col1/doc1/col2/doc2",
                Fields     = { ValueSerializer.SerializeMap(poco) }
            };

            return(DocumentSnapshot.ForDocument(db, proto, readTime));
        }
コード例 #15
0
        public void ExistingDocument()
        {
            var db       = FirestoreDb.Create("proj", "db", new FakeFirestoreClient());
            var readTime = new Timestamp(10, 2);
            var proto    = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = "projects/proj/databases/db/documents/col1/doc1/col2/doc2"
            };
            var document = DocumentSnapshot.ForDocument(db, proto, readTime);

            Assert.Equal(db.Document("col1/doc1/col2/doc2"), document.Reference);
            Assert.Equal("doc2", document.Id);
            Assert.Same(db, document.Database);
            Assert.Same(proto, document.Document);
            Assert.Equal(new Timestamp(1, 10), document.CreateTime);
            Assert.Equal(new Timestamp(2, 20), document.UpdateTime);
            Assert.Equal(readTime, document.ReadTime);
            Assert.True(document.Exists);
            // Tests for data access are performed separately.
        }
コード例 #16
0
        public void ConvertTo_WithId()
        {
            var db       = FirestoreDb.Create("proj", "db", new FakeFirestoreClient());
            var readTime = new Timestamp(10, 2);
            var proto    = new Document
            {
                CreateTime = CreateProtoTimestamp(1, 10),
                UpdateTime = CreateProtoTimestamp(2, 20),
                Name       = "projects/proj/databases/db/documents/col1/doc1/col2/doc2",
                Fields     =
                {
                    ["Name"]  = ProtoHelpers.CreateValue("text"),
                    ["Value"] = ProtoHelpers.CreateValue(100)
                }
            };
            var document = DocumentSnapshot.ForDocument(db, proto, readTime);

            var converted = document.ConvertTo <SampleDataWithDocumentId>();

            Assert.Equal("text", converted.Name);
            Assert.Equal(100, converted.Value);
            Assert.Equal("doc2", converted.DocumentId);
        }
コード例 #17
0
        public async Task Listen(SerializableTest wrapper)
        {
            ListenTest test  = wrapper.Test.Listen;
            var        db    = FirestoreDb.Create(ProjectId, DatabaseId, new FakeFirestoreClient());
            var        query = db.Collection("C").OrderBy("a");

            Func <Task> action = async() =>
            {
                List <QuerySnapshot> snapshots = new List <QuerySnapshot>();
                var watchState = new WatchState(query, (snapshot, token) => { snapshots.Add(snapshot); return(Task.FromResult(1)); });
                watchState.OnStreamInitialization(StreamInitializationCause.WatchStarting);
                foreach (var response in test.Responses)
                {
                    // Fix up the test response to use our watch target ID.
                    ReplaceWatchTargetId(response.TargetChange?.TargetIds);
                    ReplaceWatchTargetId(response.DocumentChange?.TargetIds);
                    ReplaceWatchTargetId(response.DocumentChange?.RemovedTargetIds);
                    ReplaceWatchTargetId(response.DocumentDelete?.RemovedTargetIds);
                    ReplaceWatchTargetId(response.DocumentRemove?.RemovedTargetIds);

                    var result = await watchState.HandleResponseAsync(response, default);

                    if (result == WatchResponseResult.ResetStream)
                    {
                        watchState.OnStreamInitialization(StreamInitializationCause.ResetRequested);
                    }
                }
                var expectedSnapshots = test.Snapshots.Select(snapshot => ConvertSnapshot(snapshot)).ToList();
                Assert.Equal(expectedSnapshots, snapshots);
            };

            if (test.IsError)
            {
                // TODO: Should we actually check that it's only the last response that causes the exception?
                var exception = await Assert.ThrowsAnyAsync <Exception>(action);

                Assert.True(exception is ArgumentException || exception is InvalidOperationException,
                            $"Exception type: {exception.GetType()}");
            }
            else
            {
                await action();
            }

            // Different clients use different watch target IDs. The test data always uses 1
            // to mean "the target ID that the client uses".
            void ReplaceWatchTargetId(RepeatedField <int> ids)
            {
                if (ids == null)
                {
                    return;
                }
                for (int i = 0; i < ids.Count; i++)
                {
                    if (ids[i] == 1)
                    {
                        ids[i] = WatchStream.WatchTargetId;
                    }
                }
            }

            // Converts from a test proto snapshot to a QuerySnapshot
            QuerySnapshot ConvertSnapshot(Snapshot snapshot)
            {
                var readTime = Timestamp.FromProto(snapshot.ReadTime);
                var changes  = snapshot.Changes.Select(change => ConvertChange(change, readTime)).ToList();
                var docs     = snapshot.Docs.Select(doc => DocumentSnapshot.ForDocument(db, doc, readTime)).ToList();

                return(QuerySnapshot.ForChanges(query, docs, changes, readTime));
            }

            DocumentChange ConvertChange(DocChange change, Timestamp readTime)
            {
                var snapshot = DocumentSnapshot.ForDocument(db, change.Doc, readTime);

                return(new DocumentChange(snapshot, (DocumentChange.Type)change.Kind,
                                          change.OldIndex == -1 ? default(int?) : change.OldIndex, change.NewIndex == -1 ? default(int?) : change.NewIndex));
            }
        }
コード例 #18
0
        public void Query(SerializableTest wrapper)
        {
            QueryTest test = wrapper.Test.Query;

            if (test.IsError)
            {
                var exception = Assert.ThrowsAny <Exception>(() => BuildQuery());
                Assert.True(exception is ArgumentException || exception is InvalidOperationException, $"Exception type: {exception.GetType()}");
            }
            else
            {
                var query = BuildQuery();
                Assert.Equal(test.Query, query.ToStructuredQuery());
            }

            Query BuildQuery()
            {
                Query query = GetCollectionReference(test.CollPath);

                foreach (var clause in test.Clauses)
                {
                    switch (clause.ClauseCase)
                    {
                    case Clause.ClauseOneofCase.EndAt:
                        query = query.EndAt(ConvertCursor(clause.EndAt));
                        break;

                    case Clause.ClauseOneofCase.EndBefore:
                        query = query.EndBefore(ConvertCursor(clause.EndBefore));
                        break;

                    case Clause.ClauseOneofCase.Limit:
                        query = query.Limit(clause.Limit);
                        break;

                    case Clause.ClauseOneofCase.Offset:
                        query = query.Offset(clause.Offset);
                        break;

                    case Clause.ClauseOneofCase.OrderBy:
                        var ordering = clause.OrderBy;
                        var path     = ConvertFieldPath(ordering.Path);
                        query = ordering.Direction == "asc" ? query.OrderBy(path) : query.OrderByDescending(path);
                        break;

                    case Clause.ClauseOneofCase.Select:
                        query = query.Select(clause.Select.Fields.Select(ConvertFieldPath).ToArray());
                        break;

                    case Clause.ClauseOneofCase.StartAfter:
                        query = query.StartAfter(ConvertCursor(clause.StartAfter));
                        break;

                    case Clause.ClauseOneofCase.StartAt:
                        query = query.StartAt(ConvertCursor(clause.StartAt));
                        break;

                    case Clause.ClauseOneofCase.Where:
                        var filterPath = ConvertFieldPath(clause.Where.Path);
                        if (!QueryOperators.TryGetValue(clause.Where.Op, out var filterProvider))
                        {
                            throw new ArgumentException($"Invalid where operator: {clause.Where.Op}");
                        }
                        var value = DeserializeJson(clause.Where.JsonValue);
                        query = filterProvider(query, filterPath, value);
                        break;

                    default:
                        throw new InvalidOperationException($"Unexpected clause case: {clause.ClauseCase}");
                    }
                }
                return(query);
            }

            // Note: dynamic to allow a DocumentSnapshot to be returned and used in overload resolution.
            dynamic ConvertCursor(Cursor cursor)
            {
                var docSnapshot = cursor.DocSnapshot;

                if (docSnapshot == null)
                {
                    return(cursor.JsonValues.Select(DeserializeJson).ToArray());
                }
                var docRef = GetDocumentReference(docSnapshot.Path);

                return(DocumentSnapshot.ForDocument(
                           docRef.Database,
                           new Document
                {
                    Name = docRef.Path,
                    Fields = { ValueSerializer.SerializeMap(DeserializeJson(cursor.DocSnapshot.JsonData)) },
                    CreateTime = wkt::Timestamp.FromDateTimeOffset(DateTimeOffset.MinValue),
                    UpdateTime = wkt::Timestamp.FromDateTimeOffset(DateTimeOffset.MinValue),
                },
                           Timestamp.FromDateTimeOffset(DateTimeOffset.MinValue)));
            }
        }