@@ -49,36 +49,34 @@ var (
4949 }
5050)
5151
52- // Config holds datastore client configuration.
53- type Config struct {
54- // AuthConfig is passed to the auth package for authentication.
55- // Can be nil to use defaults.
56- AuthConfig * auth.Config
57-
58- // APIURL is the base URL for the Datastore API.
59- // Defaults to production if empty.
60- APIURL string
61- }
52+ // ClientOption is an option for a Datastore client.
53+ type ClientOption func (* clientOptionsInternal )
6254
63- // configKey is the key for storing Config in context.
64- type configKey struct {}
55+ // clientOptionsInternal holds internal client configuration that can be modified by ClientOption.
56+ type clientOptionsInternal struct {
57+ authConfig * auth.Config
58+ logger * slog.Logger
59+ baseURL string
60+ }
6561
66- // WithConfig returns a new context with the given datastore config.
67- // This also sets the auth config if provided.
68- func WithConfig (ctx context.Context , cfg * Config ) context.Context {
69- if cfg .AuthConfig != nil {
70- ctx = auth .WithConfig (ctx , cfg .AuthConfig )
62+ // WithEndpoint returns a ClientOption that sets the API base URL.
63+ func WithEndpoint (url string ) ClientOption {
64+ return func (o * clientOptionsInternal ) {
65+ o .baseURL = url
7166 }
72- return context .WithValue (ctx , configKey {}, cfg )
7367}
7468
75- // getConfig retrieves the datastore config from context, or returns defaults .
76- func getConfig ( ctx context. Context ) * Config {
77- if cfg , ok := ctx . Value ( configKey {}).( * Config ); ok && cfg != nil {
78- return cfg
69+ // WithLogger returns a ClientOption that sets the logger .
70+ func WithLogger ( logger * slog. Logger ) ClientOption {
71+ return func ( o * clientOptionsInternal ) {
72+ o . logger = logger
7973 }
80- return & Config {
81- APIURL : defaultAPIURL ,
74+ }
75+
76+ // WithAuth returns a ClientOption that sets the authentication configuration.
77+ func WithAuth (cfg * auth.Config ) ClientOption {
78+ return func (o * clientOptionsInternal ) {
79+ o .authConfig = cfg
8280 }
8381}
8482
@@ -93,37 +91,52 @@ type Client struct {
9391
9492// NewClient creates a new Datastore client.
9593// If projectID is empty, it will be fetched from the GCP metadata server.
96- // Configuration can be provided via WithConfig in the context .
97- func NewClient (ctx context.Context , projectID string ) (* Client , error ) {
98- return NewClientWithDatabase (ctx , projectID , "" )
94+ // Options can be provided to configure the client .
95+ func NewClient (ctx context.Context , projectID string , opts ... ClientOption ) (* Client , error ) {
96+ return NewClientWithDatabase (ctx , projectID , "" , opts ... )
9997}
10098
10199// NewClientWithDatabase creates a new Datastore client with a specific database.
102- // Configuration can be provided via WithConfig in the context.
103- func NewClientWithDatabase (ctx context.Context , projID , dbID string ) (* Client , error ) {
104- logger := slog .Default ()
105- cfg := getConfig (ctx )
100+ // Options can be provided to configure the client.
101+ func NewClientWithDatabase (ctx context.Context , projID , dbID string , opts ... ClientOption ) (* Client , error ) {
102+ // Apply default internal options
103+ options := & clientOptionsInternal {
104+ baseURL : defaultAPIURL ,
105+ logger : slog .Default (),
106+ }
107+
108+ // Apply provided options
109+ for _ , opt := range opts {
110+ opt (options )
111+ }
106112
113+ // --- Existing NewClientWithDatabase logic starts here ---
107114 if projID == "" {
115+ // Inject auth config into context before fetching project ID
116+ fetchCtx := ctx
117+ if options .authConfig != nil {
118+ fetchCtx = auth .WithConfig (ctx , options .authConfig )
119+ }
120+
108121 if ! testing .Testing () {
109- logger .InfoContext (ctx , "project ID not provided, fetching from metadata server" )
122+ options . logger .InfoContext (ctx , "project ID not provided, fetching from metadata server" )
110123 }
111- pid , err := auth .ProjectID (ctx )
124+ pid , err := auth .ProjectID (fetchCtx )
112125 if err != nil {
113- logger .ErrorContext (ctx , "failed to get project ID from metadata server" , "error" , err )
126+ options . logger .ErrorContext (ctx , "failed to get project ID from metadata server" , "error" , err )
114127 return nil , fmt .Errorf ("project ID required: %w" , err )
115128 }
116129 projID = pid
117130 if ! testing .Testing () {
118- logger .InfoContext (ctx , "fetched project ID from metadata server" , "project_id" , projID )
131+ options . logger .InfoContext (ctx , "fetched project ID from metadata server" , "project_id" , projID )
119132 }
120133 }
121134
122135 if ! testing .Testing () {
123- logger .InfoContext (ctx , "creating datastore client" , "project_id" , projID , "database_id" , dbID )
136+ options . logger .InfoContext (ctx , "creating datastore client" , "project_id" , projID , "database_id" , dbID )
124137 }
125138
126- baseURL := cfg . APIURL
139+ baseURL := options . baseURL
127140 if baseURL == "" {
128141 baseURL = defaultAPIURL
129142 }
@@ -132,8 +145,8 @@ func NewClientWithDatabase(ctx context.Context, projID, dbID string) (*Client, e
132145 projectID : projID ,
133146 databaseID : dbID ,
134147 baseURL : baseURL ,
135- authConfig : cfg . AuthConfig ,
136- logger : logger ,
148+ authConfig : options . authConfig , // Use authConfig from options
149+ logger : options . logger , // Use logger from options
137150 }, nil
138151}
139152
0 commit comments