Skip to content

Commit 01b6b5f

Browse files
committed
helper/schema: initial work
1 parent 3e3be5e commit 01b6b5f

4 files changed

Lines changed: 173 additions & 0 deletions

File tree

helper/schema/resource.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package schema
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
)
7+
8+
// The functions below are the CRUD function types for a Resource.
9+
type CreateFunc func(*ResourceData) error
10+
type ReadFunc func(*ResourceData) error
11+
type UpdateFunc func(*ResourceData) error
12+
type DeleteFunc func(*ResourceData) error
13+
14+
// Resource represents a thing in Terraform that has a set of configurable
15+
// attributes and generally also has a lifecycle (create, read, update,
16+
// delete).
17+
//
18+
// The Resource schema is an abstraction that allows provider writers to
19+
// worry only about CRUD operations while off-loading validation, diff
20+
// generation, etc. to this higher level library.
21+
type Resource struct {
22+
Schema map[string]*Schema
23+
24+
Create CreateFunc
25+
Read ReadFunc
26+
Update UpdateFunc
27+
Delete DeleteFunc
28+
}
29+
30+
// InternalValidate should be called to validate the structure
31+
// of the resource.
32+
//
33+
// This should be called in a unit test for any resource to verify
34+
// before release that a resource is properly configured for use with
35+
// this library.
36+
func (r *Resource) InternalValidate() error {
37+
if r == nil {
38+
return errors.New("resource is nil")
39+
}
40+
41+
for k, v := range r.Schema {
42+
if v.Type == TypeInvalid {
43+
return fmt.Errorf("%s: Type must be specified", k)
44+
}
45+
46+
if v.Optional && v.Required {
47+
return fmt.Errorf("%s: Optional or Required must be set, not both", k)
48+
}
49+
50+
if v.Required && v.Computed {
51+
return fmt.Errorf("%s: Cannot be both Required and Computed", k)
52+
}
53+
}
54+
55+
return nil
56+
}

helper/schema/resource_data.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package schema
2+
3+
// ResourceData is used to query and set the attributes of a resource.
4+
type ResourceData struct{}

helper/schema/resource_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package schema
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestResourceInternalValidate(t *testing.T) {
8+
cases := []struct {
9+
In *Resource
10+
Err bool
11+
}{
12+
{
13+
nil,
14+
true,
15+
},
16+
17+
// No optional and no required
18+
{
19+
&Resource{
20+
Schema: map[string]*Schema{
21+
"foo": &Schema{
22+
Type: TypeInt,
23+
Optional: true,
24+
Required: true,
25+
},
26+
},
27+
},
28+
true,
29+
},
30+
31+
// Missing Type
32+
{
33+
&Resource{
34+
Schema: map[string]*Schema{
35+
"foo": &Schema{
36+
Required: true,
37+
},
38+
},
39+
},
40+
true,
41+
},
42+
43+
// Required but computed
44+
{
45+
&Resource{
46+
Schema: map[string]*Schema{
47+
"foo": &Schema{
48+
Type: TypeInt,
49+
Required: true,
50+
Computed: true,
51+
},
52+
},
53+
},
54+
true,
55+
},
56+
57+
// Looks good
58+
{
59+
&Resource{
60+
Schema: map[string]*Schema{
61+
"foo": &Schema{
62+
Type: TypeString,
63+
Required: true,
64+
},
65+
},
66+
},
67+
false,
68+
},
69+
}
70+
71+
for i, tc := range cases {
72+
err := tc.In.InternalValidate()
73+
if (err != nil) != tc.Err {
74+
t.Fatalf("%d: bad: %s", i, err)
75+
}
76+
}
77+
}

helper/schema/schema.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package schema
2+
3+
// ValueType is an enum of the type that can be represented by a schema.
4+
type ValueType int
5+
6+
const (
7+
TypeInvalid ValueType = iota
8+
TypeBoolean
9+
TypeInt
10+
TypeString
11+
TypeList
12+
)
13+
14+
// Schema is used to describe the structure of a value.
15+
type Schema struct {
16+
// Type is the type of the value and must be one of the ValueType values.
17+
Type ValueType
18+
19+
// If one of these is set, then this item can come from the configuration.
20+
// Both cannot be set. If Optional is set, the value is optional. If
21+
// Required is set, the value is required.
22+
Optional bool
23+
Required bool
24+
25+
// The fields below relate to diffs: if Computed is true, then the
26+
// result of this value is computed (unless specified by config).
27+
// If ForceNew is true
28+
Computed bool
29+
ForceNew bool
30+
31+
// Elem must be either a *Schema or a *Resource only if the Type is
32+
// TypeList, and represents what the element type is. If it is *Schema,
33+
// the element type is just a simple value. If it is *Resource, the
34+
// element type is a complex structure, potentially with its own lifecycle.
35+
Elem interface{}
36+
}

0 commit comments

Comments
 (0)