-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathglobal.go
More file actions
78 lines (68 loc) · 3.26 KB
/
global.go
File metadata and controls
78 lines (68 loc) · 3.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package platform
import (
"context"
chi "github.com/go-chi/chi/v5"
"github.com/jmoiron/sqlx"
"github.com/titpetric/platform/internal"
"github.com/titpetric/platform/pkg/telemetry"
)
// global is a value to prevent pollution of the global package namespace.
// for testing purposes the global state should be empty. The state is
// cloned as necessary into the *Platform object, on server creation.
var global = struct {
registry *Registry
db *internal.DatabaseProvider
}{
registry: &Registry{},
db: internal.NewDatabaseProvider(telemetry.Open),
}
// Router is a local shim that aliases the chi router interface.
type Router = chi.Router
// DatabaseProvider is the implementation interface for working with named connections.
// If no connection name is passed, the "default" connection will be used.
// There's no assumption to how the database connection is provided, and
// the interface supports using external providers, enforces context awareness.
//
// The connection names, singleton behaviour, retries, fallback mechanisms,
// multiple-name logic and everything else to produce a *sql.DB is left to
// the implementation. The first party implementation uses the process environment
// and decodes `PLATFORM_DB_*` and uses the environment variable name for the key
// and the definition of the connection. It doesn't carry other logic like
// reconnecting.
//
// It's also likely that the first party database provider will be a public
// API package in the future. I'd like this to be swappable so people can
// bring in something like AWS secretsmanager or vault, or other.
type DatabaseProvider interface {
// Open takes a context, a different implementation may use it for context awareness.
// For example, Open may retrieve connection details from the database. The context
// is used for tracing that operation, and the error returned may be the
// result of a query issued against the database.
Open(ctx context.Context, names ...string) (*sqlx.DB, error)
// Connect has the semantics of Open + PingContext against the database,
// verifying that the connection is live. An error is returned if
// the storage is unreachable.
//
// A real database provider options may dictate additional behaviour.
// For example, if a connection fails, it may retry a number of times,
// it may back-off, it may continue to retry the connection in a
// blocking way. It may also grab additional fail-over information from
// keys based on the input parameters. An example of that would be to
// define `name` and `name/failover` connections. If the connection to
// the first fails, the second upstream is used.
Connect(ctx context.Context, names ...string) (*sqlx.DB, error)
}
// Database is a holder of the database provider api in package namespace.
var Database DatabaseProvider = global.db
// Register will register a module in the platform global registry.
// It should not be relied upon in tests, keeping global state empty.
// This enables registering modules using blank imports.
func Register(m Module) {
global.registry.Register(m)
}
// Use will add a middleware to the platform router.
// It should not be relied upon in tests, keeping global state empty.
// This should be used from main() to define any global middleware.
func Use(mw Middleware) {
global.registry.Use(mw)
}