From 89a3efdd4bd6dafbb3c37652875679e3126c501d Mon Sep 17 00:00:00 2001 From: Andres Martinez Gotor Date: Thu, 24 Oct 2024 16:20:26 +0200 Subject: [PATCH] datasource-http-backend: Example migration with experimental APIs --- .../pkg/kinds/query.go | 5 ++- .../pkg/kinds/query.panel.schema.json | 6 ++- .../pkg/kinds/query.request.schema.json | 6 ++- .../pkg/kinds/query.types.json | 8 +++- .../pkg/plugin/convert_query.go | 43 +++++++++++++++++++ .../pkg/plugin/datasource.go | 9 ++-- .../src/components/QueryEditor.tsx | 4 +- .../datasource-http-backend/src/datasource.ts | 14 ++++-- .../datasource-http-backend/src/module.ts | 3 +- .../datasource-http-backend/src/plugin.json | 6 +-- examples/datasource-http-backend/src/types.ts | 2 +- 11 files changed, 85 insertions(+), 21 deletions(-) create mode 100644 examples/datasource-http-backend/pkg/plugin/convert_query.go diff --git a/examples/datasource-http-backend/pkg/kinds/query.go b/examples/datasource-http-backend/pkg/kinds/query.go index e26916882..4fca7c1b0 100644 --- a/examples/datasource-http-backend/pkg/kinds/query.go +++ b/examples/datasource-http-backend/pkg/kinds/query.go @@ -10,7 +10,10 @@ import ( type DataQuery struct { v0alpha1.CommonQueryProperties - // Multiplier is the number to multiply the input by + // Multiply is the number to multiply the input by + Multiply int `json:"multiply,omitempty"` + + // Deprecated: Use Multiply instead Multiplier int `json:"multiplier,omitempty"` } diff --git a/examples/datasource-http-backend/pkg/kinds/query.panel.schema.json b/examples/datasource-http-backend/pkg/kinds/query.panel.schema.json index 525bc92ff..06919267f 100644 --- a/examples/datasource-http-backend/pkg/kinds/query.panel.schema.json +++ b/examples/datasource-http-backend/pkg/kinds/query.panel.schema.json @@ -41,7 +41,11 @@ "type": "integer" }, "multiplier": { - "description": "Multiplier is the number to multiply the input by", + "description": "Deprecated: Use Multiply instead", + "type": "integer" + }, + "multiply": { + "description": "Multiply is the number to multiply the input by", "type": "integer" }, "queryType": { diff --git a/examples/datasource-http-backend/pkg/kinds/query.request.schema.json b/examples/datasource-http-backend/pkg/kinds/query.request.schema.json index 4e3815da3..a0c7adbe6 100644 --- a/examples/datasource-http-backend/pkg/kinds/query.request.schema.json +++ b/examples/datasource-http-backend/pkg/kinds/query.request.schema.json @@ -51,7 +51,11 @@ "type": "integer" }, "multiplier": { - "description": "Multiplier is the number to multiply the input by", + "description": "Deprecated: Use Multiply instead", + "type": "integer" + }, + "multiply": { + "description": "Multiply is the number to multiply the input by", "type": "integer" }, "queryType": { diff --git a/examples/datasource-http-backend/pkg/kinds/query.types.json b/examples/datasource-http-backend/pkg/kinds/query.types.json index 0afd9ea38..11a635c6f 100644 --- a/examples/datasource-http-backend/pkg/kinds/query.types.json +++ b/examples/datasource-http-backend/pkg/kinds/query.types.json @@ -8,7 +8,7 @@ { "metadata": { "name": "default", - "resourceVersion": "1728987397884", + "resourceVersion": "1729779295393", "creationTimestamp": "2024-10-15T10:11:05Z" }, "spec": { @@ -47,7 +47,11 @@ "type": "integer" }, "multiplier": { - "description": "Multiplier is the number to multiply the input by", + "description": "Deprecated: Use Multiply instead", + "type": "integer" + }, + "multiply": { + "description": "Multiply is the number to multiply the input by", "type": "integer" }, "queryType": { diff --git a/examples/datasource-http-backend/pkg/plugin/convert_query.go b/examples/datasource-http-backend/pkg/plugin/convert_query.go new file mode 100644 index 000000000..388b0bb41 --- /dev/null +++ b/examples/datasource-http-backend/pkg/plugin/convert_query.go @@ -0,0 +1,43 @@ +package plugin + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/grafana/datasource-http-backend/pkg/kinds" + "github.com/grafana/grafana-plugin-sdk-go/backend" +) + +// convertQuery parses a given DataQuery and migrates it if necessary. +func convertQuery(orig backend.DataQuery) (*kinds.DataQuery, error) { + input := &kinds.DataQuery{} + err := json.Unmarshal(orig.JSON, input) + if err != nil { + return nil, fmt.Errorf("unmarshal: %w", err) + } + if input.Multiplier != 0 && input.Multiply == 0 { + input.Multiply = input.Multiplier + input.Multiplier = 0 + } + return input, nil +} + +// convertQueryRequest migrates a given QueryDataRequest which can contain multiple queries. +func convertQueryRequest(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryConversionResponse, error) { + queries := make([]any, 0, len(req.Queries)) + for _, q := range req.Queries { + input, err := convertQuery(q) + if err != nil { + return nil, err + } + q.JSON, err = json.Marshal(input) + if err != nil { + return nil, fmt.Errorf("marshal: %w", err) + } + queries = append(queries, q) + } + return &backend.QueryConversionResponse{ + Queries: queries, + }, nil +} diff --git a/examples/datasource-http-backend/pkg/plugin/datasource.go b/examples/datasource-http-backend/pkg/plugin/datasource.go index 82ed33e4e..5e001c02c 100644 --- a/examples/datasource-http-backend/pkg/plugin/datasource.go +++ b/examples/datasource-http-backend/pkg/plugin/datasource.go @@ -9,7 +9,6 @@ import ( "strconv" "time" - "github.com/grafana/datasource-http-backend/pkg/kinds" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" @@ -75,6 +74,7 @@ var DatasourceOpts = datasource.ManageOpts{ attribute.String("my_plugin.my_attribute", "custom value"), }, }, + QueryConversionHandler: backend.ConvertQueryFunc(convertQueryRequest), } // Datasource is an example datasource which can respond to data queries, reports @@ -174,13 +174,12 @@ func (d *Datasource) query(ctx context.Context, pCtx backend.PluginContext, quer return backend.DataResponse{}, fmt.Errorf("new request with context: %w", err) } if len(query.JSON) > 0 { - input := &kinds.DataQuery{} - err = json.Unmarshal(query.JSON, input) + input, err := convertQuery(query) if err != nil { - return backend.DataResponse{}, fmt.Errorf("unmarshal: %w", err) + return backend.DataResponse{}, err } q := req.URL.Query() - q.Add("multiplier", strconv.Itoa(input.Multiplier)) + q.Add("multiplier", strconv.Itoa(input.Multiply)) req.URL.RawQuery = q.Encode() } httpResp, err := d.httpClient.Do(req) diff --git a/examples/datasource-http-backend/src/components/QueryEditor.tsx b/examples/datasource-http-backend/src/components/QueryEditor.tsx index 3cf13b0e4..985105e64 100644 --- a/examples/datasource-http-backend/src/components/QueryEditor.tsx +++ b/examples/datasource-http-backend/src/components/QueryEditor.tsx @@ -15,8 +15,8 @@ export class QueryEditor extends PureComponent { type="number" id="multiplier" name="multiplier" - value={this.props.query.multiplier} - onChange={(e) => this.props.onChange({ ...this.props.query, multiplier: e.currentTarget.valueAsNumber })} + value={this.props.query.multiply} + onChange={(e) => this.props.onChange({ ...this.props.query, multiply: e.currentTarget.valueAsNumber })} /> ); diff --git a/examples/datasource-http-backend/src/datasource.ts b/examples/datasource-http-backend/src/datasource.ts index 19d31d869..768b98d0a 100644 --- a/examples/datasource-http-backend/src/datasource.ts +++ b/examples/datasource-http-backend/src/datasource.ts @@ -1,14 +1,22 @@ import { CoreApp, DataSourceInstanceSettings } from '@grafana/data'; import { MyQuery, MyDataSourceOptions } from './types'; -import { DataSourceWithBackend } from '@grafana/runtime'; +import { DataSourceWithBackend, MigrationHandler } from '@grafana/runtime'; +import { DataQuery } from '@grafana/schema'; + +export class DataSource extends DataSourceWithBackend implements MigrationHandler { + hasBackendMigration: boolean; -export class DataSource extends DataSourceWithBackend { constructor(instanceSettings: DataSourceInstanceSettings) { super(instanceSettings); + this.hasBackendMigration = true; } getDefaultQuery(_: CoreApp): Partial { - return { multiplier: 1 }; + return { multiply: 1 }; + } + + shouldMigrate(query: DataQuery): boolean { + return !query.hasOwnProperty('multiply'); } } diff --git a/examples/datasource-http-backend/src/module.ts b/examples/datasource-http-backend/src/module.ts index b8231ebbd..33b0bf122 100644 --- a/examples/datasource-http-backend/src/module.ts +++ b/examples/datasource-http-backend/src/module.ts @@ -3,7 +3,8 @@ import { DataSource } from './datasource'; import { ConfigEditor } from './components/ConfigEditor'; import { QueryEditor } from './components/QueryEditor'; import { MyQuery, MyDataSourceOptions } from './types'; +import { QueryEditorWithMigration } from '@grafana/runtime'; export const plugin = new DataSourcePlugin(DataSource) .setConfigEditor(ConfigEditor) - .setQueryEditor(QueryEditor); + .setQueryEditor(QueryEditorWithMigration(QueryEditor)); diff --git a/examples/datasource-http-backend/src/plugin.json b/examples/datasource-http-backend/src/plugin.json index 8f8e45028..ca18b77e3 100644 --- a/examples/datasource-http-backend/src/plugin.json +++ b/examples/datasource-http-backend/src/plugin.json @@ -12,9 +12,7 @@ "author": { "name": "Grafana Labs" }, - "keywords": [ - "datasource" - ], + "keywords": ["datasource"], "logos": { "small": "img/logo.svg", "large": "img/logo.svg" @@ -34,7 +32,7 @@ "updated": "%TODAY%" }, "dependencies": { - "grafanaDependency": ">=10.4.0", + "grafanaDependency": ">=11.4.0", "plugins": [] } } diff --git a/examples/datasource-http-backend/src/types.ts b/examples/datasource-http-backend/src/types.ts index 9ffefa5be..c61a9f691 100644 --- a/examples/datasource-http-backend/src/types.ts +++ b/examples/datasource-http-backend/src/types.ts @@ -2,7 +2,7 @@ import type { DataSourceJsonData } from '@grafana/data'; import type { DataQuery } from '@grafana/schema'; export interface MyQuery extends DataQuery { - multiplier: number; + multiply: number; } /**