Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generator produces invalid models when using custom generic fields wrapping non-stdlib types #442

Open
kralewitz opened this issue Jan 17, 2025 · 1 comment
Labels
bug Something isn't working good first issue Good for newcomers

Comments

@kralewitz
Copy link

Environment:

  • OS: linux
  • Database: sqlite
  • Database driver: modernc.org/sqlite
  • Jet version 2.12.0

Describe the bug

If I customize the generator to use a model with a generic field, the generator produces invalid model in case the generic field contains a non-stdlib type:

import "github.com/google/uuid"

// generator customization snippet
UseField(func(column metadata.Column) template.TableModelField {
	defaultTableModelField := template.DefaultTableModelField(column)
	switch column.Name {
	case "col1":
		defaultTableModelField.Type = template.NewType(sql.Null[string]{})
	case "col2":
		defaultTableModelField.Type = template.NewType(uuid.UUID{})
	case "col3":
		defaultTableModelField.Type = template.NewType(sql.Null[uuid.UUID]{})
	}
	return defaultTableModelField
})

// generated invalid model.go
package model

import (
	"database/sql"
	"github.com/google/uuid"
)

type T struct {
	Col1 sql.Null[string]  
	Col2 uuid.UUID  
	Col3 sql.Null[github.com/google/uuid.UUID]  // invalid
}

// failed to process database : failed to generate model types: failed to generate table model types: failed to save 't' model type: failed to format 't', check 'gen/model/t.go' for syntax errors: 21:26: missing ',' in type argument list

Expected behavior

I expected the generator to produce a correct model file:

import (
	"database/sql"
	"github.com/google/uuid"
)

type T struct {
	Col1 sql.Null[string]  
	Col2 uuid.UUID  
	Col3 sql.Null[uuid.UUID]  
}

Code snippet

Full runnable example:

package main

import (
	"database/sql"
	"fmt"
	"os"

	"github.com/go-jet/jet/v2/generator/metadata"
	sqlitegen "github.com/go-jet/jet/v2/generator/sqlite"
	"github.com/go-jet/jet/v2/generator/template"
	jetsqlite "github.com/go-jet/jet/v2/sqlite"
	"github.com/google/uuid"

	"modernc.org/sqlite"
)

const (
	dbURI  = "file::memory:?cache=shared"
	genDir = "./gen"
)

var schemaTemplate = template.Default(jetsqlite.Dialect).
	UseSchema(func(schemaMetaData metadata.Schema) template.Schema {
		return template.DefaultSchema(schemaMetaData).
			UseModel(template.DefaultModel().
				UseTable(func(table metadata.Table) template.TableModel {
					return template.DefaultTableModel(table).
						UseField(func(column metadata.Column) template.TableModelField {
							defaultTableModelField := template.DefaultTableModelField(column)

							switch column.Name {
							case "col1":
								defaultTableModelField.Type = template.NewType(sql.Null[string]{})
							case "col2":
								defaultTableModelField.Type = template.NewType(uuid.UUID{})
							case "col3":
								defaultTableModelField.Type = template.NewType(sql.Null[uuid.UUID]{})
							}

							return defaultTableModelField
						})
				}),
			).
			UseSQLBuilder(template.DefaultSQLBuilder().
				UseTable(func(table metadata.Table) template.TableSQLBuilder {
					return template.DefaultTableSQLBuilder(table)
				}),
			)
	})

func main() {
	if err := generateSchema(); err != nil {
		fmt.Println("error generating schema: " + err.Error())
		os.Exit(1)
	}
}

func generateSchema() error {

	sql.Register("sqlite3", &sqlite.Driver{})
	db, err := sql.Open("sqlite", dbURI)
	if err != nil {
		return fmt.Errorf("open db: %v", err)
	}

	if _, err := db.Exec("create table t(col1 text, col2 text, col3 text)"); err != nil {
		return err
	}

	if err := sqlitegen.GenerateDSN(dbURI, genDir, schemaTemplate); err != nil {
		return fmt.Errorf("generate schema: %v", err)
	}

	return nil
}
@kralewitz kralewitz added the bug Something isn't working label Jan 17, 2025
@go-jet
Copy link
Owner

go-jet commented Jan 17, 2025

Thanks for the detailed explanation. As a workaround, you can directly set the Type field:

defaultTableModelField.Type = template.Type{
	ImportPath: "github.com/google/uuid",
	Name:       "sql.Null[uuid.UUID]",
}

@go-jet go-jet added the good first issue Good for newcomers label Jan 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

2 participants