sqlc-dev / sqlc

Generate type-safe code from SQL
https://sqlc.dev
MIT License
12.24k stars 778 forks source link

Exposed and more customisable golang generator #2395

Open popescu-af opened 1 year ago

popescu-af commented 1 year ago

What do you want to change?

Recently I had to write a plugin for slight alterations of the default behavior of the golang generator for postgres. To build the plugin, I needed to

In my opinion, although this works, it would be great if the sqlc's generators would be

What database engines need to be changed?

PostgreSQL

What programming language backends need to be changed?

Go

jwc-clinnection commented 1 year ago

Do you mean something like this? https://github.com/kyleconroy/sqlc/pull/2302

kyleconroy commented 1 year ago

The majority of the code is kept in the internal package so that it's easy for us to change the internals of sqlc without causing backwards incompatible changes. Plugins have been supported for a few versions now. You can learn how to author a plugin and see two of our plugins here:

I'm very hesitant to expose the templates publicly, as they're really difficult to maintain. There was little to no thought into how they're structured. I've talked to @jwc-clinnection about creating a plugin that makes it easy to bring your own templates, and it sounds like that would be helpful for you.

popescu-af commented 1 year ago

The majority of the code is kept in the internal package so that it's easy for us to change the internals of sqlc without causing backwards incompatible changes. Plugins have been supported for a few versions now. You can learn how to author a plugin and see two of our plugins here:

I'm very hesitant to expose the templates publicly, as they're really difficult to maintain. There was little to no thought into how they're structured. I've talked to @jwc-clinnection about creating a plugin that makes it easy to bring your own templates, and it sounds like that would be helpful for you.

Makes sense. I checked the plugin section, but from what I could see the generator has to be written entirely for each plugin. Which in my case means implementing the default sqlc behavior with slight alterations. But I think the plugin you are mentioning would be perfect for my use case, looking forward to it.

popescu-af commented 1 year ago

Do you mean something like this? #2302

Yes seems to be similar.

justinrixx commented 8 months ago

I would find this useful as well.

My use-case is putting metric emission for timings into the generated code. This allows me to see db query timings easily on my operations dashboard.

Example:

func (c *Client) GetCatalogEntry(ctx context.Context, componentID string) (CatalogEntry, error) {
    var entry CatalogEntry

    defer instrument.NewMetricTimer("db.get-catalog-entry").Record()
    result := c.db.QueryRowContext(ctx, queryGetCatalogEntry, componentID)

    err := result.Scan(&entry.ProjectID, &entry.Active, &entry.CreatedAt)
    if err != nil {
        return CatalogEntry{}, errors.Wrap(err)
    }

    return entry, nil
}

The defer line starts a timer, then records it when this function completes. A workaround exists: give instrumentation responsibility to the callers, but I've been bitten before by forgetting to instrument every single call. The other workaround is to add a wrapper function for all of the generated functions which handles the metric emission and then calls the generated function, but this is also less than ideal.

fdietze commented 1 month ago

I just created a plugin to support custom templates: https://github.com/fdietze/sqlc-gen-from-template

Feedback appreciated.

For example, I'm wondering if there should be a template to generate one file per query. Or a giant template file which gets access to the whole GenerateRequest data structure?

edit: I setteled with giving the template access to the full GenerateRequest struct.