Skip to content

Commit 2d766dc

Browse files
authored
feat: Add support for jsonschema (#1214)
I was a bit blocked on the backend so took a short detour on our SDK. This will be needed for our upcoming cloud version as we need to generate forms automatically for every plugin version. The JSON schema will also go into the registry backend and we can also integrate it nicely with the hub - with something like https://codesandbox.io/s/material-ui-json-schema-viewer-2u6zq
1 parent aa01b1f commit 2d766dc

File tree

6 files changed

+43
-0
lines changed

6 files changed

+43
-0
lines changed

examples/simple_plugin/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ require (
3535
github.com/mattn/go-isatty v0.0.19 // indirect
3636
github.com/pierrec/lz4/v4 v4.1.18 // indirect
3737
github.com/pmezard/go-difflib v1.0.0 // indirect
38+
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
3839
github.com/spf13/cobra v1.6.1 // indirect
3940
github.com/spf13/pflag v1.0.5 // indirect
4041
github.com/stretchr/testify v1.8.4 // indirect

examples/simple_plugin/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
193193
github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c=
194194
github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w=
195195
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
196+
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
197+
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
196198
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
197199
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
198200
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/google/uuid v1.3.1
1414
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0
1515
github.com/rs/zerolog v1.29.1
16+
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
1617
github.com/spf13/cobra v1.6.1
1718
github.com/stretchr/testify v1.8.4
1819
github.com/thoas/go-funk v0.9.3

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
202202
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
203203
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
204204
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
205+
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
206+
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
205207
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
206208
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
207209
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=

plugin/options.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ func WithBuildTargets(targets []BuildTarget) Option {
2323
}
2424
}
2525

26+
func WithJSONSchema(schema string) Option {
27+
return func(p *Plugin) {
28+
p.schema = schema
29+
}
30+
}
31+
2632
type TableOptions struct {
2733
Tables []string
2834
SkipTables []string

plugin/plugin.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ package plugin
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
7+
"strings"
68
"sync"
79

810
"github.com/apache/arrow/go/v14/arrow"
911
"github.com/cloudquery/plugin-sdk/v4/message"
1012
"github.com/cloudquery/plugin-sdk/v4/schema"
1113
"github.com/rs/zerolog"
14+
"github.com/santhosh-tekuri/jsonschema/v5"
1215
)
1316

1417
var ErrNotImplemented = fmt.Errorf("not implemented")
@@ -66,6 +69,10 @@ type Plugin struct {
6669
// NoInternalColumns if set to true will not add internal columns to tables such as _cq_id and _cq_parent_id
6770
// useful for sources such as PostgreSQL and other databases
6871
internalColumns bool
72+
// schema is the JSONSchema of the plugin spec
73+
schema string
74+
// validator object to validate specs
75+
schemaValidator *jsonschema.Schema
6976
}
7077

7178
// NewPlugin returns a new CloudQuery Plugin with the given name, version and implementation.
@@ -81,6 +88,19 @@ func NewPlugin(name string, version string, newClient NewClientFunc, options ...
8188
for _, opt := range options {
8289
opt(&p)
8390
}
91+
if p.schema != "" {
92+
c := jsonschema.NewCompiler()
93+
c.Draft = jsonschema.Draft2020
94+
if err := c.AddResource("schema.json", strings.NewReader(p.schema)); err != nil {
95+
panic(fmt.Errorf("failed add plugin JSONSchema: %w", err))
96+
}
97+
schemaValidator, err := c.Compile("schema.json")
98+
if err != nil {
99+
panic(fmt.Errorf("failed to compile plugin JSONSchema: %w", err))
100+
}
101+
p.schemaValidator = schemaValidator
102+
}
103+
84104
return &p
85105
}
86106

@@ -120,6 +140,17 @@ func (p *Plugin) Init(ctx context.Context, spec []byte, options NewClientOptions
120140
}
121141
defer p.mu.Unlock()
122142
var err error
143+
144+
if p.schemaValidator != nil {
145+
var v any
146+
if err := json.Unmarshal(spec, &v); err != nil {
147+
return fmt.Errorf("failed to unmarshal plugin spec: %w", err)
148+
}
149+
if err := p.schemaValidator.Validate(v); err != nil {
150+
return fmt.Errorf("plugin spec is invalid: %w", err)
151+
}
152+
}
153+
123154
p.client, err = p.newClient(ctx, p.logger, spec, options)
124155
if err != nil {
125156
return fmt.Errorf("failed to initialize client: %w", err)

0 commit comments

Comments
 (0)