| Index: doc.go
|
| diff --git a/doc.go b/doc.go
|
| index f33019758deb1629e2728c96313290071c1b96f3..0131c449d5d974a233bb9140752c1f22d77c3d66 100644
|
| --- a/doc.go
|
| +++ b/doc.go
|
| @@ -9,13 +9,10 @@
|
| // Features
|
| //
|
| // gae currently provides interfaces for:
|
| -// - RawDatastore (a less reflection-magic version of Datastore)
|
| +// - Datastore
|
| // - Memcache
|
| // - TaskQueue
|
| -// - GlobalInfo (e.g. Namespace, AppID, etc.)
|
| -//
|
| -// In addition, it provides a 'Datastore' service which adds all the reflection
|
| -// magic of the original SDK's datastore package on top of RawDatastore.
|
| +// - Info (e.g. Namespace, AppID, etc.)
|
| //
|
| // Additional features include:
|
| // - true service interfaces (not package-level functions)
|
| @@ -28,6 +25,9 @@
|
| // - transparent retries
|
| // - truly parallel in-memory testing implementation. No more need for
|
| // dev_appserver.py subprocesses :).
|
| +// - Separate service and user-facing interfaces
|
| +// - Allows easier filter and service implementation while retaining the
|
| +// benefits of a user-friendly interface.
|
| //
|
| // Package Organization
|
| //
|
| @@ -46,7 +46,7 @@
|
| // "net/http"
|
| //
|
| // "github.com/luci/gae/impl/prod"
|
| -// "github.com/luci/gae/service/rawdatastore"
|
| +// "github.com/luci/gae/service/datastore"
|
| // "golang.org/x/net/context"
|
| // )
|
| //
|
| @@ -56,16 +56,19 @@
|
| // innerHandler(c, w)
|
| // }
|
| //
|
| +// type CoolStruct struct {
|
| +// ID `gae:"$id"`
|
| +//
|
| +// Value string
|
| +// }
|
| +//
|
| // func innerHandler(c context.Context, w http.ResponseWriter) {
|
| -// rds := rawdatastore.Get(c)
|
| -// data := rawdatastore.PropertyMap{
|
| -// "Value": {rawdatastore.MkProperty("hello")},
|
| -// }
|
| -// newKey, err := rds.Put(rds.NewKey("Kind", "", 0, nil), data)
|
| -// if err != nil {
|
| +// rds := datastore.Get(c)
|
| +// obj := &CoolStruct{Value: "hello"}
|
| +// if err := rds.Put(obj); err != nil {
|
| // http.Error(w, err.String(), http.StatusInternalServerError)
|
| // }
|
| -// fmt.Fprintf(w, "I wrote: %s", newKey)
|
| +// fmt.Fprintf(w, "I wrote: %s", ds.KeyForObj(obj))
|
| // }
|
| //
|
| // And in your test do:
|
| @@ -76,16 +79,16 @@
|
| // "net/http"
|
| //
|
| // "github.com/luci/gae/impl/memory"
|
| -// "github.com/luci/gae/service/rawdatastore"
|
| +// "github.com/luci/gae/service/datastore"
|
| // "golang.org/x/net/context"
|
| // )
|
| //
|
| // func TestHandler(t *testing.T) {
|
| // t.Parallel()
|
| // c := memory.Use(context.Background())
|
| -// // use rawdatastore here to monkey with the database, install
|
| -// // testing filters like featureBreaker to test error conditions in
|
| -// // innerHandler, etc.
|
| +// // use datastore here to monkey with the database, install testing
|
| +// // filters like featureBreaker to test error conditions in innerHandler,
|
| +// // etc.
|
| // innerHandler(c, ...)
|
| // }
|
| //
|
| @@ -95,23 +98,46 @@
|
| // user-facing interface for a service. Each service has a few common types and
|
| // functions. Common types are:
|
| //
|
| -// service.Interface - the main service interface
|
| -// service.Testable - any additional methods that a 'testing' implementation
|
| -// should provide. It's expected that tests will cast
|
| -// the Interface from Get() to Testable in order to
|
| -// access these methods.
|
| -// service.Factory - a function returning an Interface
|
| -// service.Filter - a function returning a new Interface based on the
|
| -// previous filtered interface.
|
| +// service.Interface - the main user-friendly service interface.
|
| +//
|
| +// service.RawInterface - the internal service interface used by service
|
| +// and filter implementations. Note that some services
|
| +// like Info don't distinguish between the service
|
| +// interface and the user interface.
|
| +//
|
| +// service.Testable - any additional methods that a 'testing'
|
| +// implementation should provide. It's expected that
|
| +// tests will cast the RawInterface from GetRaw() to
|
| +// Testable in order to access these methods.
|
| +//
|
| +// service.RawFactory - a function returning a RawInterface
|
| +//
|
| +// service.RawFilter - a function returning a new RawInterface based on
|
| +// the previous filtered interface. Filters chain
|
| +// together to allow behavioral service features
|
| +// without needing to agument the underlying service
|
| +// implementations directly.
|
| //
|
| // And common functions are:
|
| -// service.Get - Retrieve the current, filtered Interface
|
| -// implementation from the context. This is the most
|
| -// frequently used service function by far.
|
| -// service.AddFilters - adds one or more Filters to the context.
|
| -// service.SetFactory - adds a Factory to the context
|
| -// service.Set - adds an implementation of Interface to the context
|
| -// (shorthand for SetFactory, useful for testing)
|
| +// service.Get - Retrieve the current, filtered Interface
|
| +// implementation from the context. This is the most
|
| +// frequently used service function by far.
|
| +//
|
| +// service.GetRaw - Retrieve the current, filtered RawInterface
|
| +// implementation from the context. This is less
|
| +// frequently used, but can be useful if you want to
|
| +// avoid some of the overhead of the user-friendly
|
| +// Interface, which can do sometimes-unnecessary amounts
|
| +// of reflection or allocation. The RawInterface and
|
| +// Interface for a service are fully interchangable and
|
| +// usage of them can be freely mixed in an application.
|
| +//
|
| +// service.AddRawFilters - adds one or more Filters to the context.
|
| +//
|
| +// service.SetRawFactory - adds a Factory to the context
|
| +//
|
| +// service.SetRaw - adds an implementation of RawInterface to the context
|
| +// (shorthand for SetRawFactory, useful for testing)
|
| //
|
| // Implementations
|
| //
|
| @@ -127,6 +153,11 @@
|
| // the services' Testable interface, for those services which define those
|
| // interfaces.
|
| //
|
| +// 'dummy' provides a bunch of implementations of the various RawInterfaces.
|
| +// These implementations just panic with an appropriate message, depending on
|
| +// which API method was called. They're useful to embed in filter or service
|
| +// implementations as stubs while you're implementing the filter.
|
| +//
|
| // Usage
|
| //
|
| // You will typically access one of the service interfaces in your code like:
|
| @@ -143,44 +174,38 @@
|
| // }
|
| //
|
| // func CoolFunc(c context.Context, ...) {
|
| -// rds := gae.GetRDS(c) // returns a RawDatastore object
|
| -// mc := gae.GetMC(c) // returns a Memcache object
|
| +// ds := datastore.Get(c) // returns a datastore.Interface object
|
| +// mc := memcache.Get(c) // returns a memcache.Interface object
|
| // // use them here
|
| //
|
| -// // don't pass rds/mc/etc. directly, pass the context instead.
|
| +// // don't pass ds/mc/etc. directly, pass the context instead.
|
| // SomeOtherFunction(c, ...)
|
| //
|
| // // because you might need to:
|
| -// rds.RunInTransaction(func (c context.Context) error {
|
| -// SomeOtherFunction(c, ...) // c contains transaction versions of everything
|
| +// ds.RunInTransaction(func (c context.Context) error {
|
| +// SomeOtherFunction(c, ...) // c contains transactional versions of everything
|
| // }, nil)
|
| // }
|
| //
|
| -// RawDatastore struct serialization is provided by the `rawdatastore`
|
| -// subpackage. All supported struct types and interfaces are provided in this
|
| -// package, however. You can operate without any struct
|
| -// serizialization/reflection by exclusively using PropertyMap. A goon-style
|
| -// Datastore interface is also provided in the `datastore` service package.
|
| -//
|
| // Filters
|
| //
|
| // Each service also supports "filters". Filters are proxy objects which have
|
| // the same interface as the service they're filtering, and pass data through to
|
| // the previous filter in the stack. Conceptually, a filtered version of, for
|
| -// example, the RawDatastore, could look like:
|
| +// example, the Datastore, could look like:
|
| // User code
|
| // <count filter (counts how many times each API is called by the user)>
|
| -// <mcache filter (attempts to use memcache as a cache for rawdatastore)>
|
| +// <dscache filter (attempts to use memcache as a cache for datastore)>
|
| // <count filter (counts how many times each API is actually hit)>
|
| -// memory RawDatastore implementation
|
| +// memory datastore.RawInterface implementation
|
| //
|
| -// So rawdatastore.Get would return the full stack. In code, this would look
|
| +// So datastore.Get would return the full stack. In code, this would look
|
| // like:
|
| // func HTTPHandler(r *http.Request) {
|
| -// c := prod.Use(appengine.NewContext(r)) // production datastore
|
| -// c, rawCount := count.FilterRDS() // add count filter
|
| -// c = mcache.FilterRDS(c) // add mcache filter
|
| -// c, userCount := count.FilterRDS() // add another count filter
|
| +// c := prod.UseRequest(r) // production datastore
|
| +// c, rawCount := count.FilterRDS(c) // add count filter
|
| +// c = dscache.FilterRDS(c) // add dscache filter
|
| +// c, userCount := count.FilterRDS(c) // add another count filter
|
| // }
|
| //
|
| // Filters may or may not have state, it's up to the filter itself. In the case
|
| @@ -189,4 +214,9 @@
|
| // Since filters stack, we can compare counts from rawCount versus userCount to
|
| // see how many calls to the actual real datastore went through, vs. how many
|
| // went to memcache, for example.
|
| +//
|
| +// Note that Filters apply only to the service.RawInterface. All implementations
|
| +// of service.Interface boil down to calls to service.RawInterface methods, but
|
| +// it's possible that bad calls to the service.Interface methods could return
|
| +// an error before ever reaching the filters or service implementation.
|
| package gae
|
|
|