From 5917f627db73a5cb46efd2c4bbdb00687ed09a4e Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Wed, 23 Mar 2022 15:10:41 -0400 Subject: [PATCH] feat: add Features + datastore scoping The motivation for this is to enable "dispatching" datastores that dynamically implement the type of the datastore they are dispatching to, so that type assertions behave equivalently on the dispatcher as on the dispatchee. We also want this to be backwards-compatible with existing code using type assertions. At a high level, this works by generating a concrete implementation of every possible combination of "features", and then picking the right implementation at runtime. This is necessary due to language constraints in Go--it is currently impossible to create a concrete type dynamically with reflection that implements an interface. "Features" are introduced here, which are supplemental, optional interfaces that datastores may implement. These are backwards-compatible with existing "features", which are: * Batching * CheckedDatastore * GCDatastore * PersistentDatastore * ScrubbedDatastore * TTLDatastore * TxnDatastore New features can also be added in a backwards-compatible way. E.g. if datastore A is scoped down to datastore B, a new feature F is added, and then implemented on B, then A will continue to implement the same set of features since it hasn't implemented F yet (and vice versa if F is implemented on A but not B). Examples of things this enables: * Allow us to deprecate ErrBatchUnsupported * Allow existing dispatching datastores to support all features (keytransform, retrystore, MutexDatastore, autobatch, etc.) * Features supported by a Mount datastore could be scoped down to the intersection of all children * Communication with data about what functionality a datastore supports (e.g. for cross-language/RPC support) Some related issues: * https://github.com/ipfs/go-datastore/issues/160 * https://github.com/ipfs/go-datastore/issues/88 --- basic_ds.go | 56 - basic_ds_test.go | 12 +- datastore.go | 27 +- features.go | 142 +++ features_test.go | 80 ++ null_ds.go | 123 ++ null_ds_test.go | 14 + scoped/doc.go | 40 + scoped/generate/main.go | 102 ++ scoped/impls.go | 2570 +++++++++++++++++++++++++++++++++++++++ scoped/scoped.go | 42 + scoped/scoped_test.go | 61 + 12 files changed, 3183 insertions(+), 86 deletions(-) create mode 100644 features.go create mode 100644 features_test.go create mode 100644 null_ds.go create mode 100644 null_ds_test.go create mode 100644 scoped/doc.go create mode 100644 scoped/generate/main.go create mode 100644 scoped/impls.go create mode 100644 scoped/scoped.go create mode 100644 scoped/scoped_test.go diff --git a/basic_ds.go b/basic_ds.go index 95f03fe..22cfd70 100644 --- a/basic_ds.go +++ b/basic_ds.go @@ -89,62 +89,6 @@ func (d *MapDatastore) Close() error { return nil } -// NullDatastore stores nothing, but conforms to the API. -// Useful to test with. -type NullDatastore struct { -} - -var _ Datastore = (*NullDatastore)(nil) -var _ Batching = (*NullDatastore)(nil) - -// NewNullDatastore constructs a null datastoe -func NewNullDatastore() *NullDatastore { - return &NullDatastore{} -} - -// Put implements Datastore.Put -func (d *NullDatastore) Put(ctx context.Context, key Key, value []byte) (err error) { - return nil -} - -// Sync implements Datastore.Sync -func (d *NullDatastore) Sync(ctx context.Context, prefix Key) error { - return nil -} - -// Get implements Datastore.Get -func (d *NullDatastore) Get(ctx context.Context, key Key) (value []byte, err error) { - return nil, ErrNotFound -} - -// Has implements Datastore.Has -func (d *NullDatastore) Has(ctx context.Context, key Key) (exists bool, err error) { - return false, nil -} - -// Has implements Datastore.GetSize -func (d *NullDatastore) GetSize(ctx context.Context, key Key) (size int, err error) { - return -1, ErrNotFound -} - -// Delete implements Datastore.Delete -func (d *NullDatastore) Delete(ctx context.Context, key Key) (err error) { - return nil -} - -// Query implements Datastore.Query -func (d *NullDatastore) Query(ctx context.Context, q dsq.Query) (dsq.Results, error) { - return dsq.ResultsWithEntries(q, nil), nil -} - -func (d *NullDatastore) Batch(ctx context.Context) (Batch, error) { - return NewBasicBatch(d), nil -} - -func (d *NullDatastore) Close() error { - return nil -} - // LogDatastore logs all accesses through the datastore. type LogDatastore struct { Name string diff --git a/basic_ds_test.go b/basic_ds_test.go index 4353bb1..7957283 100644 --- a/basic_ds_test.go +++ b/basic_ds_test.go @@ -5,24 +5,18 @@ import ( "log" "testing" - dstore "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore" dstest "github.com/ipfs/go-datastore/test" ) func TestMapDatastore(t *testing.T) { - ds := dstore.NewMapDatastore() + ds := datastore.NewMapDatastore() dstest.SubtestAll(t, ds) } -func TestNullDatastore(t *testing.T) { - ds := dstore.NewNullDatastore() - // The only test that passes. Nothing should be found. - dstest.SubtestNotFounds(t, ds) -} - func TestLogDatastore(t *testing.T) { defer log.SetOutput(log.Writer()) log.SetOutput(ioutil.Discard) - ds := dstore.NewLogDatastore(dstore.NewMapDatastore(), "") + ds := datastore.NewLogDatastore(datastore.NewMapDatastore(), "") dstest.SubtestAll(t, ds) } diff --git a/datastore.go b/datastore.go index 0d075df..8926bb4 100644 --- a/datastore.go +++ b/datastore.go @@ -4,7 +4,6 @@ import ( "context" "errors" "io" - "time" query "github.com/ipfs/go-datastore/query" ) @@ -103,8 +102,7 @@ type Read interface { // capabilities of a `Batch`, but the reverse is NOT true. type Batching interface { Datastore - - Batch(ctx context.Context) (Batch, error) + BatchingFeature } // ErrBatchUnsupported is returned if the by Batch if the Datastore doesn't @@ -115,8 +113,7 @@ var ErrBatchUnsupported = errors.New("this datastore does not support batching") // which may need checking on-disk data integrity. type CheckedDatastore interface { Datastore - - Check(ctx context.Context) error + CheckedFeature } // ScrubbedDatastore is an interface that should be implemented by datastores @@ -124,25 +121,21 @@ type CheckedDatastore interface { // error correction. type ScrubbedDatastore interface { Datastore - - Scrub(ctx context.Context) error + ScrubbedFeature } // GCDatastore is an interface that should be implemented by datastores which // don't free disk space by just removing data from them. type GCDatastore interface { Datastore - - CollectGarbage(ctx context.Context) error + GCFeature } // PersistentDatastore is an interface that should be implemented by datastores // which can report disk usage. type PersistentDatastore interface { Datastore - - // DiskUsage returns the space used by a datastore, in bytes. - DiskUsage(ctx context.Context) (uint64, error) + PersistentFeature } // DiskUsage checks if a Datastore is a @@ -163,13 +156,6 @@ type TTLDatastore interface { TTL } -// TTL encapulates the methods that deal with entries with time-to-live. -type TTL interface { - PutWithTTL(ctx context.Context, key Key, value []byte, ttl time.Duration) error - SetTTL(ctx context.Context, key Key, ttl time.Duration) error - GetExpiration(ctx context.Context, key Key) (time.Time, error) -} - // Txn extends the Datastore type. Txns allow users to batch queries and // mutations to the Datastore into atomic groups, or transactions. Actions // performed on a transaction will not take hold until a successful call to @@ -194,8 +180,7 @@ type Txn interface { // support transactions. type TxnDatastore interface { Datastore - - NewTransaction(ctx context.Context, readOnly bool) (Txn, error) + TxnFeature } // Errors diff --git a/features.go b/features.go new file mode 100644 index 0000000..5350c05 --- /dev/null +++ b/features.go @@ -0,0 +1,142 @@ +package datastore + +import ( + "context" + "reflect" + "time" +) + +const ( + FeatureNameBatching = "Batching" + FeatureNameChecked = "Checked" + FeatureNameGC = "GC" + FeatureNamePersistent = "Persistent" + FeatureNameScrubbed = "Scrubbed" + FeatureNameTTL = "TTL" + FeatureNameTransaction = "Transaction" +) + +type BatchingFeature interface { + Batch(ctx context.Context) (Batch, error) +} + +type CheckedFeature interface { + Check(ctx context.Context) error +} + +type ScrubbedFeature interface { + Scrub(ctx context.Context) error +} + +type GCFeature interface { + CollectGarbage(ctx context.Context) error +} + +type PersistentFeature interface { + // DiskUsage returns the space used by a datastore, in bytes. + DiskUsage(ctx context.Context) (uint64, error) +} + +// TTL encapulates the methods that deal with entries with time-to-live. +type TTL interface { + PutWithTTL(ctx context.Context, key Key, value []byte, ttl time.Duration) error + SetTTL(ctx context.Context, key Key, ttl time.Duration) error + GetExpiration(ctx context.Context, key Key) (time.Time, error) +} + +type TxnFeature interface { + NewTransaction(ctx context.Context, readOnly bool) (Txn, error) +} + +// Feature contains metadata about a datastore Feature. +type Feature struct { + Name string + // Interface is the nil interface of the feature. + Interface interface{} + // DatastoreInterface is the nil interface of the feature's corresponding datastore interface. + DatastoreInterface interface{} +} + +var featuresByName map[string]Feature + +func init() { + featuresByName = map[string]Feature{} + for _, f := range Features() { + featuresByName[f.Name] = f + } +} + +// Features returns a list of all known datastore features. +// This serves both to provide an authoritative list of features, +// and to define a canonical ordering of features. +func Features() []Feature { + // for backwards compatibility, only append to this list + return []Feature{ + { + Name: FeatureNameBatching, + Interface: (*BatchingFeature)(nil), + DatastoreInterface: (*Batching)(nil), + }, + { + Name: FeatureNameChecked, + Interface: (*CheckedFeature)(nil), + DatastoreInterface: (*CheckedDatastore)(nil), + }, + { + Name: FeatureNameGC, + Interface: (*GCFeature)(nil), + DatastoreInterface: (*GCDatastore)(nil), + }, + { + Name: FeatureNamePersistent, + Interface: (*PersistentFeature)(nil), + DatastoreInterface: (*PersistentDatastore)(nil), + }, + { + Name: FeatureNameScrubbed, + Interface: (*ScrubbedFeature)(nil), + DatastoreInterface: (*ScrubbedDatastore)(nil), + }, + { + Name: FeatureNameTTL, + Interface: (*TTL)(nil), + DatastoreInterface: (*TTLDatastore)(nil), + }, + { + Name: FeatureNameTransaction, + Interface: (*TxnFeature)(nil), + DatastoreInterface: (*TxnDatastore)(nil), + }, + } +} + +// FeaturesByNames returns the features with the given names, if they are known. +func FeaturesByNames(names ...string) (features []Feature) { + for _, n := range names { + if feat, ok := featuresByName[n]; ok { + features = append(features, feat) + } + } + return +} + +// FeatureByName returns the feature with the given name, if known. +func FeatureByName(name string) (Feature, bool) { + feat, known := featuresByName[name] + return feat, known +} + +// FeaturesForDatastore returns the features supported by the given datastore. +func FeaturesForDatastore(dstore Datastore) (features []Feature) { + if dstore == nil { + return nil + } + dstoreType := reflect.ValueOf(dstore).Type() + for _, f := range Features() { + fType := reflect.TypeOf(f.Interface).Elem() + if dstoreType.Implements(fType) { + features = append(features, f) + } + } + return +} diff --git a/features_test.go b/features_test.go new file mode 100644 index 0000000..2741fce --- /dev/null +++ b/features_test.go @@ -0,0 +1,80 @@ +package datastore + +import ( + "reflect" + "testing" +) + +func TestFeaturesByNames(t *testing.T) { + feats := FeaturesByNames() + if feats != nil { + t.Fatalf("expected nil features, got %v", feats) + } + + feats = FeaturesByNames(FeatureNameBatching) + if len(feats) != 1 || + feats[0].Name != FeatureNameBatching || + feats[0].Interface != (*BatchingFeature)(nil) || + feats[0].DatastoreInterface != (*Batching)(nil) { + t.Fatalf("expected a batching feature, got %v", feats) + } + + feats = FeaturesByNames(FeatureNameBatching, "UnknownFeature") + if len(feats) != 1 || feats[0].Name != FeatureNameBatching { + t.Fatalf("expected a batching feature, got %v", feats) + } +} + +func TestFeatureByName(t *testing.T) { + feat, ok := FeatureByName(FeatureNameBatching) + if !ok { + t.Fatalf("expected a batching feature") + } + if feat.Name != FeatureNameBatching || + feat.Interface != (*BatchingFeature)(nil) || + feat.DatastoreInterface != (*Batching)(nil) { + t.Fatalf("expected a batching feature, got %v", feat) + } + + feat, ok = FeatureByName("UnknownFeature") + if ok { + t.Fatalf("expected UnknownFeature not to be found") + } +} + +func TestFeaturesForDatastore(t *testing.T) { + cases := []struct { + name string + d Datastore + expectedFeatures []string + }{ + { + name: "MapDatastore", + d: &MapDatastore{}, + expectedFeatures: []string{"Batching"}, + }, + { + name: "NullDatastore", + d: &NullDatastore{}, + expectedFeatures: []string{"Batching"}, + }, + { + name: "LogDatastore", + d: &LogDatastore{}, + expectedFeatures: []string{"Batching", "Checked", "GC", "Persistent", "Scrubbed"}, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + feats := FeaturesForDatastore(c.d) + if len(feats) != len(c.expectedFeatures) { + t.Fatalf("expected %d features, got %v", len(c.expectedFeatures), feats) + } + expectedFeats := FeaturesByNames(c.expectedFeatures...) + if !reflect.DeepEqual(expectedFeats, feats) { + t.Fatalf("expected features %v, got %v", c.expectedFeatures, feats) + } + }) + } +} diff --git a/null_ds.go b/null_ds.go new file mode 100644 index 0000000..8bc5ad4 --- /dev/null +++ b/null_ds.go @@ -0,0 +1,123 @@ +package datastore + +import ( + "context" + + dsq "github.com/ipfs/go-datastore/query" + query "github.com/ipfs/go-datastore/query" +) + +// NullDatastore stores nothing, but conforms to the API. +// Useful to test with. +type NullDatastore struct { +} + +var _ Datastore = (*NullDatastore)(nil) +var _ Batching = (*NullDatastore)(nil) +var _ ScrubbedDatastore = (*NullDatastore)(nil) +var _ CheckedDatastore = (*NullDatastore)(nil) +var _ PersistentDatastore = (*NullDatastore)(nil) +var _ GCDatastore = (*NullDatastore)(nil) +var _ TxnDatastore = (*NullDatastore)(nil) + +// NewNullDatastore constructs a null datastoe +func NewNullDatastore() *NullDatastore { + return &NullDatastore{} +} + +// Put implements Datastore.Put +func (d *NullDatastore) Put(ctx context.Context, key Key, value []byte) (err error) { + return nil +} + +// Sync implements Datastore.Sync +func (d *NullDatastore) Sync(ctx context.Context, prefix Key) error { + return nil +} + +// Get implements Datastore.Get +func (d *NullDatastore) Get(ctx context.Context, key Key) (value []byte, err error) { + return nil, ErrNotFound +} + +// Has implements Datastore.Has +func (d *NullDatastore) Has(ctx context.Context, key Key) (exists bool, err error) { + return false, nil +} + +// Has implements Datastore.GetSize +func (d *NullDatastore) GetSize(ctx context.Context, key Key) (size int, err error) { + return -1, ErrNotFound +} + +// Delete implements Datastore.Delete +func (d *NullDatastore) Delete(ctx context.Context, key Key) (err error) { + return nil +} + +func (d *NullDatastore) Scrub(ctx context.Context) error { + return nil +} + +func (d *NullDatastore) Check(ctx context.Context) error { + return nil +} + +// Query implements Datastore.Query +func (d *NullDatastore) Query(ctx context.Context, q dsq.Query) (dsq.Results, error) { + return dsq.ResultsWithEntries(q, nil), nil +} + +func (d *NullDatastore) Batch(ctx context.Context) (Batch, error) { + return NewBasicBatch(d), nil +} + +func (d *NullDatastore) CollectGarbage(ctx context.Context) error { + return nil +} + +func (d *NullDatastore) DiskUsage(ctx context.Context) (uint64, error) { + return 0, nil +} + +func (d *NullDatastore) Close() error { + return nil +} + +func (d *NullDatastore) NewTransaction(ctx context.Context, readOnly bool) (Txn, error) { + return &nullTxn{}, nil +} + +type nullTxn struct{} + +func (t *nullTxn) Get(ctx context.Context, key Key) (value []byte, err error) { + return nil, nil +} + +func (t *nullTxn) Has(ctx context.Context, key Key) (exists bool, err error) { + return false, nil +} + +func (t *nullTxn) GetSize(ctx context.Context, key Key) (size int, err error) { + return 0, nil +} + +func (t *nullTxn) Query(ctx context.Context, q query.Query) (query.Results, error) { + return dsq.ResultsWithEntries(q, nil), nil +} + +func (t *nullTxn) Put(ctx context.Context, key Key, value []byte) error { + return nil +} + +func (t *nullTxn) Delete(ctx context.Context, key Key) error { + return nil +} + +func (t *nullTxn) Commit(ctx context.Context) error { + return nil +} + +func (t *nullTxn) Discard(ctx context.Context) { + return +} diff --git a/null_ds_test.go b/null_ds_test.go new file mode 100644 index 0000000..eba032d --- /dev/null +++ b/null_ds_test.go @@ -0,0 +1,14 @@ +package datastore_test + +import ( + "testing" + + "github.com/ipfs/go-datastore" + dstest "github.com/ipfs/go-datastore/test" +) + +func TestNullDatastore(t *testing.T) { + ds := datastore.NewNullDatastore() + // The only test that passes. Nothing should be found. + dstest.SubtestNotFounds(t, ds) +} diff --git a/scoped/doc.go b/scoped/doc.go new file mode 100644 index 0000000..12afef7 --- /dev/null +++ b/scoped/doc.go @@ -0,0 +1,40 @@ +// Package scoped introduces a Datastore Shim that scopes down a source datastore +// to the features supported by a target datastore. This is useful e.g. for dispatching +// datastores, where the dispatcher needs to dynamically implement the same features +// as the dispatchee, without knowing them statically. +// +// Use the Wrap function to wrap a datastore so that its interface is scoped down to +// only those features supported both by it and its target datastore. Note that this +// is a set intersection--if the target implements a feature not supported by the +// wrapped datastore, then the resulting shim will not implement them either. +// +// For example: +// +// import ( +// "context" +// scopedds "github.com/ipfs/go-datastore/scoped" +// ds "github.com/ipfs/go-datastore" +// ) +// +// type BatchingDS struct { ds.Datastore } +// +// func (b *BatchingDS) Batch(ctx context.Context) (ds.Batch, error) { +// // custom batching +// return nil, nil +// } +// +// type BoringDS struct { ds.Datastore } +// +// func Dispatcher(dstore ds.Datastore) ds.Datastore { +// dispatcher := &BatchingDS{Datastore: dstore} +// dispatchee := &BoringDS{Datastore: dstore} +// +// // the dispatcher supports batching, but since the dispatchee +// // doesn't, the returned dispatcher does NOT implement ds.Batching +// +// return scoped.Wrap(dispatcher, dispatchee) +// } + +package scoped + +//go:generate go run generate/main.go diff --git a/scoped/generate/main.go b/scoped/generate/main.go new file mode 100644 index 0000000..d823914 --- /dev/null +++ b/scoped/generate/main.go @@ -0,0 +1,102 @@ +//go:build generate +// +build generate + +package main + +import ( + "bytes" + "go/format" + "math" + "os" + "reflect" + "text/template" + + ds "github.com/ipfs/go-datastore" +) + +var tmpl = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT. + +package scoped + +import ( + ds "github.com/ipfs/go-datastore" +) + +{{ range $idx, $features := .StructFeatures -}} +type ds{{ $idx }} struct { + ds.Datastore + {{- range $feat := $features }} + ds.{{ $feat.IFace }} + {{- end }} +} +func (d *ds{{ $idx }}) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} +{{ end }} +var ctors = map[int]func(ds.Datastore) ds.Datastore{ + {{- range $idx, $features := .StructFeatures }} + {{ $idx }}: func(dstore ds.Datastore) ds.Datastore { + return &ds{{ $idx }}{ + Datastore: dstore, + {{- range $feat := $features }} + {{ $feat.IFace }}: dstore.(ds.{{ $feat.DatastoreIFace }}), + {{- end }} + } + }, + {{- end }} +} +`)) + +func main() { + type feat struct { + IFace string + DatastoreIFace string + } + + type templateData struct { + StructFeatures [][]feat + Features []feat + } + + tmplData := templateData{} + features := ds.Features() + + for _, f := range features { + tmplData.Features = append(tmplData.Features, feat{ + IFace: reflect.TypeOf(f.Interface).Elem().Name(), + DatastoreIFace: reflect.TypeOf(f.DatastoreInterface).Elem().Name(), + }) + } + + numStructs := int(math.Pow(2, float64(len(features)))) + tmplData.StructFeatures = make([][]feat, numStructs) + for i := 0; i < numStructs; i++ { + for bit := 0; bit < len(features); bit++ { + if ((i >> bit) & 1) == 1 { + tmplData.StructFeatures[i] = append(tmplData.StructFeatures[i], tmplData.Features[bit]) + } + } + } + + buf := bytes.Buffer{} + err := tmpl.Execute(&buf, tmplData) + if err != nil { + panic(err) + } + + b, err := format.Source(buf.Bytes()) + if err != nil { + panic(err) + } + + f, err := os.Create("impls.go") + if err != nil { + panic(err) + } + defer f.Close() + + _, err = f.Write(b) + if err != nil { + panic(err) + } +} diff --git a/scoped/impls.go b/scoped/impls.go new file mode 100644 index 0000000..00616a2 --- /dev/null +++ b/scoped/impls.go @@ -0,0 +1,2570 @@ +// Code generated by go generate; DO NOT EDIT. + +package scoped + +import ( + ds "github.com/ipfs/go-datastore" +) + +type ds0 struct { + ds.Datastore +} + +func (d *ds0) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds1 struct { + ds.Datastore + ds.BatchingFeature +} + +func (d *ds1) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds2 struct { + ds.Datastore + ds.CheckedFeature +} + +func (d *ds2) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds3 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature +} + +func (d *ds3) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds4 struct { + ds.Datastore + ds.GCFeature +} + +func (d *ds4) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds5 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature +} + +func (d *ds5) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds6 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature +} + +func (d *ds6) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds7 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature +} + +func (d *ds7) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds8 struct { + ds.Datastore + ds.PersistentFeature +} + +func (d *ds8) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds9 struct { + ds.Datastore + ds.BatchingFeature + ds.PersistentFeature +} + +func (d *ds9) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds10 struct { + ds.Datastore + ds.CheckedFeature + ds.PersistentFeature +} + +func (d *ds10) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds11 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.PersistentFeature +} + +func (d *ds11) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds12 struct { + ds.Datastore + ds.GCFeature + ds.PersistentFeature +} + +func (d *ds12) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds13 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.PersistentFeature +} + +func (d *ds13) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds14 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature +} + +func (d *ds14) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds15 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature +} + +func (d *ds15) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds16 struct { + ds.Datastore + ds.ScrubbedFeature +} + +func (d *ds16) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds17 struct { + ds.Datastore + ds.BatchingFeature + ds.ScrubbedFeature +} + +func (d *ds17) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds18 struct { + ds.Datastore + ds.CheckedFeature + ds.ScrubbedFeature +} + +func (d *ds18) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds19 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.ScrubbedFeature +} + +func (d *ds19) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds20 struct { + ds.Datastore + ds.GCFeature + ds.ScrubbedFeature +} + +func (d *ds20) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds21 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.ScrubbedFeature +} + +func (d *ds21) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds22 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.ScrubbedFeature +} + +func (d *ds22) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds23 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.ScrubbedFeature +} + +func (d *ds23) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds24 struct { + ds.Datastore + ds.PersistentFeature + ds.ScrubbedFeature +} + +func (d *ds24) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds25 struct { + ds.Datastore + ds.BatchingFeature + ds.PersistentFeature + ds.ScrubbedFeature +} + +func (d *ds25) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds26 struct { + ds.Datastore + ds.CheckedFeature + ds.PersistentFeature + ds.ScrubbedFeature +} + +func (d *ds26) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds27 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.PersistentFeature + ds.ScrubbedFeature +} + +func (d *ds27) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds28 struct { + ds.Datastore + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature +} + +func (d *ds28) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds29 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature +} + +func (d *ds29) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds30 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature +} + +func (d *ds30) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds31 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature +} + +func (d *ds31) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds32 struct { + ds.Datastore + ds.TTL +} + +func (d *ds32) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds33 struct { + ds.Datastore + ds.BatchingFeature + ds.TTL +} + +func (d *ds33) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds34 struct { + ds.Datastore + ds.CheckedFeature + ds.TTL +} + +func (d *ds34) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds35 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.TTL +} + +func (d *ds35) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds36 struct { + ds.Datastore + ds.GCFeature + ds.TTL +} + +func (d *ds36) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds37 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.TTL +} + +func (d *ds37) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds38 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.TTL +} + +func (d *ds38) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds39 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.TTL +} + +func (d *ds39) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds40 struct { + ds.Datastore + ds.PersistentFeature + ds.TTL +} + +func (d *ds40) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds41 struct { + ds.Datastore + ds.BatchingFeature + ds.PersistentFeature + ds.TTL +} + +func (d *ds41) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds42 struct { + ds.Datastore + ds.CheckedFeature + ds.PersistentFeature + ds.TTL +} + +func (d *ds42) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds43 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.PersistentFeature + ds.TTL +} + +func (d *ds43) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds44 struct { + ds.Datastore + ds.GCFeature + ds.PersistentFeature + ds.TTL +} + +func (d *ds44) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds45 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.PersistentFeature + ds.TTL +} + +func (d *ds45) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds46 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.TTL +} + +func (d *ds46) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds47 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.TTL +} + +func (d *ds47) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds48 struct { + ds.Datastore + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds48) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds49 struct { + ds.Datastore + ds.BatchingFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds49) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds50 struct { + ds.Datastore + ds.CheckedFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds50) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds51 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds51) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds52 struct { + ds.Datastore + ds.GCFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds52) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds53 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds53) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds54 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds54) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds55 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds55) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds56 struct { + ds.Datastore + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds56) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds57 struct { + ds.Datastore + ds.BatchingFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds57) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds58 struct { + ds.Datastore + ds.CheckedFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds58) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds59 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds59) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds60 struct { + ds.Datastore + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds60) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds61 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds61) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds62 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds62) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds63 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL +} + +func (d *ds63) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds64 struct { + ds.Datastore + ds.TxnFeature +} + +func (d *ds64) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds65 struct { + ds.Datastore + ds.BatchingFeature + ds.TxnFeature +} + +func (d *ds65) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds66 struct { + ds.Datastore + ds.CheckedFeature + ds.TxnFeature +} + +func (d *ds66) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds67 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.TxnFeature +} + +func (d *ds67) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds68 struct { + ds.Datastore + ds.GCFeature + ds.TxnFeature +} + +func (d *ds68) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds69 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.TxnFeature +} + +func (d *ds69) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds70 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.TxnFeature +} + +func (d *ds70) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds71 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.TxnFeature +} + +func (d *ds71) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds72 struct { + ds.Datastore + ds.PersistentFeature + ds.TxnFeature +} + +func (d *ds72) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds73 struct { + ds.Datastore + ds.BatchingFeature + ds.PersistentFeature + ds.TxnFeature +} + +func (d *ds73) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds74 struct { + ds.Datastore + ds.CheckedFeature + ds.PersistentFeature + ds.TxnFeature +} + +func (d *ds74) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds75 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.PersistentFeature + ds.TxnFeature +} + +func (d *ds75) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds76 struct { + ds.Datastore + ds.GCFeature + ds.PersistentFeature + ds.TxnFeature +} + +func (d *ds76) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds77 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.PersistentFeature + ds.TxnFeature +} + +func (d *ds77) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds78 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.TxnFeature +} + +func (d *ds78) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds79 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.TxnFeature +} + +func (d *ds79) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds80 struct { + ds.Datastore + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds80) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds81 struct { + ds.Datastore + ds.BatchingFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds81) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds82 struct { + ds.Datastore + ds.CheckedFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds82) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds83 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds83) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds84 struct { + ds.Datastore + ds.GCFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds84) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds85 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds85) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds86 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds86) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds87 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds87) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds88 struct { + ds.Datastore + ds.PersistentFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds88) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds89 struct { + ds.Datastore + ds.BatchingFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds89) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds90 struct { + ds.Datastore + ds.CheckedFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds90) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds91 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds91) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds92 struct { + ds.Datastore + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds92) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds93 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds93) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds94 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds94) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds95 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TxnFeature +} + +func (d *ds95) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds96 struct { + ds.Datastore + ds.TTL + ds.TxnFeature +} + +func (d *ds96) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds97 struct { + ds.Datastore + ds.BatchingFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds97) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds98 struct { + ds.Datastore + ds.CheckedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds98) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds99 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds99) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds100 struct { + ds.Datastore + ds.GCFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds100) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds101 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds101) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds102 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds102) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds103 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds103) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds104 struct { + ds.Datastore + ds.PersistentFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds104) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds105 struct { + ds.Datastore + ds.BatchingFeature + ds.PersistentFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds105) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds106 struct { + ds.Datastore + ds.CheckedFeature + ds.PersistentFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds106) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds107 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.PersistentFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds107) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds108 struct { + ds.Datastore + ds.GCFeature + ds.PersistentFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds108) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds109 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.PersistentFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds109) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds110 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds110) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds111 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds111) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds112 struct { + ds.Datastore + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds112) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds113 struct { + ds.Datastore + ds.BatchingFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds113) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds114 struct { + ds.Datastore + ds.CheckedFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds114) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds115 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds115) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds116 struct { + ds.Datastore + ds.GCFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds116) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds117 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds117) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds118 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds118) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds119 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds119) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds120 struct { + ds.Datastore + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds120) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds121 struct { + ds.Datastore + ds.BatchingFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds121) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds122 struct { + ds.Datastore + ds.CheckedFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds122) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds123 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds123) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds124 struct { + ds.Datastore + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds124) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds125 struct { + ds.Datastore + ds.BatchingFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds125) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds126 struct { + ds.Datastore + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds126) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +type ds127 struct { + ds.Datastore + ds.BatchingFeature + ds.CheckedFeature + ds.GCFeature + ds.PersistentFeature + ds.ScrubbedFeature + ds.TTL + ds.TxnFeature +} + +func (d *ds127) Children() []ds.Datastore { + return []ds.Datastore{d.Datastore} +} + +var ctors = map[int]func(ds.Datastore) ds.Datastore{ + 0: func(dstore ds.Datastore) ds.Datastore { + return &ds0{ + Datastore: dstore, + } + }, + 1: func(dstore ds.Datastore) ds.Datastore { + return &ds1{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + } + }, + 2: func(dstore ds.Datastore) ds.Datastore { + return &ds2{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + } + }, + 3: func(dstore ds.Datastore) ds.Datastore { + return &ds3{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + } + }, + 4: func(dstore ds.Datastore) ds.Datastore { + return &ds4{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + } + }, + 5: func(dstore ds.Datastore) ds.Datastore { + return &ds5{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + } + }, + 6: func(dstore ds.Datastore) ds.Datastore { + return &ds6{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + } + }, + 7: func(dstore ds.Datastore) ds.Datastore { + return &ds7{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + } + }, + 8: func(dstore ds.Datastore) ds.Datastore { + return &ds8{ + Datastore: dstore, + PersistentFeature: dstore.(ds.PersistentDatastore), + } + }, + 9: func(dstore ds.Datastore) ds.Datastore { + return &ds9{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + PersistentFeature: dstore.(ds.PersistentDatastore), + } + }, + 10: func(dstore ds.Datastore) ds.Datastore { + return &ds10{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + } + }, + 11: func(dstore ds.Datastore) ds.Datastore { + return &ds11{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + } + }, + 12: func(dstore ds.Datastore) ds.Datastore { + return &ds12{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + } + }, + 13: func(dstore ds.Datastore) ds.Datastore { + return &ds13{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + } + }, + 14: func(dstore ds.Datastore) ds.Datastore { + return &ds14{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + } + }, + 15: func(dstore ds.Datastore) ds.Datastore { + return &ds15{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + } + }, + 16: func(dstore ds.Datastore) ds.Datastore { + return &ds16{ + Datastore: dstore, + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 17: func(dstore ds.Datastore) ds.Datastore { + return &ds17{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 18: func(dstore ds.Datastore) ds.Datastore { + return &ds18{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 19: func(dstore ds.Datastore) ds.Datastore { + return &ds19{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 20: func(dstore ds.Datastore) ds.Datastore { + return &ds20{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 21: func(dstore ds.Datastore) ds.Datastore { + return &ds21{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 22: func(dstore ds.Datastore) ds.Datastore { + return &ds22{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 23: func(dstore ds.Datastore) ds.Datastore { + return &ds23{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 24: func(dstore ds.Datastore) ds.Datastore { + return &ds24{ + Datastore: dstore, + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 25: func(dstore ds.Datastore) ds.Datastore { + return &ds25{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 26: func(dstore ds.Datastore) ds.Datastore { + return &ds26{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 27: func(dstore ds.Datastore) ds.Datastore { + return &ds27{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 28: func(dstore ds.Datastore) ds.Datastore { + return &ds28{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 29: func(dstore ds.Datastore) ds.Datastore { + return &ds29{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 30: func(dstore ds.Datastore) ds.Datastore { + return &ds30{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 31: func(dstore ds.Datastore) ds.Datastore { + return &ds31{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + } + }, + 32: func(dstore ds.Datastore) ds.Datastore { + return &ds32{ + Datastore: dstore, + TTL: dstore.(ds.TTLDatastore), + } + }, + 33: func(dstore ds.Datastore) ds.Datastore { + return &ds33{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + TTL: dstore.(ds.TTLDatastore), + } + }, + 34: func(dstore ds.Datastore) ds.Datastore { + return &ds34{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 35: func(dstore ds.Datastore) ds.Datastore { + return &ds35{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 36: func(dstore ds.Datastore) ds.Datastore { + return &ds36{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 37: func(dstore ds.Datastore) ds.Datastore { + return &ds37{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 38: func(dstore ds.Datastore) ds.Datastore { + return &ds38{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 39: func(dstore ds.Datastore) ds.Datastore { + return &ds39{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 40: func(dstore ds.Datastore) ds.Datastore { + return &ds40{ + Datastore: dstore, + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 41: func(dstore ds.Datastore) ds.Datastore { + return &ds41{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 42: func(dstore ds.Datastore) ds.Datastore { + return &ds42{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 43: func(dstore ds.Datastore) ds.Datastore { + return &ds43{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 44: func(dstore ds.Datastore) ds.Datastore { + return &ds44{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 45: func(dstore ds.Datastore) ds.Datastore { + return &ds45{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 46: func(dstore ds.Datastore) ds.Datastore { + return &ds46{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 47: func(dstore ds.Datastore) ds.Datastore { + return &ds47{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 48: func(dstore ds.Datastore) ds.Datastore { + return &ds48{ + Datastore: dstore, + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 49: func(dstore ds.Datastore) ds.Datastore { + return &ds49{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 50: func(dstore ds.Datastore) ds.Datastore { + return &ds50{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 51: func(dstore ds.Datastore) ds.Datastore { + return &ds51{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 52: func(dstore ds.Datastore) ds.Datastore { + return &ds52{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 53: func(dstore ds.Datastore) ds.Datastore { + return &ds53{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 54: func(dstore ds.Datastore) ds.Datastore { + return &ds54{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 55: func(dstore ds.Datastore) ds.Datastore { + return &ds55{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 56: func(dstore ds.Datastore) ds.Datastore { + return &ds56{ + Datastore: dstore, + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 57: func(dstore ds.Datastore) ds.Datastore { + return &ds57{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 58: func(dstore ds.Datastore) ds.Datastore { + return &ds58{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 59: func(dstore ds.Datastore) ds.Datastore { + return &ds59{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 60: func(dstore ds.Datastore) ds.Datastore { + return &ds60{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 61: func(dstore ds.Datastore) ds.Datastore { + return &ds61{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 62: func(dstore ds.Datastore) ds.Datastore { + return &ds62{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 63: func(dstore ds.Datastore) ds.Datastore { + return &ds63{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + } + }, + 64: func(dstore ds.Datastore) ds.Datastore { + return &ds64{ + Datastore: dstore, + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 65: func(dstore ds.Datastore) ds.Datastore { + return &ds65{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 66: func(dstore ds.Datastore) ds.Datastore { + return &ds66{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 67: func(dstore ds.Datastore) ds.Datastore { + return &ds67{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 68: func(dstore ds.Datastore) ds.Datastore { + return &ds68{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 69: func(dstore ds.Datastore) ds.Datastore { + return &ds69{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 70: func(dstore ds.Datastore) ds.Datastore { + return &ds70{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 71: func(dstore ds.Datastore) ds.Datastore { + return &ds71{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 72: func(dstore ds.Datastore) ds.Datastore { + return &ds72{ + Datastore: dstore, + PersistentFeature: dstore.(ds.PersistentDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 73: func(dstore ds.Datastore) ds.Datastore { + return &ds73{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + PersistentFeature: dstore.(ds.PersistentDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 74: func(dstore ds.Datastore) ds.Datastore { + return &ds74{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 75: func(dstore ds.Datastore) ds.Datastore { + return &ds75{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 76: func(dstore ds.Datastore) ds.Datastore { + return &ds76{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 77: func(dstore ds.Datastore) ds.Datastore { + return &ds77{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 78: func(dstore ds.Datastore) ds.Datastore { + return &ds78{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 79: func(dstore ds.Datastore) ds.Datastore { + return &ds79{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 80: func(dstore ds.Datastore) ds.Datastore { + return &ds80{ + Datastore: dstore, + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 81: func(dstore ds.Datastore) ds.Datastore { + return &ds81{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 82: func(dstore ds.Datastore) ds.Datastore { + return &ds82{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 83: func(dstore ds.Datastore) ds.Datastore { + return &ds83{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 84: func(dstore ds.Datastore) ds.Datastore { + return &ds84{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 85: func(dstore ds.Datastore) ds.Datastore { + return &ds85{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 86: func(dstore ds.Datastore) ds.Datastore { + return &ds86{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 87: func(dstore ds.Datastore) ds.Datastore { + return &ds87{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 88: func(dstore ds.Datastore) ds.Datastore { + return &ds88{ + Datastore: dstore, + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 89: func(dstore ds.Datastore) ds.Datastore { + return &ds89{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 90: func(dstore ds.Datastore) ds.Datastore { + return &ds90{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 91: func(dstore ds.Datastore) ds.Datastore { + return &ds91{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 92: func(dstore ds.Datastore) ds.Datastore { + return &ds92{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 93: func(dstore ds.Datastore) ds.Datastore { + return &ds93{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 94: func(dstore ds.Datastore) ds.Datastore { + return &ds94{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 95: func(dstore ds.Datastore) ds.Datastore { + return &ds95{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 96: func(dstore ds.Datastore) ds.Datastore { + return &ds96{ + Datastore: dstore, + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 97: func(dstore ds.Datastore) ds.Datastore { + return &ds97{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 98: func(dstore ds.Datastore) ds.Datastore { + return &ds98{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 99: func(dstore ds.Datastore) ds.Datastore { + return &ds99{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 100: func(dstore ds.Datastore) ds.Datastore { + return &ds100{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 101: func(dstore ds.Datastore) ds.Datastore { + return &ds101{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 102: func(dstore ds.Datastore) ds.Datastore { + return &ds102{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 103: func(dstore ds.Datastore) ds.Datastore { + return &ds103{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 104: func(dstore ds.Datastore) ds.Datastore { + return &ds104{ + Datastore: dstore, + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 105: func(dstore ds.Datastore) ds.Datastore { + return &ds105{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 106: func(dstore ds.Datastore) ds.Datastore { + return &ds106{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 107: func(dstore ds.Datastore) ds.Datastore { + return &ds107{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 108: func(dstore ds.Datastore) ds.Datastore { + return &ds108{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 109: func(dstore ds.Datastore) ds.Datastore { + return &ds109{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 110: func(dstore ds.Datastore) ds.Datastore { + return &ds110{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 111: func(dstore ds.Datastore) ds.Datastore { + return &ds111{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 112: func(dstore ds.Datastore) ds.Datastore { + return &ds112{ + Datastore: dstore, + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 113: func(dstore ds.Datastore) ds.Datastore { + return &ds113{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 114: func(dstore ds.Datastore) ds.Datastore { + return &ds114{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 115: func(dstore ds.Datastore) ds.Datastore { + return &ds115{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 116: func(dstore ds.Datastore) ds.Datastore { + return &ds116{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 117: func(dstore ds.Datastore) ds.Datastore { + return &ds117{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 118: func(dstore ds.Datastore) ds.Datastore { + return &ds118{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 119: func(dstore ds.Datastore) ds.Datastore { + return &ds119{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 120: func(dstore ds.Datastore) ds.Datastore { + return &ds120{ + Datastore: dstore, + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 121: func(dstore ds.Datastore) ds.Datastore { + return &ds121{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 122: func(dstore ds.Datastore) ds.Datastore { + return &ds122{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 123: func(dstore ds.Datastore) ds.Datastore { + return &ds123{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 124: func(dstore ds.Datastore) ds.Datastore { + return &ds124{ + Datastore: dstore, + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 125: func(dstore ds.Datastore) ds.Datastore { + return &ds125{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 126: func(dstore ds.Datastore) ds.Datastore { + return &ds126{ + Datastore: dstore, + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, + 127: func(dstore ds.Datastore) ds.Datastore { + return &ds127{ + Datastore: dstore, + BatchingFeature: dstore.(ds.Batching), + CheckedFeature: dstore.(ds.CheckedDatastore), + GCFeature: dstore.(ds.GCDatastore), + PersistentFeature: dstore.(ds.PersistentDatastore), + ScrubbedFeature: dstore.(ds.ScrubbedDatastore), + TTL: dstore.(ds.TTLDatastore), + TxnFeature: dstore.(ds.TxnDatastore), + } + }, +} diff --git a/scoped/scoped.go b/scoped/scoped.go new file mode 100644 index 0000000..16fad13 --- /dev/null +++ b/scoped/scoped.go @@ -0,0 +1,42 @@ +package scoped + +import ( + ds "github.com/ipfs/go-datastore" +) + +func getFeatureSet(dstore ds.Datastore) map[interface{}]bool { + features := ds.FeaturesForDatastore(dstore) + featureSet := map[interface{}]bool{} + for _, f := range features { + featureSet[f.Interface] = true + } + return featureSet +} + +// Wrap returns a datastore based on the source, whose concrete type is scoped down to only the features supported by the target. +func Wrap(source ds.Datastore, target ds.Datastore) ds.Datastore { + if source == nil || target == nil { + return nil + } + return WithFeatures(source, ds.FeaturesForDatastore(target)) +} + +// WithFeatures returns a wrapped datastore that implements the intersection of the given datastore's features with the provided features. +func WithFeatures(dstore ds.Datastore, features []ds.Feature) ds.Datastore { + dstoreFeatures := getFeatureSet(dstore) + + dstoreFeatureSet := map[string]bool{} + for _, f := range features { + if _, ok := dstoreFeatures[f.Interface]; ok { + dstoreFeatureSet[f.Name] = true + } + } + + ctor := 0 + for i, f := range ds.Features() { + if _, ok := dstoreFeatureSet[f.Name]; ok { + ctor += (1 << i) + } + } + return ctors[ctor](dstore) +} diff --git a/scoped/scoped_test.go b/scoped/scoped_test.go new file mode 100644 index 0000000..7db922c --- /dev/null +++ b/scoped/scoped_test.go @@ -0,0 +1,61 @@ +package scoped + +import ( + "reflect" + "testing" + + ds "github.com/ipfs/go-datastore" +) + +func TestWithFeatures(t *testing.T) { + cases := []struct { + name string + dstore ds.Datastore + features []ds.Feature + + expectedFeatures []ds.Feature + }{ + { + name: "no features should return a base datastore", + dstore: &ds.MapDatastore{}, + features: nil, + expectedFeatures: nil, + }, + { + name: "identity case", + dstore: &ds.MapDatastore{}, + features: ds.FeaturesByNames("Batching"), + expectedFeatures: ds.FeaturesByNames("Batching"), + }, + { + name: "should scope down correctly", + dstore: &ds.LogDatastore{}, + features: ds.FeaturesByNames("Batching"), + expectedFeatures: ds.FeaturesByNames("Batching"), + }, + { + name: "takes intersection of features", + dstore: &ds.MapDatastore{}, + features: ds.FeaturesByNames("Batching", "Checked"), + expectedFeatures: ds.FeaturesByNames("Batching"), + }, + { + name: "uses correct impl even if features are not canonically sorted", + dstore: &ds.NullDatastore{}, + features: ds.FeaturesByNames("Checked", "Batching", "Scrubbed"), + expectedFeatures: ds.FeaturesByNames("Batching", "Checked", "Scrubbed"), + }, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + new := WithFeatures(c.dstore, c.features) + newFeats := ds.FeaturesForDatastore(new) + if len(newFeats) != len(c.expectedFeatures) { + t.Fatalf("expected %d features, got %v", len(c.expectedFeatures), newFeats) + } + if !reflect.DeepEqual(newFeats, c.expectedFeatures) { + t.Fatalf("expected features %v, got %v", c.expectedFeatures, newFeats) + } + }) + } +}