Repository: jensneuse/graphql-go-tools
Pull request #131 (2019-12-04 09:47:50)

Feature/add complex path selections
This PR will add complex field selectors and simplify mappings by replacing the @path and @mapTo directive with a more capable @mapping directive. More on that can be found in the description of the directive itself.


Patch:
diff --git a/go.mod b/go.mod
index 994a36dc..1cb22046 100644
--- a/go.mod
+++ b/go.mod
@@ -15,6 +15,7 @@ require (
 	github.com/pkg/errors v0.8.1 // indirect
 	github.com/sebdah/goldie v0.0.0-20180424091453-8784dd1ab561
 	github.com/stretchr/testify v1.4.0 // indirect
+	github.com/tidwall/gjson v1.3.5
 	github.com/valyala/fasttemplate v1.1.0
 	go.uber.org/atomic v1.4.0 // indirect
 	go.uber.org/multierr v1.2.0 // indirect
diff --git a/go.sum b/go.sum
index 95a34db7..7404f535 100644
--- a/go.sum
+++ b/go.sum
@@ -89,6 +89,12 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/tidwall/gjson v1.3.5 h1:2oW9FBNu8qt9jy5URgrzsVx/T/KSn3qn/smJQ0crlDQ=
+github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
+github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
+github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
+github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
+github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go
index cf6f2eb5..20767324 100644
--- a/pkg/ast/ast.go
+++ b/pkg/ast/ast.go
@@ -799,6 +799,10 @@ func (d *Document) EnumValueNameBytes(ref int) ByteSlice {
 	return d.Input.ByteSlice(d.EnumValues[ref].Name)
 }
 
+func (d *Document) EnumValueNameString(ref int) string {
+	return unsafebytes.BytesToString(d.Input.ByteSlice(d.EnumValues[ref].Name))
+}
+
 func (d *Document) EnumValuesAreEqual(left, right int) bool {
 	return d.Input.ByteSliceReferenceContentEquals(d.EnumValueName(left), d.EnumValueName(right))
 }
diff --git a/pkg/execution/a_execution-packr.go b/pkg/execution/a_execution-packr.go
index bf7e54f3..b7961ed7 100644
--- a/pkg/execution/a_execution-packr.go
+++ b/pkg/execution/a_execution-packr.go
@@ -10,10 +10,10 @@ func init() {
 	_ = packr.PackJSONBytes("./graphql_definitions", "directives/graphql_datasource.graphql", "\"ZGlyZWN0aXZlIEBHcmFwaFFMRGF0YVNvdXJjZSAoCiAgICAiIiIKICAgIHRoZSBob3N0IG9mIHRoZSBvcmlnaW4KICAgICIiIgogICAgaG9zdDogU3RyaW5nIQogICAgIiIiCiAgICB0aGUgdXJsIG9mIHRoZSBvcmlnaW4KICAgICIiIgogICAgdXJsOiBTdHJpbmchCiAgICAiIiIKICAgIHRoZSBIVFRQIG1ldGhvZCB0aGUgY2xpZW50IHNob3VsZCB1c2UgZm9yIHRoZSByZXF1ZXN0LCBkZWZhdWx0cyB0byBHRVQKICAgICIiIgogICAgbWV0aG9kOiBIVFRQX01FVEhPRCA9IFBPU1QKICAgICIiIgogICAgcGFyYW1ldGVycwogICAgIiIiCiAgICBwYXJhbXM6IFtQYXJhbWV0ZXJdCikgb24gRklFTERfREVGSU5JVElPTg==\"")
 	_ = packr.PackJSONBytes("./graphql_definitions", "directives/http_json_datasource.graphql", "\"ZGlyZWN0aXZlIEBIdHRwSnNvbkRhdGFTb3VyY2UgKAogICAgIiIiCiAgICB0aGUgaG9zdCBvZiB0aGUgb3JpZ2luCiAgICAiIiIKICAgIGhvc3Q6IFN0cmluZyEKICAgICIiIgogICAgdGhlIHVybCBvZiB0aGUgb3JpZ2luCiAgICAiIiIKICAgIHVybDogU3RyaW5nIQogICAgIiIiCiAgICB0aGUgSFRUUCBtZXRob2QgdGhlIGNsaWVudCBzaG91bGQgdXNlIGZvciB0aGUgcmVxdWVzdCwgZGVmYXVsdHMgdG8gR0VUCiAgICAiIiIKICAgIG1ldGhvZDogSFRUUF9NRVRIT0QgPSBHRVQKICAgICIiIgogICAgcGFyYW1ldGVycwogICAgIiIiCiAgICBwYXJhbXM6IFtQYXJhbWV0ZXJdCiAgICAiIiIKICAgIGJvZHkgaXMgdGhlIG9wdGlvbmFsIGRlZmluaXRpb24gb2YgdGhlIGh0dHAgYm9keSB0byBiZSBzZW50IHRvIHRoZSB1cHN0cmVhbQogICAgZ29sYW5nIHRlbXBsYXRpbmcgc3ludGF4IG1pZ2h0IGJlIHVzZWQgdG8gY3JlYXRlIHRoZSBib2R5CiAgICAiIiIKICAgIGJvZHk6IFN0cmluZwogICAgIiIiCiAgICBoZWFkZXJzIGFyZSB0aGUga2V5IHZhbHVlIHBhaXJzIHRvIGJlIHNldCBvbiB0aGUgdXBzdHJlYW0gcmVxdWVzdAogICAgIiIiCiAgICBoZWFkZXJzOiBbSGVhZGVyXQopIG9uIEZJRUxEX0RFRklOSVRJT04=\"")
 	_ = packr.PackJSONBytes("./graphql_definitions", "directives/http_polling_stream_datasource.graphql", "\"IiIiCkh0dHBQb2xsaW5nU3RyZWFtRGF0YVNvdXJjZQoiIiIKZGlyZWN0aXZlIEBIdHRwUG9sbGluZ1N0cmVhbURhdGFTb3VyY2UgKAogICAgIiIiCiAgICBob3N0IGlzIHRoZSBob3N0IG5hbWUgb2YgdGhlIGRhdGEgc291cmNlLCBlLmcuIGV4YW1wbGUuY29tCiAgICAiIiIKICAgIGhvc3Q6IFN0cmluZyEKICAgICIiIgogICAgdXJsIGlzIHRoZSBVUkwgZnJvbSB3aGljaCB0aGUgZGF0YSBzb3VyY2Ugc2hvdWxkIHBvbGwgZGF0YSBmcm9tCiAgICB5b3UgY291bGQgdXNlIGdvbGFuZyB0ZW1wbGF0aW5nIHN5bnRheCwgZS5nLjoKICAgICcvdXNlcnMve3sgLklkIH19JyArIHBhcmFtZXRlciBuYW1lZCBpZCB3aXRoIHZhbHVlIDEgKHNlZSBiZWxvdykgd2lsbCByZW5kZXIgdG8gVVJMICcvdXNlcnMvMScKICAgICIiIgogICAgdXJsOiBTdHJpbmchCiAgICAibWV0aG9kIGlzIHRoZSBIVFRQIG1ldGhvZCB0aGUgZGF0YSBzb3VyY2Ugc2hvdWxkIHVzZSB0byBmZXRjaCBkYXRhIGZyb20gdGhlIHVwc3RyZWFtIgogICAgbWV0aG9kOiBIVFRQX01FVEhPRCA9IEdFVAogICAgInRoZSBkZWxheSBpbiBzZWNvbmRzIGJldHdlZW4gZWFjaCBwb2xsaW5nIgogICAgZGVsYXlTZWNvbmRzOiBJbnQgPSA1CiAgICAiIiIKICAgIHBhcmFtcyBhcmUgdGhlIHBhcmFtZXRlcnMgdGhhdCBzaG91bGQgZ2V0IHBhc3NlZCB0byB0aGUgZGF0YSBzb3VyY2UKICAgIHlvdSBjb3VsZCB1c2UgdGhpcyBmdW5jdGlvbiB0byBwYXNzIHZhcmlhYmxlcyBmcm9tIGZpZWxkIHZhcmlhYmxlcywgdGhlIGNvbnRleHQgb3IgcGFyZW50IG9iamVjdCB0byB0aGUgZGF0YSBzb3VyY2UKICAgIHRoc2UgY291bGQgYmUgdXNlZCB0byAncmVuZGVyJyB0aGUgdXJsIGR5bmFtaWNhbGx5CiAgICAiIiIKICAgIHBhcmFtczogW1BhcmFtZXRlcl0KKSBvbiBGSUVMRF9ERUZJTklUSU9O\"")
-	_ = packr.PackJSONBytes("./graphql_definitions", "directives/map_to.graphql", "\"ZGlyZWN0aXZlIEBtYXBUbygKICAgIG9iamVjdEZpZWxkOiBTdHJpbmchCikgb24gRklFTERfREVGSU5JVElPTg==\"")
-	_ = packr.PackJSONBytes("./graphql_definitions", "directives/path.graphql", "\"ZGlyZWN0aXZlIEBwYXRoKAogICAgIiIiCiAgICBhcHBlbmQgd2lsbCBhcHBlbmQgdGhlIGxpc3Qgb2YgcGF0aCBlbGVtZW50cyB0byB0aGUgcGF0aCBnZW5lcmF0ZWQgYnkgdGhlIHF1ZXJ5IHBsYW5uZXIKICAgICIiIgogICAgYXBwZW5kOiBbU3RyaW5nIV0KICAgICIiIgogICAgcHJlcGVuZCB3aWxsIHByZXBlbmQgdGhlIGxpc3Qgb2YgcGF0aCBlbGVtZW50cyB0byB0aGUgcGF0aCBnZW5lcmF0ZWQgYnkgdGhlIHF1ZXJ5IHBsYW5uZXIKICAgICIiIgogICAgcHJlcGVuZDogW1N0cmluZyFdCikgb24gRklFTERfREVGSU5JVElPTg==\"")
+	_ = packr.PackJSONBytes("./graphql_definitions", "directives/mapping.graphql", "\"IiIiCm1hcHBpbmcgaXMgdGhlIGRpcmVjdGl2ZSB0byBkZWZpbmUgbWFwcGluZ3MgZnJvbSByZXNwb25zZSBvYmplY3RzIHRvIEdyYXBoUUwgZmllbGRzCiIiIgpkaXJlY3RpdmUgQG1hcHBpbmcoCiAgICAiIiIKICAgIG1vZGUgZGVmaW5lcyB0aGUgb3BlcmF0aW5nIG1vZGUgb2YgdGhlIG1hcHBpbmcKICAgICIiIgogICAgbW9kZTogTUFQUElOR19NT0RFISA9IFBBVEhfU0VMRUNUT1IKICAgICIiIgogICAgcGF0aFNlbGVjdG9yIGlzIHRoZSBvcHRpb25hbCBzZWxlY3RvciBTdHJpbmcgdG8gY3VzdG9taXplIHRoZSBtYXBwaW5ncwogICAgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS90aWR3YWxsL2dqc29uIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHdoYXQgc3ludGF4IGlzIHBvc3NpYmxlCiAgICAiIiIKICAgIHBhdGhTZWxlY3RvcjogU3RyaW5nCikgb24gRklFTERfREVGSU5JVElPTg==\"")
 	_ = packr.PackJSONBytes("./graphql_definitions", "directives/static_datasource.graphql", "\"ZGlyZWN0aXZlIEBTdGF0aWNEYXRhU291cmNlICgKICAgIGRhdGE6IFN0cmluZwopIG9uIEZJRUxEX0RFRklOSVRJT04=\"")
 	_ = packr.PackJSONBytes("./graphql_definitions", "enums/http_method.graphql", "\"ZW51bSBIVFRQX01FVEhPRCB7CiAgICBHRVQKICAgIFBPU1QKICAgIFVQREFURQogICAgREVMRVRFCn0=\"")
+	_ = packr.PackJSONBytes("./graphql_definitions", "enums/mapping_mode.graphql", "\"IiIiCk1BUFBJTkdfTU9ERSBpcyB0aGUgZW51bSB0byBkZWZpbmUgdGhlIGRpZmZlcmVudCBtYXBwZXIgbW9kZXMKIiIiCmVudW0gTUFQUElOR19NT0RFIHsKICAgICIiIgogICAgTk9ORSBpcyB0aGUgbW9kZSB0byBza2lwIG1hcHBpbmdzIGF0IGFsbCwgdGhlcmVmb3JlIHRoZSBwYXJlbnQgb2JqZWN0IHdpbGwgZGlyZWN0bHkgZ2V0IHBhc3NlZCB0byB0aGUgY2hpbGQKICAgICIiIgogICAgTk9ORQogICAgIiIiCiAgICBQQVRIX1NFTEVDVE9SIGlzIHRoZSBtb2RlIHdoaWNoIGFwcGxpZXMgYSBwYXRoIHNlbGVjdG9yIHN0cmluZyBvbiB0aGUgcGFyZW50IG9iamVjdCBiZWZvcmUgcGFzc2luZyBpdCB0byB0aGUgY2hpbGQKICAgIHNlZSBodHRwczovL2dpdGh1Yi5jb20vdGlkd2FsbC9nanNvbiBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB3aGF0IHN5bnRheCBpcyBwb3NzaWJsZQogICAgIiIiCiAgICBQQVRIX1NFTEVDVE9SCn0=\"")
 	_ = packr.PackJSONBytes("./graphql_definitions", "enums/parameter_source.graphql", "\"IlBBUkFNRVRFUl9TT1VSQ0UgZGVmaW5lcyB0aGUgc291cmNlIG9mIGEgZHlhbm1pYyBwYXJhbWV0ZXIiCmVudW0gUEFSQU1FVEVSX1NPVVJDRSB7CiAgICAicGFyYW1ldGVyIGZyb20gdGhlIGNvbnRleHQgb2JqZWN0IHdoaWNoIGNvdWxkIGJlIHB1cHVsYXRlZCBieSB0aGUgaHR0cCB3cmFwcGVyIgogICAgQ09OVEVYVF9WQVJJQUJMRQogICAgIiIiCiAgICBwYXJhbWV0ZXIgZnJvbSB0aGUgcGFyZW50IG9iamVjdAogICAgZXhhbXBsZToKICAgIGNvbnNpZGVyIHRoZSBmb2xsb3dpbmcgcXVlcnk6CiAgICB7CiAgICAgICAgdXNlcihpZDogMSkgewogICAgICAgICAgICB1c2VySUQKICAgICAgICAgICAgZnJpZW5kcwogICAgICAgIH0KICAgIH0KICAgIFVzaW5nIHRoZSBQQVJBTUVURVJfU09VUkNFICdPQkpFQ1RfVkFSSUFCTEVfQVJHVU1FTlQnIHdpdGggc291cmNlTmFtZSAndXNlcklEJyByZXR1cm5zIHRoZSB1c2VySUQgZm9yIHVzZXIgd2l0aCBpZCAxIGF0IHJ1bnRpbWUuCiAgICBUaGlzIHdheSB5b3UgY2FuIGR5bmFtaWNhbGx5IGJ1aWxkIGEgcXVlcnkgdG8gdGhlIGZyaWVuZHMgcmVzc291cmNlIHVzaW5nIHRoZSB1c2VySUQgYXQgcnVudGltZSBhbmQgaW5qZWN0IGl0IGludG8gdGhlIHNlY29uZCBxdWVyeS4KICAgICIiIgogICAgT0JKRUNUX1ZBUklBQkxFX0FSR1VNRU5UCiAgICAiIiIKICAgIHBhcmFtZXRlciBmcm9tIHRoZSBmaWVsZCBhcmd1bWVudHMKICAgIGV4YW1wbGU6CiAgICBjb25zaWRlciB0aGUgZm9sbG93aW5nIHF1ZXJ5OgogICAgewogICAgICAgIHVzZXIoaWQ6IDEpIHsKICAgICAgICAgICAgZnJpZW5kcwogICAgICAgIH0KICAgIH0KICAgIFVzaW5nIHRoZSBQQVJBTUVURVJfU09VUkNFICdGSUVMRF9BUkdVTUVOVFMnIHdpdGggc291cmNlTmFtZSAnaWQnIHJldHVybnMgMSBhdCBydW50aW1lLgogICAgVGhpcyB3YXkgeW91IGNhbiByZW5kZXIgdGhlIHJlc3NvdXJjZSB1cmwgZm9yIC91c2VyLzppZCB0byAvdXNlci8xIGF0IHJ1bnRpbWUgZHluYW1pY2FsbHkuCiAgICAiIiIKICAgIEZJRUxEX0FSR1VNRU5UUwp9\"")
 	_ = packr.PackJSONBytes("./graphql_definitions", "inputs/header.graphql", "\"aW5wdXQgSGVhZGVyIHsKICAgIGtleTogU3RyaW5nIQogICAgdmFsdWU6IFN0cmluZyEKfQ==\"")
 	_ = packr.PackJSONBytes("./graphql_definitions", "inputs/parameter.graphql", "\"IiIiClBhcmFtZXRlciBpcyB1c2VmdWwgdG8gbWFwIHZhcmlhYmxlcyBmcm9tIHZhcmlvdXMgc291cmNlcyBpbnRvIHRoZSBkYXRhIHNvdXJjZSBleGVjdXRvci4KIiIiCmlucHV0IFBhcmFtZXRlciB7CiAgICAiIiIKICAgIHRoaXMgaXMgdGhlIG5hbWUgYnkgd2hpY2ggdGhlIGV4ZWN1dGlvbiBlbmdpbmUgd2lsbCBhY2Nlc3MgdGhlIHZhcmlhYmxlCiAgICAiIiIKICAgIG5hbWU6IFN0cmluZyEKICAgICIiIgogICAgdGhlIGtpbmQgb2YgdGhlIHBhcmFtZXRlciBzb3VyY2UKICAgIGN1cnJlbnRseSBzb3VyY2VzOiB0aGUgY29udGV4dCwgdGhlIGVuY2xvc2luZyBvYmplY3QgKGF0IGV4ZWN1dGlvbiB0aW1lKSwgZmllbGQgdmFyaWFibGVzCiAgICAiIiIKICAgIHNvdXJjZUtpbmQ6IFBBUkFNRVRFUl9TT1VSQ0UhCiAgICAiIiIKICAgIG5hbWUgb2YgdGhlIHBhcmFtZXRlciBvbiB0aGUgc291cmNlCiAgICAiIiIKICAgIHNvdXJjZU5hbWU6IFN0cmluZyEKICAgICIiIgogICAgdHlwZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSwgdXNlZCB0byBnZW5lcmF0ZSBhIHZhbGlkIEdyYXBoUUwgcXVlcnkgZm9yIHRoZSB1cHN0cmVhbQogICAgIiIiCiAgICB2YXJpYWJsZVR5cGU6IFN0cmluZyEKfQ==\"")
diff --git a/pkg/execution/datasource.go b/pkg/execution/datasource.go
index 35ecfcd4..ca324052 100644
--- a/pkg/execution/datasource.go
+++ b/pkg/execution/datasource.go
@@ -45,7 +45,7 @@ type DataSourcePlanner interface {
 	// resolverParameters are the parameters from the @directive params field
 	Initialize(walker *astvisitor.Walker, operation, definition *ast.Document, args []Argument, resolverParameters []ResolverParameter)
 	/*
-		OverrideRootFieldPath gives the DataSourcePlanner the capability to change the path of the root field
+		OverrideRootPathSelector gives the DataSourcePlanner the capability to change the path of the root field
 		Example:
 
 		HTTP API response for /foo:
@@ -61,7 +61,6 @@ type DataSourcePlanner interface {
 		The path will be generated by the planner, however the planner doesn't know that the HTTP API response is flat.
 		Therefore in case of the HTTP API we need to override the path to be nil and leave the path as is for GraphQL APIs.
 	*/
-	OverrideRootFieldPath(path []string) []string
 	astvisitor.EnterInlineFragmentVisitor
 	astvisitor.LeaveInlineFragmentVisitor
 	astvisitor.EnterSelectionSetVisitor
diff --git a/pkg/execution/datasource_graphql.go b/pkg/execution/datasource_graphql.go
index cc399876..4cac092b 100644
--- a/pkg/execution/datasource_graphql.go
+++ b/pkg/execution/datasource_graphql.go
@@ -42,10 +42,6 @@ func (g *GraphQLDataSourcePlanner) DirectiveDefinition() []byte {
 	return data
 }
 
-func (g *GraphQLDataSourcePlanner) OverrideRootFieldPath(path []string) []string {
-	return path
-}
-
 func (g *GraphQLDataSourcePlanner) DirectiveName() []byte {
 	return []byte("GraphQLDataSource")
 }
@@ -160,7 +156,7 @@ func (g *GraphQLDataSourcePlanner) EnterField(ref int) {
 		g.rootFieldRef = ref
 
 		var fieldName []byte
-		objectName, ok := g.walker.FieldDefinitionDirectiveArgumentValueByName(ref, []byte("mapTo"), []byte("objectField"))
+		objectName, ok := g.walker.FieldDefinitionDirectiveArgumentValueByName(ref, []byte("mapping"), []byte("pathSelector"))
 		if ok && objectName.Kind == ast.ValueKindString {
 			fieldName = g.definition.StringValueContentBytes(objectName.Ref)
 		} else {
diff --git a/pkg/execution/datasource_http_json.go b/pkg/execution/datasource_http_json.go
index dfeb6b3d..cd3631ce 100644
--- a/pkg/execution/datasource_http_json.go
+++ b/pkg/execution/datasource_http_json.go
@@ -31,13 +31,6 @@ func (h *HttpJsonDataSourcePlanner) DirectiveDefinition() []byte {
 	return data
 }
 
-func (h *HttpJsonDataSourcePlanner) OverrideRootFieldPath(path []string) []string {
-	if len(path) <= 1 {
-		return nil
-	}
-	return path[1:]
-}
-
 func (h *HttpJsonDataSourcePlanner) DirectiveName() []byte {
 	return []byte("HttpJsonDataSource")
 }
@@ -94,9 +87,9 @@ func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) {
 	variableValue := h.definition.StringValueContentBytes(value.Ref)
 	arg := &StaticVariableArgument{
 		Name:  literal.URL,
-		Value: make([]byte,len(variableValue)),
+		Value: make([]byte, len(variableValue)),
 	}
-	copy(arg.Value,variableValue)
+	copy(arg.Value, variableValue)
 	h.args = append([]Argument{arg}, h.args...)
 	value, exists = h.definition.DirectiveArgumentValueByName(directive, literal.HOST)
 	if !exists {
@@ -105,9 +98,9 @@ func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) {
 	variableValue = h.definition.StringValueContentBytes(value.Ref)
 	arg = &StaticVariableArgument{
 		Name:  literal.HOST,
-		Value: make([]byte,len(variableValue)),
+		Value: make([]byte, len(variableValue)),
 	}
-	copy(arg.Value,variableValue)
+	copy(arg.Value, variableValue)
 	h.args = append([]Argument{arg}, h.args...)
 
 	// method
@@ -116,9 +109,9 @@ func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) {
 		variableValue = h.definition.EnumValueNameBytes(value.Ref)
 		arg = &StaticVariableArgument{
 			Name:  literal.METHOD,
-			Value: make([]byte,len(variableValue)),
+			Value: make([]byte, len(variableValue)),
 		}
-		copy(arg.Value,variableValue)
+		copy(arg.Value, variableValue)
 		h.args = append(h.args, arg)
 	} else { // must refactor into functions!
 		inputValueDefinition := h.definition.DirectiveArgumentInputValueDefinition(h.definition.DirectiveNameBytes(directive), literal.METHOD)
@@ -129,9 +122,9 @@ func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) {
 					value := h.definition.EnumValueNameBytes(defaultValue.Ref)
 					arg = &StaticVariableArgument{
 						Name:  literal.METHOD,
-						Value: make([]byte,len(value)),
+						Value: make([]byte, len(value)),
 					}
-					copy(arg.Value,value)
+					copy(arg.Value, value)
 					h.args = append(h.args, arg)
 				}
 			}
@@ -144,9 +137,9 @@ func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) {
 		variableValue = h.definition.StringValueContentBytes(value.Ref)
 		arg = &StaticVariableArgument{
 			Name:  literal.BODY,
-			Value: make([]byte,len(variableValue)),
+			Value: make([]byte, len(variableValue)),
 		}
-		copy(arg.Value,variableValue)
+		copy(arg.Value, variableValue)
 		h.args = append(h.args, arg)
 	}
 
@@ -160,12 +153,12 @@ func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) {
 				continue
 			}
 			variableName := h.operation.VariableValueNameBytes(value.Ref)
-			name := append([]byte(".arguments."),argName...)
+			name := append([]byte(".arguments."), argName...)
 			arg := &ContextVariableArgument{
 				VariableName: variableName,
-				Name: make([]byte,len(name)),
+				Name:         make([]byte, len(name)),
 			}
-			copy(arg.Name,name)
+			copy(arg.Name, name)
 			h.args = append(h.args, arg)
 		}
 	}
@@ -176,7 +169,7 @@ func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) {
 		listArg := &ListArgument{
 			Name: literal.HEADERS,
 		}
-		for _,i := range h.definition.ListValues[value.Ref].Refs {
+		for _, i := range h.definition.ListValues[value.Ref].Refs {
 			listValue := h.definition.Values[i]
 			if listValue.Kind != ast.ValueKindObject {
 				continue
@@ -187,12 +180,12 @@ func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) {
 			if len(fields) != 2 {
 				continue
 			}
-			for _,j := range fields {
+			for _, j := range fields {
 				fieldName := h.definition.ObjectFieldNameBytes(j)
 				switch {
-				case bytes.Equal(fieldName,literal.KEY):
+				case bytes.Equal(fieldName, literal.KEY):
 					key = h.definition.StringValueContentBytes(h.definition.ObjectFieldValue(j).Ref)
-				case bytes.Equal(fieldName,literal.VALUE):
+				case bytes.Equal(fieldName, literal.VALUE):
 					value = h.definition.StringValueContentBytes(h.definition.ObjectFieldValue(j).Ref)
 				}
 			}
@@ -200,12 +193,12 @@ func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) {
 				continue
 			}
 			arg := &StaticVariableArgument{
-				Name:  make([]byte,len(key)),
-				Value: make([]byte,len(value)),
+				Name:  make([]byte, len(key)),
+				Value: make([]byte, len(value)),
 			}
-			copy(arg.Name,key)
-			copy(arg.Value,value)
-			listArg.Arguments = append(listArg.Arguments,arg)
+			copy(arg.Name, key)
+			copy(arg.Value, value)
+			listArg.Arguments = append(listArg.Arguments, arg)
 		}
 
 		if len(listArg.Arguments) != 0 {
@@ -232,13 +225,13 @@ func (r *HttpJsonDataSource) Resolve(ctx Context, args ResolvedArgs, out io.Writ
 
 	switch {
 	case hostArg == nil:
-		r.log.Error(fmt.Sprintf("arg '%s' must not be nil",string(literal.HOST)))
+		r.log.Error(fmt.Sprintf("arg '%s' must not be nil", string(literal.HOST)))
 		return CloseConnectionIfNotStream
 	case urlArg == nil:
-		r.log.Error(fmt.Sprintf("arg '%s' must not be nil",string(literal.URL)))
+		r.log.Error(fmt.Sprintf("arg '%s' must not be nil", string(literal.URL)))
 		return CloseConnectionIfNotStream
 	case methodArg == nil:
-		r.log.Error(fmt.Sprintf("arg '%s' must not be nil",string(literal.METHOD)))
+		r.log.Error(fmt.Sprintf("arg '%s' must not be nil", string(literal.METHOD)))
 		return CloseConnectionIfNotStream
 	}
 
@@ -264,11 +257,11 @@ func (r *HttpJsonDataSource) Resolve(ctx Context, args ResolvedArgs, out io.Writ
 	header := make(http.Header)
 	if len(headersArg) != 0 {
 		err := jsonparser.ObjectEach(headersArg, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
-			header.Set(string(key),string(value))
+			header.Set(string(key), string(value))
 			return nil
 		})
 		if err != nil {
-			r.log.Error("accessing headers",zap.Error(err))
+			r.log.Error("accessing headers", zap.Error(err))
 		}
 	}
 
@@ -286,7 +279,7 @@ func (r *HttpJsonDataSource) Resolve(ctx Context, args ResolvedArgs, out io.Writ
 
 	var bodyReader io.Reader
 	if len(bodyArg) != 0 {
-		bodyArg = bytes.ReplaceAll(bodyArg,literal.BACKSLASH,nil)
+		bodyArg = bytes.ReplaceAll(bodyArg, literal.BACKSLASH, nil)
 		bodyReader = bytes.NewReader(bodyArg)
 	}
 
diff --git a/pkg/execution/datasource_http_polling_stream.go b/pkg/execution/datasource_http_polling_stream.go
index 42226b5c..c4f32989 100644
--- a/pkg/execution/datasource_http_polling_stream.go
+++ b/pkg/execution/datasource_http_polling_stream.go
@@ -26,10 +26,6 @@ func (h *HttpPollingStreamDataSourcePlanner) DirectiveDefinition() []byte {
 	return data
 }
 
-func (h *HttpPollingStreamDataSourcePlanner) OverrideRootFieldPath(path []string) []string {
-	return nil
-}
-
 func NewHttpPollingStreamDataSourcePlanner(baseDataSourcePlanner BaseDataSourcePlanner) *HttpPollingStreamDataSourcePlanner {
 	return &HttpPollingStreamDataSourcePlanner{
 		BaseDataSourcePlanner: baseDataSourcePlanner,
diff --git a/pkg/execution/datasource_schema.go b/pkg/execution/datasource_schema.go
index e8fb3f28..ce956ab6 100644
--- a/pkg/execution/datasource_schema.go
+++ b/pkg/execution/datasource_schema.go
@@ -32,10 +32,6 @@ func (s *SchemaDataSourcePlanner) DirectiveDefinition() []byte {
 	return nil
 }
 
-func (s *SchemaDataSourcePlanner) OverrideRootFieldPath(path []string) []string {
-	return path
-}
-
 func (s *SchemaDataSourcePlanner) DirectiveName() []byte {
 	return []byte("resolveSchema")
 }
diff --git a/pkg/execution/datasource_static.go b/pkg/execution/datasource_static.go
index 7dbfe077..40eef5cf 100644
--- a/pkg/execution/datasource_static.go
+++ b/pkg/execution/datasource_static.go
@@ -23,10 +23,6 @@ func (s *StaticDataSourcePlanner) DirectiveDefinition() []byte {
 	return data
 }
 
-func (s *StaticDataSourcePlanner) OverrideRootFieldPath(path []string) []string {
-	return nil
-}
-
 func (s *StaticDataSourcePlanner) DirectiveName() []byte {
 	return []byte("StaticDataSource")
 }
diff --git a/pkg/execution/datasource_type.go b/pkg/execution/datasource_type.go
index 521c7351..26cc2b3f 100644
--- a/pkg/execution/datasource_type.go
+++ b/pkg/execution/datasource_type.go
@@ -20,10 +20,6 @@ func (t *TypeDataSourcePlanner) DirectiveDefinition() []byte {
 	return nil
 }
 
-func (t *TypeDataSourcePlanner) OverrideRootFieldPath(path []string) []string {
-	return path
-}
-
 func (t *TypeDataSourcePlanner) DirectiveName() []byte {
 	return []byte("resolveType")
 }
diff --git a/pkg/execution/execution.go b/pkg/execution/execution.go
index d12f363f..079d425e 100644
--- a/pkg/execution/execution.go
+++ b/pkg/execution/execution.go
@@ -10,6 +10,7 @@ import (
 	"github.com/jensneuse/graphql-go-tools/pkg/ast"
 	"github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
 	"github.com/jensneuse/graphql-go-tools/pkg/lexer/runes"
+	"github.com/tidwall/gjson"
 	"github.com/valyala/fasttemplate"
 	"io"
 	"strconv"
@@ -75,9 +76,10 @@ func (e *Executor) resolveNode(node Node, data []byte, path string, prefetch *sy
 	switch node := node.(type) {
 	case *Object:
 
-		if data != nil && node.Path != nil {
-			data, _, _, e.err = jsonparser.Get(data, node.Path...)
-			if e.err == jsonparser.KeyPathNotFoundError {
+		if data != nil && node.PathSelector.Path != "" {
+			result := gjson.GetBytes(data, node.PathSelector.Path)
+			data = unsafebytes.StringToBytes(result.Raw)
+			if len(data) == 0 {
 				e.err = nil
 				e.write(literal.NULL)
 				return
@@ -139,7 +141,7 @@ func (e *Executor) resolveNode(node Node, data []byte, path string, prefetch *sy
 			e.write(literal.NULL)
 			return
 		}
-		if len(node.Path) == 0 {
+		if node.PathSelector.Path == "" {
 			if node.QuoteValue {
 				e.write(literal.QUOTE)
 			}
@@ -149,7 +151,13 @@ func (e *Executor) resolveNode(node Node, data []byte, path string, prefetch *sy
 			}
 			return
 		}
-		data, _, _, e.err = jsonparser.Get(data, node.Path...)
+		result := gjson.GetBytes(data, node.PathSelector.Path)
+		if result.Type == gjson.String {
+			data = unsafebytes.StringToBytes(result.Str)
+		} else {
+			data = unsafebytes.StringToBytes(result.Raw)
+		}
+
 		if e.err == jsonparser.KeyPathNotFoundError {
 			e.err = nil
 			e.write(literal.NULL)
@@ -174,10 +182,26 @@ func (e *Executor) resolveNode(node Node, data []byte, path string, prefetch *sy
 				shouldPrefetch = true
 			}
 		}
-		var listItems [][]byte
-		_, e.err = jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
+
+		/*_, e.err = jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
 			listItems = append(listItems, value)
-		}, node.Path...)
+		}, node.Path...)*/
+
+		var result []gjson.Result
+		if node.PathSelector.Path == "" {
+			result = gjson.ParseBytes(data).Array()
+		} else {
+			result = gjson.GetBytes(data, node.PathSelector.Path).Array()
+		}
+
+		listItems := make([][]byte, len(result))
+		for i := range result {
+			if result[i].Type == gjson.String {
+				listItems[i] = unsafebytes.StringToBytes(result[i].Str)
+			} else {
+				listItems[i] = unsafebytes.StringToBytes(result[i].Raw)
+			}
+		}
 
 		path = path + "."
 
@@ -228,7 +252,8 @@ func (e *Executor) ResolveArgs(args []Argument, data []byte) ResolvedArgs {
 			resolved[i].Value = arg.Value
 		case *ObjectVariableArgument:
 			resolved[i].Key = arg.Name
-			resolved[i].Value, _, _, _ = jsonparser.Get(data, arg.Path...)
+			result := gjson.GetBytes(data, arg.PathSelector.Path)
+			resolved[i].Value = unsafebytes.StringToBytes(result.Raw)
 		case *ContextVariableArgument:
 			resolved[i].Key = arg.Name
 			resolved[i].Value = e.context.Variables[xxhash.Sum64(arg.VariableName)]
@@ -266,7 +291,7 @@ func (e *Executor) ResolveArgs(args []Argument, data []byte) ResolvedArgs {
 			}
 			for j := range resolved {
 				key := string(resolved[j].Key)
-				if strings.HasPrefix(tag,".") && !strings.HasPrefix(key,"."){
+				if strings.HasPrefix(tag, ".") && !strings.HasPrefix(key, ".") {
 					key = "." + key
 				}
 				if !strings.HasPrefix(tag, key) {
@@ -381,9 +406,13 @@ func (c *ContextVariableArgument) ArgName() []byte {
 	return c.Name
 }
 
+type PathSelector struct {
+	Path string
+}
+
 type ObjectVariableArgument struct {
-	Name []byte
-	Path []string
+	Name         []byte
+	PathSelector PathSelector
 }
 
 func (o *ObjectVariableArgument) ArgName() []byte {
@@ -410,7 +439,7 @@ func (l ListArgument) ArgName() []byte {
 
 type Object struct {
 	Fields        []Field
-	Path          []string
+	PathSelector  PathSelector
 	Fetch         Fetch
 	operationType ast.OperationType
 }
@@ -517,7 +546,12 @@ func (i *IfEqual) Evaluate(ctx Context, data []byte) bool {
 	case *ContextVariableArgument:
 		left = ctx.Variables[xxhash.Sum64(value.VariableName)]
 	case *ObjectVariableArgument:
-		left, _, _, _ = jsonparser.Get(data, value.Path...)
+		result := gjson.GetBytes(data, value.PathSelector.Path)
+		if result.Type == gjson.String {
+			left = unsafebytes.StringToBytes(result.Str)
+		} else {
+			left = unsafebytes.StringToBytes(result.Raw)
+		}
 	case *StaticVariableArgument:
 		left = value.Value
 	}
@@ -526,7 +560,12 @@ func (i *IfEqual) Evaluate(ctx Context, data []byte) bool {
 	case *ContextVariableArgument:
 		right = ctx.Variables[xxhash.Sum64(value.VariableName)]
 	case *ObjectVariableArgument:
-		right, _, _, _ = jsonparser.Get(data, value.Path...)
+		result := gjson.GetBytes(data, value.PathSelector.Path)
+		if result.Type == gjson.String {
+			right = unsafebytes.StringToBytes(result.Str)
+		} else {
+			right = unsafebytes.StringToBytes(result.Raw)
+		}
 	case *StaticVariableArgument:
 		right = value.Value
 	}
@@ -551,8 +590,8 @@ func (*Field) Kind() NodeKind {
 }
 
 type Value struct {
-	Path       []string
-	QuoteValue bool
+	PathSelector PathSelector
+	QuoteValue   bool
 }
 
 func (value *Value) HasResolvers() bool {
@@ -564,9 +603,9 @@ func (*Value) Kind() NodeKind {
 }
 
 type List struct {
-	Path   []string
-	Value  Node
-	Filter ListFilter
+	PathSelector PathSelector
+	Value        Node
+	Filter       ListFilter
 }
 
 func (l *List) HasResolvers() bool {
diff --git a/pkg/execution/fixtures/render_graphql_definitions.golden b/pkg/execution/fixtures/render_graphql_definitions.golden
index 7c9f85aa..f805baba 100644
--- a/pkg/execution/fixtures/render_graphql_definitions.golden
+++ b/pkg/execution/fixtures/render_graphql_definitions.golden
@@ -71,19 +71,19 @@ directive @HttpPollingStreamDataSource
     params: [Parameter]
  on FIELD_DEFINITION
 
-directive @mapTo
-    objectField: String!
- on FIELD_DEFINITION
-
-directive @path
+"""
+mapping is the directive to define mappings from response objects to GraphQL fields
+"""
+directive @mapping
     """
-    append will append the list of path elements to the path generated by the query planner
+    mode defines the operating mode of the mapping
     """
-    append: [String!] 
+    mode: MAPPING_MODE! = PATH_SELECTOR 
     """
-    prepend will prepend the list of path elements to the path generated by the query planner
+    pathSelector is the optional selector String to customize the mappings
+    see https://github.com/tidwall/gjson for more information on what syntax is possible
     """
-    prepend: [String!]
+    pathSelector: String
  on FIELD_DEFINITION
 
 directive @StaticDataSource
@@ -97,6 +97,21 @@ enum HTTP_METHOD {
     DELETE
 }
 
+"""
+MAPPING_MODE is the enum to define the different mapper modes
+"""
+enum MAPPING_MODE {
+    """
+    NONE is the mode to skip mappings at all, therefore the parent object will directly get passed to the child
+    """
+    NONE
+    """
+    PATH_SELECTOR is the mode which applies a path selector string on the parent object before passing it to the child
+    see https://github.com/tidwall/gjson for more information on what syntax is possible
+    """
+    PATH_SELECTOR
+}
+
 "PARAMETER_SOURCE defines the source of a dyanmic parameter"
 enum PARAMETER_SOURCE {
     "parameter from the context object which could be pupulated by the http wrapper"
diff --git a/pkg/execution/graphql_definitions/directives/map_to.graphql b/pkg/execution/graphql_definitions/directives/map_to.graphql
deleted file mode 100644
index 0d62603d..00000000
--- a/pkg/execution/graphql_definitions/directives/map_to.graphql
+++ /dev/null
@@ -1,3 +0,0 @@
-directive @mapTo(
-    objectField: String!
-) on FIELD_DEFINITION
\ No newline at end of file
diff --git a/pkg/execution/graphql_definitions/directives/mapping.graphql b/pkg/execution/graphql_definitions/directives/mapping.graphql
new file mode 100644
index 00000000..bdfa6635
--- /dev/null
+++ b/pkg/execution/graphql_definitions/directives/mapping.graphql
@@ -0,0 +1,14 @@
+"""
+mapping is the directive to define mappings from response objects to GraphQL fields
+"""
+directive @mapping(
+    """
+    mode defines the operating mode of the mapping
+    """
+    mode: MAPPING_MODE! = PATH_SELECTOR
+    """
+    pathSelector is the optional selector String to customize the mappings
+    see https://github.com/tidwall/gjson for more information on what syntax is possible
+    """
+    pathSelector: String
+) on FIELD_DEFINITION
\ No newline at end of file
diff --git a/pkg/execution/graphql_definitions/directives/path.graphql b/pkg/execution/graphql_definitions/directives/path.graphql
deleted file mode 100644
index 88dfb728..00000000
--- a/pkg/execution/graphql_definitions/directives/path.graphql
+++ /dev/null
@@ -1,10 +0,0 @@
-directive @path(
-    """
-    append will append the list of path elements to the path generated by the query planner
-    """
-    append: [String!]
-    """
-    prepend will prepend the list of path elements to the path generated by the query planner
-    """
-    prepend: [String!]
-) on FIELD_DEFINITION
\ No newline at end of file
diff --git a/pkg/execution/graphql_definitions/enums/mapping_mode.graphql b/pkg/execution/graphql_definitions/enums/mapping_mode.graphql
new file mode 100644
index 00000000..c927da9b
--- /dev/null
+++ b/pkg/execution/graphql_definitions/enums/mapping_mode.graphql
@@ -0,0 +1,14 @@
+"""
+MAPPING_MODE is the enum to define the different mapper modes
+"""
+enum MAPPING_MODE {
+    """
+    NONE is the mode to skip mappings at all, therefore the parent object will directly get passed to the child
+    """
+    NONE
+    """
+    PATH_SELECTOR is the mode which applies a path selector string on the parent object before passing it to the child
+    see https://github.com/tidwall/gjson for more information on what syntax is possible
+    """
+    PATH_SELECTOR
+}
\ No newline at end of file
diff --git a/pkg/execution/planning.go b/pkg/execution/planning.go
index 992429dd..ad27470c 100644
--- a/pkg/execution/planning.go
+++ b/pkg/execution/planning.go
@@ -2,6 +2,7 @@ package execution
 
 import (
 	"bytes"
+	"github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
 	"github.com/jensneuse/graphql-go-tools/pkg/ast"
 	"github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
 	"github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
@@ -139,7 +140,9 @@ func (p *planningVisitor) EnterField(ref int) {
 			case bytes.Equal(params[i].sourceKind, []byte("OBJECT_VARIABLE_ARGUMENT")):
 				resolveArgs = append(resolveArgs, &ObjectVariableArgument{
 					Name: params[i].name,
-					Path: []string{string(params[i].sourceName)},
+					PathSelector: PathSelector{
+						Path: unsafebytes.BytesToString(params[i].sourceName),
+					},
 				})
 			case bytes.Equal(params[i].sourceKind, []byte("FIELD_ARGUMENTS")):
 				arg, exists := p.operation.FieldArgument(ref, params[i].sourceName)
@@ -168,16 +171,20 @@ func (p *planningVisitor) EnterField(ref int) {
 	switch parent := p.currentNode[len(p.currentNode)-1].(type) {
 	case *Object:
 
-		var planner DataSourcePlanner
+		/*var planner DataSourcePlanner
 		resolveRef := p.planners[len(p.planners)-1]
 		if resolveRef.path.Equals(p.Path) && resolveRef.fieldRef == ref {
 			planner = resolveRef.planner
 		}
 
-		path := p.fieldPath(ref)
 		if planner != nil {
-			path = planner.OverrideRootFieldPath(path)
-		}
+			pathSelector = planner.OverrideRootPathSelector(pathSelector)
+		}*/
+
+		fieldName := p.operation.FieldNameString(ref)
+		_ = fieldName
+
+		pathSelector := p.fieldPathSelector(ref)
 
 		var value Node
 		fieldDefinitionType := p.definition.FieldDefinitionType(definition)
@@ -192,7 +199,7 @@ func (p *planningVisitor) EnterField(ref int) {
 			}
 
 			list := &List{
-				Path:  path,
+				PathSelector:  pathSelector,
 				Value: value,
 			}
 
@@ -217,12 +224,12 @@ func (p *planningVisitor) EnterField(ref int) {
 
 		if !p.operation.FieldHasSelections(ref) {
 			value = &Value{
-				Path:       path,
+				PathSelector:  pathSelector,
 				QuoteValue: p.quoteValue(fieldDefinitionType),
 			}
 		} else {
 			value = &Object{
-				Path: path,
+				PathSelector:  pathSelector,
 			}
 		}
 
@@ -232,7 +239,9 @@ func (p *planningVisitor) EnterField(ref int) {
 			typeConditionName := p.operation.InlineFragmentTypeConditionName(ancestor.Ref)
 			skipCondition = &IfNotEqual{
 				Left: &ObjectVariableArgument{
-					Path: []string{"__typename"},
+					PathSelector: PathSelector{
+						Path: "__typename",
+					},
 				},
 				Right: &StaticVariableArgument{
 					Value: typeConditionName,
@@ -387,29 +396,48 @@ func (p *planningVisitor) quoteValue(valueType int) bool {
 	}
 }
 
-func (p *planningVisitor) fieldPath(ref int) []string {
-	path := []string{
-		p.operation.FieldNameString(ref),
-	}
+func (p *planningVisitor) fieldPathSelector(ref int) (selector PathSelector) {
+	selector.Path = p.operation.FieldNameString(ref)
 	definition, ok := p.FieldDefinition(ref)
 	if !ok {
-		return path
+		return
 	}
-	directive, ok := p.definition.FieldDefinitionDirectiveByName(definition, []byte("mapTo"))
+	fieldName := p.operation.FieldNameString(ref)
+	_ = fieldName
+	directive, ok := p.definition.FieldDefinitionDirectiveByName(definition, []byte("mapping"))
 	if ok {
-		value, ok := p.definition.DirectiveArgumentValueByName(directive, []byte("objectField"))
-		if ok && value.Kind == ast.ValueKindString {
-			path[0] = p.definition.StringValueContentString(value.Ref)
+		value, ok := p.definition.DirectiveArgumentValueByName(directive, []byte("mode"))
+		if !ok {
+			def := p.definition.DirectiveArgumentInputValueDefinition([]byte("mapping"),[]byte("mode"))
+			if def == -1 {
+				return
+			}
+			ok = p.definition.InputValueDefinitionHasDefaultValue(def)
+			value = p.definition.InputValueDefinitionDefaultValue(def)
+		}
+		if ok && value.Kind == ast.ValueKindEnum {
+			mode := p.definition.EnumValueNameString(value.Ref)
+			switch mode {
+			case "NONE":
+				selector.Path = ""
+				return
+			case "PATH_SELECTOR":
+				value, ok = p.definition.DirectiveArgumentValueByName(directive, []byte("pathSelector"))
+				if ok && value.Kind == ast.ValueKindString {
+					selector.Path = p.definition.StringValueContentString(value.Ref)
+					return
+				}
+			}
 		}
 	}
 
-	def, ok := p.FieldDefinition(ref)
+/*	def, ok := p.FieldDefinition(ref)
 	if !ok {
-		return path
+		return
 	}
 	pathDirective, ok := p.definition.FieldDefinitionDirectiveByName(def, []byte("path"))
 	if !ok {
-		return path
+		return
 	}
 	appendValue, ok := p.definition.DirectiveArgumentValueByName(pathDirective, []byte("append"))
 	if ok && appendValue.Kind == ast.ValueKindList {
@@ -418,7 +446,7 @@ func (p *planningVisitor) fieldPath(ref int) []string {
 			if listValue.Kind != ast.ValueKindString {
 				continue
 			}
-			path = append(path, p.definition.StringValueContentString(listValue.Ref))
+			selector.Path += "." + p.definition.StringValueContentString(listValue.Ref)
 		}
 	}
 	prependValue, ok := p.definition.DirectiveArgumentValueByName(pathDirective, []byte("prepend"))
@@ -428,9 +456,8 @@ func (p *planningVisitor) fieldPath(ref int) []string {
 			if listValue.Kind != ast.ValueKindString {
 				continue
 			}
-			path = append([]string{p.definition.StringValueContentString(listValue.Ref)}, path...)
+			selector.Path += "." + p.definition.StringValueContentString(listValue.Ref)
 		}
-	}
-
-	return path
+	}*/
+	return
 }


Test patch:
diff --git a/pkg/execution/execution_test.go b/pkg/execution/execution_test.go
index e918528e..6974a48c 100644
--- a/pkg/execution/execution_test.go
+++ b/pkg/execution/execution_test.go
@@ -10,6 +10,7 @@ import (
 	"github.com/jensneuse/graphql-go-tools/pkg/ast"
 	"github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
 	"github.com/sebdah/goldie"
+	"github.com/tidwall/gjson"
 	"go.uber.org/zap"
 	"io"
 	"io/ioutil"
@@ -141,37 +142,49 @@ func TestExecution(t *testing.T) {
 							Name:        []byte("__type"),
 							HasResolver: true,
 							Value: &Object{
-								Path: []string{"__type"},
+								PathSelector: PathSelector{
+									Path: "__type",
+								},
 								Fields: []Field{
 									{
 										Name: []byte("name"),
 										Value: &Value{
-											Path:       []string{"name"},
+											PathSelector: PathSelector{
+												Path: "name",
+											},
 											QuoteValue: true,
 										},
 									},
 									{
 										Name: []byte("fields"),
 										Value: &List{
-											Path: []string{"fields"},
+											PathSelector: PathSelector{
+												Path: "fields",
+											},
 											Value: &Object{
 												Fields: []Field{
 													{
 														Name: []byte("name"),
 														Value: &Value{
-															Path:       []string{"name"},
+															PathSelector: PathSelector{
+																Path: "name",
+															},
 															QuoteValue: true,
 														},
 													},
 													{
 														Name: []byte("type"),
 														Value: &Object{
-															Path: []string{"type"},
+															PathSelector: PathSelector{
+																Path: "type",
+															},
 															Fields: []Field{
 																{
 																	Name: []byte("name"),
 																	Value: &Value{
-																		Path:       []string{"name"},
+																		PathSelector: PathSelector{
+																			Path: "name",
+																		},
 																		QuoteValue: true,
 																	},
 																},
@@ -189,7 +202,9 @@ func TestExecution(t *testing.T) {
 							Name:        []byte("user"),
 							HasResolver: true,
 							Value: &Object{
-								Path: []string{"user"},
+								PathSelector: PathSelector{
+									Path: "user",
+								},
 								Fetch: &ParallelFetch{
 									Fetches: []Fetch{
 										&SingleFetch{
@@ -209,7 +224,9 @@ func TestExecution(t *testing.T) {
 													},
 													&ObjectVariableArgument{
 														Name: []byte("id"),
-														Path: []string{"id"},
+														PathSelector: PathSelector{
+															Path: "id",
+														},
 													},
 												},
 												DataSource: &HttpJsonDataSource{
@@ -235,7 +252,9 @@ func TestExecution(t *testing.T) {
 													},
 													&ObjectVariableArgument{
 														Name: []byte("id"),
-														Path: []string{"id"},
+														PathSelector: PathSelector{
+															Path: "id",
+														},
 													},
 												},
 												DataSource: &GraphQLDataSource{
@@ -250,20 +269,26 @@ func TestExecution(t *testing.T) {
 									{
 										Name: []byte("id"),
 										Value: &Value{
-											Path: []string{"id"},
+											PathSelector: PathSelector{
+												Path: "id",
+											},
 										},
 									},
 									{
 										Name: []byte("name"),
 										Value: &Value{
-											Path:       []string{"name"},
+											PathSelector: PathSelector{
+												Path: "name",
+											},
 											QuoteValue: true,
 										},
 									},
 									{
 										Name: []byte("birthday"),
 										Value: &Value{
-											Path:       []string{"birthday"},
+											PathSelector: PathSelector{
+												Path: "birthday",
+											},
 											QuoteValue: true,
 										},
 									},
@@ -289,7 +314,9 @@ func TestExecution(t *testing.T) {
 															},
 															&ObjectVariableArgument{
 																Name: []byte("id"),
-																Path: []string{"id"},
+																PathSelector: PathSelector{
+																	Path: "id",
+																},
 															},
 														},
 														DataSource: &HttpJsonDataSource{
@@ -302,21 +329,27 @@ func TestExecution(t *testing.T) {
 													{
 														Name: []byte("id"),
 														Value: &Value{
-															Path:       []string{"id"},
+															PathSelector: PathSelector{
+																Path: "id",
+															},
 															QuoteValue: false,
 														},
 													},
 													{
 														Name: []byte("name"),
 														Value: &Value{
-															Path:       []string{"name"},
+															PathSelector: PathSelector{
+																Path: "name",
+															},
 															QuoteValue: true,
 														},
 													},
 													{
 														Name: []byte("birthday"),
 														Value: &Value{
-															Path:       []string{"birthday"},
+															PathSelector: PathSelector{
+																Path: "birthday",
+															},
 															QuoteValue: true,
 														},
 													},
@@ -329,33 +362,43 @@ func TestExecution(t *testing.T) {
 																	{
 																		Name: []byte("__typename"),
 																		Value: &Value{
-																			Path:       []string{"__typename"},
+																			PathSelector: PathSelector{
+																				Path: "__typename",
+																			},
 																			QuoteValue: true,
 																		},
 																	},
 																	{
 																		Name: []byte("name"),
 																		Value: &Value{
-																			Path:       []string{"name"},
+																			PathSelector: PathSelector{
+																				Path: "name",
+																			},
 																			QuoteValue: true,
 																		},
 																	},
 																	{
 																		Name: []byte("nickname"),
 																		Value: &Value{
-																			Path:       []string{"nickname"},
+																			PathSelector: PathSelector{
+																				Path: "nickname",
+																			},
 																			QuoteValue: true,
 																		},
 																	},
 																	{
 																		Name: []byte("woof"),
 																		Value: &Value{
-																			Path:       []string{"woof"},
+																			PathSelector: PathSelector{
+																				Path: "woof",
+																			},
 																			QuoteValue: true,
 																		},
 																		Skip: &IfNotEqual{
 																			Left: &ObjectVariableArgument{
-																				Path: []string{"__typename"},
+																				PathSelector: PathSelector{
+																					Path: "__typename",
+																				},
 																			},
 																			Right: &StaticVariableArgument{
 																				Value: []byte("Dog"),
@@ -365,12 +408,16 @@ func TestExecution(t *testing.T) {
 																	{
 																		Name: []byte("meow"),
 																		Value: &Value{
-																			Path:       []string{"meow"},
+																			PathSelector: PathSelector{
+																				Path: "meow",
+																			},
 																			QuoteValue: true,
 																		},
 																		Skip: &IfNotEqual{
 																			Left: &ObjectVariableArgument{
-																				Path: []string{"__typename"},
+																				PathSelector: PathSelector{
+																					Path: "__typename",
+																				},
 																			},
 																			Right: &StaticVariableArgument{
 																				Value: []byte("Cat"),
@@ -389,39 +436,51 @@ func TestExecution(t *testing.T) {
 										Name:        []byte("pets"),
 										HasResolver: true,
 										Value: &List{
-											Path: []string{"userPets"},
+											PathSelector: PathSelector{
+												Path: "userPets",
+											},
 											Value: &Object{
 												Fields: []Field{
 													{
 														Name: []byte("__typename"),
 														Value: &Value{
-															Path:       []string{"__typename"},
+															PathSelector: PathSelector{
+																Path: "__typename",
+															},
 															QuoteValue: true,
 														},
 													},
 													{
 														Name: []byte("name"),
 														Value: &Value{
-															Path:       []string{"name"},
+															PathSelector: PathSelector{
+																Path: "name",
+															},
 															QuoteValue: true,
 														},
 													},
 													{
 														Name: []byte("nickname"),
 														Value: &Value{
-															Path:       []string{"nickname"},
+															PathSelector: PathSelector{
+																Path: "nickname",
+															},
 															QuoteValue: true,
 														},
 													},
 													{
 														Name: []byte("woof"),
 														Value: &Value{
-															Path:       []string{"woof"},
+															PathSelector: PathSelector{
+																Path: "woof",
+															},
 															QuoteValue: true,
 														},
 														Skip: &IfNotEqual{
 															Left: &ObjectVariableArgument{
-																Path: []string{"__typename"},
+																PathSelector: PathSelector{
+																	Path: "__typename",
+																},
 															},
 															Right: &StaticVariableArgument{
 																Value: []byte("Dog"),
@@ -431,12 +490,16 @@ func TestExecution(t *testing.T) {
 													{
 														Name: []byte("meow"),
 														Value: &Value{
-															Path:       []string{"meow"},
+															PathSelector: PathSelector{
+																Path: "meow",
+															},
 															QuoteValue: true,
 														},
 														Skip: &IfNotEqual{
 															Left: &ObjectVariableArgument{
-																Path: []string{"__typename"},
+																PathSelector: PathSelector{
+																	Path: "__typename",
+																},
 															},
 															Right: &StaticVariableArgument{
 																Value: []byte("Cat"),
@@ -586,35 +649,47 @@ func genField() Field {
 					Name:        []byte("__type"),
 					HasResolver: true,
 					Value: &Object{
-						Path: []string{"__type"},
+						PathSelector: PathSelector{
+							Path: "__type",
+						},
 						Fields: []Field{
 							{
 								Name: []byte("name"),
 								Value: &Value{
-									Path: []string{"name"},
+									PathSelector: PathSelector{
+										Path: "name",
+									},
 								},
 							},
 							{
 								Name: []byte("fields"),
 								Value: &List{
-									Path: []string{"fields"},
+									PathSelector: PathSelector{
+										Path: "fields",
+									},
 									Value: &Object{
 										Fields: []Field{
 											{
 												Name: []byte("name"),
 												Value: &Value{
-													Path: []string{"name"},
+													PathSelector: PathSelector{
+														Path: "name",
+													},
 												},
 											},
 											{
 												Name: []byte("type"),
 												Value: &Object{
-													Path: []string{"type"},
+													PathSelector: PathSelector{
+														Path: "type",
+													},
 													Fields: []Field{
 														{
 															Name: []byte("name"),
 															Value: &Value{
-																Path: []string{"name"},
+																PathSelector: PathSelector{
+																	Path: "name",
+																},
 															},
 														},
 													},
@@ -642,7 +717,9 @@ func genField() Field {
 											},
 											&ObjectVariableArgument{
 												Name: []byte("id"),
-												Path: []string{"id"},
+												PathSelector: PathSelector{
+													Path: "id",
+												},
 											},
 										},
 										DataSource: &FakeDataSource{
@@ -668,7 +745,9 @@ func genField() Field {
 											},
 											&ObjectVariableArgument{
 												Name: []byte("id"),
-												Path: []string{"id"},
+												PathSelector: PathSelector{
+													Path: "id",
+												},
 											},
 										},
 										DataSource: &FakeDataSource{
@@ -679,25 +758,33 @@ func genField() Field {
 								},
 							},
 						},
-						Path: []string{"data", "user"},
+						PathSelector: PathSelector{
+							Path: "data.user",
+						},
 						Fields: []Field{
 							{
 								Name: []byte("id"),
 								Value: &Value{
-									Path: []string{"id"},
+									PathSelector: PathSelector{
+										Path: "id",
+									},
 								},
 							},
 							{
 								Name: []byte("name"),
 								Value: &Value{
-									Path:       []string{"name"},
+									PathSelector: PathSelector{
+										Path: "name",
+									},
 									QuoteValue: true,
 								},
 							},
 							{
 								Name: []byte("birthday"),
 								Value: &Value{
-									Path: []string{"birthday"},
+									PathSelector: PathSelector{
+										Path: "birthday",
+									},
 								},
 							},
 							{
@@ -709,20 +796,26 @@ func genField() Field {
 											{
 												Name: []byte("id"),
 												Value: &Value{
-													Path: []string{"id"},
+													PathSelector: PathSelector{
+														Path: "id",
+													},
 												},
 											},
 											{
 												Name: []byte("name"),
 												Value: &Value{
-													Path:       []string{"name"},
+													PathSelector: PathSelector{
+														Path: "name",
+													},
 													QuoteValue: true,
 												},
 											},
 											{
 												Name: []byte("birthday"),
 												Value: &Value{
-													Path: []string{"birthday"},
+													PathSelector: PathSelector{
+														Path: "birthday",
+													},
 												},
 											},
 										},
@@ -733,36 +826,48 @@ func genField() Field {
 								Name:        []byte("pets"),
 								HasResolver: true,
 								Value: &List{
-									Path: []string{"data", "userPets"},
+									PathSelector: PathSelector{
+										Path: "data.userPets",
+									},
 									Value: &Object{
 										Fields: []Field{
 											{
 												Name: []byte("__typename"),
 												Value: &Value{
-													Path: []string{"__typename"},
+													PathSelector: PathSelector{
+														Path: "__typename",
+													},
 												},
 											},
 											{
 												Name: []byte("name"),
 												Value: &Value{
-													Path: []string{"name"},
+													PathSelector: PathSelector{
+														Path: "name",
+													},
 												},
 											},
 											{
 												Name: []byte("nickname"),
 												Value: &Value{
-													Path: []string{"nickname"},
+													PathSelector: PathSelector{
+														Path: "nickname",
+													},
 												},
 											},
 											{
 												Name: []byte("woof"),
 												Value: &Value{
-													Path:       []string{"woof"},
+													PathSelector: PathSelector{
+														Path: "woof",
+													},
 													QuoteValue: true,
 												},
 												Skip: &IfNotEqual{
 													Left: &ObjectVariableArgument{
-														Path: []string{"__typename"},
+														PathSelector: PathSelector{
+															Path: "__typename",
+														},
 													},
 													Right: &StaticVariableArgument{
 														Value: []byte("Dog"),
@@ -772,12 +877,16 @@ func genField() Field {
 											{
 												Name: []byte("meow"),
 												Value: &Value{
-													Path:       []string{"meow"},
+													PathSelector: PathSelector{
+														Path: "meow",
+													},
 													QuoteValue: true,
 												},
 												Skip: &IfNotEqual{
 													Left: &ObjectVariableArgument{
-														Path: []string{"__typename"},
+														PathSelector: PathSelector{
+															Path: "__typename",
+														},
 													},
 													Right: &StaticVariableArgument{
 														Value: []byte("Cat"),
@@ -932,14 +1041,18 @@ func TestStreamExecution(t *testing.T) {
 									{
 										Name: []byte("bar"),
 										Value: &Value{
-											Path:       []string{"bar"},
+											PathSelector: PathSelector{
+												Path: "bar",
+											},
 											QuoteValue: true,
 										},
 									},
 									{
 										Name: []byte("baz"),
 										Value: &Value{
-											Path:       []string{"baz"},
+											PathSelector: PathSelector{
+												Path: "baz",
+											},
 											QuoteValue: false,
 										},
 									},
@@ -1019,7 +1132,9 @@ func TestExecutor_ListFilterFirstN(t *testing.T) {
 										{
 											Name: []byte("bar"),
 											Value: &Value{
-												Path:       []string{"bar"},
+												PathSelector: PathSelector{
+													Path: "bar",
+												},
 												QuoteValue: true,
 											},
 										},
@@ -1076,13 +1191,17 @@ func TestExecutor_ListWithPath(t *testing.T) {
 							Name:        []byte("apis"),
 							HasResolver: true,
 							Value: &List{
-								Path: []string{"apis"},
+								PathSelector: PathSelector{
+									Path: "apis",
+								},
 								Value: &Object{
 									Fields: []Field{
 										{
 											Name: []byte("id"),
 											Value: &Value{
-												Path:       []string{"id"},
+												PathSelector: PathSelector{
+													Path: "id",
+												},
 												QuoteValue: false,
 											},
 										},
@@ -1139,7 +1258,9 @@ func TestExecutor_ObjectWithPath(t *testing.T) {
 							Name:        []byte("id"),
 							HasResolver: true,
 							Value: &Value{
-								Path:       []string{"api", "id"},
+								PathSelector: PathSelector{
+									Path: "api.id",
+								},
 								QuoteValue: false,
 							},
 						},
@@ -1760,6 +1881,112 @@ func TestExecutor_HTTPJSONDataSourceWithHeaders(t *testing.T) {
 	}
 }
 
+func TestExecutor_HTTPJSONDataSourceWithPathSelector(t *testing.T) {
+
+	response := []byte(`
+{
+	"name": {"first": "Tom", "last": "Anderson"},
+	"age":37,
+	"children": ["Sara","Alex","Jack"],
+	"fav.movie": "Deer Hunter",
+	"friends": [
+		{"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
+		{"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
+		{"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
+	]
+}`)
+
+	REST1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		_, _ = w.Write(response)
+	}))
+
+	plan := &Object{
+		operationType: ast.OperationTypeQuery,
+		Fields: []Field{
+			{
+				Name: []byte("data"),
+				Value: &Object{
+					Fetch: &SingleFetch{
+						BufferName: "friends",
+						Source: &DataSourceInvocation{
+							DataSource: &HttpJsonDataSource{
+								log: zap.NewNop(),
+							},
+							Args: []Argument{
+								&StaticVariableArgument{
+									Name:  []byte("host"),
+									Value: []byte(REST1.URL),
+								},
+								&StaticVariableArgument{
+									Name:  []byte("url"),
+									Value: []byte("/"),
+								},
+								&StaticVariableArgument{
+									Name:  []byte("method"),
+									Value: []byte("GET"),
+								},
+							},
+						},
+					},
+					Fields: []Field{
+						{
+							Name:        []byte("friends"),
+							HasResolver: true,
+							Value: &Object{
+								Fields: []Field{
+									{
+										Name: []byte("firstNames"),
+										Value: &List{
+											PathSelector:PathSelector{
+												Path: "friends.#.first",
+											},
+											Value: &Value{
+												QuoteValue: true,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	out := &bytes.Buffer{}
+	ex := NewExecutor()
+	ctx := Context{
+		Context: context.Background(),
+	}
+
+	_, err := ex.Execute(ctx, plan, out)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expected := map[string]interface{}{
+		"data": map[string]interface{}{
+			"friends": map[string]interface{}{
+				"firstNames": []string{"Dale", "Roger", "Jane"},
+			},
+		},
+	}
+
+	wantResult, err := json.MarshalIndent(expected, "", "  ")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want := string(wantResult)
+	got := prettyJSON(out)
+
+	if want != got {
+		t.Fatalf("want: %s\ngot: %s\n", want, got)
+		return
+	}
+}
+
 func prettyJSON(r io.Reader) string {
 	data := map[string]interface{}{}
 	err := json.NewDecoder(r).Decode(&data)
@@ -1772,3 +1999,23 @@ func prettyJSON(r io.Reader) string {
 	}
 	return string(out)
 }
+
+func TestSelectList(t *testing.T){
+	data := []byte(`
+[
+   {
+      "id":2,
+      "name":"Yaara",
+      "birthday":"1990 I guess? ;-)"
+   },
+   {
+      "id":3,
+      "name":"Ahmet",
+      "birthday":"1980"
+   }
+]
+`)
+
+	result := gjson.ParseBytes(data)
+	_ = result
+}
\ No newline at end of file
diff --git a/pkg/execution/planning_test.go b/pkg/execution/planning_test.go
index 1356eb69..1697b589 100644
--- a/pkg/execution/planning_test.go
+++ b/pkg/execution/planning_test.go
@@ -101,26 +101,34 @@ func TestPlanner_Plan(t *testing.T) {
 								Name:        []byte("country"),
 								HasResolver: true,
 								Value: &Object{
-									Path: []string{"country"},
+									PathSelector: PathSelector{
+										Path: "country",
+									},
 									Fields: []Field{
 										{
 											Name: []byte("code"),
 											Value: &Value{
-												Path:       []string{"code"},
+												PathSelector: PathSelector{
+													Path: "code",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("name"),
 											Value: &Value{
-												Path:       []string{"name"},
+												PathSelector: PathSelector{
+													Path: "name",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("aliased"),
 											Value: &Value{
-												Path:       []string{"native"},
+												PathSelector: PathSelector{
+													Path: "native",
+												},
 												QuoteValue: true,
 											},
 										},
@@ -185,19 +193,25 @@ func TestPlanner_Plan(t *testing.T) {
 								Name:        []byte("likePost"),
 								HasResolver: true,
 								Value: &Object{
-									Path: []string{"likePost"},
+									PathSelector: PathSelector{
+										Path: "likePost",
+									},
 									Fields: []Field{
 										{
 											Name: []byte("id"),
 											Value: &Value{
-												Path:       []string{"id"},
+												PathSelector: PathSelector{
+													Path: "id",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("likes"),
 											Value: &Value{
-												Path:       []string{"likes"},
+												PathSelector: PathSelector{
+													Path: "likes",
+												},
 												QuoteValue: false,
 											},
 										},
@@ -313,26 +327,34 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("header"),
 											Value: &Object{
-												Path: []string{"headers"},
+												PathSelector: PathSelector{
+													Path: "headers",
+												},
 												Fields: []Field{
 													{
 														Name: []byte("Accept"),
 														Value: &Value{
-															Path:       []string{"Accept"},
+															PathSelector: PathSelector{
+																Path: "Accept",
+															},
 															QuoteValue: true,
 														},
 													},
 													{
 														Name: []byte("Host"),
 														Value: &Value{
-															Path:       []string{"Host"},
+															PathSelector: PathSelector{
+																Path: "Host",
+															},
 															QuoteValue: true,
 														},
 													},
 													{
 														Name: []byte("acceptEncoding"),
 														Value: &Value{
-															Path:       []string{"Accept-Encoding"},
+															PathSelector: PathSelector{
+																Path: "Accept-Encoding",
+															},
 															QuoteValue: true,
 														},
 													},
@@ -359,7 +381,9 @@ func TestPlanner_Plan(t *testing.T) {
 												},
 												&ObjectVariableArgument{
 													Name: []byte("postId"),
-													Path: []string{"id"},
+													PathSelector: PathSelector{
+														Path: "id",
+													},
 												},
 												&StaticVariableArgument{
 													Name:  []byte("method"),
@@ -374,7 +398,9 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("id"),
 											Value: &Value{
-												Path:       []string{"id"},
+												PathSelector: PathSelector{
+													Path: "id",
+												},
 												QuoteValue: false,
 											},
 										},
@@ -387,7 +413,9 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("id"),
 															Value: &Value{
-																Path:       []string{"id"},
+																PathSelector: PathSelector{
+																	Path: "id",
+																},
 																QuoteValue: false,
 															},
 														},
@@ -510,7 +538,9 @@ func TestPlanner_Plan(t *testing.T) {
 								Name:        []byte("withPath"),
 								HasResolver: true,
 								Value: &Value{
-									Path:       []string{"subObject"},
+									PathSelector: PathSelector{
+										Path: "subObject",
+									},
 									QuoteValue: true,
 								},
 							},
@@ -571,7 +601,9 @@ func TestPlanner_Plan(t *testing.T) {
 											{
 												Name: []byte("id"),
 												Value: &Value{
-													Path:       []string{"id"},
+													PathSelector: PathSelector{
+														Path: "id",
+													},
 													QuoteValue: true,
 												},
 											},
@@ -631,13 +663,17 @@ func TestPlanner_Plan(t *testing.T) {
 								Name:        []byte("listWithPath"),
 								HasResolver: true,
 								Value: &List{
-									Path: []string{"items"},
+									PathSelector: PathSelector{
+										Path: "items",
+									},
 									Value: &Object{
 										Fields: []Field{
 											{
 												Name: []byte("id"),
 												Value: &Value{
-													Path:       []string{"id"},
+													PathSelector: PathSelector{
+														Path: "id",
+													},
 													QuoteValue: true,
 												},
 											},
@@ -813,7 +849,9 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("bar"),
 											Value: &Value{
-												Path:       []string{"bar"},
+												PathSelector: PathSelector{
+													Path: "bar",
+												},
 												QuoteValue: true,
 											},
 										},
@@ -869,37 +907,49 @@ func TestPlanner_Plan(t *testing.T) {
 							Name:        []byte("__type"),
 							HasResolver: true,
 							Value: &Object{
-								Path: []string{"__type"},
+								PathSelector: PathSelector{
+									Path: "__type",
+								},
 								Fields: []Field{
 									{
 										Name: []byte("name"),
 										Value: &Value{
-											Path:       []string{"name"},
+											PathSelector: PathSelector{
+												Path: "name",
+											},
 											QuoteValue: true,
 										},
 									},
 									{
 										Name: []byte("fields"),
 										Value: &List{
-											Path: []string{"fields"},
+											PathSelector: PathSelector{
+												Path: "fields",
+											},
 											Value: &Object{
 												Fields: []Field{
 													{
 														Name: []byte("name"),
 														Value: &Value{
-															Path:       []string{"name"},
+															PathSelector: PathSelector{
+																Path: "name",
+															},
 															QuoteValue: true,
 														},
 													},
 													{
 														Name: []byte("type"),
 														Value: &Object{
-															Path: []string{"type"},
+															PathSelector: PathSelector{
+																Path: "type",
+															},
 															Fields: []Field{
 																{
 																	Name: []byte("name"),
 																	Value: &Value{
-																		Path:       []string{"name"},
+																		PathSelector: PathSelector{
+																			Path: "name",
+																		},
 																		QuoteValue: true,
 																	},
 																},
@@ -970,26 +1020,34 @@ func TestPlanner_Plan(t *testing.T) {
 								Name:        []byte("user"),
 								HasResolver: true,
 								Value: &Object{
-									Path: []string{"user"},
+									PathSelector: PathSelector{
+										Path: "user",
+									},
 									Fields: []Field{
 										{
 											Name: []byte("id"),
 											Value: &Value{
-												Path:       []string{"id"},
+												PathSelector: PathSelector{
+													Path: "id",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("name"),
 											Value: &Value{
-												Path:       []string{"name"},
+												PathSelector: PathSelector{
+													Path: "name",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("birthday"),
 											Value: &Value{
-												Path:       []string{"birthday"},
+												PathSelector: PathSelector{
+													Path: "birthday",
+												},
 												QuoteValue: true,
 											},
 										},
@@ -1057,21 +1115,27 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("id"),
 											Value: &Value{
-												Path:       []string{"id"},
+												PathSelector: PathSelector{
+													Path: "id",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("name"),
 											Value: &Value{
-												Path:       []string{"name"},
+												PathSelector: PathSelector{
+													Path: "name",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("birthday"),
 											Value: &Value{
-												Path:       []string{"birthday"},
+												PathSelector: PathSelector{
+													Path: "birthday",
+												},
 												QuoteValue: true,
 											},
 										},
@@ -1148,7 +1212,9 @@ func TestPlanner_Plan(t *testing.T) {
 								Name:        []byte("user"),
 								HasResolver: true,
 								Value: &Object{
-									Path: []string{"user"},
+									PathSelector: PathSelector{
+										Path: "user",
+									},
 									Fetch: &SingleFetch{
 										Source: &DataSourceInvocation{
 											Args: []Argument{
@@ -1162,7 +1228,9 @@ func TestPlanner_Plan(t *testing.T) {
 												},
 												&ObjectVariableArgument{
 													Name: []byte("id"),
-													Path: []string{"id"},
+													PathSelector: PathSelector{
+														Path: "id",
+													},
 												},
 												&StaticVariableArgument{
 													Name:  []byte("method"),
@@ -1177,21 +1245,27 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("id"),
 											Value: &Value{
-												Path:       []string{"id"},
+												PathSelector: PathSelector{
+													Path: "id",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("name"),
 											Value: &Value{
-												Path:       []string{"name"},
+												PathSelector: PathSelector{
+													Path: "name",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("birthday"),
 											Value: &Value{
-												Path:       []string{"birthday"},
+												PathSelector: PathSelector{
+													Path: "birthday",
+												},
 												QuoteValue: true,
 											},
 										},
@@ -1204,21 +1278,27 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("id"),
 															Value: &Value{
-																Path:       []string{"id"},
+																PathSelector: PathSelector{
+																	Path: "id",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("name"),
 															Value: &Value{
-																Path:       []string{"name"},
+																PathSelector: PathSelector{
+																	Path: "name",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("birthday"),
 															Value: &Value{
-																Path:       []string{"birthday"},
+																PathSelector: PathSelector{
+																	Path: "birthday",
+																},
 																QuoteValue: true,
 															},
 														},
@@ -1329,7 +1409,9 @@ func TestPlanner_Plan(t *testing.T) {
 								Name:        []byte("user"),
 								HasResolver: true,
 								Value: &Object{
-									Path: []string{"user"},
+									PathSelector: PathSelector{
+										Path: "user",
+									},
 									Fetch: &ParallelFetch{
 										Fetches: []Fetch{
 											&SingleFetch{
@@ -1345,7 +1427,9 @@ func TestPlanner_Plan(t *testing.T) {
 														},
 														&ObjectVariableArgument{
 															Name: []byte("id"),
-															Path: []string{"id"},
+															PathSelector: PathSelector{
+																Path: "id",
+															},
 														},
 														&StaticVariableArgument{
 															Name:  []byte("method"),
@@ -1373,7 +1457,9 @@ func TestPlanner_Plan(t *testing.T) {
 														},
 														&ObjectVariableArgument{
 															Name: []byte("userId"),
-															Path: []string{"id"},
+															PathSelector: PathSelector{
+																Path: "id",
+															},
 														},
 													},
 													DataSource: &GraphQLDataSource{},
@@ -1386,14 +1472,18 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("id"),
 											Value: &Value{
-												Path:       []string{"id"},
+												PathSelector: PathSelector{
+													Path: "id",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("name"),
 											Value: &Value{
-												Path:       []string{"name"},
+												PathSelector: PathSelector{
+													Path: "name",
+												},
 												QuoteValue: true,
 											},
 										},
@@ -1419,7 +1509,9 @@ func TestPlanner_Plan(t *testing.T) {
 																},
 																&ObjectVariableArgument{
 																	Name: []byte("userId"),
-																	Path: []string{"id"},
+																	PathSelector: PathSelector{
+																		Path: "id",
+																	},
 																},
 															},
 															DataSource: &GraphQLDataSource{},
@@ -1430,21 +1522,27 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("id"),
 															Value: &Value{
-																Path:       []string{"id"},
+																PathSelector: PathSelector{
+																	Path: "id",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("name"),
 															Value: &Value{
-																Path:       []string{"name"},
+																PathSelector: PathSelector{
+																	Path: "name",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("birthday"),
 															Value: &Value{
-																Path:       []string{"birthday"},
+																PathSelector: PathSelector{
+																	Path: "birthday",
+																},
 																QuoteValue: true,
 															},
 														},
@@ -1452,32 +1550,42 @@ func TestPlanner_Plan(t *testing.T) {
 															Name:        []byte("pets"),
 															HasResolver: true,
 															Value: &List{
-																Path: []string{"userPets"},
+																PathSelector: PathSelector{
+																	Path: "userPets",
+																},
 																Value: &Object{
 																	Fields: []Field{
 																		{
 																			Name: []byte("__typename"),
 																			Value: &Value{
-																				Path:       []string{"__typename"},
+																				PathSelector: PathSelector{
+																					Path: "__typename",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
 																		{
 																			Name: []byte("nickname"),
 																			Value: &Value{
-																				Path:       []string{"nickname"},
+																				PathSelector: PathSelector{
+																					Path: "nickname",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
 																		{
 																			Name: []byte("name"),
 																			Value: &Value{
-																				Path:       []string{"name"},
+																				PathSelector: PathSelector{
+																					Path: "name",
+																				},
 																				QuoteValue: true,
 																			},
 																			Skip: &IfNotEqual{
 																				Left: &ObjectVariableArgument{
-																					Path: []string{"__typename"},
+																					PathSelector: PathSelector{
+																						Path: "__typename",
+																					},
 																				},
 																				Right: &StaticVariableArgument{
 																					Value: []byte("Dog"),
@@ -1487,12 +1595,16 @@ func TestPlanner_Plan(t *testing.T) {
 																		{
 																			Name: []byte("woof"),
 																			Value: &Value{
-																				Path:       []string{"woof"},
+																				PathSelector: PathSelector{
+																					Path: "woof",
+																				},
 																				QuoteValue: true,
 																			},
 																			Skip: &IfNotEqual{
 																				Left: &ObjectVariableArgument{
-																					Path: []string{"__typename"},
+																					PathSelector: PathSelector{
+																						Path: "__typename",
+																					},
 																				},
 																				Right: &StaticVariableArgument{
 																					Value: []byte("Dog"),
@@ -1502,12 +1614,16 @@ func TestPlanner_Plan(t *testing.T) {
 																		{
 																			Name: []byte("name"),
 																			Value: &Value{
-																				Path:       []string{"name"},
+																				PathSelector: PathSelector{
+																					Path: "name",
+																				},
 																				QuoteValue: true,
 																			},
 																			Skip: &IfNotEqual{
 																				Left: &ObjectVariableArgument{
-																					Path: []string{"__typename"},
+																					PathSelector: PathSelector{
+																						Path: "__typename",
+																					},
 																				},
 																				Right: &StaticVariableArgument{
 																					Value: []byte("Cat"),
@@ -1517,12 +1633,16 @@ func TestPlanner_Plan(t *testing.T) {
 																		{
 																			Name: []byte("meow"),
 																			Value: &Value{
-																				Path:       []string{"meow"},
+																				PathSelector: PathSelector{
+																					Path: "meow",
+																				},
 																				QuoteValue: true,
 																			},
 																			Skip: &IfNotEqual{
 																				Left: &ObjectVariableArgument{
-																					Path: []string{"__typename"},
+																					PathSelector: PathSelector{
+																						Path: "__typename",
+																					},
 																				},
 																				Right: &StaticVariableArgument{
 																					Value: []byte("Cat"),
@@ -1541,32 +1661,42 @@ func TestPlanner_Plan(t *testing.T) {
 											Name:        []byte("pets"),
 											HasResolver: true,
 											Value: &List{
-												Path: []string{"userPets"},
+												PathSelector: PathSelector{
+													Path: "userPets",
+												},
 												Value: &Object{
 													Fields: []Field{
 														{
 															Name: []byte("__typename"),
 															Value: &Value{
-																Path:       []string{"__typename"},
+																PathSelector: PathSelector{
+																	Path: "__typename",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("nickname"),
 															Value: &Value{
-																Path:       []string{"nickname"},
+																PathSelector: PathSelector{
+																	Path: "nickname",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("name"),
 															Value: &Value{
-																Path:       []string{"name"},
+																PathSelector: PathSelector{
+																	Path: "name",
+																},
 																QuoteValue: true,
 															},
 															Skip: &IfNotEqual{
 																Left: &ObjectVariableArgument{
-																	Path: []string{"__typename"},
+																	PathSelector: PathSelector{
+																		Path: "__typename",
+																	},
 																},
 																Right: &StaticVariableArgument{
 																	Value: []byte("Dog"),
@@ -1576,12 +1706,16 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("woof"),
 															Value: &Value{
-																Path:       []string{"woof"},
+																PathSelector: PathSelector{
+																	Path: "woof",
+																},
 																QuoteValue: true,
 															},
 															Skip: &IfNotEqual{
 																Left: &ObjectVariableArgument{
-																	Path: []string{"__typename"},
+																	PathSelector: PathSelector{
+																		Path: "__typename",
+																	},
 																},
 																Right: &StaticVariableArgument{
 																	Value: []byte("Dog"),
@@ -1591,12 +1725,16 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("name"),
 															Value: &Value{
-																Path:       []string{"name"},
+																PathSelector: PathSelector{
+																	Path: "name",
+																},
 																QuoteValue: true,
 															},
 															Skip: &IfNotEqual{
 																Left: &ObjectVariableArgument{
-																	Path: []string{"__typename"},
+																	PathSelector: PathSelector{
+																		Path: "__typename",
+																	},
 																},
 																Right: &StaticVariableArgument{
 																	Value: []byte("Cat"),
@@ -1606,12 +1744,16 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("meow"),
 															Value: &Value{
-																Path:       []string{"meow"},
+																PathSelector: PathSelector{
+																	Path: "meow",
+																},
 																QuoteValue: true,
 															},
 															Skip: &IfNotEqual{
 																Left: &ObjectVariableArgument{
-																	Path: []string{"__typename"},
+																	PathSelector: PathSelector{
+																		Path: "__typename",
+																	},
 																},
 																Right: &StaticVariableArgument{
 																	Value: []byte("Cat"),
@@ -1625,7 +1767,9 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("birthday"),
 											Value: &Value{
-												Path:       []string{"birthday"},
+												PathSelector: PathSelector{
+													Path: "birthday",
+												},
 												QuoteValue: true,
 											},
 										},
@@ -1763,17 +1907,23 @@ func TestPlanner_Plan(t *testing.T) {
 								Name:        []byte("__schema"),
 								HasResolver: true,
 								Value: &Object{
-									Path: []string{"__schema"},
+									PathSelector: PathSelector{
+										Path: "__schema",
+									},
 									Fields: []Field{
 										{
 											Name: []byte("queryType"),
 											Value: &Object{
-												Path: []string{"queryType"},
+												PathSelector: PathSelector{
+													Path: "queryType",
+												},
 												Fields: []Field{
 													{
 														Name: []byte("name"),
 														Value: &Value{
-															Path:       []string{"name"},
+															PathSelector: PathSelector{
+																Path: "name",
+															},
 															QuoteValue: true,
 														},
 													},
@@ -1783,12 +1933,16 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("mutationType"),
 											Value: &Object{
-												Path: []string{"mutationType"},
+												PathSelector: PathSelector{
+													Path: "mutationType",
+												},
 												Fields: []Field{
 													{
 														Name: []byte("name"),
 														Value: &Value{
-															Path:       []string{"name"},
+															PathSelector: PathSelector{
+																Path: "name",
+															},
 															QuoteValue: true,
 														},
 													},
@@ -1798,12 +1952,16 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("subscriptionType"),
 											Value: &Object{
-												Path: []string{"subscriptionType"},
+												PathSelector: PathSelector{
+													Path: "subscriptionType",
+												},
 												Fields: []Field{
 													{
 														Name: []byte("name"),
 														Value: &Value{
-															Path:       []string{"name"},
+															PathSelector: PathSelector{
+																Path: "name",
+															},
 															QuoteValue: true,
 														},
 													},
@@ -1813,81 +1971,105 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("types"),
 											Value: &List{
-												Path: []string{"types"},
+												PathSelector: PathSelector{
+													Path: "types",
+												},
 												Value: &Object{
 													Fields: []Field{
 														{
 															Name: []byte("kind"),
 															Value: &Value{
-																Path:       []string{"kind"},
+																PathSelector: PathSelector{
+																	Path: "kind",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("name"),
 															Value: &Value{
-																Path:       []string{"name"},
+																PathSelector: PathSelector{
+																	Path: "name",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("description"),
 															Value: &Value{
-																Path:       []string{"description"},
+																PathSelector: PathSelector{
+																	Path: "description",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("fields"),
 															Value: &List{
-																Path: []string{"fields"},
+																PathSelector: PathSelector{
+																	Path: "fields",
+																},
 																Value: &Object{
 																	Fields: []Field{
 																		{
 																			Name: []byte("name"),
 																			Value: &Value{
-																				Path:       []string{"name"},
+																				PathSelector: PathSelector{
+																					Path: "name",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
 																		{
 																			Name: []byte("description"),
 																			Value: &Value{
-																				Path:       []string{"description"},
+																				PathSelector: PathSelector{
+																					Path: "description",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
 																		{
 																			Name: []byte("args"),
 																			Value: &List{
-																				Path: []string{"args"},
+																				PathSelector: PathSelector{
+																					Path: "args",
+																				},
 																				Value: &Object{
 																					Fields: []Field{
 																						{
 																							Name: []byte("name"),
 																							Value: &Value{
-																								Path:       []string{"name"},
+																								PathSelector: PathSelector{
+																									Path: "name",
+																								},
 																								QuoteValue: true,
 																							},
 																						},
 																						{
 																							Name: []byte("description"),
 																							Value: &Value{
-																								Path:       []string{"description"},
+																								PathSelector: PathSelector{
+																									Path: "description",
+																								},
 																								QuoteValue: true,
 																							},
 																						},
 																						{
 																							Name: []byte("type"),
 																							Value: &Object{
-																								Path:   []string{"type"},
+																								PathSelector: PathSelector{
+																									Path: "type",
+																								},
 																								Fields: kindNameDeepFields,
 																							},
 																						},
 																						{
 																							Name: []byte("defaultValue"),
 																							Value: &Value{
-																								Path:       []string{"defaultValue"},
+																								PathSelector: PathSelector{
+																									Path: "defaultValue",
+																								},
 																								QuoteValue: true,
 																							},
 																						},
@@ -1898,21 +2080,27 @@ func TestPlanner_Plan(t *testing.T) {
 																		{
 																			Name: []byte("type"),
 																			Value: &Object{
-																				Path:   []string{"type"},
+																				PathSelector: PathSelector{
+																					Path: "type",
+																				},
 																				Fields: kindNameDeepFields,
 																			},
 																		},
 																		{
 																			Name: []byte("isDeprecated"),
 																			Value: &Value{
-																				Path:       []string{"isDeprecated"},
+																				PathSelector: PathSelector{
+																					Path: "isDeprecated",
+																				},
 																				QuoteValue: false,
 																			},
 																		},
 																		{
 																			Name: []byte("deprecationReason"),
 																			Value: &Value{
-																				Path:       []string{"deprecationReason"},
+																				PathSelector: PathSelector{
+																					Path: "deprecationReason",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
@@ -1923,34 +2111,44 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("inputFields"),
 															Value: &List{
-																Path: []string{"inputFields"},
+																PathSelector: PathSelector{
+																	Path: "inputFields",
+																},
 																Value: &Object{
 																	Fields: []Field{
 																		{
 																			Name: []byte("name"),
 																			Value: &Value{
-																				Path:       []string{"name"},
+																				PathSelector: PathSelector{
+																					Path: "name",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
 																		{
 																			Name: []byte("description"),
 																			Value: &Value{
-																				Path:       []string{"description"},
+																				PathSelector: PathSelector{
+																					Path: "description",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
 																		{
 																			Name: []byte("type"),
 																			Value: &Object{
-																				Path:   []string{"type"},
+																				PathSelector: PathSelector{
+																					Path: "type",
+																				},
 																				Fields: kindNameDeepFields,
 																			},
 																		},
 																		{
 																			Name: []byte("defaultValue"),
 																			Value: &Value{
-																				Path:       []string{"defaultValue"},
+																				PathSelector: PathSelector{
+																					Path: "defaultValue",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
@@ -1961,7 +2159,9 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("interfaces"),
 															Value: &List{
-																Path: []string{"interfaces"},
+																PathSelector: PathSelector{
+																	Path: "interfaces",
+																},
 																Value: &Object{
 																	Fields: kindNameDeepFields,
 																},
@@ -1970,34 +2170,44 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("enumValues"),
 															Value: &List{
-																Path: []string{"enumValues"},
+																PathSelector: PathSelector{
+																	Path: "enumValues",
+																},
 																Value: &Object{
 																	Fields: []Field{
 																		{
 																			Name: []byte("name"),
 																			Value: &Value{
-																				Path:       []string{"name"},
+																				PathSelector: PathSelector{
+																					Path: "name",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
 																		{
 																			Name: []byte("description"),
 																			Value: &Value{
-																				Path:       []string{"description"},
+																				PathSelector: PathSelector{
+																					Path: "description",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
 																		{
 																			Name: []byte("isDeprecated"),
 																			Value: &Value{
-																				Path:       []string{"isDeprecated"},
+																				PathSelector: PathSelector{
+																					Path: "isDeprecated",
+																				},
 																				QuoteValue: false,
 																			},
 																		},
 																		{
 																			Name: []byte("deprecationReason"),
 																			Value: &Value{
-																				Path:       []string{"deprecationReason"},
+																				PathSelector: PathSelector{
+																					Path: "deprecationReason",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
@@ -2008,7 +2218,9 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("possibleTypes"),
 															Value: &List{
-																Path: []string{"possibleTypes"},
+																PathSelector: PathSelector{
+																	Path: "possibleTypes",
+																},
 																Value: &Object{
 																	Fields: kindNameDeepFields,
 																},
@@ -2021,27 +2233,35 @@ func TestPlanner_Plan(t *testing.T) {
 										{
 											Name: []byte("directives"),
 											Value: &List{
-												Path: []string{"directives"},
+												PathSelector: PathSelector{
+													Path: "directives",
+												},
 												Value: &Object{
 													Fields: []Field{
 														{
 															Name: []byte("name"),
 															Value: &Value{
-																Path:       []string{"name"},
+																PathSelector: PathSelector{
+																	Path: "name",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("description"),
 															Value: &Value{
-																Path:       []string{"description"},
+																PathSelector: PathSelector{
+																	Path: "description",
+																},
 																QuoteValue: true,
 															},
 														},
 														{
 															Name: []byte("locations"),
 															Value: &List{
-																Path: []string{"locations"},
+																PathSelector: PathSelector{
+																	Path: "locations",
+																},
 																Value: &Value{
 																	QuoteValue: true,
 																},
@@ -2050,34 +2270,44 @@ func TestPlanner_Plan(t *testing.T) {
 														{
 															Name: []byte("args"),
 															Value: &List{
-																Path: []string{"args"},
+																PathSelector: PathSelector{
+																	Path: "args",
+																},
 																Value: &Object{
 																	Fields: []Field{
 																		{
 																			Name: []byte("name"),
 																			Value: &Value{
-																				Path:       []string{"name"},
+																				PathSelector: PathSelector{
+																					Path: "name",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
 																		{
 																			Name: []byte("description"),
 																			Value: &Value{
-																				Path:       []string{"description"},
+																				PathSelector: PathSelector{
+																					Path: "description",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
 																		{
 																			Name: []byte("type"),
 																			Value: &Object{
-																				Path:   []string{"type"},
+																				PathSelector: PathSelector{
+																					Path: "type",
+																				},
 																				Fields: kindNameDeepFields,
 																			},
 																		},
 																		{
 																			Name: []byte("defaultValue"),
 																			Value: &Value{
-																				Path:       []string{"defaultValue"},
+																				PathSelector: PathSelector{
+																					Path: "defaultValue",
+																				},
 																				QuoteValue: true,
 																			},
 																		},
@@ -2152,14 +2382,18 @@ func TestPlanner_Plan(t *testing.T) {
 									{
 										Name: []byte("bar"),
 										Value: &Value{
-											Path:       []string{"bar"},
+											PathSelector: PathSelector{
+												Path: "bar",
+											},
 											QuoteValue: true,
 										},
 									},
 									{
 										Name: []byte("baz"),
 										Value: &Value{
-											Path:       []string{"baz"},
+											PathSelector: PathSelector{
+												Path: "baz",
+											},
 											QuoteValue: false,
 										},
 									},
@@ -2224,14 +2458,18 @@ func TestPlanner_Plan(t *testing.T) {
 									{
 										Name: []byte("bar"),
 										Value: &Value{
-											Path:       []string{"bar"},
+											PathSelector: PathSelector{
+												Path: "bar",
+											},
 											QuoteValue: true,
 										},
 									},
 									{
 										Name: []byte("baz"),
 										Value: &Value{
-											Path:       []string{"baz"},
+											PathSelector: PathSelector{
+												Path: "baz",
+											},
 											QuoteValue: false,
 										},
 									},
@@ -2289,7 +2527,9 @@ func TestPlanner_Plan(t *testing.T) {
 											{
 												Name: []byte("bar"),
 												Value: &Value{
-													Path:       []string{"bar"},
+													PathSelector: PathSelector{
+														Path: "bar",
+													},
 													QuoteValue: true,
 												},
 											},
@@ -2396,6 +2636,7 @@ type Query {
 		@StaticDataSource(
             data: "[{\"bar\":\"baz\"},{\"bar\":\"bal\"},{\"bar\":\"bat\"}]"
         )
+		@mapping(mode: NONE)
 }
 
 type Foo {
@@ -2423,6 +2664,7 @@ type Subscription {
 			host: "foo.bar.baz"
 			url: "/bal"
 		)
+		@mapping(mode: NONE)
 }
 
 type Foo {
@@ -2451,6 +2693,7 @@ type Subscription {
 			url: "/bal"
 			delaySeconds: 3
 		)
+		@mapping(mode: NONE)
 }
 
 type Foo {
@@ -2467,10 +2710,16 @@ directive @GraphQLDataSource (
     params: [Parameter]
 ) on FIELD_DEFINITION
 
-directive @mapTo(
-	objectField: String!
+directive @mapping(
+    mode: MAPPING_MODE! = PATH_SELECTOR
+    pathSelector: String
 ) on FIELD_DEFINITION
 
+enum MAPPING_MODE {
+    NONE
+    PATH_SELECTOR
+}
+
 enum HTTP_METHOD {
     GET
     POST
@@ -2568,11 +2817,15 @@ directive @HttpJsonDataSource (
 	body: String
 ) on FIELD_DEFINITION
 
-directive @mapTo(
-	objectField: String!
+directive @mapping(
+    mode: MAPPING_MODE! = PATH_SELECTOR
+    pathSelector: String
 ) on FIELD_DEFINITION
 
-directive @path(append: [String!], prepend: [String!]) on FIELD_DEFINITION
+enum MAPPING_MODE {
+    NONE
+    PATH_SELECTOR
+}
 
 enum HTTP_METHOD {
     GET
@@ -2605,11 +2858,11 @@ type Foo {
 type Headers {
     Accept: String!
     Host: String!
-	acceptEncoding: String @mapTo(objectField: "Accept-Encoding")
+	acceptEncoding: String @mapping(pathSelector: "Accept-Encoding")
 }
 
 type HttpBinGet {
-	header: Headers! @mapTo(objectField: "headers")
+	header: Headers! @mapping(pathSelector: "headers")
 }
 
 type JSONPlaceholderPost {
@@ -2630,6 +2883,7 @@ type JSONPlaceholderPost {
                 }
             ]
         )
+		@mapping(mode: NONE)
 }
 
 type JSONPlaceholderComment {
@@ -2647,11 +2901,13 @@ type Query {
             host: "httpbin.org"
             url: "/get"
         )
+		@mapping(mode: NONE)
 	post(id: Int!): JSONPlaceholderPost
         @HttpJsonDataSource(
             host: "jsonplaceholder.typicode.com"
             url: "/posts/{{ .arguments.id }}"
         )
+		@mapping(mode: NONE)
 	withBody(input: WithBodyInput!): String!
         @HttpJsonDataSource(
             host: "httpbin.org"
@@ -2659,6 +2915,7 @@ type Query {
             method: POST
             body: 	"{\"key\":\"{{ .arguments.input.foo }}\"}"
         )
+		@mapping(mode: NONE)
 	withHeaders: String!
         @HttpJsonDataSource(
             host: "httpbin.org"
@@ -2674,23 +2931,25 @@ type Query {
 				}
 			]
         )
+		@mapping(mode: NONE)
 	withPath: String!
-		@path(append: ["subObject"])
 		@HttpJsonDataSource(
             host: "httpbin.org"
             url: "/anything"
         )
+		@mapping(pathSelector: "subObject")
 	listItems: [ListItem]
 		@HttpJsonDataSource(
             host: "httpbin.org"
             url: "/anything"
         )
+		@mapping(mode: NONE)
 	listWithPath: [ListItem]
-		@path(append: ["items"])
 		@HttpJsonDataSource(
             host: "httpbin.org"
             url: "/anything"
         )
+		@mapping(pathSelector: "items")
     __schema: __Schema!
     __type(name: String!): __Type
 }
@@ -2719,14 +2978,17 @@ type Query {
 		@StaticDataSource(
             data: "World!"
         )
+		@mapping(mode: NONE)
 	nullableInt: Int
         @StaticDataSource(
             data: null
         )
+		@mapping(mode: NONE)
 	foo: Foo!
         @StaticDataSource(
             data: "{\"bar\":\"baz\"}"
         )
+		@mapping(mode: NONE)
 }`
 
 const complexSchema = `
@@ -2744,10 +3006,16 @@ directive @GraphQLDataSource (
     params: [Parameter]
 ) on FIELD_DEFINITION
 
-directive @mapTo(
-	objectField: String!
+directive @mapping(
+    mode: MAPPING_MODE! = PATH_SELECTOR
+    pathSelector: String
 ) on FIELD_DEFINITION
 
+enum MAPPING_MODE {
+    NONE
+    PATH_SELECTOR
+}
+
 enum HTTP_METHOD {
     GET
     POST
@@ -2831,6 +3099,7 @@ type Query {
 			host: "localhost:9001"
 			url: "/user/{{ .arguments.id }}"
 		)
+		@mapping(mode: NONE)
 }
 type User {
 	id: String
@@ -2849,10 +3118,8 @@ type User {
 				}
 			]
 		)
+		@mapping(mode: NONE)
 	pets: [Pet]
-		@mapTo(
-			objectField: "userPets"
-		)
 		@GraphQLDataSource(
 			host: "localhost:8002"
 			url: "/graphql"
@@ -2865,6 +3132,7 @@ type User {
 				}
 			]
 		)
+		@mapping(pathSelector: "userPets")
 }
 interface Pet {
 	nickname: String!
@@ -3072,147 +3340,193 @@ var kindNameDeepFields = []Field{
 	{
 		Name: []byte("kind"),
 		Value: &Value{
-			Path:       []string{"kind"},
+			PathSelector: PathSelector{
+				Path: "kind",
+			},
 			QuoteValue: true,
 		},
 	},
 	{
 		Name: []byte("name"),
 		Value: &Value{
-			Path:       []string{"name"},
+			PathSelector: PathSelector{
+				Path: "name",
+			},
 			QuoteValue: true,
 		},
 	},
 	{
 		Name: []byte("ofType"),
 		Value: &Object{
-			Path: []string{"ofType"},
+			PathSelector: PathSelector{
+				Path: "ofType",
+			},
 			Fields: []Field{
 				{
 					Name: []byte("kind"),
 					Value: &Value{
-						Path:       []string{"kind"},
+						PathSelector: PathSelector{
+							Path: "kind",
+						},
 						QuoteValue: true,
 					},
 				},
 				{
 					Name: []byte("name"),
 					Value: &Value{
-						Path:       []string{"name"},
+						PathSelector: PathSelector{
+							Path: "name",
+						},
 						QuoteValue: true,
 					},
 				},
 				{
 					Name: []byte("ofType"),
 					Value: &Object{
-						Path: []string{"ofType"},
+						PathSelector: PathSelector{
+							Path: "ofType",
+						},
 						Fields: []Field{
 							{
 								Name: []byte("kind"),
 								Value: &Value{
-									Path:       []string{"kind"},
+									PathSelector: PathSelector{
+										Path: "kind",
+									},
 									QuoteValue: true,
 								},
 							},
 							{
 								Name: []byte("name"),
 								Value: &Value{
-									Path:       []string{"name"},
+									PathSelector: PathSelector{
+										Path: "name",
+									},
 									QuoteValue: true,
 								},
 							},
 							{
 								Name: []byte("ofType"),
 								Value: &Object{
-									Path: []string{"ofType"},
+									PathSelector: PathSelector{
+										Path: "ofType",
+									},
 									Fields: []Field{
 										{
 											Name: []byte("kind"),
 											Value: &Value{
-												Path:       []string{"kind"},
+												PathSelector: PathSelector{
+													Path: "kind",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("name"),
 											Value: &Value{
-												Path:       []string{"name"},
+												PathSelector: PathSelector{
+													Path: "name",
+												},
 												QuoteValue: true,
 											},
 										},
 										{
 											Name: []byte("ofType"),
 											Value: &Object{
-												Path: []string{"ofType"},
+												PathSelector: PathSelector{
+													Path: "ofType",
+												},
 												Fields: []Field{
 													{
 														Name: []byte("kind"),
 														Value: &Value{
-															Path:       []string{"kind"},
+															PathSelector: PathSelector{
+																Path: "kind",
+															},
 															QuoteValue: true,
 														},
 													},
 													{
 														Name: []byte("name"),
 														Value: &Value{
-															Path:       []string{"name"},
+															PathSelector: PathSelector{
+																Path: "name",
+															},
 															QuoteValue: true,
 														},
 													},
 													{
 														Name: []byte("ofType"),
 														Value: &Object{
-															Path: []string{"ofType"},
+															PathSelector: PathSelector{
+																Path: "ofType",
+															},
 															Fields: []Field{
 																{
 																	Name: []byte("kind"),
 																	Value: &Value{
-																		Path:       []string{"kind"},
+																		PathSelector: PathSelector{
+																			Path: "kind",
+																		},
 																		QuoteValue: true,
 																	},
 																},
 																{
 																	Name: []byte("name"),
 																	Value: &Value{
-																		Path:       []string{"name"},
+																		PathSelector: PathSelector{
+																			Path: "name",
+																		},
 																		QuoteValue: true,
 																	},
 																},
 																{
 																	Name: []byte("ofType"),
 																	Value: &Object{
-																		Path: []string{"ofType"},
+																		PathSelector: PathSelector{
+																			Path: "ofType",
+																		},
 																		Fields: []Field{
 																			{
 																				Name: []byte("kind"),
 																				Value: &Value{
-																					Path:       []string{"kind"},
+																					PathSelector: PathSelector{
+																						Path: "kind",
+																					},
 																					QuoteValue: true,
 																				},
 																			},
 																			{
 																				Name: []byte("name"),
 																				Value: &Value{
-																					Path:       []string{"name"},
+																					PathSelector: PathSelector{
+																						Path: "name",
+																					},
 																					QuoteValue: true,
 																				},
 																			},
 																			{
 																				Name: []byte("ofType"),
 																				Value: &Object{
-																					Path: []string{"ofType"},
+																					PathSelector: PathSelector{
+																						Path: "ofType",
+																					},
 																					Fields: []Field{
 																						{
 																							Name: []byte("kind"),
 																							Value: &Value{
-																								Path:       []string{"kind"},
+																								PathSelector: PathSelector{
+																									Path: "kind",
+																								},
 																								QuoteValue: true,
 																							},
 																						},
 																						{
 																							Name: []byte("name"),
 																							Value: &Value{
-																								Path:       []string{"name"},
+																								PathSelector: PathSelector{
+																									Path: "name",
+																								},
 																								QuoteValue: true,
 																							},
 																						},