Skip to content

Commit 3321a3a

Browse files
Implements '*'(expand all) field selector. Closes: #147
Fixes `schema.Array` behaviour with `schema.Reference`. Adds projection validation to items within `schema.Array`.
1 parent 0163c13 commit 3321a3a

17 files changed

+588
-117
lines changed

README.md

+23
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,29 @@ $ http -b :8080/api/users/ar6eimekj5lfktka9mt0/posts fields=='meta{title,body}'
973973
]
974974
```
975975
976+
Also `all fields` expansion is supported:
977+
```sh
978+
$ http -b :8080/api/users/ar6eimekj5lfktka9mt0/posts fields=='*,user{*}'
979+
[
980+
{
981+
"_etag": "ar6eimukj5lfl07r0uv0",
982+
"id": "ar6eimukj5lfl07r0ugz",
983+
"created": "2015-07-27T21:46:55.355857401+02:00",
984+
"updated": "2015-07-27T21:46:55.355857989+02:00",
985+
"user": {
986+
"id": "ar6eimukj5lfl07gzb0b",
987+
"created": "2015-07-24T21:46:55.355857401+02:00",
988+
"updated": "2015-07-24T21:46:55.355857989+02:00",
989+
"name": "John Snow",
990+
},
991+
"meta": {
992+
"title": "test",
993+
"body": "example"
994+
}
995+
}
996+
]
997+
```
998+
976999
#### Field Aliasing
9771000
9781001
It's also possible to rename fields in the response using aliasing. To create an alias, prefix the field name by the wanted alias separated by a colon (`:`):

resource/index.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ type refChecker struct {
109109
}
110110

111111
// ReferenceChecker implements the schema.ReferenceChecker interface.
112-
func (rc refChecker) ReferenceChecker(path string) schema.FieldValidator {
112+
func (rc refChecker) ReferenceChecker(path string) (schema.FieldValidator, schema.Validator) {
113113
rsc, exists := rc.index.GetResource(path, nil)
114114
if !exists {
115-
return nil
115+
return nil, nil
116116
}
117117
validator := rsc.Schema().Fields["id"].Validator
118118

@@ -134,7 +134,7 @@ func (rc refChecker) ReferenceChecker(path string) schema.FieldValidator {
134134
return nil, err
135135
}
136136
return id, nil
137-
})
137+
}), rsc.Validator()
138138
}
139139

140140
// assertNotBound asserts a given resource name is not already bound.

schema/all_test.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,9 @@ func (tc fieldSerializerTestCase) Run(t *testing.T) {
154154
}
155155

156156
type fakeReferenceChecker map[string]struct {
157-
IDs []interface{}
158-
Validator schema.FieldValidator
157+
IDs []interface{}
158+
Validator schema.FieldValidator
159+
SchemaValidator schema.Validator
159160
}
160161

161162
func (rc fakeReferenceChecker) Compile() error {
@@ -172,10 +173,10 @@ func (rc fakeReferenceChecker) Compile() error {
172173
return nil
173174
}
174175

175-
func (rc fakeReferenceChecker) ReferenceChecker(path string) schema.FieldValidator {
176+
func (rc fakeReferenceChecker) ReferenceChecker(path string) (schema.FieldValidator, schema.Validator) {
176177
rsc, ok := rc[path]
177178
if !ok {
178-
return nil
179+
return nil, nil
179180
}
180181
return schema.FieldValidatorFunc(func(value interface{}) (interface{}, error) {
181182
var id interface{}
@@ -197,5 +198,5 @@ func (rc fakeReferenceChecker) ReferenceChecker(path string) schema.FieldValidat
197198
}
198199
}
199200
return nil, errors.New("not found")
200-
})
201+
}), rsc.SchemaValidator
201202
}

schema/alloff_test.go

+12-8
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ func TestAllOfValidator(t *testing.T) {
5151
},
5252
ReferenceChecker: fakeReferenceChecker{
5353
"foo": {
54-
IDs: []interface{}{"foo1"},
55-
Validator: &schema.String{},
54+
IDs: []interface{}{"foo1"},
55+
Validator: &schema.String{},
56+
SchemaValidator: &schema.Schema{},
5657
},
5758
"bar": {
58-
IDs: []interface{}{"bar1", "bar2", "bar3"},
59-
Validator: &schema.String{},
59+
IDs: []interface{}{"bar1", "bar2", "bar3"},
60+
Validator: &schema.String{},
61+
SchemaValidator: &schema.Schema{},
6062
},
6163
},
6264
Input: "foo1",
@@ -96,12 +98,14 @@ func TestAllOfQueryValidator(t *testing.T) {
9698
},
9799
ReferenceChecker: fakeReferenceChecker{
98100
"foo": {
99-
IDs: []interface{}{"foo1"},
100-
Validator: &schema.String{},
101+
IDs: []interface{}{"foo1"},
102+
Validator: &schema.String{},
103+
SchemaValidator: &schema.Schema{},
101104
},
102105
"bar": {
103-
IDs: []interface{}{"bar1", "bar2", "bar3"},
104-
Validator: &schema.String{},
106+
IDs: []interface{}{"bar1", "bar2", "bar3"},
107+
Validator: &schema.String{},
108+
SchemaValidator: &schema.Schema{},
105109
},
106110
},
107111
Input: "foo1",

schema/anyof_test.go

+14-10
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ func TestAnyOfCompile(t *testing.T) {
4949
{
5050
Name: "{Reference{Path:valid}}",
5151
Compiler: &schema.AnyOf{&schema.Reference{Path: "items"}},
52-
ReferenceChecker: fakeReferenceChecker{"items": {IDs: []interface{}{1, 2, 3}, Validator: &schema.Integer{}}},
52+
ReferenceChecker: fakeReferenceChecker{"items": {IDs: []interface{}{1, 2, 3}, Validator: &schema.Integer{}, SchemaValidator: &schema.Schema{}}},
5353
},
5454
{
5555
Name: "{Reference{Path:invalid}}",
5656
Compiler: &schema.AnyOf{&schema.Reference{Path: "foobar"}},
57-
ReferenceChecker: fakeReferenceChecker{"items": {IDs: []interface{}{1, 2, 3}, Validator: &schema.Integer{}}},
57+
ReferenceChecker: fakeReferenceChecker{"items": {IDs: []interface{}{1, 2, 3}, Validator: &schema.Integer{}, SchemaValidator: &schema.Schema{}}},
5858
Error: "can't find resource 'foobar'",
5959
},
6060
}
@@ -97,12 +97,14 @@ func TestAnyOfValidate(t *testing.T) {
9797
},
9898
ReferenceChecker: fakeReferenceChecker{
9999
"foo": {
100-
IDs: []interface{}{"foo1"},
101-
Validator: &schema.String{},
100+
IDs: []interface{}{"foo1"},
101+
Validator: &schema.String{},
102+
SchemaValidator: &schema.Schema{},
102103
},
103104
"bar": {
104-
IDs: []interface{}{"bar1", "bar2", "bar3"},
105-
Validator: &schema.String{},
105+
IDs: []interface{}{"bar1", "bar2", "bar3"},
106+
Validator: &schema.String{},
107+
SchemaValidator: &schema.Schema{},
106108
},
107109
},
108110
Input: "foo1",
@@ -148,12 +150,14 @@ func TestAnyOfQueryValidate(t *testing.T) {
148150
},
149151
ReferenceChecker: fakeReferenceChecker{
150152
"foo": {
151-
IDs: []interface{}{"foo1"},
152-
Validator: &schema.String{},
153+
IDs: []interface{}{"foo1"},
154+
Validator: &schema.String{},
155+
SchemaValidator: &schema.Schema{},
153156
},
154157
"bar": {
155-
IDs: []interface{}{"bar1", "bar2", "bar3"},
156-
Validator: &schema.String{},
158+
IDs: []interface{}{"bar1", "bar2", "bar3"},
159+
Validator: &schema.String{},
160+
SchemaValidator: &schema.Schema{},
157161
},
158162
},
159163
Input: "foo1",

schema/compiler.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ type Compiler interface {
1010
type ReferenceChecker interface {
1111
// ReferenceChecker should return a FieldValidator that can be used for validate that a referenced ID exists and
1212
// is of the right format. If there is no resource matching path, nil should e returned.
13-
ReferenceChecker(path string) FieldValidator
13+
ReferenceChecker(path string) (FieldValidator, Validator)
1414
}
1515

1616
// ReferenceCheckerFunc is an adapter that allows ordinary functions to be used as reference checkers.

schema/dict_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ func TestDictCompile(t *testing.T) {
3636
{
3737
Name: "{Values.Validator:Reference{Path:valid}}",
3838
Compiler: &schema.Dict{Values: schema.Field{Validator: &schema.Reference{Path: "foo"}}},
39-
ReferenceChecker: fakeReferenceChecker{"foo": {}},
39+
ReferenceChecker: fakeReferenceChecker{"foo": {SchemaValidator: &schema.Schema{}}},
4040
},
4141
{
4242
Name: "{Values.Validator:Reference{Path:invalid}}",
4343
Compiler: &schema.Dict{Values: schema.Field{Validator: &schema.Reference{Path: "bar"}}},
44-
ReferenceChecker: fakeReferenceChecker{"foo": {}},
44+
ReferenceChecker: fakeReferenceChecker{"foo": {SchemaValidator: &schema.Schema{}}},
4545
Error: "can't find resource 'bar'",
4646
},
4747
}

schema/object_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ func TestObjectCompile(t *testing.T) {
3232
Compiler: &schema.Object{Schema: &schema.Schema{Fields: schema.Fields{
3333
"foo": {Validator: &schema.Reference{Path: "bar"}},
3434
}}},
35-
ReferenceChecker: fakeReferenceChecker{"bar": {}},
35+
ReferenceChecker: fakeReferenceChecker{"bar": {SchemaValidator: &schema.Schema{}}},
3636
},
3737
{
3838
Name: `{Schema:{"foo":Reference{Path:invalid}}}`,
3939
Compiler: &schema.Object{Schema: &schema.Schema{Fields: schema.Fields{
4040
"foo": {Validator: &schema.Reference{Path: "foobar"}},
4141
}}},
42-
ReferenceChecker: fakeReferenceChecker{"bar": {}},
42+
ReferenceChecker: fakeReferenceChecker{"bar": {SchemaValidator: &schema.Schema{}}},
4343
Error: "foo: can't find resource 'foobar'",
4444
},
4545
}
@@ -81,7 +81,7 @@ func TestObjectValidate(t *testing.T) {
8181
"foo": {Validator: &schema.Reference{Path: "bar"}},
8282
}}},
8383
ReferenceChecker: fakeReferenceChecker{
84-
"bar": {IDs: []interface{}{"a", "b"}, Validator: &schema.String{}},
84+
"bar": {IDs: []interface{}{"a", "b"}, Validator: &schema.String{}, SchemaValidator: &schema.Schema{}},
8585
},
8686
Input: map[string]interface{}{"foo": "a"},
8787
Expect: map[string]interface{}{"foo": "a"},
@@ -92,7 +92,7 @@ func TestObjectValidate(t *testing.T) {
9292
"foo": {Validator: &schema.Reference{Path: "bar"}},
9393
}}},
9494
ReferenceChecker: fakeReferenceChecker{
95-
"bar": {IDs: []interface{}{"a", "b"}, Validator: &schema.String{}},
95+
"bar": {IDs: []interface{}{"a", "b"}, Validator: &schema.String{}, SchemaValidator: &schema.Schema{}},
9696
},
9797
Input: map[string]interface{}{"foo": "c"},
9898
Error: "foo is [not found]",

schema/query/projection.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ type ProjectionField struct {
3333
}
3434

3535
// Validate validates the projection against the provided validator.
36-
func (p Projection) Validate(validator schema.Validator) error {
36+
func (p Projection) Validate(fg schema.FieldGetter) error {
3737
for _, pf := range p {
38-
if err := pf.Validate(validator); err != nil {
38+
if err := pf.Validate(fg); err != nil {
3939
return err
4040
}
4141
}

0 commit comments

Comments
 (0)