// // DISCLAIMER // // Copyright 2017-2021 ArangoDB GmbH, Cologne, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Copyright holder is ArangoDB GmbH, Cologne, Germany // // Author Ewout Prangsma // Author Tomasz Mielech // package driver import ( "context" "encoding/json" "path" ) // newCollection creates a new Collection implementation. func newCollection(name string, db *database) (Collection, error) { if name == "" { return nil, WithStack(InvalidArgumentError{Message: "name is empty"}) } if db == nil { return nil, WithStack(InvalidArgumentError{Message: "db is nil"}) } return &collection{ name: name, db: db, conn: db.conn, }, nil } type collection struct { name string db *database conn Connection } // relPath creates the relative path to this collection (`_db//_api//`) func (c *collection) relPath(apiName string) string { escapedName := pathEscape(c.name) return path.Join(c.db.relPath(), "_api", apiName, escapedName) } // Name returns the name of the collection. func (c *collection) Name() string { return c.name } // Database returns the database containing the collection. func (c *collection) Database() Database { return c.db } // Status fetches the current status of the collection. func (c *collection) Status(ctx context.Context) (CollectionStatus, error) { req, err := c.conn.NewRequest("GET", c.relPath("collection")) if err != nil { return CollectionStatus(0), WithStack(err) } resp, err := c.conn.Do(ctx, req) if err != nil { return CollectionStatus(0), WithStack(err) } if err := resp.CheckStatus(200); err != nil { return CollectionStatus(0), WithStack(err) } var data CollectionInfo if err := resp.ParseBody("", &data); err != nil { return CollectionStatus(0), WithStack(err) } return data.Status, nil } // Count fetches the number of document in the collection. func (c *collection) Count(ctx context.Context) (int64, error) { req, err := c.conn.NewRequest("GET", path.Join(c.relPath("collection"), "count")) if err != nil { return 0, WithStack(err) } resp, err := c.conn.Do(ctx, req) if err != nil { return 0, WithStack(err) } if err := resp.CheckStatus(200); err != nil { return 0, WithStack(err) } var data struct { Count int64 `json:"count,omitempty"` } if err := resp.ParseBody("", &data); err != nil { return 0, WithStack(err) } return data.Count, nil } // Statistics returns the number of documents and additional statistical information about the collection. func (c *collection) Statistics(ctx context.Context) (CollectionStatistics, error) { req, err := c.conn.NewRequest("GET", path.Join(c.relPath("collection"), "figures")) if err != nil { return CollectionStatistics{}, WithStack(err) } resp, err := c.conn.Do(ctx, req) if err != nil { return CollectionStatistics{}, WithStack(err) } if err := resp.CheckStatus(200); err != nil { return CollectionStatistics{}, WithStack(err) } var data CollectionStatistics if err := resp.ParseBody("", &data); err != nil { return CollectionStatistics{}, WithStack(err) } return data, nil } // Revision fetches the revision ID of the collection. // The revision ID is a server-generated string that clients can use to check whether data // in a collection has changed since the last revision check. func (c *collection) Revision(ctx context.Context) (string, error) { req, err := c.conn.NewRequest("GET", path.Join(c.relPath("collection"), "revision")) if err != nil { return "", WithStack(err) } resp, err := c.conn.Do(ctx, req) if err != nil { return "", WithStack(err) } if err := resp.CheckStatus(200); err != nil { return "", WithStack(err) } var data CollectionProperties if err := resp.ParseBody("", &data); err != nil { return "", WithStack(err) } 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")) if err != nil { return CollectionProperties{}, WithStack(err) } resp, err := c.conn.Do(ctx, req) if err != nil { return CollectionProperties{}, WithStack(err) } if err := resp.CheckStatus(200); err != nil { return CollectionProperties{}, WithStack(err) } var data struct { CollectionProperties ReplicationFactorV2 replicationFactor `json:"replicationFactor,omitempty"` } if err := resp.ParseBody("", &data); err != nil { return CollectionProperties{}, WithStack(err) } data.ReplicationFactor = int(data.ReplicationFactorV2) return data.CollectionProperties, nil } // SetProperties changes properties of the collection. func (c *collection) SetProperties(ctx context.Context, options SetCollectionPropertiesOptions) error { req, err := c.conn.NewRequest("PUT", path.Join(c.relPath("collection"), "properties")) if err != nil { return WithStack(err) } if _, err := req.SetBody(options.asInternal()); err != nil { return WithStack(err) } resp, err := c.conn.Do(ctx, req) if err != nil { return WithStack(err) } if err := resp.CheckStatus(200); err != nil { return WithStack(err) } return nil } // Shards fetches shards information of the collection. func (c *collection) Shards(ctx context.Context, details bool) (CollectionShards, error) { req, err := c.conn.NewRequest("GET", path.Join(c.relPath("collection"), "shards")) if err != nil { return CollectionShards{}, WithStack(err) } if details { req.SetQuery("details", "true") } resp, err := c.conn.Do(ctx, req) if err != nil { return CollectionShards{}, WithStack(err) } if err := resp.CheckStatus(200); err != nil { return CollectionShards{}, WithStack(err) } var data struct { CollectionShards ReplicationFactorV2 replicationFactor `json:"replicationFactor,omitempty"` } if err := resp.ParseBody("", &data); err != nil { return CollectionShards{}, WithStack(err) } data.ReplicationFactor = int(data.ReplicationFactorV2) return data.CollectionShards, nil } // Load the collection into memory. func (c *collection) Load(ctx context.Context) error { req, err := c.conn.NewRequest("PUT", path.Join(c.relPath("collection"), "load")) if err != nil { return WithStack(err) } opts := struct { Count bool `json:"count"` }{ Count: false, } if _, err := req.SetBody(opts); err != nil { return WithStack(err) } resp, err := c.conn.Do(ctx, req) if err != nil { return WithStack(err) } if err := resp.CheckStatus(200); err != nil { return WithStack(err) } return nil } // UnLoad the collection from memory. func (c *collection) Unload(ctx context.Context) error { req, err := c.conn.NewRequest("PUT", path.Join(c.relPath("collection"), "unload")) if err != nil { return WithStack(err) } resp, err := c.conn.Do(ctx, req) if err != nil { return WithStack(err) } if err := resp.CheckStatus(200); err != nil { return WithStack(err) } return nil } // Remove removes the entire collection. // If the collection does not exist, a NotFoundError is returned. func (c *collection) Remove(ctx context.Context) error { req, err := c.conn.NewRequest("DELETE", c.relPath("collection")) if err != nil { return WithStack(err) } applyContextSettings(ctx, req) resp, err := c.conn.Do(ctx, req) if err != nil { return WithStack(err) } if err := resp.CheckStatus(200); err != nil { return WithStack(err) } return nil } // Truncate removes all documents from the collection, but leaves the indexes intact. func (c *collection) Truncate(ctx context.Context) error { req, err := c.conn.NewRequest("PUT", path.Join(c.relPath("collection"), "truncate")) if err != nil { return WithStack(err) } resp, err := c.conn.Do(ctx, req) if err != nil { return WithStack(err) } if err := resp.CheckStatus(200); err != nil { return WithStack(err) } return nil } type setCollectionPropertiesOptionsInternal struct { WaitForSync *bool `json:"waitForSync,omitempty"` JournalSize int64 `json:"journalSize,omitempty"` ReplicationFactor replicationFactor `json:"replicationFactor,omitempty"` CacheEnabled *bool `json:"cacheEnabled,omitempty"` ComputedValues []ComputedValue `json:"computedValues,omitempty"` // Deprecated: use 'WriteConcern' instead MinReplicationFactor int `json:"minReplicationFactor,omitempty"` // Available from 3.6 arangod version. WriteConcern int `json:"writeConcern,omitempty"` Schema *CollectionSchemaOptions `json:"schema,omitempty"` } func (p *SetCollectionPropertiesOptions) asInternal() setCollectionPropertiesOptionsInternal { return setCollectionPropertiesOptionsInternal{ WaitForSync: p.WaitForSync, JournalSize: p.JournalSize, CacheEnabled: p.CacheEnabled, ComputedValues: p.ComputedValues, ReplicationFactor: replicationFactor(p.ReplicationFactor), MinReplicationFactor: p.MinReplicationFactor, WriteConcern: p.WriteConcern, Schema: p.Schema, } } func (p *SetCollectionPropertiesOptions) fromInternal(i *setCollectionPropertiesOptionsInternal) { p.WaitForSync = i.WaitForSync p.JournalSize = i.JournalSize p.CacheEnabled = i.CacheEnabled p.ReplicationFactor = int(i.ReplicationFactor) p.MinReplicationFactor = i.MinReplicationFactor p.WriteConcern = i.WriteConcern p.Schema = i.Schema } // MarshalJSON converts SetCollectionPropertiesOptions into json func (p *SetCollectionPropertiesOptions) MarshalJSON() ([]byte, error) { return json.Marshal(p.asInternal()) } // UnmarshalJSON loads SetCollectionPropertiesOptions from json func (p *SetCollectionPropertiesOptions) UnmarshalJSON(d []byte) error { var internal setCollectionPropertiesOptionsInternal if err := json.Unmarshal(d, &internal); err != nil { return err } p.fromInternal(&internal) return nil }