Documentation
¶
Index ¶
Constants ¶
View Source
const FojiDotYaml = `` /* 3177-byte string literal not displayed */
View Source
const FojiSlashDbListDotConsoleDotTpl = `` /* 1605-byte string literal not displayed */
View Source
const FojiSlashEmbedDotGoDotTpl = `// Code generated by foji {{ version }}, template: {{ templateFile }}; DO NOT EDIT.
package {{ .PackageName }}
import "os"
func List() []string {
return []string{
{{- range .FileGroups }}
{{- range .Files }}
"{{ .Name }}",
{{- end }}
{{- end}}
}
}
func Get(filename string) ([]byte, error) {
switch filename {
{{- range .FileGroups }}
{{- range .Files }}
case "{{ .Name }}":
return {{ case (goToken .Name) }}Bytes, nil
{{- end }}
{{- end}}
}
return nil, os.ErrNotExist
}
func GetString(filename string) (string, error) {
switch filename {
{{- range .FileGroups }}
{{- range .Files }}
case "{{ .Name }}":
return {{ case (goToken .Name) }}, nil
{{- end }}
{{- end}}
}
return "", os.ErrNotExist
}
{{- range .FileGroups }}
{{- range .Files }}
// {{.Name}}
var {{ case (goToken .Name) }}Bytes = []byte({{ case (goToken .Name) }})
const {{ case (goToken .Name) }} = ` + "`" + `{{ backQuote (toString .Content) }}` + "`" + `
{{- end -}}
{{end -}}`
View Source
const FojiSlashEnumDotGoDotTpl = `` /* 3759-byte string literal not displayed */
View Source
const FojiSlashFieldsDotGoDotTpl = `` /* 11105-byte string literal not displayed */
View Source
const FojiSlashOpenapiSlashAuthDotGoDotTpl = `` /* 3781-byte string literal not displayed */
View Source
const FojiSlashOpenapiSlashDocsDotGoDotTpl = `` /* 589-byte string literal not displayed */
View Source
const FojiSlashOpenapiSlashHandlerDotGoDotTpl = `` /* 11915-byte string literal not displayed */
View Source
const FojiSlashOpenapiSlashMainDotGoDotTpl = `package main
import (
"context"
"errors"
"fmt"
"net/http"
"os"
"os/signal"
"sync"
"time"
"github.com/bir/iken/config"
"github.com/bir/iken/errs"
"github.com/bir/iken/httplog"
"github.com/go-chi/chi/v5"
"github.com/lavaai/kit/auth"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
chiTrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi.v5"
"{{ .Params.Package }}"
)
type Config struct {
Debug bool ` + "`" + `env:"DEBUG"` + "`" + `
Port int ` + "`" + `env:"PORT, 3500"` + "`" + `
HttpWriteTimeout time.Duration ` + "`" + `env:"HTTP_WRITE_TIMEOUT, 30s"` + "`" + `
HttpReadTimeout time.Duration ` + "`" + `env:"HTTP_READ_TIMEOUT, 30s"` + "`" + `
HttpIdleTimeout time.Duration ` + "`" + `env:"HTTP_IDLE_TIMEOUT, 50s"` + "`" + `
HttpShutdownTimeout time.Duration ` + "`" + `env:"HTTP_SHUTDOWN_TIMEOUT, 5s"` + "`" + `
}
func main() {
var cfg Config
err := config.Load(&cfg)
if err != nil {
log.Fatal().Err(err).Msg("loading config")
}
l := setupLogging(true)
router := chi.NewRouter().With(
httplog.RecoverLogger(l),
chiTrace.Middleware(),
httplog.RequestLogger(httplog.LogAll),
)
svc := {{ $.PackageName }}.New()
{{ $.PackageName }}.RegisterHTTP(svc, router
{{- if .HasAuthentication -}}
{{- range $security, $value := .File.API.Components.SecuritySchemes -}}
, {{ $.PackageName }}.{{ pascal $security }}Auth({{ pascal $security }}Auth)
{{- end -}}
{{- if .HasAuthorization -}}
, Authorize
{{- end -}}
{{- end -}}
)
httpServer := http.Server{
Addr: fmt.Sprintf(":%d", cfg.Port),
WriteTimeout: cfg.HttpWriteTimeout,
ReadTimeout: cfg.HttpReadTimeout,
IdleTimeout: cfg.HttpIdleTimeout,
Handler: router,
}
httpServerExit := make(chan int, 1)
go func() {
defer func() { httpServerExit <- 1 }()
l.Info().Msgf("Serving on: http://%s", httpServer.Addr)
if err := httpServer.ListenAndServe(); err != nil {
if !errors.Is(err, http.ErrServerClosed) {
log.Error().Stack().Err(err).Msg("HTTP Server error")
}
}
log.Info().Msg("HTTP Server stopped")
}()
sigInt := make(chan os.Signal, 1)
signal.Notify(sigInt, os.Interrupt) // We'll start graceful shutdowns when quit via SIGINT (Ctrl+C)
var wg sync.WaitGroup // Block until we receive any signal.
select {
case <-sigInt:
shutdownServer(&httpServer, cfg.HttpShutdownTimeout, &wg)
log.Info().Msg("SIGINT received, shutting down.")
case <-httpServerExit:
log.Info().Msg("HTTP Server exited")
}
wg.Wait()
}
func setupLogging(consoleLog bool) zerolog.Logger {
zerolog.DurationFieldInteger = true
zerolog.DurationFieldUnit = time.Millisecond
zerolog.ErrorStackMarshaler = errs.MarshalStack
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
if consoleLog {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
}
zerolog.DefaultContextLogger = &log.Logger
return log.Logger
}
func shutdownServer(server *http.Server, duration time.Duration, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
defer wg.Done()
ctx, cancel := context.WithTimeout(context.Background(), duration)
defer cancel()
err := server.Shutdown(ctx)
if err != nil {
log.Error().Stack().Err(err).Msg("Error shutting down server.")
}
}()
}
{{- if .HasAuthentication -}}
{{- range $security, $value := .File.API.Components.SecuritySchemes }}
func {{ pascal $security }}Auth(ctx context.Context, key string) (*{{ $.CheckPackage $.Params.Auth "" }}, error){
return nil, {{ $.PackageName }}.ErrNotImplemented
}
{{- end -}}
{{- if .HasAuthentication }}
func Authorize(ctx context.Context, user *auth.LavaUser, scopes []string) error {
return form.ErrNotImplemented
}
{{- end -}}
{{- end -}}`
View Source
const FojiSlashOpenapiSlashModelDotGoDotTpl = `{{- define "propertyDeclaration"}}
{{- $key := .RuntimeParams.key }}
{{- $schema := .RuntimeParams.schema }}
{{- $typeName := .RuntimeParams.typeName }}
{{- goDoc $schema.Value.Description }}
{{ pascal $key }} {{ $.GetType .PackageName (print $typeName " " $key) $schema }} ` + "`" + `json:"{{$key}},omitempty"` + "`" + `
{{- end -}}
{{- define "enum"}}
{{- $schema := .RuntimeParams.schema }}
{{- $description := .RuntimeParams.description }}
{{- $name := .RuntimeParams.name }}
{{- $enumType := $.CheckPackage ($.EnumName $name) $.PackageName -}}
{{- if and (empty $schema.Ref) (not (empty $schema.Value.Enum)) }}
// {{$enumType}}
{{- goDoc $description }}
type {{ $enumType }} int8
const (
Unknown{{ $enumType }} {{ $enumType }} = iota
{{- range $i, $value := $schema.Value.Enum }}
{{ $enumType }}{{ pascal (goToken (printf "%v" $value)) }}
{{- end }}
)
func New{{ $enumType }}(name string) {{ $enumType }} {
switch name {
{{- range $schema.Value.Enum }}
case "{{ . }}":
return {{ $enumType }}{{ pascal (goToken (printf "%v" .)) }}
{{- end }}
}
return {{ $enumType }}(0)
}
var {{ $enumType }}String = map[{{ $enumType }}]string{
{{- range $schema.Value.Enum }}
{{ $enumType }}{{ pascal (goToken (printf "%v" .)) }}: "{{ (printf "%v" .) }}",
{{- end }}
}
func (e {{ $enumType }}) String() string {
return {{ $enumType }}String[e]
}
func (e *{{ $enumType }}) UnmarshalJSON(input []byte) (err error) {
var i int8
err = json.Unmarshal(input, &i)
if err == nil {
*e = {{ $enumType }}(i)
return nil
}
var s string
err = json.Unmarshal(input, &s)
if err != nil {
return err
}
*e = New{{ $enumType }}(s)
return nil
}
func (e *{{ $enumType }}) MarshalJSON() ([]byte, error) {
return json.Marshal(e.String())
}
{{- end -}}
{{- end -}}
{{- define "typeDeclaration"}}
{{ $schema := .RuntimeParams.schema }}
{{- $key := .RuntimeParams.key }}
{{- $label := .RuntimeParams.label }}
{{- if not ($.HasExtension $schema "x-go-type" )}}
{{- $typeName := $.GetType $.PackageName $key $schema }}
// {{ $typeName}}
{{- goDoc $schema.Value.Description }}
//
// OpenAPI {{$label}}: {{ $key }}
{{- if in $schema.Value.Type "object" "" }}
type {{ pascal $key }} struct {
{{- range $key, $schema := $.SchemaProperties $schema false}}
{{- template "propertyDeclaration" ($.WithParams "key" $key "schema" $schema "typeName" $typeName)}}
{{- end }}
{{- range $schema.Value.AllOf }}
{{- if notEmpty .Ref }}
// OpenAPI Ref: {{ .Ref }}
{{ $.GetType $.PackageName "" . }}
{{- end }}
{{- end }}
}
{{- else }}
type {{ pascal $key }} {{ $.GetType $.PackageName (pascal (print $typeName " Item" )) $schema }}
{{- end }}
{{- /* Nested Types */}}
{{- range $key, $schema := $.SchemaProperties $schema false }}
{{- if not (empty $schema.Value.Properties )}}
{{- if empty $schema.Ref -}}
{{- template "typeDeclaration" ($.WithParams "key" (pascal (print $typeName " " $key)) "schema" $schema "label" (print $typeName " inline " $key))}}
{{- end -}}
{{- else if eq $schema.Value.Type "array"}}
{{- if empty $schema.Value.Items.Ref -}}
{{- if not (empty ($.SchemaProperties $schema.Value.Items false ))}}
{{- template "typeDeclaration" ($.WithParams "key" (pascal (print $typeName " " $key)) "schema" $schema.Value.Items "label" (print $typeName " inline item " $key))}}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- /* Nested Arrays */}}
{{- if eq $schema.Value.Type "array"}}
{{- if empty $schema.Value.Items.Ref -}}
{{- if not (empty ($.SchemaProperties $schema.Value.Items false ))}}
{{- template "typeDeclaration" ($.WithParams "key" (pascal (print $typeName " Item" )) "schema" $schema.Value.Items "label" (print $typeName " inline item " $key))}}
{{- end }}
{{- end }}
{{- end }}
{{- /* Regex Validation Patterns */ -}}
{{- range $key, $schema := $.SchemaProperties $schema false}}
{{- if notEmpty $schema.Value.Pattern }}
var {{ camel $typeName }}{{ pascal $key }}Pattern = regexp.MustCompile(` + "`" + `{{ $schema.Value.Pattern }}` + "`" + `)
{{- end}}
{{- end }}
{{- /* Enums */}}
{{- range $key, $schema := $.SchemaEnums $schema }}
{{- template "enum" ($.WithParams "name" (print $typeName " " $key) "schema" $schema "description" (print $label " : " $key ))}}
{{- end -}}
{{- $hasValidation := $.HasValidation $schema -}}
{{- if or $hasValidation $schema.Value.Required }}
func (p *{{ pascal $key }}) UnmarshalJSON(b []byte) error {
{{- if $schema.Value.Required }}
var requiredCheck map[string]interface{}
if err := json.Unmarshal(b, &requiredCheck); err != nil {
return validation.Error{err.Error(), fmt.Errorf("{{ pascal $key }}.UnmarshalJSON Required: ` + "`" + `%v` + "`" + `: %w", string(b), err)}
}
var validationErrors validation.Errors
{{ range $field := $schema.Value.Required }}
if _, ok := requiredCheck["{{ $field }}"]; !ok {
validationErrors.Add("{{ $field }}", "missing required field")
}
{{ end }}
if validationErrors != nil {
return validationErrors.GetErr()
}
{{ end }}
type {{ pascal $key }}JSON {{ pascal $key }}
var parseObject {{ pascal $key }}JSON
if err := json.Unmarshal(b, &parseObject); err != nil {
return validation.Error{err.Error(), fmt.Errorf("{{ pascal $key }}.UnmarshalJSON: ` + "`" + `%v` + "`" + `: %w", string(b), err)}
}
v := {{ pascal $key }}(parseObject)
{{ if $hasValidation}}
if err := v.Validate(); err != nil {
return err
}
{{ end }}
p = &v
return nil
}
{{ if $hasValidation}}
func (p {{ pascal $key }}) MarshalJSON() ([]byte, error) {
if err := p.Validate(); err != nil {
return nil, err
}
b, err := json.Marshal(p)
if err != nil {
return nil, fmt.Errorf("{{ pascal $key }}.Marshal: ` + "`" + `%+v` + "`" + `: %w", p, err)
}
return b, nil
}
{{ end }}
{{end}}
{{- if $.HasValidation $schema }}
func (p {{ pascal $key }}) Validate() error {
var err validation.Errors
{{- range $key, $schema := $.SchemaProperties $schema true }}
{{- if in $schema.Value.Type "number" "integer" }}
{{- $fieldType := $.GetType $.PackageName $key $schema }}
{{- if isNotNil $schema.Value.Min }}
if p.{{ pascal $key }} <{{ if $schema.Value.ExclusiveMin }}={{end}} {{ $schema.Value.Min }} {
_ = err.Add("{{$key}}", "must be >{{ if not $schema.Value.ExclusiveMin }}={{end}} {{ $schema.Value.Min }}")
}
{{- end }}
{{- if isNotNil $schema.Value.Max }}
if p.{{ pascal $key }} >{{ if $schema.Value.ExclusiveMax }}={{end}} {{ $schema.Value.Max }} {
_ = err.Add("{{$key}}", "must be <{{ if not $schema.Value.ExclusiveMax }}={{end}} {{ $schema.Value.Max }}")
}
{{- end }}
{{- if isNotNil $schema.Value.MultipleOf }}
{{- if eq $schema.Value.Type "integer" }}
if p.{{ pascal $key }} % {{ $schema.Value.MultipleOf }} != 0 {
_ = err.Add("{{$key}}", "must be multiple of {{ $schema.Value.MultipleOf }}")
}
{{- else }}
if math.Mod({{ if not (eq $fieldType "float64") }}float64({{ end }}p.{{ pascal $key }}{{ if not (eq $fieldType "float64") }}){{end}}, {{ $schema.Value.MultipleOf }}) != 0 {
_ = err.Add("{{$key}}", "must be multiple of {{ $schema.Value.MultipleOf }}")
}
{{- end }}
{{- end }}
{{- else if eq $schema.Value.Type "string" }}
{{- $fieldType := $.GetType $.PackageName $key $schema }}
{{- if gt $schema.Value.MinLength 0 }}
if len(p.{{ pascal $key }}) < {{ $schema.Value.MinLength }} {
_ = err.Add("{{$key}}", "length must be >= {{ $schema.Value.MinLength }}")
}
{{- end }}
{{- if isNotNil $schema.Value.MaxLength }}
if len(p.{{ pascal $key }}) > {{ $schema.Value.MaxLength }} {
_ = err.Add("{{$key}}", "length must be <= {{ $schema.Value.MaxLength }}")
}
{{- end }}
{{- if notEmpty $schema.Value.Pattern }}
if !{{ camel $typeName }}{{ pascal $key }}Pattern.MatchString( p.{{ pascal $key }}) {
_ = err.Add("{{$key}}", ` + "`" + `must match "{{ $schema.Value.Pattern }}"` + "`" + `)
}
{{- end }}
{{- else if eq $schema.Value.Type "array" }}
{{- if gt $schema.Value.MinItems 0 }}
if len(p.{{ pascal $key }}) < {{ $schema.Value.MinItems }} {
_ = err.Add("{{$key}}", "length must be >= {{ $schema.Value.MinItems }}")
}
{{- end }}
{{- if isNotNil $schema.Value.MaxItems }}
if len(p.{{ pascal $key }}) > {{ $schema.Value.MaxItems }} {
_ = err.Add("{{$key}}", "length must be <= {{ $schema.Value.MaxItems }}")
}
{{- end }}
{{- else if notEmpty $schema.Ref }}
{{- if $.HasValidation $schema }}
if subErr := p.{{ pascal $key }}.Validate(); subErr != nil {
_ = err.Add("{{ $key }}", subErr)
}
{{- end -}}
{{- end }}
{{- end }}
return err.GetErr()
}
{{- end -}}
{{- end -}}
{{- end -}}
// Code generated by foji {{ version }}, template: {{ templateFile }}; DO NOT EDIT.
package {{ .PackageName }}
import (
"regexp"
{{- .CheckAllTypes .PackageName -}}
{{ range .GoImports }}
"{{ . }}"
{{- end }}
"github.com/bir/iken/validation"
)
// Component Schemas
{{ range $key, $schema := .ComponentSchemas }}
{{- template "typeDeclaration" ($.WithParams "key" $key "schema" $schema "label" "Component Schema")}}
{{- end }}
// Component Parameters
{{ range $key, $param := .ComponentParameters }}
{{- template "paramDeclaration" ($.WithParams "param" $param "name" "" "label" "Component Parameter: ")}}
{{- end }}
{{- define "paramDeclaration"}}
{{- $param := .RuntimeParams.param }}
{{- $name := .RuntimeParams.name }}
{{- $label := .RuntimeParams.label }}
{{- if empty $param.Ref -}}
{{- template "enum" ($.WithParams "name" (print $name " " $param.Value.Name) "schema" $param.Value.Schema "description" (print $param.Value.Description "\n" $label $param.Value.Name ))}}
{{- if eq $param.Value.Schema.Value.Type "array"}}
{{- template "enum" ($.WithParams "name" (print $name " " $param.Value.Name) "schema" $param.Value.Schema.Value.Items "description" (print $label $param.Value.Name " Item"))}}
{{- end }}
{{- end -}}
{{- end }}
// Path Operations
{{/* Inline Request/Reponse Types */ -}}
{{ range $name, $path := .API.Paths }}
{{- range $verb, $op := $path.Operations }}
{{- /* Inline Request */ -}}
{{- $bodySchema := $.GetRequestBodyLocal $op}}
{{- if $.SchemaIsComplex $bodySchema -}}
{{- template "typeDeclaration" ($.WithParams "key" (print $op.OperationID "Request") "schema" $bodySchema "label" (print $op.OperationID " Body") )}}
{{- end }}
{{- /* Inline Response */ -}}
{{- $opResponse := $.GetOpHappyResponse $.PackageName $op }}
{{- if isNotNil $opResponse.MediaType }}
{{- if $.SchemaIsComplex $opResponse.MediaType.Schema -}}
{{- template "typeDeclaration" ($.WithParams "key" (print $op.OperationID " Response") "schema" $opResponse.MediaType.Schema "label" (print $op.OperationID " Response") )}}
{{- end }}
{{- end }}
{{- /* Inline Params */ -}}
{{- range $param := $.OpParams $path $op }}
{{- template "paramDeclaration" ($.WithParams "param" $param "name" $op.OperationID "label" (print "Op: " $op.OperationID " Param: "))}}
{{- end }}
{{- end }}
{{- end }}
`
View Source
const FojiSlashOpenapiSlashServiceDotGoDotTpl = `` /* 2048-byte string literal not displayed */
View Source
const FojiSlashOpenapiSlashStubDotYamlDotTpl = `` /* 4893-byte string literal not displayed */
View Source
const FojiSlashPgxSlashDbDotGoDotTpl = `` /* 668-byte string literal not displayed */
View Source
const FojiSlashPgxSlashModelDotGoDotTpl = `// 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 }}
import (
"fmt"
{{- range .Imports }}
"{{ . }}"
{{- end }}
)
// {{$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}}
)
`
View Source
const FojiSlashPgxSlashTableDotGoDotTpl = `// Code generated by foji {{ version }}, template: {{ templateFile }}; DO NOT EDIT.
{{- $pkgName := "pg" }}
{{- $table := .Table.Name}}
{{- $schema := .Table.Schema.Name}}
{{- $goName := case $table }}
{{- $hasSoftDeletes := .Table.Columns.Names.Contains "deleted_at"}}
{{- $mutableCols := (.Table.Columns.Filter .Table.PrimaryKeys.Paths).ByOrdinal.Names }}
{{- $mutableFields := (cases $mutableCols).Sprintf "row.%s"}}
{{- $scanFields := (cases .Table.Columns.ByOrdinal.Names).Sprintf "&row.%s"}}
{{- $selectFields := csv .Table.Columns.ByOrdinal.Names}}
{{- $PKs := cases .Table.PrimaryKeys.ByOrdinal.Names }}
{{- $PKFields := csv ($PKs.Sprintf "row.%s")}}
{{- $PKScanFields := csv ($PKs.Sprintf "&row.%s")}}
package {{ $pkgName }}
import (
"context"
"fmt"
"github.com/jackc/pgx/v5"
"{{.Params.Package}}"
{{- range .Imports }}
"{{ . }}"
{{- end }}
)
const querySelect{{$goName}} = ` + "`" + `SELECT
{{ $selectFields }}
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 }})
if err != nil {
return nil, fmt.Errorf("scan{{$goName}}:%w", err)
}
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
}
// All retrieves all rows from '{{$table}}' as a slice of {{$goName}}.
func (r Repo) All{{$goName}}(ctx context.Context) ([]*{{$.PackageName}}.{{$goName}}, error) {
query := querySelect{{$goName }}
{{- 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()...)
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" -}}
{{$nums := numbers 1 . -}}
{{$indices := $nums.Sprintf "$%s" -}}
{{csv $indices -}}
{{end}}
// Insert inserts the row into the database.
func (r Repo) Insert{{$goName}}(ctx context.Context, row *{{$.PackageName}}.{{$goName}}) error {
const query = ` + "`" + `INSERT INTO {{$schema}}.{{$table}}
{{- if gt (len $mutableCols) 0}}
({{ csv $mutableCols }})
VALUES
({{template "values" (len $mutableCols) }})
{{- else}}
DEFAULT VALUES
{{- end}}
RETURNING
{{csv .Table.PrimaryKeys.Names.Sort }}` + "`" + `
q := r.db.QueryRow(ctx, query,{{- csv $mutableFields }})
return q.Scan({{$PKScanFields}})
}
{{if gt (len $mutableCols) 0}}
// Update the Row in the database.
func (r Repo) Update{{$goName}}(ctx context.Context, row *{{$.PackageName}}.{{$goName}}) error {
query := ` + "`" + `UPDATE {{$schema}}.{{$table}}
SET
({{csv $mutableCols }}) =
({{ template "values" (len $mutableCols) }})
WHERE
{{$last := sum (len .Table.PrimaryKeys) (len $mutableCols)}}
{{- $first := inc (len $mutableCols)}}
{{- range $x, $name := .Table.PrimaryKeys.Names.Sort -}}
{{$name}} = ${{sum $first $x}}{{if lt (sum $x $first) $last}} AND {{end}}
{{- 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([]interface{}{ set.Value }, where.Values()...)...)
if err != nil {
return 0, fmt.Errorf("{{$goName}}:%w", err)
}
return res.RowsAffected(), nil
}
{{- if .Table.HasPrimaryKey }}
{{- if $hasSoftDeletes}}
// Delete{{$goName}} soft deletes the row from the database. Returns the number of items soft deleted.
{{else}}
// Delete{{$goName}} deletes the Row from the database. Returns the number of items deleted.
{{end}}
func (r Repo) Delete{{$goName}}( ctx context.Context, {{ $.Parameterize .Table.PrimaryKeys "%s %s" $pkgName }}) (int64, error) {
{{- if $hasSoftDeletes}}
const query = ` + "`" + `UPDATE {{$schema}}.{{$table}}
SET deleted_at = now()
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 NULL
` + "`" + `
{{- else }}
const query = ` + "`" + `DELETE FROM {{$schema}}.{{$table}} WHERE
{{ 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}}
// DeletePermanent{{$goName}} deletes the Row from the database. This bypasses the soft delete mechanism.
// Returns the number of items deleted.
func (r Repo) DeletePermanent{{$goName}}( ctx context.Context, {{ $.Parameterize .Table.PrimaryKeys "%s %s" $pkgName }}) (int64, error) {
const query = ` + "`" + `DELETE FROM {{$schema}}.{{$table}} WHERE
{{ 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 "") -}}
{{- if $.Table.PrimaryKeys.Names.ContainsAll .Columns.Names -}}
{{- $FuncName = print "Get" $goName -}}
{{- end -}}
// {{$FuncName}} retrieves a row from '{{$.Table.Schema.Name}}.{{$.Table.Name}}'.
//
// Generated from index '{{.Name}}'.
func (r Repo) {{ $FuncName }}(ctx context.Context, {{ $.Parameterize .Columns "%s %s" $pkgName }}) ({{ if not .IsUnique }}[]{{ end }}*{{$.PackageName}}.{{$goName}}, error) {
query := querySelect{{$goName}} + ` + "`" + ` WHERE {{csv .Columns.Names.Sort }} = {{template "values" (len .Columns)}}
{{- if $hasSoftDeletes }} AND deleted_at is NULL{{ end}}` + "`" + `
{{- if .IsUnique }}
q := r.db.QueryRow(ctx, query, {{ csv (.Columns.Names.Sort.Camel) }})
{{- else }}
q, err := r.db.Query(ctx, query, {{ csv (.Columns.Names.Sort.Camel) }})
if err != nil {
return nil, fmt.Errorf("{{$goName}}.{{ $FuncName }}:%w", err)
}
{{- end }}
{{- if .IsUnique }}
return scanOne{{$goName}}(q)
{{- else }}
return scan{{$goName}}(q)
{{- end }}
}
{{ end }}`
View Source
const FojiSlashSqlRepoDotGoDotTpl = `// Code generated by foji {{ version }}, template: {{ templateFile }}; DO NOT EDIT.
package pg
import (
"context"
"fmt"
{{- range .Imports }}
"{{ . }}"
{{- end }}
)
{{- range .Queries }}
{{ $resultType := $.GetType .Result.TypeParam $.PackageName }}
{{- if .Result.GenerateType }}
// {{.Result.Type}} represents a result from '{{.Name}}'.
type {{.Result.Type}} struct {
{{- range .Result.Params.ByOrdinal }}
{{ pascal .Name }} {{ $.GetType . $.PackageName }} ` + "`" + `json:"{{ .Name }},omitempty"` + "`" + ` // postgres type: {{ .Type }} {{- if .Nullable }} NULLABLE {{ end }}
{{- end }}
}
{{- end }}
// {{.Name}} returns {{ $resultType }}
{{- if notEmpty .Comment }}
// {{.Comment}}
{{- end }}
func (r Repo) {{ .Name }}(ctx context.Context{{if gt (len .Params) 0}}, {{end}}{{ $.Parameterize .Params.ByOrdinal "%s %s" $.PackageName }}) ({{ if .IsType "query" }}[]{{ end }}*{{$resultType}}, error) {
const query = ` + "`" + `{{ backQuote .SQL }}` + "`" + `
{{- if .IsType "query" }}
q, err := r.db.Query(ctx, query{{if gt (len .Params) 0}}, {{ csv (.Params.ByQuery.Names.Camel)}}{{end}})
if err != nil {
return nil, fmt.Errorf("{{.Name}}.Query:%w", err)
}
var out []*{{ $resultType }}
for q.Next() {
row := {{ $resultType }}{}
err := q.Scan({{ csv (.Result.Params.ByQuery.Names.Pascal.Sprintf "&row.%s")}})
if err != nil {
return nil, fmt.Errorf("{{.Name}}.Scan:%w", err)
}
out = append(out, &row)
}
return out, nil
{{- else }}
q := r.db.QueryRow(ctx, query{{if gt (len .Params) 0}},{{end}} {{ csv (.Params.ByQuery.Names.Camel) }})
{{/* return scanOne{{$goName}}(q)*/}}
{{- end }}
}
{{- end }}
`
View Source
const InitDotYaml = `` /* 269-byte string literal not displayed */
Variables ¶
View Source
var FojiDotYamlBytes = []byte(FojiDotYaml)
foji.yaml
View Source
var FojiSlashDbListDotConsoleDotTplBytes = []byte(FojiSlashDbListDotConsoleDotTpl)
foji/dbList.console.tpl
View Source
var FojiSlashEmbedDotGoDotTplBytes = []byte(FojiSlashEmbedDotGoDotTpl)
foji/embed.go.tpl
View Source
var FojiSlashEnumDotGoDotTplBytes = []byte(FojiSlashEnumDotGoDotTpl)
foji/enum.go.tpl
View Source
var FojiSlashFieldsDotGoDotTplBytes = []byte(FojiSlashFieldsDotGoDotTpl)
foji/fields.go.tpl
View Source
var FojiSlashOpenapiSlashAuthDotGoDotTplBytes = []byte(FojiSlashOpenapiSlashAuthDotGoDotTpl)
foji/openapi/auth.go.tpl
View Source
var FojiSlashOpenapiSlashDocsDotGoDotTplBytes = []byte(FojiSlashOpenapiSlashDocsDotGoDotTpl)
foji/openapi/docs.go.tpl
View Source
var FojiSlashOpenapiSlashHandlerDotGoDotTplBytes = []byte(FojiSlashOpenapiSlashHandlerDotGoDotTpl)
foji/openapi/handler.go.tpl
View Source
var FojiSlashOpenapiSlashMainDotGoDotTplBytes = []byte(FojiSlashOpenapiSlashMainDotGoDotTpl)
foji/openapi/main.go.tpl
View Source
var FojiSlashOpenapiSlashModelDotGoDotTplBytes = []byte(FojiSlashOpenapiSlashModelDotGoDotTpl)
foji/openapi/model.go.tpl
View Source
var FojiSlashOpenapiSlashServiceDotGoDotTplBytes = []byte(FojiSlashOpenapiSlashServiceDotGoDotTpl)
foji/openapi/service.go.tpl
View Source
var FojiSlashOpenapiSlashStubDotYamlDotTplBytes = []byte(FojiSlashOpenapiSlashStubDotYamlDotTpl)
foji/openapi/stub.yaml.tpl
View Source
var FojiSlashPgxSlashDbDotGoDotTplBytes = []byte(FojiSlashPgxSlashDbDotGoDotTpl)
foji/pgx/db.go.tpl
View Source
var FojiSlashPgxSlashModelDotGoDotTplBytes = []byte(FojiSlashPgxSlashModelDotGoDotTpl)
foji/pgx/model.go.tpl
View Source
var FojiSlashPgxSlashTableDotGoDotTplBytes = []byte(FojiSlashPgxSlashTableDotGoDotTpl)
foji/pgx/table.go.tpl
View Source
var FojiSlashSqlRepoDotGoDotTplBytes = []byte(FojiSlashSqlRepoDotGoDotTpl)
foji/sqlRepo.go.tpl
View Source
var InitDotYamlBytes = []byte(InitDotYaml)
init.yaml
Functions ¶
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.