What does HackerNews think of squirrel?

Fluent SQL generation for golang

Language: Go

Libraries like Jooq and SQLDelight include what I'm talking about and then build on top of it with codegen which is even nicer since it adds compiler safety

But even without codegen you'd still a much nicer interface than manually hacking together strings as the Golang example others have linked shows: https://github.com/Masterminds/squirrel

golang https://github.com/Masterminds/squirrel

Constructing sql by concat strings has a few issues, its repetitive and hard to assemble certain queries conditionally, and at least in golang its easy to write code vulnerable to sql injection and you can avoid that by using types

I've been using Ent for some time on a project and its been quite nice to just be able to write the schema in Go, testing has been a breeze with the enttest package, hooks work well, and everything feels intuitive to me unlike most other ORMs or ORM-adjacent tools.

My preferred package before Ent was Squirrel [1] but I definitely plan to use Ent for future projects.

[1] https://github.com/Masterminds/squirrel

You should be, but because a lot sql in Go is still just strings it makes it easy for someone to bypass because of laziness/sloppiness/distracted/whatever when composing queries. There is also the issue that if the Go code needs to run on Postgres it has to use '$' params instead of '?'. So again, back to string concatenation to support both or use some library like squirrel[1].

[1] https://github.com/Masterminds/squirrel

There is no real good framework and anybody can write a trie based router in 2 hours:

https://vluxe.io/golang-router.html

However, Go ecosystem is starting to look interesting library-wise, as long as your project doesn't involve enterprise integration with legacy XML services or SOAP, because Go sucks at mostly anything XML.

For templating I use Jet because the standard templating library is too basic for professional use https://github.com/CloudyKit/jet .

I don't use ORM, I use https://github.com/Masterminds/squirrel for query building and https://github.com/jmoiron/sqlx which helps deals with row<=>struct conversion. For database migrations, I use https://github.com/rubenv/sql-migrate , but if you need an ORM gorm https://github.com/jinzhu/gorm is OK if you do code first and sqlboiler https://github.com/volatiletech/sqlboiler is OK if you do database first.

For session handling I use scs github.com/alexedwards/scs , for converting form encoded data to go structs I use github.com/gorilla/schema, for logging I use zap https://github.com/uber-go/zap. For managing roles in an app I use either the voter pattern https://symfony.com/doc/current/security/voters.html in simple cases or casbin github.com/casbin/casbin . For background jobs I used https://github.com/gocraft/work and https://github.com/gocelery/gocelery , for caching i just use redis https://github.com/go-redis/redis , for data validation I used https://github.com/asaskevich/govalidator or https://github.com/go-ozzo/ozzo-validation . For sending mails to customers I used https://github.com/go-gomail/gomail

If i need html forms, I first describe form elements as a struct then write form helpers in jet templating to display them like that:

    type LoginForm struct {
            Login, Password string
            Form
    }

    func (form *LoginForm) validate(r *http.Request) error {
            r.ParseForm()
            form.Decoder().Decode(form, r.Form)
            form.Errors = map[string][]string{}
            if err := (requiredValidator{}).validate(form.Login); err != nil {
                    form.Errors["Login"] = append(form.Errors["Login"], err.Error())
            }
            if err := (requiredValidator{}).validate(form.Password); err != nil {
                    form.Errors["Password"] = append(form.Errors["Password"], err.Error())
            }
            return form.getErrors()
    }
    func (form LoginForm) LoginFormView() LoginFormView {
            return LoginFormView{Fields: []Field{
                    {Name: "Login", Label: "Email", Type: "text", Value: form.Login, Required: true, Errors: form.Errors["Login"]},
                    {Name: "Password", Label: "Password", Type: "password", Value: form.Password, Required: true, Errors: form.Errors["Password"]},
                    {Type: "submit", Value: "Submit", Required: true},
                    {Type: "reset", Value: "Reset", Required: true},
            }, Method: "POST", Name: "LoginForm"}
    }
Then I can just write an helper in jet to display the the form view:

    {* tag attributes *}
    {{ block attributes() }}
        {{range .}}
            {{.Key}}="{{.Value}}"
        {{end}}
    {{ end }}
    {* form field *}
    {{block field()}}
    
        {{.Label}}
        
{{if .Type == "textarea" }} {* textarea *} {{.Value}} {{ else if .Type == "select" }} {* select *} {{ range .Options }} {{.Label}} {{ end }} {{ else }} {* basic input *} {{ end }} {{end}} {* form template *} {{block form()}} {{ range .Fields }} {{yield field() .}} {{end}} {{end}}
This is the exact app structure I use to deal with dependencies and filters :

https://medium.com/statuscode/how-i-write-go-http-services-a...