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 |