Add -version flag, add CONTRIBUTING.md, update dependencies

This commit is contained in:
sunboyy 2021-03-30 19:16:46 +07:00
parent aa16d6f1b6
commit b3d9bf3f8f
9 changed files with 210 additions and 165 deletions

7
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,7 @@
# Contributing
## Styleguides
- Use default `goimports` for code formatting.
- Use default `golint`, `golangci-lint` and `go vet` for linting.
- Do not use boolean flag in function arguments.

6
go.mod
View file

@ -7,11 +7,11 @@ require (
github.com/fatih/camelcase v1.0.0
github.com/golang/snappy v0.0.2 // indirect
github.com/klauspost/compress v1.11.7 // indirect
go.mongodb.org/mongo-driver v1.4.6
go.mongodb.org/mongo-driver v1.5.0
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
golang.org/x/mod v0.4.1 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 // indirect
golang.org/x/text v0.3.5 // indirect
golang.org/x/tools v0.1.0
)

18
go.sum
View file

@ -87,21 +87,22 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo=
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.mongodb.org/mongo-driver v1.4.6 h1:rh7GdYmDrb8AQSkF8yteAus8qYOgOASWDOv1BWqBXkU=
go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
go.mongodb.org/mongo-driver v1.5.0 h1:REddm85e1Nl0JPXGGhgZkgJdG/yOe6xvpXUcYK5WLt0=
go.mongodb.org/mongo-driver v1.5.0/go.mod h1:boiGPFqyBs5R0R5qf2ErokGRekMfwn+MqKaUyHs7wy0=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -126,11 +127,10 @@ golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 h1:64ChN/hjER/taL4YJuA+gpLfIMT+/NFherRZixbxOhg=
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View file

@ -63,57 +63,6 @@ const (
OrderingDescending = "DESC"
)
// UpdateOperation is a method specification for update operations
type UpdateOperation struct {
Update Update
Mode QueryMode
Query QuerySpec
}
// Update is an interface of update operation type
type Update interface {
Name() string
NumberOfArguments() int
}
// UpdateFields is a type of update operation that update specific fields
type UpdateFields []UpdateField
// Name returns UpdateFields name 'Fields'
func (u UpdateFields) Name() string {
return "Fields"
}
// NumberOfArguments returns number of update fields
func (u UpdateFields) NumberOfArguments() int {
return len(u)
}
// UpdateModel is a type of update operation that update the whole model
type UpdateModel struct {
}
// Name returns UpdateModel name 'Model'
func (u UpdateModel) Name() string {
return "Model"
}
// NumberOfArguments returns 1
func (u UpdateModel) NumberOfArguments() int {
return 1
}
// Name returns "Update" operation name
func (o UpdateOperation) Name() string {
return "Update"
}
// UpdateField stores mapping between field name in the model and the parameter index
type UpdateField struct {
FieldReference FieldReference
ParamIndex int
}
// DeleteOperation is a method specification for delete operations
type DeleteOperation struct {
Mode QueryMode

View file

@ -43,29 +43,3 @@ func TestOperationName(t *testing.T) {
})
}
}
type UpdateTypeTestCase struct {
Update spec.Update
ExpectedName string
}
func TestUpdateTypeName(t *testing.T) {
testTable := []UpdateTypeTestCase{
{
Update: spec.UpdateModel{},
ExpectedName: "Model",
},
{
Update: spec.UpdateFields{},
ExpectedName: "Fields",
},
}
for _, testCase := range testTable {
t.Run(testCase.ExpectedName, func(t *testing.T) {
if testCase.Update.Name() != testCase.ExpectedName {
t.Errorf("Expected = %v\nReceived = %v", testCase.ExpectedName, testCase.Update.Name())
}
})
}
}

View file

@ -235,79 +235,6 @@ func (p interfaceMethodParser) extractModelOrSliceReturns(returns []code.Type) (
return "", UnsupportedReturnError
}
func (p interfaceMethodParser) parseUpdateOperation(tokens []string) (Operation, error) {
mode, err := p.extractIntOrBoolReturns(p.Method.Returns)
if err != nil {
return nil, err
}
if err := p.validateContextParam(); err != nil {
return nil, err
}
updateTokens, queryTokens := p.splitUpdateAndQueryTokens(tokens)
update, err := p.parseUpdate(updateTokens)
if err != nil {
return nil, err
}
querySpec, err := p.parseQuery(queryTokens, 1+update.NumberOfArguments())
if err != nil {
return nil, err
}
if err := p.validateQueryFromParams(p.Method.Params[update.NumberOfArguments()+1:], querySpec); err != nil {
return nil, err
}
return UpdateOperation{
Update: update,
Mode: mode,
Query: querySpec,
}, nil
}
func (p interfaceMethodParser) parseUpdate(tokens []string) (Update, error) {
if len(tokens) == 0 {
requiredType := code.PointerType{ContainedType: p.StructModel.ReferencedType()}
if len(p.Method.Params) <= 1 || p.Method.Params[1].Type != requiredType {
return nil, InvalidUpdateFieldsError
}
return UpdateModel{}, nil
}
updateFieldTokens, ok := splitByAnd(tokens)
if !ok {
return nil, InvalidUpdateFieldsError
}
var updateFields UpdateFields
paramIndex := 1
for _, updateFieldToken := range updateFieldTokens {
updateFieldReference, ok := p.fieldResolver.ResolveStructField(p.StructModel, updateFieldToken)
if !ok {
return nil, NewStructFieldNotFoundError(updateFieldToken)
}
updateFields = append(updateFields, UpdateField{
FieldReference: updateFieldReference,
ParamIndex: paramIndex,
})
paramIndex++
}
for _, field := range updateFields {
if len(p.Method.Params) <= field.ParamIndex ||
field.FieldReference.ReferencedField().Type != p.Method.Params[field.ParamIndex].Type {
return nil, InvalidUpdateFieldsError
}
}
return updateFields, nil
}
func splitByAnd(tokens []string) ([][]string, bool) {
var updateFieldTokens [][]string
var aggregatedToken []string

127
internal/spec/update.go Normal file
View file

@ -0,0 +1,127 @@
package spec
import "github.com/sunboyy/repogen/internal/code"
// UpdateOperation is a method specification for update operations
type UpdateOperation struct {
Update Update
Mode QueryMode
Query QuerySpec
}
// Name returns "Update" operation name
func (o UpdateOperation) Name() string {
return "Update"
}
// Update is an interface of update operation type
type Update interface {
Name() string
NumberOfArguments() int
}
// UpdateModel is a type of update operation that update the whole model
type UpdateModel struct {
}
// Name returns UpdateModel name 'Model'
func (u UpdateModel) Name() string {
return "Model"
}
// NumberOfArguments returns 1
func (u UpdateModel) NumberOfArguments() int {
return 1
}
// UpdateFields is a type of update operation that update specific fields
type UpdateFields []UpdateField
// Name returns UpdateFields name 'Fields'
func (u UpdateFields) Name() string {
return "Fields"
}
// NumberOfArguments returns number of update fields
func (u UpdateFields) NumberOfArguments() int {
return len(u)
}
// UpdateField stores mapping between field name in the model and the parameter index
type UpdateField struct {
FieldReference FieldReference
ParamIndex int
}
func (p interfaceMethodParser) parseUpdateOperation(tokens []string) (Operation, error) {
mode, err := p.extractIntOrBoolReturns(p.Method.Returns)
if err != nil {
return nil, err
}
if err := p.validateContextParam(); err != nil {
return nil, err
}
updateTokens, queryTokens := p.splitUpdateAndQueryTokens(tokens)
update, err := p.parseUpdate(updateTokens)
if err != nil {
return nil, err
}
querySpec, err := p.parseQuery(queryTokens, 1+update.NumberOfArguments())
if err != nil {
return nil, err
}
if err := p.validateQueryFromParams(p.Method.Params[update.NumberOfArguments()+1:], querySpec); err != nil {
return nil, err
}
return UpdateOperation{
Update: update,
Mode: mode,
Query: querySpec,
}, nil
}
func (p interfaceMethodParser) parseUpdate(tokens []string) (Update, error) {
if len(tokens) == 0 {
requiredType := code.PointerType{ContainedType: p.StructModel.ReferencedType()}
if len(p.Method.Params) <= 1 || p.Method.Params[1].Type != requiredType {
return nil, InvalidUpdateFieldsError
}
return UpdateModel{}, nil
}
updateFieldTokens, ok := splitByAnd(tokens)
if !ok {
return nil, InvalidUpdateFieldsError
}
var updateFields UpdateFields
paramIndex := 1
for _, updateFieldToken := range updateFieldTokens {
updateFieldReference, ok := p.fieldResolver.ResolveStructField(p.StructModel, updateFieldToken)
if !ok {
return nil, NewStructFieldNotFoundError(updateFieldToken)
}
updateFields = append(updateFields, UpdateField{
FieldReference: updateFieldReference,
ParamIndex: paramIndex,
})
paramIndex++
}
for _, field := range updateFields {
if len(p.Method.Params) <= field.ParamIndex ||
field.FieldReference.ReferencedField().Type != p.Method.Params[field.ParamIndex].Type {
return nil, InvalidUpdateFieldsError
}
}
return updateFields, nil
}

View file

@ -0,0 +1,33 @@
package spec_test
import (
"testing"
"github.com/sunboyy/repogen/internal/spec"
)
type UpdateTypeTestCase struct {
Update spec.Update
ExpectedName string
}
func TestUpdateTypeName(t *testing.T) {
testTable := []UpdateTypeTestCase{
{
Update: spec.UpdateModel{},
ExpectedName: "Model",
},
{
Update: spec.UpdateFields{},
ExpectedName: "Fields",
},
}
for _, testCase := range testTable {
t.Run(testCase.ExpectedName, func(t *testing.T) {
if testCase.Update.Name() != testCase.ExpectedName {
t.Errorf("Expected = %v\nReceived = %v", testCase.ExpectedName, testCase.Update.Name())
}
})
}
}

34
main.go
View file

@ -3,8 +3,10 @@ package main
import (
"errors"
"flag"
"fmt"
"go/parser"
"go/token"
"log"
"os"
"path/filepath"
@ -13,7 +15,12 @@ import (
"github.com/sunboyy/repogen/internal/spec"
)
const version = ""
func main() {
flag.Usage = printUsage
versionPtr := flag.Bool("version", false, "print repogen version")
sourcePtr := flag.String("src", "", "source file")
destPtr := flag.String("dest", "", "destination file")
modelPtr := flag.String("model", "", "model struct name")
@ -21,14 +28,22 @@ func main() {
flag.Parse()
if *versionPtr {
printVersion()
return
}
if *sourcePtr == "" {
panic("-source flag required")
printUsage()
log.Fatal("-source flag required")
}
if *modelPtr == "" {
panic("-model flag required")
printUsage()
log.Fatal("-model flag required")
}
if *repoPtr == "" {
panic("-repo flag required")
printUsage()
log.Fatal("-repo flag required")
}
code, err := generateFromRequest(*sourcePtr, *modelPtr, *repoPtr)
@ -54,6 +69,19 @@ func main() {
}
}
func printUsage() {
fmt.Println("Usage of repogen")
flag.PrintDefaults()
}
func printVersion() {
if version != "" {
fmt.Println(version)
} else {
fmt.Println("(devel)")
}
}
func generateFromRequest(fileName, structModelName, repositoryInterfaceName string) (string, error) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments)