Skip to content
Merged
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
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ jobs:
build-test:
strategy:
matrix:
go-version: [ 1.24 ]
go-version: [ 1.25 ]
os: [ ubuntu-latest ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go-version }}

Expand All @@ -29,4 +29,4 @@ jobs:
with:
files: ./coverage.txt
- name: lint
uses: golangci/golangci-lint-action@v7
uses: golangci/golangci-lint-action@v8
2 changes: 1 addition & 1 deletion cfg/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func TestOutput_All(t *testing.T) {
name string
want stringlist.StringMap
}{
{"openAPIStub", stringlist.StringMap{"!swagger.yaml": "foji/openapi/stub.yaml.tpl"}},
{"openAPIStub", stringlist.StringMap{"!openapi.yaml": "foji/openapi/stub.yaml.tpl"}},
{"embed", stringlist.StringMap{}},
{"groupTest", stringlist.StringMap{}},
}
Expand Down
6 changes: 3 additions & 3 deletions foji/foji.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ processes:
openAPIStub:
format: openapi
DbAll:
'!swagger.yaml': foji/openapi/stub.yaml.tpl
'!openapi.yaml': foji/openapi/stub.yaml.tpl
openAPI:
format: go
resources: [ api ]
OpenAPIFile:
'models_gen.go': foji/openapi/model.go.tpl
'!service.go': foji/openapi/service.go.tpl
'http_handler_gen.go': foji/openapi/handler.go.tpl
'service_gen.go': foji/openapi/service.go.tpl
'handlers_gen.go': foji/openapi/handler.go.tpl
'!cmd/serve/main.go': foji/openapi/main.go.tpl
25 changes: 10 additions & 15 deletions foji/openapi/service.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,8 @@ import (
{{- end }}
)

// New creates a new service instance.
func New() *Service {
return &Service{}
}

// Service implements all business logic for {{ .PackageName }}.
type Service struct {
// GenService holds all Unsupported mock endpoints {{ .PackageName }}.
type GenService struct {
}

{{- range $name, $path := .File.API.Paths.Map }}
Expand All @@ -49,13 +44,13 @@ type Service struct {
{{ goDoc (pascal $op.OperationID) }}
{{- goDoc $op.Summary }}
{{- goDoc $op.Description }}
func (s *Service) {{ pascal $op.OperationID}}(ctx context.Context,
{{- template "methodSignature" ($.WithParams "op" $op "path" $path "package" $.PackageName) }}{
{{- $response := $.GetOpHappyResponseType $.PackageName $op}}
return
{{- if notEmpty $response -}}nil, {{ end -}}
{{- if gt (len ($.GetOpHappyResponseHeaders $.PackageName $op)) 0 -}}http.Header{}, {{ end -}}
errors.ErrUnsupported
}
func (s *GenService) {{ pascal $op.OperationID}}(ctx context.Context,
{{- template "methodSignature" ($.WithParams "op" $op "path" $path "package" $.PackageName) }}{
{{- $response := $.GetOpHappyResponseType $.PackageName $op}}
{{- if notEmpty $response }}
return nil, errors.ErrUnsupported
{{- else }}
return errors.ErrUnsupported
{{- end }}}
{{- end }}
{{- end }}
6 changes: 0 additions & 6 deletions foji/pgx/db.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ package pg

import (
"context"
"database/sql"
"errors"

"github.com/jackc/pgx/v5/pgconn"
"github.com/jackc/pgx/v5"
Expand All @@ -18,10 +16,6 @@ type DB interface {
QueryRow(context.Context, string, ...any) pgx.Row
}

func IsErrNoRows(err error) bool {
return errors.Is(err, pgx.ErrNoRows) || errors.Is(err, sql.ErrNoRows)
}

type Repo struct {
db DB
}
Expand Down
53 changes: 25 additions & 28 deletions foji/pgx/model.go.tpl
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
// Code generated by foji {{ version }}, template: {{ templateFile }}; DO NOT EDIT.
{{- $table := .Table.Name}}
{{- $goName := case .Table.Name -}}
{{- $colNames := .Table.Columns.ByOrdinal.Names }}
{{- $pkNames := cases .Table.PrimaryKeys.ByOrdinal.Names }}

package {{ $.PackageName }}
package {{ .PackageName }}

import (
"fmt"

{{- range .Imports }}
"{{ . }}"
{{- end }}
"time"
)

// {{$goName}} represents a record from '{{.Schema.Name}}.{{$table}}'.
type {{$goName}} struct {
{{- range .Table.Columns.ByOrdinal }}
{{ case .Name }} {{ $.GetType . $.PackageName }} `json:"{{ .Name }},omitempty"`
{{- end }}
}

func (r {{$goName}}) String() string {
return fmt.Sprintf( "{{$goName}}{
{{- csv ($pkNames.Sprintf "%s:%%v" ) }}}",
{{- csv ($pkNames.Sprintf "r.%s" ) }})
}

// Field values for every column in {{.Table.Name}}. These are used for custom where clause queries
var (
{{- range .Table.Columns.ByOrdinal }}
{{$goName}}{{case .Name}} {{ title (replaceEach ( $.GetType . $.PackageName) "" "." "*" "{" "}" ) }}Field = "{{ .Name }}"
{{- end}}
)
{{ range .DB }}
{{ range .Tables }}

{{- $table := .Name}}
{{- $goName := case .Name -}}
{{- $colNames := .Columns.ByOrdinal.Names }}
{{- $pkNames := cases .PrimaryKeys.ByOrdinal.Names }}

// {{$goName}} represents a record from '{{.Schema.Name}}.{{$table}}'.
type {{$goName}} struct {
{{- range .Columns.ByOrdinal }}
{{ case .Name }} {{ $.GetType . $.PackageName }}
{{- end }}
}

func (r {{$goName}}) String() string {
return fmt.Sprintf( "{{$goName}}{
{{- csv ($pkNames.Sprintf "%s:%%v" ) }}}",
{{- csv ($pkNames.Sprintf "r.%s" ) }})
}

{{end}}
{{end}}

148 changes: 16 additions & 132 deletions foji/pgx/table.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ FROM {{$schema}}.{{$table}} `

func scan{{$goName}}(rr pgx.Rows) ([]*{{$.PackageName}}.{{$goName}}, error) {
var result []*{{$.PackageName}}.{{$goName}}

for rr.Next() {
row := {{$.PackageName}}.{{$goName}}{}
err := rr.Scan({{ csv $scanFields }})
Expand All @@ -40,15 +41,18 @@ func scan{{$goName}}(rr pgx.Rows) ([]*{{$.PackageName}}.{{$goName}}, error) {
}
result = append(result, &row)
}

return result, nil
}

func scanOne{{$goName}}(rr pgx.Row) (*{{$.PackageName}}.{{$goName}}, error) {
row := {{$.PackageName}}.{{$goName}}{}

err := rr.Scan({{ csv $scanFields }})
if err != nil {
return nil, fmt.Errorf("{{$goName}}:%w", err)
}

return &row, nil
}

Expand All @@ -58,67 +62,15 @@ func (r Repo) All{{$goName}}(ctx context.Context) ([]*{{$.PackageName}}.{{$goNam
{{- if $hasSoftDeletes -}}
+ `WHERE deleted_at is NULL `
{{- end}}
q, err := r.db.Query(ctx,query)
if err != nil {
return nil, fmt.Errorf("{{$goName}}:%w", err)
}
return scan{{$goName}}(q)
}

// Count gets size of '{{$table}}'.
func (r Repo) Count{{$goName}}(ctx context.Context, where {{$.PackageName}}.WhereClause) (int, error) {
idx := 1
query := `SELECT
count(*) as count
FROM {{$schema}}.{{$table}}
WHERE ` + where.String(&idx)

count := 0
return count, r.db.QueryRow(ctx, query, where.Values()...).Scan(&count)
}

// Select retrieves rows from '{{$table}}' as a slice of {{$goName}}.
func (r Repo) Select{{$goName}}(ctx context.Context, where {{$.PackageName}}.WhereClause) ([]*{{$.PackageName}}.{{$goName}}, error) {
idx := 1
query := querySelect{{$goName}} + " WHERE " + where.String(&idx)
{{- if $hasSoftDeletes -}}
+ ` AND deleted_at is NULL `
{{- end}}

q, err := r.db.Query(ctx, query, where.Values()...)
q, err := r.db.Query(ctx,query)
if err != nil {
return nil, fmt.Errorf("{{$goName}}:%w", err)
}
return scan{{$goName}}(q)
}

// SelectOrder retrieves rows from '{{$table}}' as a slice of {{$goName}} in a particular order.
func (r Repo) SelectOrder{{$goName}}(ctx context.Context, where {{$.PackageName}}.WhereClause, orderBy {{$.PackageName}}.OrderByClause) ([]*{{$.PackageName}}.{{$goName}}, error) {
idx := 1
query := querySelect{{$goName}} + " WHERE " + where.String(&idx)
{{- if $hasSoftDeletes -}}
+ ` AND deleted_at is NULL `
{{- end}} + " " + orderBy.String()

q, err := r.db.Query(ctx, query, where.Values()...)
if err != nil {
return nil, fmt.Errorf("{{$goName}}:%w", err)
}
return scan{{$goName}}(q)
}

// First retrieve one row from '{{$table}}' when sorted by orderBy.
func (r Repo) First{{$goName}}(ctx context.Context, where {{$.PackageName}}.WhereClause, orderBy {{$.PackageName}}.OrderByClause) (*{{$.PackageName}}.{{$goName}}, error) {
idx := 1
query := querySelect{{$goName}} + " WHERE " + where.String(&idx)
{{- if $hasSoftDeletes -}}
+ ` AND deleted_at is NULL `
{{- end}} + " " + orderBy.String() + " LIMIT 1"

q := r.db.QueryRow(ctx, query, where.Values()...)
return scanOne{{$goName}}(q)
}

{{- /* Takes the number of values to produce and produces a list of postgres
placeholders of the form $1, $2, etc */}}
{{- define "values" -}}
Expand Down Expand Up @@ -157,29 +109,20 @@ func (r Repo) Update{{$goName}}(ctx context.Context, row *{{$.PackageName}}.{{$g
{{- end}}`

_, err := r.db.Exec(ctx, query, {{csv $mutableFields }}, {{$PKFields}})
return fmt.Errorf("{{$goName}}:%w", err)
}
{{end}}
// Set sets a single column on an existing row in the database.
func (r Repo) Set{{$goName}}(ctx context.Context, set {{$.PackageName}}.Where, where {{$.PackageName}}.WhereClause) (int64, error) {
idx := 2
query := `UPDATE {{$schema}}.{{$table}} SET ` +
set.Field + " = $1 " +
`WHERE ` +
where.String(&idx)

res, err := r.db.Exec(ctx, query, append([]any{ set.Value }, where.Values()...)...)
if err != nil {
return 0, fmt.Errorf("{{$goName}}:%w", err)
return fmt.Errorf("Update{{$goName}}:%w", err)
}
return res.RowsAffected(), nil

return nil
}
{{end}}

{{- if .Table.HasPrimaryKey }}
{{- if $hasSoftDeletes}}
// Delete{{$goName}} soft deletes the row from the database. Returns the number of items soft deleted.
{{else}}
{{- else}}
// Delete{{$goName}} deletes the Row from the database. Returns the number of items deleted.
{{end}}
{{- end}}
func (r Repo) Delete{{$goName}}( ctx context.Context, {{ $.Parameterize .Table.PrimaryKeys "%s %s" $pkgName }}) (int64, error) {
{{- if $hasSoftDeletes}}
const query = `UPDATE {{$schema}}.{{$table}}
Expand All @@ -194,12 +137,14 @@ func (r Repo) Delete{{$goName}}( ctx context.Context, {{ $.Parameterize .Table.P
{{ range $x, $name := .Table.PrimaryKeys.Names.Sort -}}
{{$name}} = ${{inc $x}}{{if lt $x (sum (len $.Table.PrimaryKeys) -1)}} AND {{end}}
{{- end}}`{{- end}}

res, err := r.db.Exec(ctx, query,
{{- csv .Table.PrimaryKeys.Names.Sort.Camel -}}
)
if err != nil {
return 0, fmt.Errorf("{{$goName}}:%w", err)
}

return res.RowsAffected(), nil
}
{{- if $hasSoftDeletes}}
Expand All @@ -210,79 +155,18 @@ func (r Repo) DeletePermanent{{$goName}}( ctx context.Context, {{ $.Parameterize
{{ range $x, $name := .Table.PrimaryKeys.Names.Sort -}}
{{$name}} = ${{inc $x}}{{if lt $x (sum (len $.Table.PrimaryKeys) -1)}} AND {{end}}
{{- end}}`

res, err := r.db.Exec(ctx, query,
{{- csv .Table.PrimaryKeys.Names.Sort.Camel -}}
)
if err != nil {
return 0, fmt.Errorf("{{$goName}}:%w", err)
}

return res.RowsAffected(), nil
}
{{end}}
{{end}}
// DeleteWhere{{$goName}} deletes Rows from the database and returns the number of rows deleted.
func (r Repo) DeleteWhere{{$goName}}(ctx context.Context, where {{$.PackageName}}.WhereClause) (int64, error) {
idx := 1
{{ if $hasSoftDeletes}}
query := `UPDATE {{$schema}}.{{$table}}
SET deleted_at = now()
WHERE ` + where.String(&idx) + ` AND deleted_at is NULL`
{{ else }}
query := `DELETE FROM {{$schema}}.{{$table}}
WHERE ` + where.String(&idx)
{{ end }}
res, err := r.db.Exec(ctx, query, where.Values()...)
if err != nil {
return 0, fmt.Errorf("{{$goName}}:%w", err)
}
return res.RowsAffected(), nil
}
{{ if $hasSoftDeletes}}
// UndeleteWhere{{$goName}} undeletes the Row from the database.
func (r Repo) Undelete{{$goName}}(ctx context.Context, {{ $.Parameterize .Table.PrimaryKeys "%s %s" $pkgName }}) (int64, error) {
query := `UPDATE {{$schema}}.{{$table}}
SET deleted_at = NULL
WHERE
{{- range $x, $name := .Table.PrimaryKeys.Names.Sort }}
{{$name}} = ${{inc $x}}{{if lt $x (sum (len $.Table.PrimaryKeys) -1)}} AND {{end}}
{{- end}} AND deleted_at is not NULL`

res, err := r.db.Exec(ctx, query, {{ csv .Table.PrimaryKeys.Names.Sort.Camel -}})
if err != nil {
return 0, fmt.Errorf("{{$goName}}:%w", err)
}
return res.RowsAffected(), nil
}

// DeleteWherePermanent{{$goName}} deletes the Row from the database. This bypasses the soft delete mechanism.
// Returns the number of items deleted.
func (r Repo) DeleteWherePermanent{{$goName}}(ctx context.Context, where {{$.PackageName}}.WhereClause) (int64, error) {
idx := 1
query := `DELETE FROM {{$schema}}.{{$table}}
WHERE ` + where.String(&idx)

res, err := r.db.Exec(ctx, query, where.Values()...)
if err != nil {
return 0, fmt.Errorf("{{$goName}}:%w", err)
}
return res.RowsAffected(), nil
}

// UndeleteWhere{{$goName}} undeletes the Row from the database.
func (r Repo) UndeleteWhere{{$goName}}(ctx context.Context, where {{$.PackageName}}.WhereClause) (int64, error) {
idx := 1
query := `UPDATE {{$schema}}.{{$table}}
SET deleted_at = null
WHERE ` + where.String(&idx) + ` AND deleted_at is NOT NULL`

res, err := r.db.Exec(ctx, query, where.Values()...)
if err != nil {
return 0, fmt.Errorf("{{$goName}}:%w", err)
}
return res.RowsAffected(), nil
}

{{ end -}}

{{ range .Table.Indexes -}}
{{- $FuncName := print $goName "By" ((cases .Columns.Names).Join "") -}}
Expand Down
Loading