11package datasource
22
33import (
4+ "context"
45 "database/sql"
56 "fmt"
67 "sync"
@@ -14,28 +15,45 @@ import (
1415 "github.com/grafana/sqlds/v3"
1516)
1617
17- // AWSDatasource stores a cache of several instances.
18+ // AWSClient provides creation and caching of sessions, database connections, and API clients
19+ type AWSClient interface {
20+ Init (config backend.DataSourceInstanceSettings )
21+ GetDB (ctx context.Context , id int64 , options sqlds.Options ) (* sql.DB , error )
22+ GetAsyncDB (ctx context.Context , id int64 , options sqlds.Options ) (awsds.AsyncDB , error )
23+ GetAPI (ctx context.Context , id int64 , options sqlds.Options ) (api.AWSAPI , error )
24+ }
25+
26+ type Loader interface {
27+ LoadSettings (context.Context ) models.Settings
28+ LoadAPI (context.Context , * awsds.SessionCache , models.Settings ) (api.AWSAPI , error )
29+ LoadDriver (context.Context , api.AWSAPI ) (driver.Driver , error )
30+ LoadAsyncDriver (context.Context , api.AWSAPI ) (asyncDriver.Driver , error )
31+ }
32+
33+ // awsClient provides creation and caching of several types of instances.
1834// Each Map will depend on the datasource ID (and connection options):
1935// - sessionCache: AWS cache. This is not a Map since it does not depend on the datasource.
2036// - config: Base configuration. It will be used as base to populate datasource settings.
2137// It does not depend on connection options (only one per datasource)
2238// - api: API instance with the common methods to contact the data source API.
23- type AWSDatasource struct {
39+ type awsClient struct {
2440 sessionCache * awsds.SessionCache
2541 config sync.Map
2642 api sync.Map
43+
44+ loader Loader
2745}
2846
29- func New () * AWSDatasource {
30- ds := & AWSDatasource {sessionCache : awsds .NewSessionCache ()}
47+ func New (loader Loader ) AWSClient {
48+ ds := & awsClient {sessionCache : awsds .NewSessionCache (), loader : loader }
3149 return ds
3250}
3351
34- func (ds * AWSDatasource ) storeConfig (config backend.DataSourceInstanceSettings ) {
52+ func (ds * awsClient ) storeConfig (config backend.DataSourceInstanceSettings ) {
3553 ds .config .Store (config .ID , config )
3654}
3755
38- func (ds * AWSDatasource ) createDB (dr driver.Driver ) (* sql.DB , error ) {
56+ func (ds * awsClient ) createDB (dr driver.Driver ) (* sql.DB , error ) {
3957 db , err := dr .OpenDB ()
4058 if err != nil {
4159 return nil , fmt .Errorf ("%w: failed to connect to database (check hostname and port?)" , err )
@@ -44,7 +62,7 @@ func (ds *AWSDatasource) createDB(dr driver.Driver) (*sql.DB, error) {
4462 return db , nil
4563}
4664
47- func (ds * AWSDatasource ) createAsyncDB (dr asyncDriver.Driver ) (awsds.AsyncDB , error ) {
65+ func (ds * awsClient ) createAsyncDB (dr asyncDriver.Driver ) (awsds.AsyncDB , error ) {
4866 db , err := dr .GetAsyncDB ()
4967 if err != nil {
5068 return nil , fmt .Errorf ("%w: failed to connect to database (check hostname and port)" , err )
@@ -53,12 +71,12 @@ func (ds *AWSDatasource) createAsyncDB(dr asyncDriver.Driver) (awsds.AsyncDB, er
5371 return db , nil
5472}
5573
56- func (ds * AWSDatasource ) storeAPI (id int64 , args sqlds.Options , dsAPI api.AWSAPI ) {
74+ func (ds * awsClient ) storeAPI (id int64 , args sqlds.Options , dsAPI api.AWSAPI ) {
5775 key := connectionKey (id , args )
5876 ds .api .Store (key , dsAPI )
5977}
6078
61- func (ds * AWSDatasource ) loadAPI (id int64 , args sqlds.Options ) (api.AWSAPI , bool ) {
79+ func (ds * awsClient ) loadAPI (id int64 , args sqlds.Options ) (api.AWSAPI , bool ) {
6280 key := connectionKey (id , args )
6381 dsAPI , exists := ds .api .Load (key )
6482 if exists {
@@ -67,34 +85,34 @@ func (ds *AWSDatasource) loadAPI(id int64, args sqlds.Options) (api.AWSAPI, bool
6785 return nil , false
6886}
6987
70- func (ds * AWSDatasource ) createAPI (id int64 , args sqlds.Options , settings models.Settings , loader api. Loader ) (api.AWSAPI , error ) {
71- dsAPI , err := loader ( ds .sessionCache , settings )
88+ func (ds * awsClient ) createAPI (ctx context. Context , id int64 , args sqlds.Options , settings models.Settings ) (api.AWSAPI , error ) {
89+ dsAPI , err := ds . loader . LoadAPI ( ctx , ds .sessionCache , settings )
7290 if err != nil {
7391 return nil , fmt .Errorf ("%w: Failed to create client" , err )
7492 }
7593 ds .storeAPI (id , args , dsAPI )
7694 return dsAPI , err
7795}
7896
79- func (ds * AWSDatasource ) createDriver (dsAPI api. AWSAPI , loader driver. Loader ) (driver.Driver , error ) {
80- dr , err := loader ( dsAPI )
97+ func (ds * awsClient ) createDriver (ctx context. Context , dsAPI api. AWSAPI ) (driver.Driver , error ) {
98+ dr , err := ds . loader . LoadDriver ( ctx , dsAPI )
8199 if err != nil {
82100 return nil , fmt .Errorf ("%w: Failed to create client" , err )
83101 }
84102
85103 return dr , nil
86104}
87105
88- func (ds * AWSDatasource ) createAsyncDriver (dsAPI api. AWSAPI , loader asyncDriver. Loader ) (asyncDriver.Driver , error ) {
89- dr , err := loader ( dsAPI )
106+ func (ds * awsClient ) createAsyncDriver (ctx context. Context , dsAPI api. AWSAPI ) (asyncDriver.Driver , error ) {
107+ dr , err := ds . loader . LoadAsyncDriver ( ctx , dsAPI )
90108 if err != nil {
91109 return nil , fmt .Errorf ("%w: Failed to create client" , err )
92110 }
93111
94112 return dr , nil
95113}
96114
97- func (ds * AWSDatasource ) parseSettings (id int64 , args sqlds.Options , settings models.Settings ) error {
115+ func (ds * awsClient ) parseSettings (id int64 , args sqlds.Options , settings models.Settings ) error {
98116 config , ok := ds .config .Load (id )
99117 if ! ok {
100118 return fmt .Errorf ("unable to find stored configuration for datasource %d. Initialize it first" , id )
@@ -108,31 +126,29 @@ func (ds *AWSDatasource) parseSettings(id int64, args sqlds.Options, settings mo
108126}
109127
110128// Init stores the data source configuration. It's needed for the GetDB and GetAPI functions
111- func (ds * AWSDatasource ) Init (config backend.DataSourceInstanceSettings ) {
129+ func (ds * awsClient ) Init (config backend.DataSourceInstanceSettings ) {
112130 ds .storeConfig (config )
113131}
114132
115133// GetDB returns a *sql.DB. It will use the loader functions to initialize the required
116134// settings, API and driver and finally create a DB.
117- func (ds * AWSDatasource ) GetDB (
135+ func (ds * awsClient ) GetDB (
136+ ctx context.Context ,
118137 id int64 ,
119138 options sqlds.Options ,
120- settingsLoader models.Loader ,
121- apiLoader api.Loader ,
122- driverLoader driver.Loader ,
123139) (* sql.DB , error ) {
124- settings := settingsLoader ( )
140+ settings := ds . loader . LoadSettings ( ctx )
125141 err := ds .parseSettings (id , options , settings )
126142 if err != nil {
127143 return nil , err
128144 }
129145
130- dsAPI , err := ds .createAPI (id , options , settings , apiLoader )
146+ dsAPI , err := ds .createAPI (ctx , id , options , settings )
131147 if err != nil {
132148 return nil , err
133149 }
134150
135- dr , err := ds .createDriver (dsAPI , driverLoader )
151+ dr , err := ds .createDriver (ctx , dsAPI )
136152 if err != nil {
137153 return nil , err
138154 }
@@ -142,25 +158,23 @@ func (ds *AWSDatasource) GetDB(
142158
143159// GetAsyncDB returns a sqlds.AsyncDB. It will use the loader functions to initialize the required
144160// settings, API and driver and finally create a DB.
145- func (ds * AWSDatasource ) GetAsyncDB (
161+ func (ds * awsClient ) GetAsyncDB (
162+ ctx context.Context ,
146163 id int64 ,
147164 options sqlds.Options ,
148- settingsLoader models.Loader ,
149- apiLoader api.Loader ,
150- driverLoader asyncDriver.Loader ,
151165) (awsds.AsyncDB , error ) {
152- settings := settingsLoader ( )
166+ settings := ds . loader . LoadSettings ( ctx )
153167 err := ds .parseSettings (id , options , settings )
154168 if err != nil {
155169 return nil , err
156170 }
157171
158- dsAPI , err := ds .createAPI (id , options , settings , apiLoader )
172+ dsAPI , err := ds .createAPI (ctx , id , options , settings )
159173 if err != nil {
160174 return nil , err
161175 }
162176
163- dr , err := ds .createAsyncDriver (dsAPI , driverLoader )
177+ dr , err := ds .createAsyncDriver (ctx , dsAPI )
164178 if err != nil {
165179 return nil , err
166180 }
@@ -171,22 +185,21 @@ func (ds *AWSDatasource) GetAsyncDB(
171185// GetAPI returns an API interface. When called multiple times with the same id and options, it
172186// will return a cached version of the API. The first time, it will use the loader
173187// functions to initialize the required settings and API.
174- func (ds * AWSDatasource ) GetAPI (
188+ func (ds * awsClient ) GetAPI (
189+ ctx context.Context ,
175190 id int64 ,
176191 options sqlds.Options ,
177- settingsLoader models.Loader ,
178- apiLoader api.Loader ,
179192) (api.AWSAPI , error ) {
180193 cachedAPI , exists := ds .loadAPI (id , options )
181194 if exists {
182195 return cachedAPI , nil
183196 }
184197
185198 // create new api
186- settings := settingsLoader ( )
199+ settings := ds . loader . LoadSettings ( ctx )
187200 err := ds .parseSettings (id , options , settings )
188201 if err != nil {
189202 return nil , err
190203 }
191- return ds .createAPI (id , options , settings , apiLoader )
204+ return ds .createAPI (ctx , id , options , settings )
192205}
0 commit comments