Skip to content

Commit cb38d3f

Browse files
authored
Merge pull request #96 from questdb/change-config-field-types
Update datasource config field types
2 parents 16d3683 + 8aa2310 commit cb38d3f

File tree

8 files changed

+279
-234
lines changed

8 files changed

+279
-234
lines changed

pkg/plugin/driver.go

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import (
55
"database/sql"
66
"encoding/json"
77
"fmt"
8-
sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
9-
"github.com/lib/pq"
10-
"golang.org/x/net/proxy"
118
"net"
129
"strconv"
1310
"strings"
1411
"time"
1512

13+
sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
14+
"github.com/lib/pq"
15+
"golang.org/x/net/proxy"
16+
1617
"github.com/grafana/grafana-plugin-sdk-go/backend"
1718
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
1819
"github.com/grafana/grafana-plugin-sdk-go/build"
@@ -106,14 +107,10 @@ func GenerateConnectionString(settings Settings, version string) (string, error)
106107
connStr += fmt.Sprintf(" application_name='%s'", version)
107108
}
108109

109-
if len(settings.Timeout) > 0 {
110-
t, err := strconv.Atoi(settings.Timeout)
111-
if err != nil {
112-
return "", errors.New(fmt.Sprintf("invalid timeout: %s", settings.Timeout))
113-
}
114-
115-
if t > -1 {
116-
connStr += fmt.Sprintf(" connect_timeout=%d", t)
110+
if settings.Timeout > 0 {
111+
t := strconv.Itoa(int(settings.Timeout))
112+
if i, err := strconv.Atoi(t); err == nil && i > -1 {
113+
connStr += fmt.Sprintf(" connect_timeout=%d", i)
117114
}
118115
}
119116

@@ -220,7 +217,7 @@ func (h *QuestDB) Settings(config backend.DataSourceInstanceSettings) sqlds.Driv
220217
settings, err := LoadSettings(config)
221218
timeout := 60
222219
if err == nil {
223-
t, err := strconv.Atoi(settings.QueryTimeout)
220+
t, err := strconv.Atoi(strconv.FormatInt(settings.QueryTimeout, 10))
224221
if err == nil {
225222
timeout = t
226223
}

pkg/plugin/settings.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ type Settings struct {
2222
TlsClientCert string
2323
TlsClientKey string
2424

25-
Timeout string `json:"timeout,omitempty"`
26-
QueryTimeout string `json:"queryTimeout,omitempty"`
25+
Timeout int64 `json:"timeout,omitempty"`
26+
QueryTimeout int64 `json:"queryTimeout,omitempty"`
2727
ProxyOptions *proxy.Options
2828
MaxOpenConnections int64 `json:"maxOpenConnections,omitempty"`
2929
MaxIdleConnections int64 `json:"maxIdleConnections,omitempty"`
@@ -83,22 +83,28 @@ func LoadSettings(config backend.DataSourceInstanceSettings) (settings Settings,
8383
}
8484

8585
if jsonData["timeout"] != nil {
86-
settings.Timeout = jsonData["timeout"].(string)
86+
if val, ok := jsonData["timeout"].(string); ok {
87+
timeout, err := strconv.ParseInt(val, 0, 64)
88+
if err != nil {
89+
return settings, fmt.Errorf("could not parse timeout value: %w", err)
90+
}
91+
settings.Timeout = timeout
92+
}
93+
if val, ok := jsonData["timeout"].(float64); ok {
94+
settings.Timeout = int64(val)
95+
}
8796
}
8897
if jsonData["queryTimeout"] != nil {
89-
if val, ok := jsonData["queryTimeout"].(string); ok {
98+
if val, ok := jsonData["queryTimeout"].(int64); ok {
9099
settings.QueryTimeout = val
91100
}
92101
if val, ok := jsonData["queryTimeout"].(float64); ok {
93-
settings.QueryTimeout = fmt.Sprintf("%d", int64(val))
102+
settings.QueryTimeout = int64(val)
94103
}
95104
}
96105

97-
if strings.TrimSpace(settings.Timeout) == "" {
98-
settings.Timeout = "10"
99-
}
100-
if strings.TrimSpace(settings.QueryTimeout) == "" {
101-
settings.QueryTimeout = "60"
106+
if strings.TrimSpace(strconv.FormatInt(settings.QueryTimeout, 10)) == "" {
107+
settings.QueryTimeout = 60
102108
}
103109
password, ok := config.DecryptedSecureJSONData["password"]
104110
if ok {
@@ -140,7 +146,7 @@ func LoadSettings(config backend.DataSourceInstanceSettings) (settings Settings,
140146

141147
if err == nil && proxyOpts != nil {
142148
// the sdk expects the timeout to not be a string
143-
timeout, err := strconv.ParseFloat(settings.Timeout, 64)
149+
timeout, err := strconv.ParseFloat(strconv.FormatInt(settings.Timeout, 10), 64)
144150
if err == nil {
145151
proxyOpts.Timeouts.Timeout = (time.Duration(timeout) * time.Second)
146152
}

pkg/plugin/settings_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestLoadSettings(t *testing.T) {
2828
args: args{
2929
config: backend.DataSourceInstanceSettings{
3030
UID: "ds-uid",
31-
JSONData: []byte(`{ "server": "test", "port": 8812, "username": "john", "timeout": "10", "queryTimeout": "50",
31+
JSONData: []byte(`{ "server": "test", "port": 8812, "username": "john", "timeout": 10, "queryTimeout": 50,
3232
"enableSecureSocksProxy": false, "tlsMode": "disable",
3333
"maxOpenConnections": 100, "maxIdleConnections": 100, "maxConnectionLifetime": 14400 }`),
3434
DecryptedSecureJSONData: map[string]string{"password": "doe"},
@@ -39,8 +39,8 @@ func TestLoadSettings(t *testing.T) {
3939
Port: 8812,
4040
Username: "john",
4141
Password: "doe",
42-
Timeout: "10",
43-
QueryTimeout: "50",
42+
Timeout: 10,
43+
QueryTimeout: 50,
4444
MaxOpenConnections: 100,
4545
MaxIdleConnections: 100,
4646
MaxConnectionLifetime: 14400,
@@ -53,7 +53,7 @@ func TestLoadSettings(t *testing.T) {
5353
args: args{
5454
config: backend.DataSourceInstanceSettings{
5555
UID: "ds-uid",
56-
JSONData: []byte(`{ "server": "test", "port": 1000, "username": "john", "timeout": "10", "queryTimeout": "50",
56+
JSONData: []byte(`{ "server": "test", "port": 1000, "username": "john", "timeout": 10, "queryTimeout": 50,
5757
"enableSecureSocksProxy": true, "tlsMode": "verify-full", "tlsConfigurationMethod": "file-content",
5858
"maxOpenConnections": 100, "maxIdleConnections": 100, "maxConnectionLifetime": 14400 }`),
5959
DecryptedSecureJSONData: map[string]string{"password": "doe", "tlsCACert": "caCert", "tlsClientCert": "clientCert", "tlsClientKey": "clientKey", "secureSocksProxyPassword": "test"},
@@ -67,8 +67,8 @@ func TestLoadSettings(t *testing.T) {
6767
TlsCACert: "caCert",
6868
TlsClientCert: "clientCert",
6969
TlsClientKey: "clientKey",
70-
Timeout: "10",
71-
QueryTimeout: "50",
70+
Timeout: 10,
71+
QueryTimeout: 50,
7272
MaxOpenConnections: 100,
7373
MaxIdleConnections: 100,
7474
MaxConnectionLifetime: 14400,
@@ -96,7 +96,7 @@ func TestLoadSettings(t *testing.T) {
9696
JSONData: []byte(`{ "server": "test", "port": 8812, "username": "john",
9797
"enableSecureSocksProxy": true, "tlsMode": "verify-ca", "tlsConfigurationMethod": "file-path",
9898
"tlsCACertFile": "/var/caCertFile", "tlsClientCertFile": "/var/clientCertFile", "tlsClientKeyFile": "/var/clientKeyFile",
99-
"timeout": "10", "queryTimeout": "50", "maxOpenConnections": 100, "maxIdleConnections": 100, "maxConnectionLifetime": 14400 }`),
99+
"timeout": 10, "queryTimeout": 50, "maxOpenConnections": 100, "maxIdleConnections": 100, "maxConnectionLifetime": 14400 }`),
100100
DecryptedSecureJSONData: map[string]string{"password": "rambo", "secureSocksProxyPassword": "test"},
101101
},
102102
},
@@ -108,8 +108,8 @@ func TestLoadSettings(t *testing.T) {
108108
TlsCACertFile: "/var/caCertFile",
109109
TlsClientCertFile: "/var/clientCertFile",
110110
TlsClientKeyFile: "/var/clientKeyFile",
111-
Timeout: "10",
112-
QueryTimeout: "50",
111+
Timeout: 10,
112+
QueryTimeout: 50,
113113
MaxOpenConnections: 100,
114114
MaxIdleConnections: 100,
115115
MaxConnectionLifetime: 14400,
@@ -133,7 +133,7 @@ func TestLoadSettings(t *testing.T) {
133133
name: "should converting string values to the correct type",
134134
args: args{
135135
config: backend.DataSourceInstanceSettings{
136-
JSONData: []byte(`{"server": "test", "username": "u", "port": "1234", "timeout": "15", "queryTimeout": "25", "maxOpenConnections": 10, "maxIdleConnections": 5, "maxConnectionLifetime": 3600 }`),
136+
JSONData: []byte(`{"server": "test", "username": "u", "port": "1234", "timeout": 15, "queryTimeout": 25, "maxOpenConnections": 10, "maxIdleConnections": 5, "maxConnectionLifetime": 3600 }`),
137137
DecryptedSecureJSONData: map[string]string{"password": "p"},
138138
},
139139
},
@@ -142,8 +142,8 @@ func TestLoadSettings(t *testing.T) {
142142
Port: 1234,
143143
Username: "u",
144144
Password: "p",
145-
Timeout: "15",
146-
QueryTimeout: "25",
145+
Timeout: 15,
146+
QueryTimeout: 25,
147147
MaxOpenConnections: 10,
148148
MaxIdleConnections: 5,
149149
MaxConnectionLifetime: 3600,

src/__mocks__/datasource.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
import { PluginType } from '@grafana/data';
2-
import {QuestDBQuery, QueryType} from '../types';
2+
import { QuestDBQuery, QueryType, Format } from '../types';
33
import { Datasource } from '../data/QuestDbDatasource';
44

55
export const mockDatasource = new Datasource({
66
id: 1,
77
uid: 'questdb_ds',
8-
type: 'questdb-questdb-datasource',
8+
type: 'grafana-questdb-datasource',
99
name: 'QuestDB',
1010
jsonData: {
1111
server: 'foo.com',
1212
port: 443,
13-
username: 'user'
13+
username: 'user',
1414
},
1515
readOnly: true,
1616
access: 'direct',
1717
meta: {
18-
id: 'questdb-grafana-datasource',
18+
id: 'questdb-questdb-datasource',
1919
name: 'QuestDB',
2020
type: PluginType.datasource,
2121
module: '',
@@ -42,5 +42,5 @@ export const mockQuery: QuestDBQuery = {
4242
refId: '',
4343
format: 1,
4444
queryType: QueryType.SQL,
45-
selectedFormat: 4,
45+
selectedFormat: Format.AUTO,
4646
};

src/selectors.ts

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,18 @@ export const Components = {
3636

3737
TLSCACertFile: {
3838
label: 'TLS/SSL Root Certificate File',
39-
placeholder: 'If the selected TLS/SSL mode requires a server root certificate, provide the path to the file here.',
39+
placeholder:
40+
'If the selected TLS/SSL mode requires a server root certificate, provide the path to the file here.',
4041
},
4142
TLSClientCertFile: {
4243
label: 'TLS/SSL Client Certificate File',
43-
placeholder: 'To authenticate with an TLS/SSL client certificate, provide the path to the file here. Be sure that the file is readable by the user executing the grafana process.',
44+
placeholder:
45+
'To authenticate with an TLS/SSL client certificate, provide the path to the file here. Be sure that the file is readable by the user executing the grafana process.',
4446
},
4547
TLSClientKeyFile: {
4648
label: 'TLS/SSL Client Key File',
47-
placeholder: 'To authenticate with a client TLS/SSL certificate, provide the path to the corresponding key file here. Be sure that the file is only readable by the user executing the grafana process.'
49+
placeholder:
50+
'To authenticate with a client TLS/SSL certificate, provide the path to the corresponding key file here. Be sure that the file is only readable by the user executing the grafana process.',
4851
},
4952

5053
Timeout: {
@@ -59,18 +62,20 @@ export const Components = {
5962
},
6063
TlsMode: {
6164
label: 'TLS/SSL Mode',
62-
tooltip: 'This option determines whether or with what priority a secure TLS/SSL TCP/IP connection will be negotiated with the server',
63-
placeholder: "TLS/SSL Mode"
65+
tooltip:
66+
'This option determines whether or with what priority a secure TLS/SSL TCP/IP connection will be negotiated with the server. For QuestDB Cloud, use "require". For self-hosted QuestDB, use "disable".',
67+
placeholder: 'TLS/SSL Mode',
6468
},
6569
TlsMethod: {
6670
label: 'TLS/SSL Method',
67-
tooltip: 'This option determines how TLS/SSL certifications are configured. Selecting ' +
68-
'"File system path" will allow you to configure certificates by specifying paths to existing ' +
69-
'certificates on the local file system where Grafana is running. Be sure that the file is ' +
70-
'readable by the user executing the Grafana process. ' +
71-
'Selecting "Certificate content" will allow you to configure certificates by specifying its ' +
72-
'content. The content will be stored encrypted in Grafana\'s database.',
73-
placeholder: 'TLS/SSL Method'
71+
tooltip:
72+
'This option determines how TLS/SSL certifications are configured. Selecting ' +
73+
'"File system path" will allow you to configure certificates by specifying paths to existing ' +
74+
'certificates on the local file system where Grafana is running. Be sure that the file is ' +
75+
'readable by the user executing the Grafana process. ' +
76+
'Selecting "Certificate content" will allow you to configure certificates by specifying its ' +
77+
"content. The content will be stored encrypted in Grafana's database.",
78+
placeholder: 'TLS/SSL Method',
7479
},
7580
SecureSocksProxy: {
7681
label: 'Enable Secure Socks Proxy',
@@ -89,7 +94,8 @@ export const Components = {
8994
MaxConnectionLifetime: {
9095
label: 'Max lifetime',
9196
placeholder: '14400',
92-
tooltip: 'The maximum amount of time (in seconds) a connection may be reused. If set to 0, connections are reused forever.',
97+
tooltip:
98+
'The maximum amount of time (in seconds) a connection may be reused. If set to 0, connections are reused forever.',
9399
},
94100
},
95101
QueryEditor: {
@@ -199,7 +205,7 @@ export const Components = {
199205
},
200206
DESIGNATED_TIMESTAMP: {
201207
label: 'Designated timestamp',
202-
tooltip: 'Select table\'s designated timestamp',
208+
tooltip: "Select table's designated timestamp",
203209
},
204210
ALIGN_TO: {
205211
label: 'Align to',

src/types.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ export interface QuestDBConfig extends DataSourceJsonData {
2323
tlsAuthWithCACert?: boolean;
2424
secure?: boolean;
2525
validate?: boolean;
26-
timeout?: string;
27-
queryTimeout?: string;
26+
timeout?: number;
27+
queryTimeout?: number;
2828
enableSecureSocksProxy?: boolean;
2929
maxOpenConnections?: number;
3030
maxIdleConnections?: number;
@@ -92,17 +92,17 @@ export enum BuilderMode {
9292
}
9393

9494
export enum SampleByFillMode {
95-
None= 'NONE',
95+
None = 'NONE',
9696
Null = 'NULL',
9797
Prev = 'PREV',
98-
Linear = 'LINEAR'
98+
Linear = 'LINEAR',
9999
}
100100

101101
export enum SampleByAlignToMode {
102102
FirstObservation = 'FIRST OBSERVATION',
103103
Calendar = 'CALENDAR',
104104
CalendarTimeZone = 'CALENDAR TIME ZONE',
105-
CalendarOffset = 'CALENDAR WITH OFFSET'
105+
CalendarOffset = 'CALENDAR WITH OFFSET',
106106
}
107107

108108
export const modeRequiresValue = (mode: SampleByAlignToMode): boolean => {
@@ -119,7 +119,7 @@ export interface SqlBuilderOptionsList {
119119
table?: string;
120120
fields?: string[];
121121
filters?: Filter[];
122-
partitionBy?: string[]
122+
partitionBy?: string[];
123123
orderBy?: OrderBy[];
124124
limit?: string;
125125
timeField: string;
@@ -227,7 +227,7 @@ export enum FilterOperator {
227227
ContainedBy = '<<',
228228
ContainedByOrEqual = '<<=',
229229
WithInGrafanaTimeRange = 'WITH IN DASHBOARD TIME RANGE',
230-
OutsideGrafanaTimeRange = 'OUTSIDE DASHBOARD TIME RANGE'
230+
OutsideGrafanaTimeRange = 'OUTSIDE DASHBOARD TIME RANGE',
231231
}
232232

233233
export interface CommonFilterProps {
@@ -248,7 +248,15 @@ export interface BooleanFilter extends CommonFilterProps {
248248
}
249249

250250
export interface StringFilter extends CommonFilterProps {
251-
operator: FilterOperator.Equals | FilterOperator.NotEquals | FilterOperator.Like | FilterOperator.NotLike | FilterOperator.ILike | FilterOperator.NotILike | FilterOperator.Match | FilterOperator.NotMatch;
251+
operator:
252+
| FilterOperator.Equals
253+
| FilterOperator.NotEquals
254+
| FilterOperator.Like
255+
| FilterOperator.NotLike
256+
| FilterOperator.ILike
257+
| FilterOperator.NotILike
258+
| FilterOperator.Match
259+
| FilterOperator.NotMatch;
252260
value: string;
253261
}
254262

@@ -307,7 +315,7 @@ export const defaultBuilderQuery: Omit<QuestDBBuilderQuery, 'refId'> = {
307315
mode: BuilderMode.List,
308316
fields: [],
309317
limit: '100',
310-
timeField: ''
318+
timeField: '',
311319
},
312320
format: Format.TABLE,
313321
selectedFormat: Format.AUTO,

0 commit comments

Comments
 (0)