github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/db/db.go (about) 1 package db 2 3 import ( 4 "fmt" 5 "slices" 6 7 "golang.org/x/exp/maps" 8 ) 9 10 type BackendType string 11 12 func (b BackendType) String() string { 13 return string(b) 14 } 15 16 // These are valid backend types. 17 // 18 // The backends themselves must be imported to be used (ie. using the blank 19 // import, `import _ "github.com/gnolang/gno/tm2/pkg/db/goleveldb"`). To allow 20 // for end-user customization at build time, the package 21 // "github.com/gnolang/gno/tm2/pkg/db/_tags" can be imported -- this package 22 // will import each database depending on whether its build tag is provided. 23 // 24 // This can be used in conjunction with specific to provide defaults, for instance: 25 // 26 // package main 27 // 28 // import ( 29 // "github.com/gnolang/gno/tm2/pkg/db" 30 // _ "github.com/gnolang/gno/tm2/pkg/db/_tags" // allow user to customize with build tags 31 // _ "github.com/gnolang/gno/tm2/pkg/db/memdb" // always support memdb 32 // ) 33 // 34 // func main() { 35 // db.NewDB("mydb", db.BackendType(userProvidedBackend), "./data") 36 // } 37 const ( 38 // GoLevelDBBackend represents goleveldb (github.com/syndtr/goleveldb - most 39 // popular implementation) 40 // - stable 41 GoLevelDBBackend BackendType = "goleveldb" 42 // MemDBBackend represents in-memory key value store, which is mostly used 43 // for testing. 44 MemDBBackend BackendType = "memdb" 45 // BoltDBBackend represents bolt (uses etcd's fork of bolt - 46 // go.etcd.io/bbolt) 47 // - EXPERIMENTAL 48 // - may be faster is some use-cases (random reads - indexer) 49 BoltDBBackend BackendType = "boltdb" 50 ) 51 52 type dbCreator func(name string, dir string) (DB, error) 53 54 var backends = map[BackendType]dbCreator{} 55 56 // InternalRegisterDBCreator is used by the init functions of imported databases 57 // to register their own dbCreators. 58 // 59 // This function is not meant for usage outside of db/. 60 func InternalRegisterDBCreator(backend BackendType, creator dbCreator, force bool) { 61 _, ok := backends[backend] 62 if !force && ok { 63 return 64 } 65 backends[backend] = creator 66 } 67 68 // BackendList returns a list of available db backends. The list is sorted. 69 func BackendList() []BackendType { 70 keys := maps.Keys(backends) 71 slices.Sort(keys) 72 return keys 73 } 74 75 // NewDB creates a new database of type backend with the given name. 76 // NOTE: function panics if: 77 // - backend is unknown (not registered) 78 // - creator function, provided during registration, returns error 79 func NewDB(name string, backend BackendType, dir string) (DB, error) { 80 dbCreator, ok := backends[backend] 81 if !ok { 82 keys := BackendList() 83 return nil, fmt.Errorf("unknown db_backend %s. Expected one of %v", backend, keys) 84 } 85 86 db, err := dbCreator(name, dir) 87 if err != nil { 88 return nil, fmt.Errorf("error initializing DB: %w", err) 89 } 90 return db, nil 91 }