SQL Expressions: Add endpoint to get Schemas (#108864)
Return the SQL schema for all DS queries in request (to provide information to AI / Autocomplete for SQL expressions). All DS queries are treated as if they were inputs to SQL expressions in terms of conversion, regardless if they are selected in a query or not. Requires feature toggle queryService = true Endpoint is apis/query.grafana.app/v0alpha1/namespaces/default/sqlschemas --------- Co-authored-by: Todd Treece <360020+toddtreece@users.noreply.github.com>
This commit is contained in:
co-authored by
Todd Treece
parent
c487952279
commit
c3d7dbc258
@@ -241,25 +241,40 @@ func (r *queryREST) Connect(connectCtx context.Context, name string, _ runtime.O
|
||||
}), nil
|
||||
}
|
||||
|
||||
func handleQuery(ctx context.Context, raw query.QueryDataRequest, b QueryAPIBuilder, httpreq *http.Request, responder responderWrapper, connectLogger log.Logger) (*backend.QueryDataResponse, error) {
|
||||
var jsonQueries = make([]*simplejson.Json, 0, len(raw.Queries))
|
||||
for _, query := range raw.Queries {
|
||||
dsRef, err := getValidDataSourceRef(ctx, query.Datasource, query.DatasourceID, b.legacyDatasourceLookup)
|
||||
if err != nil {
|
||||
connectLogger.Error("error getting valid datasource ref", err)
|
||||
}
|
||||
if dsRef != nil {
|
||||
query.Datasource = dsRef
|
||||
type preparedQuery struct {
|
||||
mReq dtos.MetricRequest
|
||||
cache datasources.CacheService
|
||||
headers map[string]string
|
||||
logger log.Logger
|
||||
builder dsquerierclient.QSDatasourceClientBuilder
|
||||
exprSvc *expr.Service
|
||||
reportMetrics func()
|
||||
}
|
||||
|
||||
func prepareQuery(
|
||||
ctx context.Context,
|
||||
raw query.QueryDataRequest,
|
||||
b QueryAPIBuilder,
|
||||
httpreq *http.Request,
|
||||
connectLogger log.Logger,
|
||||
) (*preparedQuery, error) {
|
||||
// Normalize DS refs and build []*simplejson.Json
|
||||
jsonQueries := make([]*simplejson.Json, 0, len(raw.Queries))
|
||||
for _, q := range raw.Queries {
|
||||
if dsRef, derr := getValidDataSourceRef(ctx, q.Datasource, q.DatasourceID, b.legacyDatasourceLookup); derr != nil {
|
||||
connectLogger.Error("error getting valid datasource ref", "err", derr)
|
||||
} else if dsRef != nil {
|
||||
q.Datasource = dsRef
|
||||
}
|
||||
|
||||
jsonBytes, err := json.Marshal(query)
|
||||
jsonBytes, err := json.Marshal(q)
|
||||
if err != nil {
|
||||
connectLogger.Error("error marshalling", err)
|
||||
connectLogger.Error("error marshalling query", "err", err)
|
||||
}
|
||||
|
||||
sjQuery, _ := simplejson.NewJson(jsonBytes)
|
||||
sjQuery, err := simplejson.NewJson(jsonBytes)
|
||||
if err != nil {
|
||||
connectLogger.Error("error unmarshalling", err)
|
||||
connectLogger.Error("error creating simplejson for query", "err", err)
|
||||
}
|
||||
|
||||
jsonQueries = append(jsonQueries, sjQuery)
|
||||
@@ -274,13 +289,11 @@ func handleQuery(ctx context.Context, raw query.QueryDataRequest, b QueryAPIBuil
|
||||
cache := &MyCacheService{
|
||||
legacy: b.legacyDatasourceLookup,
|
||||
}
|
||||
|
||||
headers := ExtractKnownHeaders(httpreq.Header)
|
||||
|
||||
instance, err := b.instanceProvider.GetInstance(ctx, connectLogger, headers)
|
||||
if err != nil {
|
||||
connectLogger.Error("failed to get instance configuration settings", "err", err)
|
||||
responder.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -288,12 +301,14 @@ func handleQuery(ctx context.Context, raw query.QueryDataRequest, b QueryAPIBuil
|
||||
|
||||
dsQuerierLoggerWithSlug := instance.GetLogger()
|
||||
|
||||
// Datasource client qsDsClientBuilder
|
||||
qsDsClientBuilder := dsquerierclient.NewQsDatasourceClientBuilderWithInstance(
|
||||
instance,
|
||||
ctx,
|
||||
dsQuerierLoggerWithSlug,
|
||||
)
|
||||
|
||||
// Expressions service
|
||||
exprService := expr.ProvideService(
|
||||
&setting.Cfg{
|
||||
ExpressionsEnabled: instanceConfig.ExpressionsEnabled,
|
||||
@@ -310,17 +325,37 @@ func handleQuery(ctx context.Context, raw query.QueryDataRequest, b QueryAPIBuil
|
||||
qsDsClientBuilder,
|
||||
)
|
||||
|
||||
qdr, err := service.QueryData(ctx, dsQuerierLoggerWithSlug, cache, exprService, mReq, qsDsClientBuilder, headers)
|
||||
return &preparedQuery{
|
||||
mReq: mReq,
|
||||
cache: cache,
|
||||
headers: headers,
|
||||
logger: dsQuerierLoggerWithSlug,
|
||||
builder: qsDsClientBuilder,
|
||||
exprSvc: exprService,
|
||||
reportMetrics: func() { instance.ReportMetrics() },
|
||||
}, nil
|
||||
}
|
||||
|
||||
// tell the `instance` structure that it can now report
|
||||
// metrics that are only reported once during a request
|
||||
instance.ReportMetrics()
|
||||
func handlePreparedQuery(ctx context.Context, pq *preparedQuery) (*backend.QueryDataResponse, error) {
|
||||
resp, err := service.QueryData(ctx, pq.logger, pq.cache, pq.exprSvc, pq.mReq, pq.builder, pq.headers)
|
||||
pq.reportMetrics()
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func handleQuery(
|
||||
ctx context.Context,
|
||||
raw query.QueryDataRequest,
|
||||
b QueryAPIBuilder,
|
||||
httpreq *http.Request,
|
||||
responder responderWrapper,
|
||||
connectLogger log.Logger,
|
||||
) (*backend.QueryDataResponse, error) {
|
||||
pq, err := prepareQuery(ctx, raw, b, httpreq, connectLogger)
|
||||
if err != nil {
|
||||
return qdr, err
|
||||
responder.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return qdr, nil
|
||||
return handlePreparedQuery(ctx, pq)
|
||||
}
|
||||
|
||||
type responderWrapper struct {
|
||||
|
||||
Reference in New Issue
Block a user