From 591dfc01c5c43bb5e34f40a4f707b1fc534538d2 Mon Sep 17 00:00:00 2001 From: jwierzbo Date: Mon, 17 Oct 2022 11:59:59 +0200 Subject: [PATCH 1/2] GT-214 Implement `checksum` endpoint for collections --- .gitignore | 3 +++ CHANGELOG.md | 1 + collection.go | 14 +++++++++++--- collection_impl.go | 31 +++++++++++++++++++++++++++++++ edge_collection_impl.go | 9 +++++++++ test/collection_test.go | 34 ++++++++++++++++++++++++++++++++++ vertex_collection_impl.go | 9 +++++++++ 7 files changed, 98 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 99346b86..55c32763 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ vendor # Helper files debug/ *.log + +# direnv files +.envrc diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d99609a..a56b2792 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Change Log ## [master](https://github.com/arangodb/go-driver/tree/master) (N/A) +- Add support for `checksum` in Collections ## [1.4.0](https://github.com/arangodb/go-driver/tree/v1.4.0) (2022-10-04) - Add `hex` property to analyzer's properties diff --git a/collection.go b/collection.go index 038e60c3..fc978df6 100644 --- a/collection.go +++ b/collection.go @@ -50,6 +50,11 @@ type Collection interface { // in a collection has changed since the last revision check. Revision(ctx context.Context) (string, error) + // Checksum returns a checksum for the specified collection + // withRevisions - Whether to include document revision ids in the checksum calculation. + // withData - Whether to include document body data in the checksum calculation. + Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionInfo, error) + // Properties fetches extended information about the collection. Properties(ctx context.Context) (CollectionProperties, error) @@ -81,6 +86,8 @@ type Collection interface { // CollectionInfo contains information about a collection type CollectionInfo struct { + ArangoError + // The identifier of the collection. ID string `json:"id,omitempty"` // The name of the collection. @@ -95,12 +102,15 @@ type CollectionInfo struct { IsSystem bool `json:"isSystem,omitempty"` // Global unique name for the collection GloballyUniqueId string `json:"globallyUniqueId,omitempty"` + // The collection revision id as a string. + Revision string `json:"revision,omitempty"` + // The calculated checksum as a number. + Checksum string `json:"checksum,omitempty"` } // CollectionProperties contains extended information about a collection. type CollectionProperties struct { CollectionInfo - ArangoError // WaitForSync; If true then creating, changing or removing documents will wait until the data has been synchronized to disk. WaitForSync bool `json:"waitForSync,omitempty"` @@ -157,8 +167,6 @@ type CollectionProperties struct { // Schema for collection validation Schema *CollectionSchemaOptions `json:"schema,omitempty"` - Revision string `json:"revision,omitempty"` - // IsDisjoint set isDisjoint flag for Graph. Required ArangoDB 3.7+ IsDisjoint bool `json:"isDisjoint,omitempty"` diff --git a/collection_impl.go b/collection_impl.go index c0b913ea..4cc56d48 100644 --- a/collection_impl.go +++ b/collection_impl.go @@ -150,6 +150,37 @@ func (c *collection) Revision(ctx context.Context) (string, error) { return data.Revision, nil } +// Checksum returns a checksum for the specified collection +// withRevisions - Whether to include document revision ids in the checksum calculation. +// withData - Whether to include document body data in the checksum calculation. +func (c *collection) Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionInfo, error) { + var data CollectionInfo + + req, err := c.conn.NewRequest("GET", path.Join(c.relPath("collection"), "checksum")) + if err != nil { + return data, WithStack(err) + } + if withRevisions { + req.SetQuery("withRevisions", "true") + } + if withData { + req.SetQuery("withData", "true") + } + + resp, err := c.conn.Do(ctx, req) + if err != nil { + return data, WithStack(err) + } + if err := resp.CheckStatus(200); err != nil { + return data, WithStack(err) + } + + if err := resp.ParseBody("", &data); err != nil { + return data, WithStack(err) + } + return data, nil +} + // Properties fetches extended information about the collection. func (c *collection) Properties(ctx context.Context) (CollectionProperties, error) { req, err := c.conn.NewRequest("GET", path.Join(c.relPath("collection"), "properties")) diff --git a/edge_collection_impl.go b/edge_collection_impl.go index d851825c..cdf90063 100644 --- a/edge_collection_impl.go +++ b/edge_collection_impl.go @@ -81,6 +81,15 @@ func (c *edgeCollection) Status(ctx context.Context) (CollectionStatus, error) { return result, nil } +// Checksum returns a checksum for the specified collection +func (c *edgeCollection) Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionInfo, error) { + result, err := c.rawCollection().Checksum(ctx, withRevisions, withData) + if err != nil { + return CollectionInfo{}, WithStack(err) + } + return result, nil +} + // Count fetches the number of document in the collection. func (c *edgeCollection) Count(ctx context.Context) (int64, error) { result, err := c.rawCollection().Count(ctx) diff --git a/test/collection_test.go b/test/collection_test.go index 7dbe1447..3d408666 100644 --- a/test/collection_test.go +++ b/test/collection_test.go @@ -761,6 +761,40 @@ func TestCollectionRevision(t *testing.T) { } } +// TestCollectionChecksum creates a collection, checks checksum after adding documents. +func TestCollectionChecksum(t *testing.T) { + c := createClientFromEnv(t, true) + db := ensureDatabase(nil, c, "collection_checksum", nil, t) + name := "test_collection_checksum" + col, err := db.CreateCollection(nil, name, nil) + require.NoError(t, err) + + // create some documents + for i := 0; i < 5; i++ { + before, err := col.Checksum(nil, false, false) + require.NoError(t, err) + + doc := Book{Title: fmt.Sprintf("Book %d", i)} + _, err = col.CreateDocument(nil, doc) + require.NoError(t, err) + + after, err := col.Checksum(nil, false, false) + require.NoError(t, err) + require.NotEqual(t, before.Checksum, after.Checksum) + + afterWithRevision, err := col.Checksum(nil, true, false) + require.NoError(t, err) + require.NotEqual(t, before.Checksum, afterWithRevision.Checksum) + require.NotEqual(t, after.Checksum, afterWithRevision.Checksum) + + afterWithData, err := col.Checksum(nil, false, true) + require.NoError(t, err) + require.NotEqual(t, before.Checksum, afterWithData.Checksum) + require.NotEqual(t, after.Checksum, afterWithData.Checksum) + require.NotEqual(t, afterWithRevision.Checksum, afterWithData.Checksum) + } +} + // TestCollectionStatistics creates a collection, checks statistics after adding documents. func TestCollectionStatistics(t *testing.T) { c := createClientFromEnv(t, true) diff --git a/vertex_collection_impl.go b/vertex_collection_impl.go index b6c8c7bb..9f97acf1 100644 --- a/vertex_collection_impl.go +++ b/vertex_collection_impl.go @@ -81,6 +81,15 @@ func (c *vertexCollection) Status(ctx context.Context) (CollectionStatus, error) return result, nil } +// Checksum returns a checksum for the specified collection +func (c *vertexCollection) Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionInfo, error) { + result, err := c.rawCollection().Checksum(ctx, withRevisions, withData) + if err != nil { + return CollectionInfo{}, WithStack(err) + } + return result, nil +} + // Count fetches the number of document in the collection. func (c *vertexCollection) Count(ctx context.Context) (int64, error) { result, err := c.rawCollection().Count(ctx) From f8d0962c6d386e3215caa28c382ae3474e021640 Mon Sep 17 00:00:00 2001 From: jwierzbo Date: Tue, 18 Oct 2022 13:20:00 +0200 Subject: [PATCH 2/2] Provide new `CollectionChecksum` structure --- collection.go | 17 ++++++++++++----- collection_impl.go | 4 ++-- edge_collection_impl.go | 4 ++-- vertex_collection_impl.go | 4 ++-- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/collection.go b/collection.go index fc978df6..ba097652 100644 --- a/collection.go +++ b/collection.go @@ -53,7 +53,7 @@ type Collection interface { // Checksum returns a checksum for the specified collection // withRevisions - Whether to include document revision ids in the checksum calculation. // withData - Whether to include document body data in the checksum calculation. - Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionInfo, error) + Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionChecksum, error) // Properties fetches extended information about the collection. Properties(ctx context.Context) (CollectionProperties, error) @@ -84,10 +84,16 @@ type Collection interface { CollectionDocuments } -// CollectionInfo contains information about a collection -type CollectionInfo struct { +// CollectionChecksum contains information about a collection checksum response +type CollectionChecksum struct { ArangoError + CollectionInfo + // The collection revision id as a string. + Revision string `json:"revision,omitempty"` +} +// CollectionInfo contains information about a collection +type CollectionInfo struct { // The identifier of the collection. ID string `json:"id,omitempty"` // The name of the collection. @@ -102,8 +108,6 @@ type CollectionInfo struct { IsSystem bool `json:"isSystem,omitempty"` // Global unique name for the collection GloballyUniqueId string `json:"globallyUniqueId,omitempty"` - // The collection revision id as a string. - Revision string `json:"revision,omitempty"` // The calculated checksum as a number. Checksum string `json:"checksum,omitempty"` } @@ -111,6 +115,7 @@ type CollectionInfo struct { // CollectionProperties contains extended information about a collection. type CollectionProperties struct { CollectionInfo + ArangoError // WaitForSync; If true then creating, changing or removing documents will wait until the data has been synchronized to disk. WaitForSync bool `json:"waitForSync,omitempty"` @@ -164,6 +169,8 @@ type CollectionProperties struct { // The following attribute specifies if the new MerkleTree based sync protocol // can be used on the collection. SyncByRevision bool `json:"syncByRevision,omitempty"` + // The collection revision id as a string. + Revision string `json:"revision,omitempty"` // Schema for collection validation Schema *CollectionSchemaOptions `json:"schema,omitempty"` diff --git a/collection_impl.go b/collection_impl.go index 4cc56d48..938fe5ac 100644 --- a/collection_impl.go +++ b/collection_impl.go @@ -153,8 +153,8 @@ func (c *collection) Revision(ctx context.Context) (string, error) { // Checksum returns a checksum for the specified collection // withRevisions - Whether to include document revision ids in the checksum calculation. // withData - Whether to include document body data in the checksum calculation. -func (c *collection) Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionInfo, error) { - var data CollectionInfo +func (c *collection) Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionChecksum, error) { + var data CollectionChecksum req, err := c.conn.NewRequest("GET", path.Join(c.relPath("collection"), "checksum")) if err != nil { diff --git a/edge_collection_impl.go b/edge_collection_impl.go index cdf90063..81bc8ed2 100644 --- a/edge_collection_impl.go +++ b/edge_collection_impl.go @@ -82,10 +82,10 @@ func (c *edgeCollection) Status(ctx context.Context) (CollectionStatus, error) { } // Checksum returns a checksum for the specified collection -func (c *edgeCollection) Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionInfo, error) { +func (c *edgeCollection) Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionChecksum, error) { result, err := c.rawCollection().Checksum(ctx, withRevisions, withData) if err != nil { - return CollectionInfo{}, WithStack(err) + return CollectionChecksum{}, WithStack(err) } return result, nil } diff --git a/vertex_collection_impl.go b/vertex_collection_impl.go index 9f97acf1..4b128f87 100644 --- a/vertex_collection_impl.go +++ b/vertex_collection_impl.go @@ -82,10 +82,10 @@ func (c *vertexCollection) Status(ctx context.Context) (CollectionStatus, error) } // Checksum returns a checksum for the specified collection -func (c *vertexCollection) Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionInfo, error) { +func (c *vertexCollection) Checksum(ctx context.Context, withRevisions bool, withData bool) (CollectionChecksum, error) { result, err := c.rawCollection().Checksum(ctx, withRevisions, withData) if err != nil { - return CollectionInfo{}, WithStack(err) + return CollectionChecksum{}, WithStack(err) } return result, nil }