Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(432)

Unified Diff: doc.go

Issue 1259593005: Add 'user friendly' datastore API. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: more docs Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | filter/count/count_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « no previous file | filter/count/count_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698