Skip to content

Commit

Permalink
Merge pull request #32 from strvcom/feat/string-typed-id
Browse files Browse the repository at this point in the history
feat: support for custom string IDs
  • Loading branch information
TomasKocman committed Apr 8, 2023
2 parents 404d787 + b946ebd commit 08bb6a8
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 46 deletions.
10 changes: 1 addition & 9 deletions .github/actions/setup-go/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ name: Setup Go
description: |
Setup Go
inputs:
go-version:
description: Used Go version
default: '1.19'

runs:
using: "composite"
steps:
Expand All @@ -18,7 +13,4 @@ runs:
- id: go-setup
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
- run: |
go mod download
shell: bash
go-version-file: 'go.mod'
2 changes: 1 addition & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ jobs:
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.50.1
version: v1.52.2
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ How to release a new version:

## [Unreleased]

## [0.4.0] - 2023-03-27
### Added
- Support for string IDs.

### Removed
- Useless marshalling/unmarshalling of custom IDs.

### Changed
- Updated Go version to 1.20.

## [0.3.1] - 2023-02-07
### Added
- Repo init command.
Expand Down Expand Up @@ -36,7 +46,8 @@ How to release a new version:
### Added
- Added Changelog.

[Unreleased]: https://github.com/strvcom/strv-backend-go-tea/compare/v0.3.1...HEAD
[Unreleased]: https://github.com/strvcom/strv-backend-go-tea/compare/v0.4.0...HEAD
[0.4.0]: https://github.com/strvcom/strv-backend-go-tea/compare/v0.3.1...v0.4.0
[0.3.1]: https://github.com/strvcom/strv-backend-go-tea/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/strvcom/strv-backend-go-tea/compare/v0.2.2...v0.3.0
[0.2.2]: https://github.com/strvcom/strv-backend-go-tea/compare/v0.2.1...v0.2.2
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,12 @@ import (
//go:generate tea gen id -i ./id.go -o ./id_gen.go

type (
User uint64
RefreshToken uuid.UUID
User uint64
RefreshToken uuid.UUID
DeviceIdentifier string
)
```
After triggering `go generate ./...` within an app, methods `MarshalText`, `MarshalJSON`, `UnmarshalText` and `UnmarshalJSON` are generated.
After triggering `go generate ./...` within an app, methods `MarshalText` and `UnmarshalText` along with other useful functions are generated.

### openapi
This command provides a set of tools to manage OpenAPI specifications.
Expand Down
114 changes: 83 additions & 31 deletions cmd/tea/gen_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"go/parser"
"go/token"
"os"
"sort"
"strings"
"text/template"

Expand Down Expand Up @@ -62,12 +63,19 @@ type GenIDOptions struct {
OutputFilePath string
}

const stringTemplate = `{{ range .ids }}
func (i *{{ . }}) UnmarshalText(data []byte) error {
*i = {{ . }}(data)
return nil
}
func (i {{ . }}) MarshalText() ([]byte, error) {
return []byte(i), nil
}
{{ end }}`

const uint64Template = `
func unmarshalUint64(i *uint64, idTypeName string, data []byte) error {
l := len(data)
if l > 2 && data[0] == '"' && data[l-1] == '"' {
data = data[1 : l-1]
}
uintNum, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("parsing %q id value: %w", idTypeName, err)
Expand All @@ -80,17 +88,9 @@ func (i {{ . }}) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%d", i)), nil
}
func (i {{ . }}) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%d\"", i)), nil
}
func (i *{{ . }}) UnmarshalText(data []byte) error {
return unmarshalUint64((*uint64)(i), "{{ . }}", data)
}
func (i *{{ . }}) UnmarshalJSON(data []byte) error {
return unmarshalUint64((*uint64)(i), "{{ . }}", data)
}
{{ end }}`

const uuidTemplate = `
Expand Down Expand Up @@ -124,18 +124,10 @@ func (i {{ . }}) MarshalText() ([]byte, error) {
return []byte(uuid.UUID(i).String()), nil
}
func (i {{ . }}) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%s\"", uuid.UUID(i).String())), nil
}
func (i *{{ . }}) UnmarshalText(data []byte) error {
return unmarshalUUID((*uuid.UUID)(i), "{{ . }}", data)
}
func (i *{{ . }}) UnmarshalJSON(data []byte) error {
return unmarshalUUID((*uuid.UUID)(i), "{{ . }}", data)
}
func (i *{{ . }}) Scan(data any) error {
return scanUUID((*uuid.UUID)(i), "{{ . }}", data)
}
Expand All @@ -160,6 +152,10 @@ func (i IDs) generate() ([]byte, error) {
if genData, err = i.generateUUID(); err != nil {
return nil, fmt.Errorf("generating uuid.UUID ids: %w", err)
}
case "string":
if genData, err = i.generateStringID(); err != nil {
return nil, fmt.Errorf("generating string ids: %w", err)
}
}

if _, err = output.Write(genData); err != nil {
Expand Down Expand Up @@ -214,28 +210,84 @@ func (i IDs) generateUUID() ([]byte, error) {
return generatedOutput.Bytes(), nil
}

func (i IDs) generateHeader() []byte {
var d []byte
d = append(d, "package id\n\n"...)
d = append(d, "import (\n"...)
d = append(d, "\t\"fmt\"\n"...)
func (i IDs) generateStringID() ([]byte, error) {
ids, ok := i["string"]
if !ok {
return nil, nil
}

generatedOutput := &bytes.Buffer{}
data := map[string][]string{
"ids": ids,
}

t, err := template.New("string").Parse(stringTemplate)
if err != nil {
return nil, err
}
if err = t.Execute(generatedOutput, data); err != nil {
return nil, err
}

return generatedOutput.Bytes(), nil
}

func (i IDs) generateHeader() []byte {
// In case of a new type, add import dependencies to standardImports and externalImports.
standardImports := make(map[string]struct{})
externalImports := make(map[string]struct{})
if _, ok := i["uint64"]; ok {
d = append(d, "\t\"strconv\"\n"...)
standardImports["fmt"] = struct{}{}
standardImports["strconv"] = struct{}{}
}
if _, ok := i["uuid.UUID"]; ok {
d = append(d, "\n"...)
d = append(d, "\t\"github.com/google/uuid\"\n"...)
standardImports["fmt"] = struct{}{}
externalImports["github.com/google/uuid"] = struct{}{}
}

var (
d []byte
standardImportsLen = len(standardImports)
externalImportsLen = len(externalImports)
)

d = append(d, "package id\n"...)
if standardImportsLen == 0 && externalImportsLen == 0 {
return d
}

d = append(d, "\nimport (\n"...)
for _, v := range sortedMapKeys(standardImports) {
d = append(d, fmt.Sprintf("\t\"%s\"\n", v)...)
}

if externalImportsLen == 0 {
return append(d, ")\n"...)
}

d = append(d, "\n"...)
for _, v := range sortedMapKeys(externalImports) {
d = append(d, fmt.Sprintf("\t\"%s\"\n", v)...)
}

return append(d, ")\n"...)
}

func sortedMapKeys[V any](m map[string]V) []string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}

func supportedType(typ string) bool {
if typ != "uint64" && typ != "uuid.UUID" {
return false
switch typ {
case "uint64", "uuid.UUID", "string":
return true
}
return true
return false
}

func extractIDs(filename string) (IDs, error) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module go.strv.io/tea

go 1.19
go 1.20

require (
github.com/Masterminds/sprig/v3 v3.2.2
Expand Down

0 comments on commit 08bb6a8

Please sign in to comment.