Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use bytes.Buffer instead channels and goroutines #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 56 additions & 106 deletions argument.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
package graphb

import (
"bytes"
"fmt"
)

type argumentValue interface {
stringChan() <-chan string
stringChan(buffer *bytes.Buffer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fantastic. I wanted to do this when I first created it. But I was too happy about the clever use of channels & goroutine so that I left it there. But I do think an io.Writer alike version is better.

Some suggestions:

  1. How about stringWriter() *bytes.Buffer which returns an writer instead of consuming one?
  2. Have you think about io.Writer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function name could be stringWriter so that people don't get confused.

}

type Argument struct {
Name string
Value argumentValue
}

func (a *Argument) stringChan() <-chan string {
tokenChan := make(chan string)
go func() {
tokenChan <- a.Name
tokenChan <- ":"
for str := range a.Value.stringChan() {
tokenChan <- str
}
close(tokenChan)
}()
return tokenChan
func (a *Argument) stringChan(buffer *bytes.Buffer) {
buffer.WriteString(a.Name)
buffer.WriteString(":")
a.Value.stringChan(buffer)
}

func ArgumentAny(name string, value interface{}) (Argument, error) {
Expand Down Expand Up @@ -85,143 +79,99 @@ func ArgumentCustomTypeSliceElem(values ...Argument) []Argument {
return values
}

/////////////////////////////
// ///////////////////////////
// Primitive Wrapper Types //
/////////////////////////////
// ///////////////////////////
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha, go fmt


// argBool represents a boolean value.
type argBool bool

func (v argBool) stringChan() <-chan string {
tokenChan := make(chan string)
go func() {
tokenChan <- fmt.Sprintf("%t", v)
close(tokenChan)
}()
return tokenChan
func (v argBool) stringChan(buffer *bytes.Buffer) {
buffer.WriteString(fmt.Sprintf("%t", v))
}

// argInt represents an integer value.
type argInt int

func (v argInt) stringChan() <-chan string {
tokenChan := make(chan string)
go func() {
tokenChan <- fmt.Sprintf("%d", v)
close(tokenChan)
}()
return tokenChan
func (v argInt) stringChan(buffer *bytes.Buffer) {
buffer.WriteString(fmt.Sprintf("%d", v))
}

// argString represents a string value.
type argString string

func (v argString) stringChan() <-chan string {
tokenChan := make(chan string)
go func() {
tokenChan <- fmt.Sprintf(`"%s"`, v)
close(tokenChan)
}()
return tokenChan
func (v argString) stringChan(buffer *bytes.Buffer) {
buffer.WriteString(fmt.Sprintf(`"%s"`, v))
}

//////////////////////////////////
// ////////////////////////////////
// Primitive List Wrapper Types //
//////////////////////////////////
// ////////////////////////////////

// argBoolSlice implements valueSlice
type argBoolSlice []bool

func (s argBoolSlice) stringChan() <-chan string {
tokenChan := make(chan string)
go func() {
tokenChan <- "["
for i, v := range s {
if i != 0 {
tokenChan <- ","
}
tokenChan <- fmt.Sprintf("%t", v)
func (s argBoolSlice) stringChan(buffer *bytes.Buffer) {
buffer.WriteString("[")
for i, v := range s {
if i != 0 {
buffer.WriteString(",")
}
tokenChan <- "]"
close(tokenChan)
}()
return tokenChan
buffer.WriteString(fmt.Sprintf("%t", v))
}
buffer.WriteString("]")
}

// argIntSlice implements valueSlice
type argIntSlice []int

func (s argIntSlice) stringChan() <-chan string {
tokenChan := make(chan string)
go func() {
tokenChan <- "["
for i, v := range s {
if i != 0 {
tokenChan <- ","
}
tokenChan <- fmt.Sprintf("%d", v)
func (s argIntSlice) stringChan(buffer *bytes.Buffer) {
buffer.WriteString("[")
for i, v := range s {
if i != 0 {
buffer.WriteString(",")
}
tokenChan <- "]"
close(tokenChan)
}()
return tokenChan
buffer.WriteString(fmt.Sprintf("%d", v))
}
buffer.WriteString("]")
}

// argStringSlice implements valueSlice
type argStringSlice []string

func (s argStringSlice) stringChan() <-chan string {
tokenChan := make(chan string)
go func() {
tokenChan <- "["
for i, v := range s {
if i != 0 {
tokenChan <- ","
}
tokenChan <- fmt.Sprintf(`"%s"`, v)
func (s argStringSlice) stringChan(buffer *bytes.Buffer) {
buffer.WriteString("[")
for i, v := range s {
if i != 0 {
buffer.WriteString(",")
}
tokenChan <- "]"
close(tokenChan)
}()
return tokenChan
buffer.WriteString(fmt.Sprintf(`"%s"`, v))
}
buffer.WriteString("]")
}

type argumentSlice []Argument

func (s argumentSlice) stringChan() <-chan string {
tokenChan := make(chan string)
go func() {
tokenChan <- "{"
for i, v := range s {
if i != 0 {
tokenChan <- ","
}
for str := range v.stringChan() {
tokenChan <- str
}
func (s argumentSlice) stringChan(buffer *bytes.Buffer) {
buffer.WriteString("{")
for i, v := range s {
if i != 0 {
buffer.WriteString(",")
}
tokenChan <- "}"
close(tokenChan)
}()
return tokenChan
v.stringChan(buffer)
}
buffer.WriteString("}")
}

type argCustomTypeSlice [][]Argument

func (s argCustomTypeSlice) stringChan() <-chan string {
tokenChan := make(chan string)
go func() {
tokenChan <- "["
for i, v := range s {
if i != 0 {
tokenChan <- ","
}
for str := range argumentSlice(v).stringChan() {
tokenChan <- str
}
func (s argCustomTypeSlice) stringChan(buffer *bytes.Buffer) {
buffer.WriteString("[")
for i, v := range s {
if i != 0 {
buffer.WriteString(",")
}
tokenChan <- "]"
close(tokenChan)
}()
return tokenChan
argumentSlice(v).stringChan(buffer)
}
buffer.WriteString("]")
}
32 changes: 13 additions & 19 deletions argument_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package graphb

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -69,32 +70,25 @@ func TestArgumentStringSlice(t *testing.T) {
func Test_argBool(t *testing.T) {
b := argBool(true)
i := 0
for str := range b.stringChan() {
assert.Equal(t, "true", str)
i++
}
var buf bytes.Buffer
b.stringChan(&buf)
assert.Equal(t, "true", buf.String())
i++
assert.Equal(t, 1, i)
}

func Test_argBoolSlice(t *testing.T) {
bs := argBoolSlice([]bool{true, false})
c := bs.stringChan()
i := 0
tokens := []string{"[", "true", ",", "false", "]"}
for str, ok := <-c; ok; str, ok = <-c {
assert.Equal(t, tokens[i], str)
i++
}
assert.Equal(t, len(tokens), i)
var buf bytes.Buffer
bs.stringChan(&buf)
tokens := "[true,false]"
assert.Equal(t, tokens, buf.String())
}

func Test_argIntSlice(t *testing.T) {
is := argIntSlice([]int{1, -1, 0})
tokens := []string{"[", "1", ",", "-1", ",", "0", "]"}
i := 0
for str := range is.stringChan() {
assert.Equal(t, tokens[i], str)
i++
}
assert.Equal(t, len(tokens), i)
tokens := "[1,-1,0]"
var buf bytes.Buffer
is.stringChan(&buf)
assert.Equal(t, tokens, buf.String())
}
3 changes: 2 additions & 1 deletion error.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const (
argumentName nameType = "argument name"
)

// InvalidNameErr is returned when an invalid name is used. In GraphQL, operation, alias, field and argument all have names.
// InvalidNameErr is returned when an invalid name is used.
// In GraphQL, operation, alias, field and argument all have names.
// A valid name matches ^[_A-Za-z][_0-9A-Za-z]*$ exactly.
type InvalidNameErr struct {
Type nameType
Expand Down
Loading