Skip to content

Commit

Permalink
feat: formatting feature for postgresql query (#145)
Browse files Browse the repository at this point in the history
**Relative Issues:** Resolve #106 

**Describe the pull request**
This pull request introduces a new feature: a formatting function for
PostgreSQL queries. This feature is designed to improve the readability
and maintainability of SQL queries by automatically applying consistent
formatting rules. The objective of this feature is to help developers
write clearer, more understandable SQL queries, making the code easier
to read, understand, and debug. By introducing this formatting feature,
we aim to enhance developer productivity and the overall quality of our
codebase.

**Checklist**

- [ ] I have linked the relative issue to this pull request
- [ ] I have made the modifications or added tests related to my PR
- [ ] I have added/updated the documentation for my RP
- [ ] I put my PR in Ready for Review only when all the checklist is
checked
  • Loading branch information
42atomys authored Jun 30, 2023
1 parent ec2d22d commit e2cbb72
Show file tree
Hide file tree
Showing 14 changed files with 378 additions and 152 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ require (
github.com/golang/protobuf v1.5.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
Expand Down
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
Expand Down Expand Up @@ -141,15 +143,21 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
Expand All @@ -158,10 +166,14 @@ github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZb
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
Expand Down Expand Up @@ -522,6 +534,7 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
29 changes: 19 additions & 10 deletions internal/server/v1alpha1/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ func (s *Server) WebhookHandler() http.HandlerFunc {
// it will call the security pipeline if configured and store data on each configured
// storages
func webhookService(s *Server, spec *config.WebhookSpec, r *http.Request) (err error) {
ctx := r.Context()

if spec == nil {
return config.ErrSpecNotFound
}
Expand All @@ -107,21 +109,28 @@ func webhookService(s *Server, spec *config.WebhookSpec, r *http.Request) (err e
}
}

previousPayload := data
payloadFormatter := formatting.New().
WithRequest(r).
WithPayload(data).
WithData("Spec", spec).
WithData("Config", config.Current())

for _, storage := range spec.Storage {
str, err := formatting.
NewTemplateData(storage.Formatting.Template).
WithRequest(r).
WithPayload(data).
WithData("Spec", spec).
WithData("Storage", storage).
WithData("Config", config.Current()).
Render()
payloadFormatter = payloadFormatter.WithData("Storage", storage)

storagePayload, err := payloadFormatter.WithTemplate(storage.Formatting.Template).Render()
if err != nil {
return err
}

log.Debug().Msgf("store following data: %+v", str)
if err := storage.Client.Push(str); err != nil {
// update the formatter with the rendered payload of storage formatting
// this will allow to chain formatting
payloadFormatter.WithData("PreviousPayload", previousPayload)
ctx = formatting.ToContext(ctx, payloadFormatter)

log.Debug().Msgf("store following data: %s", storagePayload)
if err := storage.Client.Push(ctx, []byte(storagePayload)); err != nil {
return err
}
log.Debug().Str("storage", storage.Client.Name()).Msgf("stored successfully")
Expand Down
78 changes: 0 additions & 78 deletions pkg/formatting/format.go

This file was deleted.

128 changes: 128 additions & 0 deletions pkg/formatting/formatter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package formatting

import (
"bytes"
"context"
"fmt"
"net/http"
"sync"
"text/template"

"github.com/rs/zerolog/log"
)

type Formatter struct {
tmplString string

mu sync.RWMutex // protect following field amd template parsing
data map[string]interface{}
}

var (
formatterCtxKey = struct{}{}
// ErrNotFoundInContext is returned when the formatting data is not found in
// the context. Use `FromContext` and `ToContext` to set and get the data in
// the context.
ErrNotFoundInContext = fmt.Errorf("unable to get the formatting data from the context")
// ErrNoTemplate is returned when no template is defined in the Formatter
// instance. Provide a template using the WithTemplate method.
ErrNoTemplate = fmt.Errorf("no template defined")
)

// NewWithTemplate returns a new Formatter instance. It takes the template
// string as a parameter. The template string is the string that will be used
// to render the template. The data is the map of data that will be used to
// render the template.
// ! DEPRECATED: use New() and WithTemplate() instead
func NewWithTemplate(tmplString string) *Formatter {
return &Formatter{
tmplString: tmplString,
data: make(map[string]interface{}),
mu: sync.RWMutex{},
}
}

// New returns a new Formatter instance. It takes no parameters. The template
// string must be set using the WithTemplate method. The data is the map of data
// that will be used to render the template.
func New() *Formatter {
return &Formatter{
data: make(map[string]interface{}),
mu: sync.RWMutex{},
}
}

// WithTemplate sets the template string. The template string is the string that
// will be used to render the template.
func (d *Formatter) WithTemplate(tmplString string) *Formatter {
d.tmplString = tmplString
return d
}

// WithData adds a key-value pair to the data map. The key is the name of the
// variable and the value is the value of the variable.
func (d *Formatter) WithData(name string, data interface{}) *Formatter {
d.mu.Lock()
defer d.mu.Unlock()

d.data[name] = data
return d
}

// WithRequest adds a http.Request object to the data map. The key of request is
// "Request".
func (d *Formatter) WithRequest(r *http.Request) *Formatter {
d.WithData("Request", r)
return d
}

// WithPayload adds a payload to the data map. The key of payload is "Payload".
// The payload is basically the body of the request.
func (d *Formatter) WithPayload(payload []byte) *Formatter {
d.WithData("Payload", string(payload))
return d
}

// Render returns the rendered template string. It takes the template string
// from the Formatter instance and the data stored in the Formatter
// instance. It returns an error if the template string is invalid or when
// rendering the template fails.
func (d *Formatter) Render() (string, error) {
d.mu.RLock()
defer d.mu.RUnlock()

if d.tmplString == "" {
return "", ErrNoTemplate
}

log.Debug().Msgf("rendering template: %s", d.tmplString)

t := template.New("formattingTmpl").Funcs(funcMap())
t, err := t.Parse(d.tmplString)
if err != nil {
return "", fmt.Errorf("error in your template: %s", err.Error())
}

buf := new(bytes.Buffer)
if err := t.Execute(buf, d.data); err != nil {
return "", fmt.Errorf("error while filling your template: %s", err.Error())
}

return buf.String(), nil
}

// FromContext returns the Formatter instance stored in the context. It returns
// an error if the Formatter instance is not found in the context.
func FromContext(ctx context.Context) (*Formatter, error) {
d, ok := ctx.Value(formatterCtxKey).(*Formatter)
if !ok {
return nil, ErrNotFoundInContext
}
return d, nil
}

// ToContext adds the Formatter instance to the context. It returns the context
// with the Formatter instance.
func ToContext(ctx context.Context, d *Formatter) context.Context {
return context.WithValue(ctx, formatterCtxKey, d)
}
Loading

0 comments on commit e2cbb72

Please sign in to comment.