Skip to content

Commit

Permalink
fix selecting relationship fields in quries (#19)
Browse files Browse the repository at this point in the history
* fix selecting relationship fields in quries

* lint

* update go version in workflow

* remove nolint

* use local lint config

* fix path

* fix path

* nolint
  • Loading branch information
imperfect-fourth committed Sep 15, 2024
1 parent 255e933 commit d0908e9
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 59 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: "1.22.2"
go-version: "1.23.1"
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: -c .golangci.yaml --out-format=colored-line-number
52 changes: 52 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# This file was adapted from https://github.com/dagger/dagger/blob/main/.golangci.yml
# to get a decent set of defaults.

linters:
disable-all: true
enable:
- bodyclose
- dogsled
- dupl
- copyloopvar
- gocritic
- gocyclo
- gofmt
- goimports
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- misspell
- nakedret
- nolintlint
- prealloc
- revive
- rowserrcheck
- staticcheck
- stylecheck
- typecheck
- unconvert
- unused
- whitespace

issues:
exclude-dirs:
- cmd/eywagen/eywatest

linters-settings:
revive:
rules:
# This rule is annoying. Often you want to name the
# parameters for clarity because it conforms to an
# interface.
- name: unused-parameter
severity: warning
disabled: true

output:
formats:
- format: colored-line-number
print-issued-lines: true
print-linter-name: true
sort-results: true
3 changes: 0 additions & 3 deletions .golangci.yml

This file was deleted.

12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,17 @@ resp, err := GetUnsafe[User]().Where(
).Limit(5).Select("id", "age").Exec(client)
```

## `fieldgen` and death to raw string literals
## `eywagen` and death to raw string literals
In the examples above, you may have noticed that the `Select` method takes raw
strings as field names. This is prone to typos. `eywa` has a codegen tool for
generating constants and functions for selecting fields.
Install fieldgen
Install eywagen
```bash
go install github.com/imperfect-fourth/eywa/cmd/fieldgen
go install github.com/imperfect-fourth/eywa/cmd/eywagen
```
Add `go:generate` comments to your code.
```go
//go:generate fieldgen -types User -output user_fields.go
//go:generate eywagen -types User -output user_fields.go
type User struct {
...
}
Expand Down Expand Up @@ -114,10 +114,10 @@ resp, err := Get[User]().Where(
).Exec(client)
```

If a model has a relationship with another model, `fieldgen` will generate a
If a model has a relationship with another model, `eywagen` will generate a
function to select fields for that relationship. Eg.
```go
//go:generate fieldgen -types User,Order -output model_fields.go
//go:generate eywagen -types User,Order -output model_fields.go
type User struct {
...
Orders []Order `json:"orders"`
Expand Down
8 changes: 4 additions & 4 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Client struct {
}

type ClientOpts struct {
HttpClient *http.Client
HTTPClient *http.Client
Headers map[string]string
}

Expand All @@ -28,11 +28,11 @@ func NewClient(gqlEndpoint string, opt *ClientOpts) *Client {
}

if opt != nil {
if opt.HttpClient != nil {
c.httpClient = opt.HttpClient
if opt.HTTPClient != nil {
c.httpClient = opt.HTTPClient
}

if opt.Headers != nil && len(opt.Headers) > 0 {
if len(opt.Headers) > 0 {
c.headers = opt.Headers
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,16 @@ func testTable_customVar[T interface{eywa.JSONValue | eywa.JSONBValue;eywa.Typed
}
}

func testTable_testTable2(subField eywa.ModelFieldName[testTable2], subFields ...eywa.ModelFieldName[testTable2]) string {
buf := bytes.NewBuffer([]byte("testTable2 {"))
func testTable_testTable2(subField eywa.ModelFieldName[testTable2], subFields ...eywa.ModelFieldName[testTable2]) eywa.ModelFieldName[testTable] {
buf := bytes.NewBuffer([]byte((new(testTable2)).ModelName()))
buf.WriteString(" {")
buf.WriteString(string(subField))
for _, f := range subFields {
buf.WriteString("\n")
buf.WriteString(string(f))
}
buf.WriteString("}")
return buf.String()
return eywa.ModelFieldName[testTable](buf.String())
}
const testTable_JsonBCol eywa.ModelFieldName[testTable] = "jsonb_col"

Expand Down
37 changes: 37 additions & 0 deletions cmd/eywagen/eywatest/eywa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,43 @@ name
}
}

func TestRelationshipSelectQuery(t *testing.T) {
age := 10
q := eywa.Get[testTable]().Limit(2).Offset(1).DistinctOn(testTable_Name).OrderBy(
eywa.Desc[testTable](testTable_Name),
).Where(
eywa.Or(
eywa.Eq[testTable](testTable_NameField("abcd")),
eywa.Eq[testTable](testTable_AgeField(&age)),
),
).Select(
testTable_Name,
testTable_testTable2(
testTable2_ID,
),
)

expected := `query get_test_table {
test_table(limit: 2, offset: 1, distinct_on: name, where: {_or: [{name: {_eq: "abcd"}}, {age: {_eq: 10}}]}, order_by: {name: desc}) {
test_table2 {id}
name
}
}`
if assert.Equal(t, expected, q.Query()) {
accessKey := os.Getenv("TEST_HGE_ACCESS_KEY")
c := eywa.NewClient("https://aware-cowbird-80.hasura.app/v1/graphql", &eywa.ClientOpts{
Headers: map[string]string{
"x-hasura-access-key": accessKey,
},
})

resp, err := q.Exec(c)

assert.NoError(t, err)
assert.Equal(t, []testTable{{Name: "abcd"}, {Name: "abc"}}, resp)
}
}

func TestUpdateQuery(t *testing.T) {
q := eywa.Update[testTable]().Where(
eywa.Eq[testTable](testTable_IDField(3)),
Expand Down
15 changes: 8 additions & 7 deletions cmd/eywagen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"go/types"
"os"
"regexp"
re "regexp"
"strings"

Expand Down Expand Up @@ -54,15 +53,16 @@ func %sVar[T interface{%s;eywa.TypedValue}](val %s) eywa.ModelField[%s] {
`

modelRelationshipNameFunc = `
func %s(subField eywa.ModelFieldName[%s], subFields ...eywa.ModelFieldName[%s]) string {
buf := bytes.NewBuffer([]byte("%s {"))
func %s(subField eywa.ModelFieldName[%s], subFields ...eywa.ModelFieldName[%s]) eywa.ModelFieldName[%s] {
buf := bytes.NewBuffer([]byte((new(%s)).ModelName()))
buf.WriteString(" {")
buf.WriteString(string(subField))
for _, f := range subFields {
buf.WriteString("\n")
buf.WriteString(string(f))
}
buf.WriteString("}")
return buf.String()
return eywa.ModelFieldName[%s](buf.String())
}
`
)
Expand Down Expand Up @@ -192,7 +192,9 @@ func parseType(typeName string, pkg *types.Package, contents *fileContent) {
fmt.Sprintf("%s_%s", typeName, field.Name()),
fieldTypeName,
fieldTypeName,
typeName,
fieldName,
typeName,
))
recurseParse = append(recurseParse, fieldTypeName)
} else {
Expand Down Expand Up @@ -279,7 +281,6 @@ func parseType(typeName string, pkg *types.Package, contents *fileContent) {
for _, t := range recurseParse {
parseType(t, pkg, contents)
}

}

func writeToFile(filename string, contents *fileContent) error {
Expand Down Expand Up @@ -313,8 +314,8 @@ func loadPackage() (*types.Package, error) {
}

func parseFieldTypeName(name, rootPkgPath string) (sourcePkgPath, typeName string) {
re, _ := regexp.Compile(`^(\*)?(.*/(.*))\.(.*)$`)
matches := re.FindStringSubmatch(name)
rgx := re.MustCompile(`^(\*)?(.*/(.*))\.(.*)$`)
matches := rgx.FindStringSubmatch(name)
if len(matches) == 0 {
return "", name
}
Expand Down
8 changes: 4 additions & 4 deletions eywa.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,16 +116,16 @@ func (fs fieldArr[M, MF]) MarshalGQL() string {
if i > 0 {
buf.WriteString(", ")
}
buf.WriteString(string(f.GetName()))
buf.WriteString(f.GetName())
buf.WriteString(": ")
buf.WriteString(f.GetValue())
}
return buf.String()
}

//func RawField[M Model](s string, v interface{}) Field[M] {
// return Field[M]{s, v}
//}
// func RawField[M Model](s string, v interface{}) Field[M] {
// return Field[M]{s, v}
// }

type Queryable interface {
Query() string
Expand Down
54 changes: 27 additions & 27 deletions gql_types.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
package eywa

//type Type interface {
// Type() string
//}
// type Type interface {
// Type() string
// }
//
//type Boolean interface {
// ~bool
//}
//type NullableBoolean interface {
// ~*bool
//}
//type Int interface {
// ~int
//}
//type NullableInt interface {
// ~*int
//}
//type Float interface {
// ~float32 | ~float64
//}
//type NullableFloat interface {
// ~*float32 | ~*float64
//}
//type String interface {
// ~string
//}
//type NullableBoolean interface {
// ~*string
//}
// type Boolean interface {
// ~bool
// }
// type NullableBoolean interface {
// ~*bool
// }
// type Int interface {
// ~int
// }
// type NullableInt interface {
// ~*int
// }
// type Float interface {
// ~float32 | ~float64
// }
// type NullableFloat interface {
// ~*float32 | ~*float64
// }
// type String interface {
// ~string
// }
// type NullableBoolean interface {
// ~*string
// }

type TypedValue interface {
Type() string
Expand Down
2 changes: 1 addition & 1 deletion query_arg.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (s set[M, F]) queryArgName() string {
return "_set"
}
func (s set[M, F]) MarshalGQL() string {
if s.fieldArr == nil || len(s.fieldArr) == 0 {
if len(s.fieldArr) == 0 {
return ""
}
return fmt.Sprintf("%s: {%s}", s.queryArgName(), s.fieldArr.MarshalGQL())
Expand Down
1 change: 0 additions & 1 deletion query_vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ func (vs queryVarArr) MarshalGQL() string {
}
buf.WriteString(")")
return buf.String()

}

func QueryVar(name string, value TypedValue) queryVar {
Expand Down
1 change: 0 additions & 1 deletion unsafe/actions_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// nolint
package unsafe

import (
Expand Down
2 changes: 1 addition & 1 deletion unsafe/eywa_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// nolint
//nolint:all
package unsafe

import (
Expand Down

0 comments on commit d0908e9

Please sign in to comment.