Skip to content

Commit 2387b57

Browse files
authored
feat: Add transformer to update table description with its table options (#2128)
Adds code we commonly reuse in plugins to add the table options to the table description
1 parent fa285f0 commit 2387b57

File tree

8 files changed

+176
-4
lines changed

8 files changed

+176
-4
lines changed

docs/table_options.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package docs
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"reflect"
7+
"regexp"
8+
"strings"
9+
10+
schemaDocs "github.com/cloudquery/codegen/jsonschema/docs"
11+
"github.com/cloudquery/plugin-sdk/v4/schema"
12+
invoschema "github.com/invopop/jsonschema"
13+
)
14+
15+
func TableOptionsDescriptionTransformer(tableOptions any, jsonSchema string) (schema.Transform, error) {
16+
var sc invoschema.Schema
17+
if err := json.Unmarshal([]byte(jsonSchema), &sc); err != nil {
18+
return nil, err
19+
}
20+
tableNamesToOptionsDocs := make(map[string]string)
21+
tableOptionsType := reflect.ValueOf(tableOptions).Elem().Type()
22+
for i := range tableOptionsType.NumField() {
23+
field := tableOptionsType.Field(i)
24+
fieldType := field.Type.String()
25+
if strings.Contains(fieldType, ".") {
26+
fieldType = strings.Split(fieldType, ".")[1]
27+
}
28+
defValue, ok := sc.Definitions[fieldType]
29+
if !ok {
30+
return nil, errors.New("definition not found for " + field.Name)
31+
}
32+
tableName := strings.Split(field.Tag.Get("json"), ",")[0]
33+
if tableName == "" {
34+
return nil, errors.New("json tag not found for table " + field.Name)
35+
}
36+
newRoot := sc
37+
newRoot.ID = "Table Options"
38+
newRoot.Ref = "#/$defs/" + "Table Options"
39+
newRoot.Definitions["Table Options"] = defValue
40+
sch, _ := json.Marshal(newRoot)
41+
doc, _ := schemaDocs.Generate(sch, 1)
42+
tocRegex := regexp.MustCompile(`# Table of contents[\s\S]+?##`)
43+
tableNamesToOptionsDocs[tableName] = tocRegex.ReplaceAllString(doc, "##")
44+
}
45+
46+
return func(table *schema.Table) error {
47+
if tableNamesToOptionsDocs[table.Name] != "" {
48+
table.Description = table.Description + "\n\n" + tableNamesToOptionsDocs[table.Name]
49+
}
50+
return nil
51+
}, nil
52+
}

docs/table_options_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package docs
2+
3+
import (
4+
_ "embed"
5+
"testing"
6+
7+
"github.com/cloudquery/plugin-sdk/v4/docs/testdata"
8+
"github.com/cloudquery/plugin-sdk/v4/schema"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
//go:embed testdata/schema.json
13+
var testSchema string
14+
15+
type testTableOptions struct {
16+
Dummy testdata.DummyTableOptions `json:"dummy,omitempty"`
17+
}
18+
19+
var testTable = &schema.Table{
20+
Name: "dummy",
21+
Description: "This is a dummy table",
22+
}
23+
24+
func TestTableOptionsDescriptionTransformer(t *testing.T) {
25+
type args struct {
26+
tableOptions any
27+
jsonSchema string
28+
table *schema.Table
29+
}
30+
tests := []struct {
31+
name string
32+
args args
33+
wantDesc string
34+
wantErr bool
35+
}{
36+
{
37+
name: "adds table options to description",
38+
args: args{tableOptions: &testTableOptions{}, jsonSchema: testSchema, table: testTable},
39+
wantDesc: "This is a dummy table\n\n## <a name=\"Table Options\"></a>Table Options\n\n DummyTableOptions contains configuration for the dummy table\n\n* `filter` (`string`)\n",
40+
},
41+
{
42+
name: "leaves description unchanged when table doesn't have options",
43+
args: args{tableOptions: &testTableOptions{}, jsonSchema: testSchema, table: &schema.Table{Description: "Foobar"}},
44+
wantDesc: "Foobar",
45+
},
46+
{
47+
name: "errors out when table options don't match schema",
48+
wantErr: true,
49+
args: args{tableOptions: &testTableOptions{}, jsonSchema: "", table: testTable},
50+
},
51+
}
52+
for _, tt := range tests {
53+
t.Run(tt.name, func(t *testing.T) {
54+
transformer, err := TableOptionsDescriptionTransformer(tt.args.tableOptions, tt.args.jsonSchema)
55+
if tt.wantErr {
56+
require.Error(t, err)
57+
return
58+
}
59+
require.NoError(t, transformer(tt.args.table))
60+
require.Equal(t, tt.wantDesc, tt.args.table.Description)
61+
})
62+
}
63+
}

docs/testdata/schema.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "test/spec",
4+
"$ref": "#/$defs/Spec",
5+
"$defs": {
6+
"Spec": {
7+
"properties": {
8+
"table_options": {
9+
"$ref": "#/$defs/TableOptions",
10+
"description": "TableOptions is a set of options to override the defaults for certain tables."
11+
}
12+
},
13+
"additionalProperties": false,
14+
"type": "object"
15+
},
16+
"TableOptions": {
17+
"properties": {
18+
"dummy": {
19+
"oneOf": [
20+
{
21+
"$ref": "#/$defs/DummyTableOptions",
22+
"description": "Options for the dummy table."
23+
},
24+
{
25+
"type": "null"
26+
}
27+
]
28+
}
29+
},
30+
"additionalProperties": false,
31+
"type": "object"
32+
},
33+
"DummyTableOptions": {
34+
"properties": {
35+
"filter": {
36+
"type": "string"
37+
}
38+
},
39+
"additionalProperties": false,
40+
"type": "object",
41+
"description": "DummyTableOptions contains configuration for the dummy table"
42+
}
43+
}
44+
}

docs/testdata/tableoptions.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package testdata
2+
3+
type DummyTableOptions struct {
4+
Filter string `json:"filter,omitempty"`
5+
}

examples/simple_plugin/go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/cloudquery/plugin-sdk/examples/simple_plugin
22

3-
go 1.23.0
3+
go 1.23.4
44

55
toolchain go1.24.1
66

@@ -33,6 +33,7 @@ require (
3333
github.com/buger/jsonparser v1.1.1 // indirect
3434
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
3535
github.com/cloudquery/cloudquery-api-go v1.13.8 // indirect
36+
github.com/cloudquery/codegen v0.3.26 // indirect
3637
github.com/cloudquery/plugin-pb-go v1.26.9 // indirect
3738
github.com/cloudquery/plugin-sdk/v2 v2.7.0 // indirect
3839
github.com/davecgh/go-spew v1.1.1 // indirect

examples/simple_plugin/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
5252
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
5353
github.com/cloudquery/cloudquery-api-go v1.13.8 h1:8n5D0G2wynbUdexr1GS8ND8i0uOwm0gXKNipJsijPe0=
5454
github.com/cloudquery/cloudquery-api-go v1.13.8/go.mod h1:ZhEjPkDGDL2KZKlQLUnsgQ0mPz3qC7qftr37q3q+IcA=
55+
github.com/cloudquery/codegen v0.3.26 h1:cWORVpObYW5/0LnjC0KO/Ocg1+vbZivJfFd+sMpb5ZY=
56+
github.com/cloudquery/codegen v0.3.26/go.mod h1:bg/M1JxFvNVABMLMFb/uAQmTGAyI2L/E4zL4kho9RFs=
5557
github.com/cloudquery/plugin-pb-go v1.26.9 h1:lkgxqIzabD6yvDm7D7oJvgO/T/bYIh7SSOojEgbMpnA=
5658
github.com/cloudquery/plugin-pb-go v1.26.9/go.mod h1:euhtVJKRtmWzukBxOjJyCKHPU9O9Gs5vasiBCaZVFRA=
5759
github.com/cloudquery/plugin-sdk/v2 v2.7.0 h1:hRXsdEiaOxJtsn/wZMFQC9/jPfU1MeMK3KF+gPGqm7U=

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/cloudquery/plugin-sdk/v4
22

3-
go 1.23.0
3+
go 1.23.4
44

55
toolchain go1.24.1
66

@@ -65,6 +65,7 @@ require (
6565
github.com/bahlo/generic-list-go v0.2.0 // indirect
6666
github.com/buger/jsonparser v1.1.1 // indirect
6767
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
68+
github.com/cloudquery/codegen v0.3.26 // indirect
6869
github.com/davecgh/go-spew v1.1.1 // indirect
6970
github.com/ghodss/yaml v1.0.0 // indirect
7071
github.com/go-logr/logr v1.4.2 // indirect
@@ -97,3 +98,5 @@ require (
9798
gopkg.in/yaml.v2 v2.4.0 // indirect
9899
gopkg.in/yaml.v3 v3.0.1 // indirect
99100
)
101+
102+
replace github.com/invopop/jsonschema => github.com/cloudquery/jsonschema v0.0.0-20240220124159-92878faa2a66

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
5252
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
5353
github.com/cloudquery/cloudquery-api-go v1.13.8 h1:8n5D0G2wynbUdexr1GS8ND8i0uOwm0gXKNipJsijPe0=
5454
github.com/cloudquery/cloudquery-api-go v1.13.8/go.mod h1:ZhEjPkDGDL2KZKlQLUnsgQ0mPz3qC7qftr37q3q+IcA=
55+
github.com/cloudquery/codegen v0.3.26 h1:cWORVpObYW5/0LnjC0KO/Ocg1+vbZivJfFd+sMpb5ZY=
56+
github.com/cloudquery/codegen v0.3.26/go.mod h1:bg/M1JxFvNVABMLMFb/uAQmTGAyI2L/E4zL4kho9RFs=
57+
github.com/cloudquery/jsonschema v0.0.0-20240220124159-92878faa2a66 h1:OZLPSIBYEfvkAUeOeM8CwTgVQy5zhayI99ishCrsFV0=
58+
github.com/cloudquery/jsonschema v0.0.0-20240220124159-92878faa2a66/go.mod h1:0SoZ/U7yJlNOR+fWsBSeTvTbGXB6DK01tzJ7m2Xfg34=
5559
github.com/cloudquery/plugin-pb-go v1.26.9 h1:lkgxqIzabD6yvDm7D7oJvgO/T/bYIh7SSOojEgbMpnA=
5660
github.com/cloudquery/plugin-pb-go v1.26.9/go.mod h1:euhtVJKRtmWzukBxOjJyCKHPU9O9Gs5vasiBCaZVFRA=
5761
github.com/cloudquery/plugin-sdk/v2 v2.7.0 h1:hRXsdEiaOxJtsn/wZMFQC9/jPfU1MeMK3KF+gPGqm7U=
@@ -99,8 +103,6 @@ github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISH
99103
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
100104
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
101105
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
102-
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
103-
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
104106
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
105107
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
106108
github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=

0 commit comments

Comments
 (0)