@@ -12,6 +12,7 @@ import (
1212 "strings"
1313 "sync"
1414 "time"
15+ "unicode"
1516
1617 "github.com/buger/jsonparser"
1718 "github.com/cespare/xxhash/v2"
@@ -400,19 +401,58 @@ func (p *Planner[T]) ConfigureSubscription() plan.SubscriptionConfiguration {
400401 }
401402}
402403
404+ func sanitize (element string ) string {
405+ // replace all invalid characters with underscore
406+ return strings .Map (func (r rune ) rune {
407+ if ! unicode .IsDigit (r ) && ! unicode .IsLetter (r ) && r != '_' {
408+ return '_'
409+ }
410+ return r
411+ }, element )
412+ }
413+
414+ func sanitizeKey (element string ) string {
415+ if element == "" {
416+ return ""
417+ }
418+
419+ sanitized := sanitize (element )
420+
421+ // remove consecutive underscores and leave only one
422+ builder := strings.Builder {}
423+ var prev rune
424+
425+ for _ , r := range sanitized {
426+ if r == '_' && prev == '_' {
427+ continue
428+ }
429+
430+ builder .WriteRune (r )
431+ prev = r
432+ }
433+
434+ return builder .String ()
435+ }
436+
437+ // buildUpstreamOperationName builds the name of the upstream operation.
438+ // An operation name can only contain characters, digits and underscores. All other characters are replaced with underscores.
439+ // As the subgraph name can contain special characters we need to make sure to sanitize it.
403440func (p * Planner [T ]) buildUpstreamOperationName (ref int ) string {
404- operationName := p .visitor .Operation .OperationDefinitionNameBytes (ref )
405- if len ( operationName ) == 0 {
441+ operationName := p .visitor .Operation .OperationDefinitionNameBytes (ref ). String ()
442+ if operationName == "" {
406443 return ""
407444 }
408445
409446 fetchID := strconv .Itoa (p .dataSourcePlannerConfig .FetchID )
410447
411448 builder := strings.Builder {}
412- builder .Grow (len (operationName ) + len (p .dataSourceConfig .Name ()) + len (fetchID ) + 4 ) // 4 is for delimiters "__"
449+ operationName = strings .Trim (operationName , "_" )
450+
451+ subgraphName := sanitizeKey (p .dataSourceConfig .Name ())
452+ subgraphName = strings .Trim (subgraphName , "_" )
413453
414- builder .Write ( operationName )
415- builder .WriteString ("__" + p . dataSourceConfig . Name () + "__" + fetchID )
454+ builder .Grow ( len ( operationName ) + len ( subgraphName ) + len ( fetchID ) + 4 ) // 4 is for delimiters "__"
455+ builder .WriteString (operationName + "__" + subgraphName + "__" + fetchID )
416456
417457 return builder .String ()
418458}
0 commit comments