diff --git a/bench/bench_util.go b/bench/bench_util.go index 54dbae5bb6..b5fa66385c 100644 --- a/bench/bench_util.go +++ b/bench/bench_util.go @@ -25,8 +25,6 @@ import ( "github.com/sourcenetwork/defradb/bench/fixtures" "github.com/sourcenetwork/defradb/client" - "github.com/sourcenetwork/defradb/db" - defradb "github.com/sourcenetwork/defradb/db" testutils "github.com/sourcenetwork/defradb/db/tests" "github.com/sourcenetwork/defradb/document" "github.com/sourcenetwork/defradb/document/key" @@ -66,20 +64,12 @@ func hashToInt64(s string) int64 { return int64(h.Sum64()) } -func SetupCollections(b *testing.B, ctx context.Context, db *defradb.DB, fixture fixtures.Generator) ([]client.Collection, error) { +func SetupCollections(b *testing.B, ctx context.Context, db client.DB, fixture fixtures.Generator) ([]client.Collection, error) { numTypes := len(fixture.Types()) collections := make([]client.Collection, numTypes) - var schema string - - // loop to get the schemas - for i := 0; i < numTypes; i++ { - gql, err := fixtures.ExtractGQLFromType(fixture.Types()[i]) - if err != nil { - return nil, fmt.Errorf("failed generating GQL: %w", err) - } - - schema += gql - schema += "\n\n" + schema, err := ConstructSchema(fixture) + if err != nil { + return nil, err } // b.Logf("Loading schema: \n%s", schema) @@ -101,7 +91,25 @@ func SetupCollections(b *testing.B, ctx context.Context, db *defradb.DB, fixture return collections, nil } -func SetupDBAndCollections(b *testing.B, ctx context.Context, fixture fixtures.Generator) (*defradb.DB, []client.Collection, error) { +func ConstructSchema(fixture fixtures.Generator) (string, error) { + numTypes := len(fixture.Types()) + var schema string + + // loop to get the schemas + for i := 0; i < numTypes; i++ { + gql, err := fixtures.ExtractGQLFromType(fixture.Types()[i]) + if err != nil { + return "", fmt.Errorf("failed generating GQL: %w", err) + } + + schema += gql + schema += "\n\n" + } + + return schema, nil +} + +func SetupDBAndCollections(b *testing.B, ctx context.Context, fixture fixtures.Generator) (client.DB, []client.Collection, error) { db, err := NewTestDB(ctx, b) if err != nil { return nil, nil, err @@ -202,10 +210,10 @@ func BackfillBenchmarkDB(b *testing.B, ctx context.Context, cols []client.Collec type dbInfo interface { Rootstore() ds.Batching - DB() *db.DB + DB() client.DB } -func NewTestDB(ctx context.Context, t testing.TB) (*db.DB, error) { +func NewTestDB(ctx context.Context, t testing.TB) (client.DB, error) { //nolint dbi, err := newBenchStoreInfo(ctx, t) return dbi.DB(), err diff --git a/bench/query/planner/utils.go b/bench/query/planner/utils.go index d3177f7d8d..a9ff1ced47 100644 --- a/bench/query/planner/utils.go +++ b/bench/query/planner/utils.go @@ -17,18 +17,19 @@ import ( benchutils "github.com/sourcenetwork/defradb/bench" "github.com/sourcenetwork/defradb/bench/fixtures" + "github.com/sourcenetwork/defradb/query/graphql/planner" + "github.com/sourcenetwork/defradb/query/graphql/schema" ) func runQueryParserBench(b *testing.B, ctx context.Context, fixture fixtures.Generator, query string) error { - db, _, err := benchutils.SetupDBAndCollections(b, ctx, fixture) + exec, err := buildExecutor(ctx, fixture) if err != nil { return err } - defer db.Close(ctx) b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := db.Executor().ParseQueryString(query) + _, err := exec.ParseQueryString(query) if err != nil { return fmt.Errorf("Failed to parse query string: %w", err) } @@ -45,9 +46,9 @@ func runMakePlanBench(b *testing.B, ctx context.Context, fixture fixtures.Genera } defer db.Close(ctx) - exec := db.Executor() - if exec == nil { - return fmt.Errorf("Executor can't be nil") + exec, err := buildExecutor(ctx, fixture) + if err != nil { + return err } q, err := exec.ParseQueryString(query) @@ -69,3 +70,24 @@ func runMakePlanBench(b *testing.B, ctx context.Context, fixture fixtures.Genera b.StopTimer() return nil } + +func buildExecutor(ctx context.Context, fixture fixtures.Generator) (*planner.QueryExecutor, error) { + sm, err := schema.NewSchemaManager() + if err != nil { + return nil, err + } + schema, err := benchutils.ConstructSchema(fixture) + if err != nil { + return nil, err + } + types, _, err := sm.Generator.FromSDL(ctx, schema) + if err != nil { + return nil, err + } + _, err = sm.Generator.CreateDescriptions(types) + if err != nil { + return nil, err + } + + return planner.NewQueryExecutor(sm) +} diff --git a/bench/query/simple/utils.go b/bench/query/simple/utils.go index c83a4e8f06..feb494c1bf 100644 --- a/bench/query/simple/utils.go +++ b/bench/query/simple/utils.go @@ -19,7 +19,7 @@ import ( benchutils "github.com/sourcenetwork/defradb/bench" "github.com/sourcenetwork/defradb/bench/fixtures" - "github.com/sourcenetwork/defradb/db" + "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/document/key" ) @@ -45,7 +45,7 @@ func runQueryBenchGet(b *testing.B, ctx context.Context, fixture fixtures.Genera func runQueryBenchGetSync( b *testing.B, ctx context.Context, - db *db.DB, + db client.DB, docCount int, dockeys [][]key.DocKey, query string, diff --git a/bench/storage/utils.go b/bench/storage/utils.go index 6cf201e073..7ce8962fe6 100644 --- a/bench/storage/utils.go +++ b/bench/storage/utils.go @@ -20,7 +20,7 @@ import ( "github.com/ipfs/go-datastore/query" benchutils "github.com/sourcenetwork/defradb/bench" - "github.com/sourcenetwork/defradb/db" + "github.com/sourcenetwork/defradb/client" ) func runStorageBenchGet(b *testing.B, ctx context.Context, valueSize, objCount, opCount int, doSync bool) error { @@ -254,7 +254,7 @@ func backfillBenchmarkStorageDB(ctx context.Context, db ds.Batching, objCount in return keys, batch.Commit(ctx) } -func backfillBenchmarkTxn(ctx context.Context, db *db.DB, objCount int, valueSize int) ([]string, error) { +func backfillBenchmarkTxn(ctx context.Context, db client.DB, objCount int, valueSize int) ([]string, error) { txn, err := db.NewTxn(ctx, false) if err != nil { return nil, err diff --git a/cli/defradb/cmd/start.go b/cli/defradb/cmd/start.go index 878e267745..b4a2d51540 100644 --- a/cli/defradb/cmd/start.go +++ b/cli/defradb/cmd/start.go @@ -13,6 +13,7 @@ package cmd import ( "context" "errors" + "fmt" gonet "net" "os" "os/signal" @@ -31,6 +32,7 @@ import ( badger "github.com/dgraph-io/badger/v3" ds "github.com/ipfs/go-datastore" + api "github.com/sourcenetwork/defradb/api/http" "github.com/sourcenetwork/defradb/logging" "github.com/spf13/cobra" "github.com/textileio/go-threads/broadcast" @@ -155,7 +157,8 @@ var startCmd = &cobra.Command{ // run the server listener in a separate goroutine go func() { - if err := db.Listen(ctx, config.Database.Address); err != nil { + s := api.NewServer(db) + if err := s.Listen(config.Database.Address); err != nil { log.ErrorE(ctx, "Failed to start API listener", err) if n != nil { n.Close() //nolint @@ -163,6 +166,7 @@ var startCmd = &cobra.Command{ db.Close(ctx) os.Exit(1) } + log.Info(ctx, fmt.Sprintf("Running HTTP API at http://%s. Try it out at > curl http://%s/graphql", config.Database.Address, config.Database.Address)) }() // wait for shutdown signal diff --git a/client/core.go b/client/core.go index a68d55e63d..f063579e4d 100644 --- a/client/core.go +++ b/client/core.go @@ -36,6 +36,8 @@ type DB interface { NewTxn(context.Context, bool) (datastore.Txn, error) ExecQuery(context.Context, string) *QueryResult + ExecTransactionalQuery(ctx context.Context, query string, txn datastore.Txn) *QueryResult + Close(context.Context) PrintDump(ctx context.Context) } diff --git a/db/api.go b/db/api.go deleted file mode 100644 index abf096aa75..0000000000 --- a/db/api.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2022 Democratized Data Foundation -// -// Use of this software is governed by the Business Source License -// included in the file licenses/BSL.txt. -// -// As of the Change Date specified in that file, in accordance with -// the Business Source License, use of this software will be governed -// by the Apache License, Version 2.0, included in the file -// licenses/APL.txt. - -package db - -import ( - "context" - "fmt" - - api "github.com/sourcenetwork/defradb/api/http" -) - -func (db *DB) Listen(ctx context.Context, address string) error { - log.Info(ctx, fmt.Sprintf("Running HTTP API at http://%s. Try it out at > curl http://%s/graphql", address, address)) - - s := api.NewServer(db) - return s.Listen(address) -} - -// func (db *DB) handlePing(w http.ResponseWriter, r *http.Request) { -// w.Write([]byte("pong")) -// } - -// func (db *DB) handleGraphqlReq(w http.ResponseWriter, r *http.Request) { -// query := r.URL.Query().Get("query") -// result := db.ExecQuery(query) -// json.NewEncoder(w).Encode(result) -// } diff --git a/db/collection.go b/db/collection.go index 13000ddd30..6ae04201de 100644 --- a/db/collection.go +++ b/db/collection.go @@ -41,12 +41,12 @@ var ( ErrUnknownCRDT = errors.New("") ) -var _ client.Collection = (*Collection)(nil) +var _ client.Collection = (*collection)(nil) -// Collection stores data records at Documents, which are gathered +// collection stores data records at Documents, which are gathered // together under a collection name. This is analogous to SQL Tables. -type Collection struct { - db *DB +type collection struct { + db *db txn datastore.Txn colID uint32 @@ -63,7 +63,7 @@ type Collection struct { // CollectionOptions object. // NewCollection returns a pointer to a newly instanciated DB Collection -func (db *DB) newCollection(desc base.CollectionDescription) (*Collection, error) { +func (db *db) newCollection(desc base.CollectionDescription) (*collection, error) { if desc.Name == "" { return nil, errors.New("Collection requires name to not be empty") } @@ -103,7 +103,7 @@ func (db *DB) newCollection(desc base.CollectionDescription) (*Collection, error }, } - return &Collection{ + return &collection{ db: db, desc: desc, colID: desc.ID, @@ -112,7 +112,7 @@ func (db *DB) newCollection(desc base.CollectionDescription) (*Collection, error // CreateCollection creates a collection and saves it to the database in its system store. // Note: Collection.ID is an autoincrementing value that is generated by the database. -func (db *DB) CreateCollection(ctx context.Context, desc base.CollectionDescription) (client.Collection, error) { +func (db *db) CreateCollection(ctx context.Context, desc base.CollectionDescription) (client.Collection, error) { // check if collection by this name exists cKey := core.NewCollectionKey(desc.Name) exists, err := db.systemstore().Has(ctx, cKey.ToDS()) @@ -172,7 +172,7 @@ func (db *DB) CreateCollection(ctx context.Context, desc base.CollectionDescript } // GetCollection returns an existing collection within the database -func (db *DB) GetCollectionByName(ctx context.Context, name string) (client.Collection, error) { +func (db *db) GetCollectionByName(ctx context.Context, name string) (client.Collection, error) { if name == "" { return nil, errors.New("Collection name can't be empty") } @@ -206,7 +206,7 @@ func (db *DB) GetCollectionByName(ctx context.Context, name string) (client.Coll sid := cid.String() log.Debug(ctx, "Retrieved collection", logging.NewKV("Name", desc.Name), logging.NewKV("Id", sid)) - return &Collection{ + return &collection{ db: db, desc: desc, colID: desc.ID, @@ -216,7 +216,7 @@ func (db *DB) GetCollectionByName(ctx context.Context, name string) (client.Coll // GetCollectionBySchemaID returns an existing collection within the database using the // schema hash ID -func (db *DB) GetCollectionBySchemaID(ctx context.Context, schemaID string) (client.Collection, error) { +func (db *db) GetCollectionBySchemaID(ctx context.Context, schemaID string) (client.Collection, error) { if schemaID == "" { return nil, fmt.Errorf("Schema ID can't be empty") } @@ -233,7 +233,7 @@ func (db *DB) GetCollectionBySchemaID(ctx context.Context, schemaID string) (cli // GetAllCollections gets all the currently defined collections in the // database -func (db *DB) GetAllCollections(ctx context.Context) ([]client.Collection, error) { +func (db *db) GetAllCollections(ctx context.Context) ([]client.Collection, error) { // create collection system prefix query prefix := core.NewCollectionKey("") q, err := db.systemstore().Query(ctx, query.Query{ @@ -269,7 +269,7 @@ func (db *DB) GetAllCollections(ctx context.Context) ([]client.Collection, error // GetAllDocKeys returns all the document keys that exist in the collection // @todo: We probably need a lock on the collection for this kind of op since // it hits every key and will cause Tx conflicts for concurrent Txs -func (c *Collection) GetAllDocKeys(ctx context.Context) (<-chan client.DocKeysResult, error) { +func (c *collection) GetAllDocKeys(ctx context.Context) (<-chan client.DocKeysResult, error) { txn, err := c.getTxn(ctx, true) if err != nil { return nil, err @@ -279,7 +279,7 @@ func (c *Collection) GetAllDocKeys(ctx context.Context) (<-chan client.DocKeysRe return c.getAllDocKeysChan(ctx, txn) } -func (c *Collection) getAllDocKeysChan(ctx context.Context, txn datastore.Txn) (<-chan client.DocKeysResult, error) { +func (c *collection) getAllDocKeysChan(ctx context.Context, txn datastore.Txn) (<-chan client.DocKeysResult, error) { prefix := c.getPrimaryIndexDocKey(core.DataStoreKey{}) // empty path for all keys prefix q, err := txn.Datastore().Query(ctx, query.Query{ Prefix: prefix.ToString(), @@ -345,38 +345,38 @@ func (c *Collection) getAllDocKeysChan(ctx context.Context, txn datastore.Txn) ( } // Description returns the base.CollectionDescription -func (c *Collection) Description() base.CollectionDescription { +func (c *collection) Description() base.CollectionDescription { return c.desc } // Name returns the collection name -func (c *Collection) Name() string { +func (c *collection) Name() string { return c.desc.Name } // Schema returns the Schema of the collection -func (c *Collection) Schema() base.SchemaDescription { +func (c *collection) Schema() base.SchemaDescription { return c.desc.Schema } // ID returns the ID of the collection -func (c *Collection) ID() uint32 { +func (c *collection) ID() uint32 { return c.colID } // Indexes returns the defined indexes on the Collection // @todo: Properly handle index creation/management -func (c *Collection) Indexes() []base.IndexDescription { +func (c *collection) Indexes() []base.IndexDescription { return c.desc.Indexes } // PrimaryIndex returns the primary index for the given collection -func (c *Collection) PrimaryIndex() base.IndexDescription { +func (c *collection) PrimaryIndex() base.IndexDescription { return c.desc.Indexes[0] } // Index returns the index with the given index ID -func (c *Collection) Index(id uint32) (base.IndexDescription, error) { +func (c *collection) Index(id uint32) (base.IndexDescription, error) { for _, index := range c.desc.Indexes { if index.ID == id { return index, nil @@ -389,18 +389,18 @@ func (c *Collection) Index(id uint32) (base.IndexDescription, error) { // CreateIndex creates a new index on the collection. Custom indexes // are always "Secondary indexes". Primary indexes are automatically created // on Collection creation, and cannot be changed. -func (c *Collection) CreateIndex(idesc base.IndexDescription) error { +func (c *collection) CreateIndex(idesc base.IndexDescription) error { panic("not implemented") } -func (c *Collection) SchemaID() string { +func (c *collection) SchemaID() string { return c.schemaID } // WithTxn returns a new instance of the collection, with a transaction // handle instead of a raw DB handle -func (c *Collection) WithTxn(txn datastore.Txn) client.Collection { - return &Collection{ +func (c *collection) WithTxn(txn datastore.Txn) client.Collection { + return &collection{ db: c.db, txn: txn, desc: c.desc, @@ -411,7 +411,7 @@ func (c *Collection) WithTxn(txn datastore.Txn) client.Collection { // Create a new document // Will verify the DocKey/CID to ensure that the new document is correctly formatted. -func (c *Collection) Create(ctx context.Context, doc *document.Document) error { +func (c *collection) Create(ctx context.Context, doc *document.Document) error { txn, err := c.getTxn(ctx, false) if err != nil { return err @@ -427,7 +427,7 @@ func (c *Collection) Create(ctx context.Context, doc *document.Document) error { // CreateMany creates a collection of documents at once. // Will verify the DocKey/CID to ensure that the new documents are correctly formatted. -func (c *Collection) CreateMany(ctx context.Context, docs []*document.Document) error { +func (c *collection) CreateMany(ctx context.Context, docs []*document.Document) error { txn, err := c.getTxn(ctx, false) if err != nil { return err @@ -443,7 +443,7 @@ func (c *Collection) CreateMany(ctx context.Context, docs []*document.Document) return c.commitImplicitTxn(ctx, txn) } -func (c *Collection) create(ctx context.Context, txn datastore.Txn, doc *document.Document) error { +func (c *collection) create(ctx context.Context, txn datastore.Txn, doc *document.Document) error { // DocKey verification buf, err := doc.Bytes() if err != nil { @@ -491,7 +491,7 @@ func (c *Collection) create(ctx context.Context, txn datastore.Txn, doc *documen // Any field that needs to be removed or cleared // should call doc.Clear(field) before. Any field that // is nil/empty that hasn't called Clear will be ignored -func (c *Collection) Update(ctx context.Context, doc *document.Document) error { +func (c *collection) Update(ctx context.Context, doc *document.Document) error { txn, err := c.getTxn(ctx, false) if err != nil { return err @@ -520,7 +520,7 @@ func (c *Collection) Update(ctx context.Context, doc *document.Document) error { // or, just update everything regardless. // Should probably be smart about the update due to the MerkleCRDT overhead, shouldn't // add to the bloat. -func (c *Collection) update(ctx context.Context, txn datastore.Txn, doc *document.Document) error { +func (c *collection) update(ctx context.Context, txn datastore.Txn, doc *document.Document) error { _, err := c.save(ctx, txn, doc) if err != nil { return err @@ -530,7 +530,7 @@ func (c *Collection) update(ctx context.Context, txn datastore.Txn, doc *documen // Save a document into the db // Either by creating a new document or by updating an existing one -func (c *Collection) Save(ctx context.Context, doc *document.Document) error { +func (c *collection) Save(ctx context.Context, doc *document.Document) error { txn, err := c.getTxn(ctx, false) if err != nil { return err @@ -555,7 +555,7 @@ func (c *Collection) Save(ctx context.Context, doc *document.Document) error { return c.commitImplicitTxn(ctx, txn) } -func (c *Collection) save(ctx context.Context, txn datastore.Txn, doc *document.Document) (cid.Cid, error) { +func (c *collection) save(ctx context.Context, txn datastore.Txn, doc *document.Document) (cid.Cid, error) { // New batch transaction/store (optional/todo) // Ensute/Set doc object marker // Loop through doc values @@ -623,7 +623,7 @@ func (c *Collection) save(ctx context.Context, txn datastore.Txn, doc *document. // false, and a ErrDocumentNotFound error. // This operation will all state relating to the given // DocKey. This includes data, block, and head storage. -func (c *Collection) Delete(ctx context.Context, key key.DocKey) (bool, error) { +func (c *collection) Delete(ctx context.Context, key key.DocKey) (bool, error) { txn, err := c.getTxn(ctx, false) if err != nil { return false, err @@ -649,7 +649,7 @@ func (c *Collection) Delete(ctx context.Context, key key.DocKey) (bool, error) { // at the moment, delete only does data storage delete. // Dag, and head store will soon follow. -func (c *Collection) delete(ctx context.Context, txn datastore.Txn, key core.DataStoreKey) (bool, error) { +func (c *collection) delete(ctx context.Context, txn datastore.Txn, key core.DataStoreKey) (bool, error) { q := query.Query{ Prefix: c.getPrimaryIndexDocKey(key).ToString(), KeysOnly: true, @@ -671,7 +671,7 @@ func (c *Collection) delete(ctx context.Context, txn datastore.Txn, key core.Dat } // Exists checks if a given document exists with supplied DocKey -func (c *Collection) Exists(ctx context.Context, key key.DocKey) (bool, error) { +func (c *collection) Exists(ctx context.Context, key key.DocKey) (bool, error) { txn, err := c.getTxn(ctx, false) if err != nil { return false, err @@ -687,11 +687,11 @@ func (c *Collection) Exists(ctx context.Context, key key.DocKey) (bool, error) { } // check if a document exists with the given key -func (c *Collection) exists(ctx context.Context, txn datastore.Txn, key core.DataStoreKey) (bool, error) { +func (c *collection) exists(ctx context.Context, txn datastore.Txn, key core.DataStoreKey) (bool, error) { return txn.Datastore().Has(ctx, c.getPrimaryIndexDocKey(key.WithValueFlag()).ToDS()) } -func (c *Collection) saveDocValue(ctx context.Context, txn datastore.Txn, key core.DataStoreKey, val document.Value) (cid.Cid, error) { +func (c *collection) saveDocValue(ctx context.Context, txn datastore.Txn, key core.DataStoreKey, val document.Value) (cid.Cid, error) { switch val.Type() { case core.LWW_REGISTER: wval, ok := val.(document.WriteableValue) @@ -714,7 +714,7 @@ func (c *Collection) saveDocValue(ctx context.Context, txn datastore.Txn, key co } } -func (c *Collection) saveValueToMerkleCRDT( +func (c *collection) saveValueToMerkleCRDT( ctx context.Context, txn datastore.Txn, key core.DataStoreKey, @@ -769,7 +769,7 @@ func (c *Collection) saveValueToMerkleCRDT( // getTxn gets or creates a new transaction from the underlying db. // If the collection already has a txn, return the existing one. // Otherwise, create a new implicit transaction. -func (c *Collection) getTxn(ctx context.Context, readonly bool) (datastore.Txn, error) { +func (c *collection) getTxn(ctx context.Context, readonly bool) (datastore.Txn, error) { if c.txn != nil { return c.txn, nil } @@ -780,34 +780,34 @@ func (c *Collection) getTxn(ctx context.Context, readonly bool) (datastore.Txn, // function only if its an implicit transaction. // Implicit transactions are transactions that are created *during* an operation execution as a side effect. // Explicit transactions are provided to the collection object via the "WithTxn(...)" function. -func (c *Collection) discardImplicitTxn(ctx context.Context, txn datastore.Txn) { +func (c *collection) discardImplicitTxn(ctx context.Context, txn datastore.Txn) { if c.txn == nil { txn.Discard(ctx) } } -func (c *Collection) commitImplicitTxn(ctx context.Context, txn datastore.Txn) error { +func (c *collection) commitImplicitTxn(ctx context.Context, txn datastore.Txn) error { if c.txn == nil { return txn.Commit(ctx) } return nil } -func (c *Collection) getPrimaryIndexDocKey(key core.DataStoreKey) core.DataStoreKey { +func (c *collection) getPrimaryIndexDocKey(key core.DataStoreKey) core.DataStoreKey { return core.DataStoreKey{ CollectionId: fmt.Sprint(c.colID), IndexId: fmt.Sprint(c.PrimaryIndex().ID), }.WithInstanceInfo(key) } -func (c *Collection) getFieldKey(key core.DataStoreKey, fieldName string) core.DataStoreKey { +func (c *collection) getFieldKey(key core.DataStoreKey, fieldName string) core.DataStoreKey { return key.WithFieldId(fmt.Sprint(c.getSchemaFieldID(fieldName))) } // getSchemaFieldID returns the FieldID of the given fieldName. // It assumes a schema exists for the collection, and that the // field exists in the schema. -func (c *Collection) getSchemaFieldID(fieldName string) uint32 { +func (c *collection) getSchemaFieldID(fieldName string) uint32 { for _, field := range c.desc.Schema.Fields { if field.Name == fieldName { return uint32(field.ID) diff --git a/db/collection_delete.go b/db/collection_delete.go index 3367112d42..579dd46f84 100644 --- a/db/collection_delete.go +++ b/db/collection_delete.go @@ -41,7 +41,7 @@ var ( // a single docKey, a single document, an array of docKeys, or an array of documents. // If you want more type safety, use the respective typed versions of Delete. // Eg: DeleteWithFilter or DeleteWithKey -func (c *Collection) DeleteWith( +func (c *collection) DeleteWith( ctx context.Context, target interface{}, opts ...client.DeleteOpt) error { @@ -73,7 +73,7 @@ func (c *Collection) DeleteWith( } // DeleteWithKey deletes using a DocKey to target a single document for delete. -func (c *Collection) DeleteWithKey( +func (c *collection) DeleteWithKey( ctx context.Context, key key.DocKey, opts ...client.DeleteOpt) (*client.DeleteResult, error) { @@ -95,7 +95,7 @@ func (c *Collection) DeleteWithKey( } // DeleteWithKeys is the same as DeleteWithKey but accepts multiple keys as a slice. -func (c *Collection) DeleteWithKeys( +func (c *collection) DeleteWithKeys( ctx context.Context, keys []key.DocKey, opts ...client.DeleteOpt) (*client.DeleteResult, error) { @@ -116,7 +116,7 @@ func (c *Collection) DeleteWithKeys( } // DeleteWithFilter deletes using a filter to target documents for delete. -func (c *Collection) DeleteWithFilter( +func (c *collection) DeleteWithFilter( ctx context.Context, filter interface{}, opts ...client.DeleteOpt) (*client.DeleteResult, error) { @@ -137,7 +137,7 @@ func (c *Collection) DeleteWithFilter( } -func (c *Collection) deleteWithKey( +func (c *collection) deleteWithKey( ctx context.Context, txn datastore.Txn, key core.DataStoreKey, @@ -167,7 +167,7 @@ func (c *Collection) deleteWithKey( return results, nil } -func (c *Collection) deleteWithKeys( +func (c *collection) deleteWithKeys( ctx context.Context, txn datastore.Txn, keys []key.DocKey, @@ -206,7 +206,7 @@ func (c *Collection) deleteWithKeys( return results, nil } -func (c *Collection) deleteWithFilter( +func (c *collection) deleteWithFilter( ctx context.Context, txn datastore.Txn, filter interface{}, @@ -285,7 +285,7 @@ func newDagDeleter(bstore datastore.DAGStore) dagDeleter { // 1) Deleting the actual blocks (blockstore). // 2) Deleting datastore state. // 3) Deleting headstore state. -func (c *Collection) applyFullDelete( +func (c *collection) applyFullDelete( ctx context.Context, txn datastore.Txn, dockey core.DataStoreKey) error { @@ -426,14 +426,14 @@ func (d dagDeleter) delete( // =================================== UNIMPLEMENTED =================================== // DeleteWithDoc deletes targeting the supplied document. -func (c *Collection) DeleteWithDoc( +func (c *collection) DeleteWithDoc( doc *document.SimpleDocument, opts ...client.DeleteOpt) error { return nil } // DeleteWithDocs deletes all the supplied documents in the slice. -func (c *Collection) DeleteWithDocs( +func (c *collection) DeleteWithDocs( docs []*document.SimpleDocument, opts ...client.DeleteOpt) error { return nil diff --git a/db/collection_get.go b/db/collection_get.go index ec83c77f59..730c9d328c 100644 --- a/db/collection_get.go +++ b/db/collection_get.go @@ -21,7 +21,7 @@ import ( "github.com/sourcenetwork/defradb/document/key" ) -func (c *Collection) Get(ctx context.Context, key key.DocKey) (*document.Document, error) { +func (c *collection) Get(ctx context.Context, key key.DocKey) (*document.Document, error) { // create txn txn, err := c.getTxn(ctx, true) if err != nil { @@ -45,7 +45,7 @@ func (c *Collection) Get(ctx context.Context, key key.DocKey) (*document.Documen return doc, c.commitImplicitTxn(ctx, txn) } -func (c *Collection) get(ctx context.Context, txn datastore.Txn, key core.DataStoreKey) (*document.Document, error) { +func (c *collection) get(ctx context.Context, txn datastore.Txn, key core.DataStoreKey) (*document.Document, error) { // create a new document fetcher df := new(fetcher.DocumentFetcher) desc := &c.desc diff --git a/db/collection_test.go b/db/collection_test.go index eb8f8f69b8..6f2eb1aec9 100644 --- a/db/collection_test.go +++ b/db/collection_test.go @@ -21,7 +21,7 @@ import ( "github.com/stretchr/testify/assert" ) -func newTestCollectionWithSchema(ctx context.Context, db *DB) (client.Collection, error) { +func newTestCollectionWithSchema(ctx context.Context, db client.DB) (client.Collection, error) { desc := base.CollectionDescription{ Name: "users", Schema: base.SchemaDescription{ @@ -53,7 +53,7 @@ func newTestCollectionWithSchema(ctx context.Context, db *DB) (client.Collection return col, err } -func createNewTestCollection(ctx context.Context, db *DB) (client.Collection, error) { +func createNewTestCollection(ctx context.Context, db client.DB) (client.Collection, error) { return db.CreateCollection(ctx, base.CollectionDescription{ Name: "test", }) diff --git a/db/collection_update.go b/db/collection_update.go index 4dbafbdb5f..6d5ac17231 100644 --- a/db/collection_update.go +++ b/db/collection_update.go @@ -30,9 +30,6 @@ import ( cbor "github.com/fxamacker/cbor/v2" ) -type UpdateOpt struct{} -type CreateOpt struct{} - var ( ErrInvalidUpdateTarget = errors.New("The doc update targeter is an unknown type") ErrUpdateTargetEmpty = errors.New("The doc update targeter cannot be empty") @@ -46,7 +43,7 @@ var ( // an array of docKeys, or an array of documents. // If you want more type safety, use the respective typed versions of Update. // Eg: UpdateWithFilter or UpdateWithKey -func (c *Collection) UpdateWith(ctx context.Context, target interface{}, updater interface{}, opts ...client.UpdateOpt) error { +func (c *collection) UpdateWith(ctx context.Context, target interface{}, updater interface{}, opts ...client.UpdateOpt) error { switch t := target.(type) { case string, map[string]interface{}, *parser.Filter: _, err := c.UpdateWithFilter(ctx, t, updater, opts...) @@ -69,7 +66,7 @@ func (c *Collection) UpdateWith(ctx context.Context, target interface{}, updater // UpdateWithFilter updates using a filter to target documents for update. // An updater value is provided, which could be a string Patch, string Merge Patch // or a parsed Patch, or parsed Merge Patch. -func (c *Collection) UpdateWithFilter(ctx context.Context, filter interface{}, updater interface{}, opts ...client.UpdateOpt) (*client.UpdateResult, error) { +func (c *collection) UpdateWithFilter(ctx context.Context, filter interface{}, updater interface{}, opts ...client.UpdateOpt) (*client.UpdateResult, error) { txn, err := c.getTxn(ctx, false) if err != nil { return nil, err @@ -85,7 +82,7 @@ func (c *Collection) UpdateWithFilter(ctx context.Context, filter interface{}, u // UpdateWithKey updates using a DocKey to target a single document for update. // An updater value is provided, which could be a string Patch, string Merge Patch // or a parsed Patch, or parsed Merge Patch. -func (c *Collection) UpdateWithKey(ctx context.Context, key key.DocKey, updater interface{}, opts ...client.UpdateOpt) (*client.UpdateResult, error) { +func (c *collection) UpdateWithKey(ctx context.Context, key key.DocKey, updater interface{}, opts ...client.UpdateOpt) (*client.UpdateResult, error) { txn, err := c.getTxn(ctx, false) if err != nil { return nil, err @@ -102,7 +99,7 @@ func (c *Collection) UpdateWithKey(ctx context.Context, key key.DocKey, updater // UpdateWithKeys is the same as UpdateWithKey but accepts multiple keys as a slice. // An updater value is provided, which could be a string Patch, string Merge Patch // or a parsed Patch, or parsed Merge Patch. -func (c *Collection) UpdateWithKeys(ctx context.Context, keys []key.DocKey, updater interface{}, opts ...client.UpdateOpt) (*client.UpdateResult, error) { +func (c *collection) UpdateWithKeys(ctx context.Context, keys []key.DocKey, updater interface{}, opts ...client.UpdateOpt) (*client.UpdateResult, error) { txn, err := c.getTxn(ctx, false) if err != nil { return nil, err @@ -119,18 +116,18 @@ func (c *Collection) UpdateWithKeys(ctx context.Context, keys []key.DocKey, upda // UpdateWithDoc updates targeting the supplied document. // An updater value is provided, which could be a string Patch, string Merge Patch // or a parsed Patch, or parsed Merge Patch. -func (c *Collection) UpdateWithDoc(doc *document.SimpleDocument, updater interface{}, opts ...client.UpdateOpt) error { +func (c *collection) UpdateWithDoc(doc *document.SimpleDocument, updater interface{}, opts ...client.UpdateOpt) error { return nil } // UpdateWithDocs updates all the supplied documents in the slice. // An updater value is provided, which could be a string Patch, string Merge Patch // or a parsed Patch, or parsed Merge Patch. -func (c *Collection) UpdateWithDocs(docs []*document.SimpleDocument, updater interface{}, opts ...client.UpdateOpt) error { +func (c *collection) UpdateWithDocs(docs []*document.SimpleDocument, updater interface{}, opts ...client.UpdateOpt) error { return nil } -func (c *Collection) updateWithKey(ctx context.Context, txn datastore.Txn, key key.DocKey, updater interface{}, opts ...client.UpdateOpt) (*client.UpdateResult, error) { +func (c *collection) updateWithKey(ctx context.Context, txn datastore.Txn, key key.DocKey, updater interface{}, opts ...client.UpdateOpt) (*client.UpdateResult, error) { patch, err := parseUpdater(updater) if err != nil { return nil, err @@ -171,7 +168,7 @@ func (c *Collection) updateWithKey(ctx context.Context, txn datastore.Txn, key k return results, nil } -func (c *Collection) updateWithKeys(ctx context.Context, txn datastore.Txn, keys []key.DocKey, updater interface{}, opts ...client.UpdateOpt) (*client.UpdateResult, error) { +func (c *collection) updateWithKeys(ctx context.Context, txn datastore.Txn, keys []key.DocKey, updater interface{}, opts ...client.UpdateOpt) (*client.UpdateResult, error) { patch, err := parseUpdater(updater) if err != nil { return nil, err @@ -215,7 +212,7 @@ func (c *Collection) updateWithKeys(ctx context.Context, txn datastore.Txn, keys return results, nil } -func (c *Collection) updateWithFilter( +func (c *collection) updateWithFilter( ctx context.Context, txn datastore.Txn, filter interface{}, @@ -288,7 +285,7 @@ func (c *Collection) updateWithFilter( return results, nil } -func (c *Collection) applyPatch(txn datastore.Txn, doc map[string]interface{}, patch []map[string]interface{}) error { +func (c *collection) applyPatch(txn datastore.Txn, doc map[string]interface{}, patch []map[string]interface{}) error { for _, op := range patch { path, ok := op["path"].(string) if !ok { @@ -314,11 +311,11 @@ func (c *Collection) applyPatch(txn datastore.Txn, doc map[string]interface{}, p return nil } -func (c *Collection) applyPatchOp(txn datastore.Txn, dockey string, field string, currentVal interface{}, patchOp map[string]interface{}) error { +func (c *collection) applyPatchOp(txn datastore.Txn, dockey string, field string, currentVal interface{}, patchOp map[string]interface{}) error { return nil } -func (c *Collection) applyMerge(ctx context.Context, txn datastore.Txn, doc map[string]interface{}, merge map[string]interface{}) error { +func (c *collection) applyMerge(ctx context.Context, txn datastore.Txn, doc map[string]interface{}, merge map[string]interface{}) error { keyStr, ok := doc["_key"].(string) if !ok { return errors.New("Document is missing key") @@ -507,7 +504,7 @@ func validateFieldSchema(val interface{}, field base.FieldDescription) (interfac return cval, err } -func (c *Collection) applyMergePatchOp( //nolint:unused +func (c *collection) applyMergePatchOp( //nolint:unused txn datastore.Txn, docKey string, field string, @@ -520,7 +517,7 @@ func (c *Collection) applyMergePatchOp( //nolint:unused // currently it doesn't support any other query operation other than filters. // (IE: No limit, order, etc) // Additionally it only queries for the root scalar fields of the object -func (c *Collection) makeSelectionQuery( +func (c *collection) makeSelectionQuery( ctx context.Context, txn datastore.Txn, filter interface{}, @@ -552,7 +549,7 @@ func (c *Collection) makeSelectionQuery( return c.db.queryExecutor.MakeSelectQuery(ctx, c.db, txn, slct) } -func (c *Collection) makeSelectLocal(filter *parser.Filter) (*parser.Select, error) { +func (c *collection) makeSelectLocal(filter *parser.Filter) (*parser.Select, error) { slct := &parser.Select{ Name: c.Name(), Filter: filter, @@ -577,13 +574,13 @@ func (c *Collection) makeSelectLocal(filter *parser.Filter) (*parser.Select, err // May need to query the database for other schema types // which requires a db transaction. It is recommended // to use collection.WithTxn(txn) for this function call. -func (c *Collection) getCollectionForPatchOpPath(txn datastore.Txn, path string) (col *Collection, isArray bool, err error) { +func (c *collection) getCollectionForPatchOpPath(txn datastore.Txn, path string) (col *collection, isArray bool, err error) { return nil, false, nil } // getTargetKeyForPatchPath walks through the given doc and Patch path. // It returns the -func (c *Collection) getTargetKeyForPatchPath(txn datastore.Txn, doc map[string]interface{}, path string) (string, error) { +func (c *collection) getTargetKeyForPatchPath(txn datastore.Txn, doc map[string]interface{}, path string) (string, error) { _, length := splitPatchPath(path) if length == 0 { return "", errors.New("Invalid patch op path") @@ -622,11 +619,6 @@ func getMapProp(doc map[string]interface{}, paths []string, length int) (string, return paths[0], val, true } -type UpdateResult struct { - Count int64 - DocKeys []string -} - type patcher interface{} func parseUpdater(updater interface{}) (patcher, error) { diff --git a/db/db.go b/db/db.go index 7b47851dba..d5f43fce48 100644 --- a/db/db.go +++ b/db/db.go @@ -42,13 +42,13 @@ var ( // make sure we match our client interface var ( - _ client.DB = (*DB)(nil) - _ client.Collection = (*Collection)(nil) + _ client.DB = (*db)(nil) + _ client.Collection = (*collection)(nil) ) // DB is the main interface for interacting with the // DefraDB storage system. -type DB struct { +type db struct { glock sync.RWMutex rootstore ds.Batching @@ -66,16 +66,20 @@ type DB struct { } // functional option type -type Option func(*DB) +type Option func(*db) func WithBroadcaster(bs corenet.Broadcaster) Option { - return func(db *DB) { + return func(db *db) { db.broadcaster = bs } } // NewDB creates a new instance of the DB using the given options -func NewDB(ctx context.Context, rootstore ds.Batching, options ...Option) (*DB, error) { +func NewDB(ctx context.Context, rootstore ds.Batching, options ...Option) (client.DB, error) { + return newDB(ctx, rootstore, options...) +} + +func newDB(ctx context.Context, rootstore ds.Batching, options ...Option) (*db, error) { log.Debug(ctx, "loading: internal datastores") root := datastore.AsDSReaderWriter(rootstore) multistore := datastore.MultiStoreFrom(root) @@ -93,7 +97,7 @@ func NewDB(ctx context.Context, rootstore ds.Batching, options ...Option) (*DB, return nil, err } - db := &DB{ + db := &db{ rootstore: rootstore, multistore: multistore, @@ -120,26 +124,26 @@ func NewDB(ctx context.Context, rootstore ds.Batching, options ...Option) (*DB, return db, nil } -func (db *DB) NewTxn(ctx context.Context, readonly bool) (datastore.Txn, error) { +func (db *db) NewTxn(ctx context.Context, readonly bool) (datastore.Txn, error) { return datastore.NewTxnFrom(ctx, db.rootstore, readonly) } -func (db *DB) Root() ds.Batching { +func (db *db) Root() ds.Batching { return db.rootstore } // Blockstore returns the internal DAG store which contains IPLD blocks -func (db *DB) Blockstore() blockstore.Blockstore { +func (db *db) Blockstore() blockstore.Blockstore { return db.multistore.DAGstore() } -func (db *DB) systemstore() datastore.DSReaderWriter { +func (db *db) systemstore() datastore.DSReaderWriter { return db.multistore.Systemstore() } // Initialize is called when a database is first run and creates all the db global meta data // like Collection ID counters -func (db *DB) initialize(ctx context.Context) error { +func (db *db) initialize(ctx context.Context) error { db.glock.Lock() defer db.glock.Unlock() @@ -171,15 +175,15 @@ func (db *DB) initialize(ctx context.Context) error { return nil } -func (db *DB) PrintDump(ctx context.Context) { +func (db *db) PrintDump(ctx context.Context) { printStore(ctx, db.multistore.Rootstore()) } -func (db *DB) Executor() *planner.QueryExecutor { +func (db *db) Executor() *planner.QueryExecutor { return db.queryExecutor } -func (db *DB) GetRelationshipIdField(fieldName, targetType, thisType string) (string, error) { +func (db *db) GetRelationshipIdField(fieldName, targetType, thisType string) (string, error) { rm := db.schema.Relations rel := rm.GetRelationByDescription(fieldName, targetType, thisType) if rel == nil { @@ -195,7 +199,7 @@ func (db *DB) GetRelationshipIdField(fieldName, targetType, thisType string) (st // Close is called when we are shutting down the database. // This is the place for any last minute cleanup or releaseing // of resources (IE: Badger instance) -func (db *DB) Close(ctx context.Context) { +func (db *db) Close(ctx context.Context) { log.Info(ctx, "Closing DefraDB process...") err := db.rootstore.Close() if err != nil { diff --git a/db/db_test.go b/db/db_test.go index 89ef5cbca1..9ec0febaac 100644 --- a/db/db_test.go +++ b/db/db_test.go @@ -29,13 +29,13 @@ import ( "github.com/stretchr/testify/assert" ) -func newMemoryDB(ctx context.Context) (*DB, error) { +func newMemoryDB(ctx context.Context) (*db, error) { opts := badgerds.Options{Options: badger.DefaultOptions("").WithInMemory(true)} rootstore, err := badgerds.NewDatastore("", &opts) if err != nil { return nil, err } - return NewDB(ctx, rootstore) + return newDB(ctx, rootstore) } func TestNewDB(t *testing.T) { diff --git a/db/fetcher/versioned_test.go b/db/fetcher/versioned_test.go index 5570685b50..2f3b0259e8 100644 --- a/db/fetcher/versioned_test.go +++ b/db/fetcher/versioned_test.go @@ -16,6 +16,7 @@ import ( "errors" "testing" + "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/core" "github.com/sourcenetwork/defradb/db" "github.com/sourcenetwork/defradb/db/base" @@ -89,7 +90,7 @@ var ( } ) -func newMemoryDB(ctx context.Context) (*db.DB, error) { +func newMemoryDB(ctx context.Context) (client.DB, error) { rootstore := ds.NewMapDatastore() return db.NewDB(ctx, rootstore) } @@ -365,7 +366,7 @@ func compareVersionedDocs(t *testing.T, doc, expected map[string]interface{}) { } } -func createDocUpdates(col *db.Collection) error { +func createDocUpdates(col client.Collection) error { // col, err := newTestCollectionWithSchema(db) // if err != ni @@ -451,7 +452,7 @@ func createDocUpdates(col *db.Collection) error { return err } -func newTestCollectionWithSchema(d *db.DB) (*db.Collection, error) { +func newTestCollectionWithSchema(d client.DB) (client.Collection, error) { desc := base.CollectionDescription{ Name: "users", Schema: base.SchemaDescription{ @@ -486,5 +487,5 @@ func newTestCollectionWithSchema(d *db.DB) (*db.Collection, error) { ctx := context.Background() col, err := d.CreateCollection(ctx, desc) - return col.(*db.Collection), err + return col, err } diff --git a/db/query.go b/db/query.go index 7bc880a4f8..794e468d7b 100644 --- a/db/query.go +++ b/db/query.go @@ -20,7 +20,7 @@ import ( gql "github.com/graphql-go/graphql" ) -func (db *DB) ExecQuery(ctx context.Context, query string) *client.QueryResult { +func (db *db) ExecQuery(ctx context.Context, query string) *client.QueryResult { res := &client.QueryResult{} // check if its Introspection query if strings.Contains(query, "IntrospectionQuery") { @@ -49,7 +49,7 @@ func (db *DB) ExecQuery(ctx context.Context, query string) *client.QueryResult { return res } -func (db *DB) ExecTransactionalQuery(ctx context.Context, query string, txn datastore.Txn) *client.QueryResult { +func (db *db) ExecTransactionalQuery(ctx context.Context, query string, txn datastore.Txn) *client.QueryResult { res := &client.QueryResult{} // check if its Introspection query if strings.Contains(query, "IntrospectionQuery") { @@ -66,7 +66,7 @@ func (db *DB) ExecTransactionalQuery(ctx context.Context, query string, txn data return res } -func (db *DB) ExecIntrospection(query string) *client.QueryResult { +func (db *db) ExecIntrospection(query string) *client.QueryResult { schema := db.schema.Schema() // t := schema.Type("userFilterArg") // spew.Dump(t.(*gql.InputObject).Fields()) diff --git a/db/schema.go b/db/schema.go index ab06aa6304..0464c2f3ba 100644 --- a/db/schema.go +++ b/db/schema.go @@ -21,7 +21,7 @@ import ( // LoadSchema takes the provided schema in SDL format, and applies it to the database, // and creates the necessary collections, query types, etc. -func (db *DB) AddSchema(ctx context.Context, schema string) error { +func (db *db) AddSchema(ctx context.Context, schema string) error { // @todo: create collection after generating query types types, astdoc, err := db.schema.Generator.FromSDL(ctx, schema) if err != nil { @@ -40,7 +40,7 @@ func (db *DB) AddSchema(ctx context.Context, schema string) error { return db.saveSchema(ctx, astdoc) } -func (db *DB) loadSchema(ctx context.Context) error { +func (db *db) loadSchema(ctx context.Context) error { var sdl string q := dsq.Query{ Prefix: "/schema", @@ -59,7 +59,7 @@ func (db *DB) loadSchema(ctx context.Context) error { return err } -func (db *DB) saveSchema(ctx context.Context, astdoc *ast.Document) error { +func (db *db) saveSchema(ctx context.Context, astdoc *ast.Document) error { // save each type individually for _, def := range astdoc.Definitions { switch defType := def.(type) { diff --git a/db/sequence.go b/db/sequence.go index cf5462fc7b..8a891bbeb9 100644 --- a/db/sequence.go +++ b/db/sequence.go @@ -20,12 +20,12 @@ import ( ) type sequence struct { - db *DB + db *db key core.SequenceKey val uint64 } -func (db *DB) getSequence(ctx context.Context, key string) (*sequence, error) { +func (db *db) getSequence(ctx context.Context, key string) (*sequence, error) { if key == "" { return nil, errors.New("key cannot be empty") } diff --git a/db/tests/utils.go b/db/tests/utils.go index c86d9c5f94..6e60acbc58 100644 --- a/db/tests/utils.go +++ b/db/tests/utils.go @@ -91,7 +91,7 @@ type QueryTestCase struct { type databaseInfo struct { name string path string - db *db.DB + db client.DB rootstore ds.Batching } @@ -99,7 +99,7 @@ func (dbi databaseInfo) Rootstore() ds.Batching { return dbi.rootstore } -func (dbi databaseInfo) DB() *db.DB { +func (dbi databaseInfo) DB() client.DB { return dbi.db } diff --git a/go.mod b/go.mod index c3a5f103a2..00f6983ae8 100644 --- a/go.mod +++ b/go.mod @@ -31,8 +31,8 @@ require ( github.com/libp2p/go-libp2p-peerstore v0.4.0 github.com/libp2p/go-libp2p-pubsub v0.6.1 github.com/mitchellh/go-homedir v1.1.0 - github.com/multiformats/go-multiaddr v0.4.1 github.com/multiformats/go-base32 v0.0.3 + github.com/multiformats/go-multiaddr v0.4.1 github.com/multiformats/go-multibase v0.0.3 github.com/multiformats/go-multihash v0.1.0 github.com/multiformats/go-varint v0.0.6 @@ -78,7 +78,6 @@ require ( github.com/golang/snappy v0.0.3 // indirect github.com/google/flatbuffers v1.12.1 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -167,7 +166,6 @@ require ( github.com/minio/sha256-simd v1.0.0 // indirect github.com/mitchellh/mapstructure v1.1.2 // indirect github.com/mr-tron/base58 v1.2.0 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect diff --git a/node/node.go b/node/node.go index b311b9a802..c11ad0dfbf 100644 --- a/node/node.go +++ b/node/node.go @@ -195,3 +195,7 @@ func newHostKey() (crypto.PrivKey, []byte, error) { } return priv, key, nil } + +func (n Node) Close() error { + return n.Peer.Close() +}