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..ba097652 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) (CollectionChecksum, error) + // Properties fetches extended information about the collection. Properties(ctx context.Context) (CollectionProperties, error) @@ -79,6 +84,14 @@ type Collection interface { CollectionDocuments } +// 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. @@ -95,6 +108,8 @@ type CollectionInfo struct { IsSystem bool `json:"isSystem,omitempty"` // Global unique name for the collection GloballyUniqueId string `json:"globallyUniqueId,omitempty"` + // The calculated checksum as a number. + Checksum string `json:"checksum,omitempty"` } // CollectionProperties contains extended information about a collection. @@ -154,11 +169,11 @@ 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"` - 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..938fe5ac 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) (CollectionChecksum, error) { + var data CollectionChecksum + + 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..81bc8ed2 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) (CollectionChecksum, error) { + result, err := c.rawCollection().Checksum(ctx, withRevisions, withData) + if err != nil { + return CollectionChecksum{}, 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..4b128f87 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) (CollectionChecksum, error) { + result, err := c.rawCollection().Checksum(ctx, withRevisions, withData) + if err != nil { + return CollectionChecksum{}, 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)