Skip to content

Commit b64a4ad

Browse files
austinvallebflad
andauthored
Add schema overrides to generator config for description (#52)
* move all implementations to their own files * add error handling to resource * initial implementation - no tests * add validation tests * add config mapping test * add simple override tests * add nested override tests * added high-level attributes testing * switch to make * update variable names + comments * Update internal/config/parse.go Co-authored-by: Brian Flad <[email protected]> * add deep nesting example --------- Co-authored-by: Brian Flad <[email protected]>
1 parent 2851201 commit b64a4ad

38 files changed

+3534
-242
lines changed

internal/cmd/testdata/petstore3/generated_framework_ir.json

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,15 @@
3232
{
3333
"name": "shipDate",
3434
"string": {
35-
"computed_optional_required": "computed"
35+
"computed_optional_required": "computed",
36+
"description": "A field representing the date and time an order will be shipped by"
3637
}
3738
},
3839
{
3940
"name": "status",
4041
"string": {
4142
"computed_optional_required": "computed",
42-
"description": "Order Status"
43+
"description": "Order status, possible values - 'placed', 'approved', or 'delivered'"
4344
}
4445
}
4546
]
@@ -70,16 +71,19 @@
7071
{
7172
"name": "name",
7273
"string": {
73-
"computed_optional_required": "computed"
74+
"computed_optional_required": "computed",
75+
"description": "The category name, possible values - 'dog', 'cat', 'bird', or 'other'"
7476
}
7577
}
76-
]
78+
],
79+
"description": "Category containing classification info about the pet"
7780
}
7881
},
7982
{
8083
"name": "name",
8184
"string": {
82-
"computed_optional_required": "computed"
85+
"computed_optional_required": "computed",
86+
"description": "The pet's full name"
8387
}
8488
},
8589
{
@@ -186,14 +190,15 @@
186190
{
187191
"name": "shipDate",
188192
"string": {
189-
"computed_optional_required": "computed_optional"
193+
"computed_optional_required": "computed_optional",
194+
"description": "A field representing the date and time an order will be shipped by"
190195
}
191196
},
192197
{
193198
"name": "status",
194199
"string": {
195200
"computed_optional_required": "computed_optional",
196-
"description": "Order Status",
201+
"description": "Order status, possible values - 'placed', 'approved', or 'delivered'",
197202
"validators": [
198203
{
199204
"custom": {
@@ -229,10 +234,12 @@
229234
{
230235
"name": "name",
231236
"string": {
232-
"computed_optional_required": "computed_optional"
237+
"computed_optional_required": "computed_optional",
238+
"description": "The category name, possible values - 'dog', 'cat', 'bird', or 'other'"
233239
}
234240
}
235-
]
241+
],
242+
"description": "Category containing classification info about the pet"
236243
}
237244
},
238245
{
@@ -245,7 +252,8 @@
245252
{
246253
"name": "name",
247254
"string": {
248-
"computed_optional_required": "required"
255+
"computed_optional_required": "required",
256+
"description": "The pet's full name"
249257
}
250258
},
251259
{

internal/cmd/testdata/petstore3/tfopenapigen_config.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ resources:
1717
method: DELETE
1818
schema:
1919
attributes:
20+
overrides:
21+
name:
22+
description: The pet's full name
23+
category:
24+
description: Category containing classification info about the pet
25+
"category.name":
26+
description: The category name, possible values - 'dog', 'cat', 'bird', or 'other'
2027
aliases:
2128
petId: id
2229

@@ -32,6 +39,11 @@ resources:
3239
method: DELETE
3340
schema:
3441
attributes:
42+
overrides:
43+
status:
44+
description: Order status, possible values - 'placed', 'approved', or 'delivered'
45+
shipDate:
46+
description: A field representing the date and time an order will be shipped by
3547
aliases:
3648
orderId: id
3749

@@ -50,6 +62,13 @@ data_sources:
5062
method: GET
5163
schema:
5264
attributes:
65+
overrides:
66+
name:
67+
description: The pet's full name
68+
category:
69+
description: Category containing classification info about the pet
70+
"category.name":
71+
description: The category name, possible values - 'dog', 'cat', 'bird', or 'other'
5372
aliases:
5473
petId: id
5574

@@ -64,5 +83,10 @@ data_sources:
6483
method: GET
6584
schema:
6685
attributes:
86+
overrides:
87+
status:
88+
description: Order status, possible values - 'placed', 'approved', or 'delivered'
89+
shipDate:
90+
description: A field representing the date and time an order will be shipped by
6791
aliases:
6892
orderId: id

internal/config/parse.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,20 @@ package config
66
import (
77
"errors"
88
"fmt"
9+
"regexp"
910

1011
"github.com/pb33f/libopenapi/index"
1112
"gopkg.in/yaml.v3"
1213
)
1314

15+
// This regex matches attribute locations, dot-separated, as represented as {attribute_name}.{nested_attribute_name}
16+
// - category = MATCH
17+
// - category.id = MATCH
18+
// - category.tags.name = MATCH
19+
// - category. = NO MATCH
20+
// - .category = NO MATCH
21+
var attributeLocationRegex = regexp.MustCompile(`^[\w]+(?:\.[\w]+)*$`)
22+
1423
// Config is tagged with `yaml` struct tags, however YAML is a superset of JSON, so it can also be parsed from JSON
1524
type Config struct {
1625
Provider Provider `yaml:"provider"`
@@ -44,7 +53,12 @@ type SchemaOptions struct {
4453
AttributeOptions AttributeOptions `yaml:"attributes"`
4554
}
4655
type AttributeOptions struct {
47-
Aliases map[string]string `yaml:"aliases"`
56+
Aliases map[string]string `yaml:"aliases"`
57+
Overrides map[string]Override `yaml:"overrides"`
58+
}
59+
60+
type Override struct {
61+
Description string `yaml:"description"`
4862
}
4963

5064
// ParseConfig takes in a byte array (of YAML), unmarshal into a Config struct, and validates the result
@@ -138,6 +152,11 @@ func (r Resource) Validate() error {
138152
result = errors.Join(result, fmt.Errorf("invalid delete: %w", err))
139153
}
140154

155+
err = r.SchemaOptions.Validate()
156+
if err != nil {
157+
result = errors.Join(result, fmt.Errorf("invalid schema: %w", err))
158+
}
159+
141160
return result
142161
}
143162

@@ -153,6 +172,11 @@ func (d DataSource) Validate() error {
153172
result = errors.Join(result, fmt.Errorf("invalid read: %w", err))
154173
}
155174

175+
err = d.SchemaOptions.Validate()
176+
if err != nil {
177+
result = errors.Join(result, fmt.Errorf("invalid schema: %w", err))
178+
}
179+
156180
return result
157181
}
158182

@@ -172,3 +196,26 @@ func (o *OpenApiSpecLocation) Validate() error {
172196

173197
return result
174198
}
199+
200+
func (s *SchemaOptions) Validate() error {
201+
var result error
202+
203+
err := s.AttributeOptions.Validate()
204+
if err != nil {
205+
result = errors.Join(result, fmt.Errorf("invalid attributes: %w", err))
206+
}
207+
208+
return result
209+
}
210+
211+
func (s *AttributeOptions) Validate() error {
212+
var result error
213+
214+
for path := range s.Overrides {
215+
if !attributeLocationRegex.MatchString(path) {
216+
result = errors.Join(result, fmt.Errorf("invalid key for override: %q - must be dot-separated string", path))
217+
}
218+
}
219+
220+
return result
221+
}

internal/config/parse_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,29 @@ resources:
4747
attributes:
4848
aliases:
4949
otherId: id`,
50+
},
51+
"valid resource with overrides": {
52+
input: `
53+
provider:
54+
name: example
55+
56+
resources:
57+
thing:
58+
create:
59+
path: /example/path/to/things
60+
method: POST
61+
read:
62+
path: /example/path/to/thing/{id}
63+
method: GET
64+
schema:
65+
attributes:
66+
overrides:
67+
hey:
68+
description: Here is a test description for the 'hey' property
69+
"hey.there":
70+
description: Here is a test description for the 'there' property in 'hey'
71+
"hey.there.nested.thing":
72+
description: Deeply nested property 'thing'`,
5073
},
5174
"valid single data source": {
5275
input: `
@@ -73,6 +96,26 @@ data_sources:
7396
attributes:
7497
aliases:
7598
otherId: id`,
99+
},
100+
"valid data source with overrides": {
101+
input: `
102+
provider:
103+
name: example
104+
105+
data_sources:
106+
thing:
107+
read:
108+
path: /example/path/to/thing/{id}
109+
method: GET
110+
schema:
111+
attributes:
112+
overrides:
113+
hey:
114+
description: Here is a test description for the 'hey' property
115+
"hey.there":
116+
description: Here is a test description for the 'there' property in 'hey'
117+
"hey.there.nested.thing":
118+
description: Deeply nested property 'thing'`,
76119
},
77120
"valid combo of resources and data sources": {
78121
input: `
@@ -270,6 +313,26 @@ resources:
270313
path: /example/path/to/things`,
271314
expectedErrRegex: `invalid delete: 'method' property is required`,
272315
},
316+
"resource - invalid override key": {
317+
input: `
318+
provider:
319+
name: example
320+
321+
resources:
322+
thing_one:
323+
create:
324+
path: /example/path/to/things
325+
method: POST
326+
read:
327+
path: /example/path/to/thing/{id}
328+
method: GET
329+
schema:
330+
attributes:
331+
overrides:
332+
".hey":
333+
description: Here is a test description for the 'hey' property`,
334+
expectedErrRegex: `invalid key for override: \".hey\"`,
335+
},
273336
"data source - read required": {
274337
input: `
275338
provider:
@@ -301,6 +364,23 @@ data_sources:
301364
path: /example/path/to/thing/{id}`,
302365
expectedErrRegex: `invalid read: 'method' property is required`,
303366
},
367+
"data source - invalid override key": {
368+
input: `
369+
provider:
370+
name: example
371+
372+
data_sources:
373+
thing_one:
374+
read:
375+
path: /example/path/to/thing/{id}
376+
method: GET
377+
schema:
378+
attributes:
379+
overrides:
380+
"hey.":
381+
description: Here is a test description for the 'hey' property`,
382+
expectedErrRegex: `invalid key for override: \"hey.\"`,
383+
},
304384
}
305385
for name, testCase := range testCases {
306386
name, testCase := name, testCase

internal/explorer/config_explorer.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,17 @@ func extractSchemaProxy(document high.Document, componentRef string) (*highbase.
136136
func extractSchemaOptions(cfgSchemaOpts config.SchemaOptions) SchemaOptions {
137137
return SchemaOptions{
138138
AttributeOptions: AttributeOptions{
139-
Aliases: cfgSchemaOpts.AttributeOptions.Aliases,
139+
Aliases: cfgSchemaOpts.AttributeOptions.Aliases,
140+
Overrides: extractOverrides(cfgSchemaOpts.AttributeOptions.Overrides),
140141
},
141142
}
142143
}
144+
145+
func extractOverrides(cfgOverrides map[string]config.Override) map[string]Override {
146+
overrides := make(map[string]Override, len(cfgOverrides))
147+
for key, cfgOverride := range cfgOverrides {
148+
overrides[key] = Override{Description: cfgOverride.Description}
149+
}
150+
151+
return overrides
152+
}

0 commit comments

Comments
 (0)