-
-
Notifications
You must be signed in to change notification settings - Fork 80
Expand file tree
/
Copy pathbackend.go
More file actions
294 lines (229 loc) · 9.09 KB
/
Copy pathbackend.go
File metadata and controls
294 lines (229 loc) · 9.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
package mcp_server //nolint:revive // fine for now
import (
"context"
"database/sql/driver"
"github.com/stackql/stackql/pkg/mcp_server/dto"
)
type Backend interface {
// Ping verifies the backend connection is active.
Ping(ctx context.Context) error
// Close gracefully shuts down the backend connection.
Close() error
// ServerInfo returns server identity and runtime metadata.
ServerInfo(ctx context.Context, args any) (dto.ServerInfoOutput, error)
// ExecQuery executes a non-row-returning SQL statement (mutations, EXEC).
ExecQuery(ctx context.Context, query string) (map[string]any, error)
// ValidateQuery parses and plans a SELECT without executing it.
ValidateQuery(ctx context.Context, query string) ([]map[string]any, error)
// RunQueryJSON executes a SELECT and returns the rows.
RunQueryJSON(ctx context.Context, input dto.QueryJSONInput) ([]map[string]interface{}, error)
// ListProviders lists available providers.
ListProviders(ctx context.Context) ([]map[string]any, error)
// ListServices lists services under a provider.
ListServices(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)
// ListResources lists resources under a provider/service.
ListResources(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)
// ListMethods lists access methods for a resource.
ListMethods(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)
// DescribeResource returns the output fields for a resource's primary read method.
DescribeResource(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)
// DescribeMethod returns the full I/O contract for one method.
DescribeMethod(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)
// ListRegistry lists providers (and their versions) available in the registry.
// When input.Provider is empty, lists all available providers; otherwise lists
// versions for that provider. Distinct from ListProviders, which lists only
// providers already pulled into the local cache.
ListRegistry(ctx context.Context, input dto.RegistryInput) ([]map[string]any, error)
// PullProvider installs a provider from the registry into the local approot
// cache. input.Provider is required; input.Version is optional (empty pulls
// the latest published version). Returns the same shape as ExecQuery.
PullProvider(ctx context.Context, input dto.RegistryInput) (map[string]any, error)
}
// QueryResult represents the result of a query execution.
type QueryResult interface {
// GetColumns returns metadata about each column in the result set.
GetColumns() []ColumnInfo
// GetRows returns the actual data returned by the query.
GetRows() [][]interface{}
// GetRowsAffected returns the number of rows affected by DML operations.
GetRowsAffected() int64
// GetExecutionTime returns the time taken to execute the query in milliseconds.
GetExecutionTime() int64
}
// ColumnInfo provides metadata about a result column.
type ColumnInfo interface {
// GetName returns the column name as returned by the query.
GetName() string
// GetType returns the data type of the column (e.g., "string", "int64", "float64").
GetType() string
// IsNullable indicates whether the column can contain null values.
IsNullable() bool
}
// SchemaProvider represents the metadata structure of available resources.
type SchemaProvider interface {
// GetProviders returns all available providers (e.g., aws, google, azure).
GetProviders() []Provider
}
// Provider represents a StackQL provider with its services and resources.
type Provider interface {
// GetName returns the provider identifier (e.g., "aws", "google").
GetName() string
// GetVersion returns the provider version.
GetVersion() string
// GetServices returns all services available in this provider.
GetServices() []Service
}
// Service represents a service within a provider.
type Service interface {
// GetName returns the service identifier (e.g., "ec2", "compute").
GetName() string
// GetResources returns all resources available in this service.
GetResources() []Resource
}
// Resource represents a queryable resource.
type Resource interface {
// GetName returns the resource identifier (e.g., "instances", "buckets").
GetName() string
// GetMethods returns the available operations for this resource.
GetMethods() []string
// GetFields returns the available fields in this resource.
GetFields() []Field
}
// Field represents a field within a resource.
type Field interface {
// GetName returns the field identifier.
GetName() string
// GetType returns the field data type.
GetType() string
// IsRequired indicates if this field is mandatory for certain operations.
IsRequired() bool
// GetDescription returns human-readable documentation for the field.
GetDescription() string
}
// BackendError represents an error that occurred in the backend.
type BackendError struct {
// Code is a machine-readable error code.
Code string `json:"code"`
// Message is a human-readable error message.
Message string `json:"message"`
// Details contains additional context about the error.
Details map[string]interface{} `json:"details,omitempty"`
}
func (e *BackendError) Error() string {
return e.Message
}
// Ensure BackendError implements the driver.Valuer interface for database compatibility.
func (e *BackendError) Value() (driver.Value, error) {
return e.Message, nil
}
// Private implementations of interfaces
type queryResult struct {
Columns []ColumnInfo `json:"columns"`
Rows [][]interface{} `json:"rows"`
RowsAffected int64 `json:"rows_affected"`
ExecutionTime int64 `json:"execution_time_ms"`
}
func (qr *queryResult) GetColumns() []ColumnInfo { return qr.Columns }
func (qr *queryResult) GetRows() [][]interface{} { return qr.Rows }
func (qr *queryResult) GetRowsAffected() int64 { return qr.RowsAffected }
func (qr *queryResult) GetExecutionTime() int64 { return qr.ExecutionTime }
type columnInfo struct {
Name string `json:"name"`
Type string `json:"type"`
Nullable bool `json:"nullable"`
}
func (ci *columnInfo) GetName() string { return ci.Name }
func (ci *columnInfo) GetType() string { return ci.Type }
func (ci *columnInfo) IsNullable() bool { return ci.Nullable }
type schemaProvider struct {
Providers []Provider `json:"providers"`
}
func (sp *schemaProvider) GetProviders() []Provider { return sp.Providers }
type provider struct {
Name string `json:"name"`
Version string `json:"version"`
Services []Service `json:"services"`
}
func (p *provider) GetName() string { return p.Name }
func (p *provider) GetVersion() string { return p.Version }
func (p *provider) GetServices() []Service { return p.Services }
type service struct {
Name string `json:"name"`
Resources []Resource `json:"resources"`
}
func (s *service) GetName() string { return s.Name }
func (s *service) GetResources() []Resource { return s.Resources }
type resource struct {
Name string `json:"name"`
Methods []string `json:"methods"`
Fields []Field `json:"fields"`
}
func (r *resource) GetName() string { return r.Name }
func (r *resource) GetMethods() []string { return r.Methods }
func (r *resource) GetFields() []Field { return r.Fields }
type field struct {
Name string `json:"name"`
Type string `json:"type"`
Required bool `json:"required"`
Description string `json:"description,omitempty"`
}
func (f *field) GetName() string { return f.Name }
func (f *field) GetType() string { return f.Type }
func (f *field) IsRequired() bool { return f.Required }
func (f *field) GetDescription() string { return f.Description }
// Factory functions
// NewQueryResult creates a new QueryResult instance.
func NewQueryResult(columns []ColumnInfo, rows [][]interface{}, rowsAffected, executionTime int64) QueryResult {
return &queryResult{
Columns: columns,
Rows: rows,
RowsAffected: rowsAffected,
ExecutionTime: executionTime,
}
}
// NewColumnInfo creates a new ColumnInfo instance.
func NewColumnInfo(name, colType string, nullable bool) ColumnInfo {
return &columnInfo{
Name: name,
Type: colType,
Nullable: nullable,
}
}
// NewSchemaProvider creates a new SchemaProvider instance.
func NewSchemaProvider(providers []Provider) SchemaProvider {
return &schemaProvider{
Providers: providers,
}
}
// NewProvider creates a new Provider instance.
func NewProvider(name, version string, services []Service) Provider {
return &provider{
Name: name,
Version: version,
Services: services,
}
}
// NewService creates a new Service instance.
func NewService(name string, resources []Resource) Service {
return &service{
Name: name,
Resources: resources,
}
}
// NewResource creates a new Resource instance.
func NewResource(name string, methods []string, fields []Field) Resource {
return &resource{
Name: name,
Methods: methods,
Fields: fields,
}
}
// NewField creates a new Field instance.
func NewField(name, fieldType string, required bool, description string) Field {
return &field{
Name: name,
Type: fieldType,
Required: required,
Description: description,
}
}