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

Groundwork for code generation for queries #329

Merged
merged 1 commit into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added a new field `QueryFolders` to `gen/drivers.DBInfo` for drivers to be able to include information about parsed queries.
- Added `gen/QueriesTemplates` which in the future will contain base templates for generating code for parsed qureries.
- Added a `QueryTemplate` field to `bobgen_helpers.Templates` for drivers to include additional templates for queries.
- Added a new reserved output key `queries`. This is handled specially for each query folder supplied by the driver.

### Changed

- Updated error constant generation to employ specific error types for making error matching easier. (thanks @mbezhanov)
Expand Down
5 changes: 5 additions & 0 deletions gen/bobgen-helpers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func Version() string {
type Templates struct {
Models []fs.FS
Factory []fs.FS
Queries []fs.FS
}

func DefaultOutputs(destination, pkgname string, noFactory bool, templates *Templates) []*gen.Output {
Expand All @@ -57,6 +58,10 @@ func DefaultOutputs(destination, pkgname string, noFactory bool, templates *Temp
PkgName: pkgname,
Templates: append(templates.Models, gen.ModelTemplates),
},
{
Key: "queries",
Templates: append(templates.Queries, gen.QueriesTemplates),
},
}

if !noFactory {
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-mysql/driver/exclude-tables.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -2339,6 +2339,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": [
{
"Type": "TypeMonstersEnumNullable",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": null,
"extra_info": null,
"driver_name": "github.com/go-sql-driver/mysql"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": null,
"extra_info": null,
"driver_name": "github.com/go-sql-driver/mysql"
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-mysql/driver/include-exclude-tables.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": null,
"extra_info": null,
"driver_name": "github.com/go-sql-driver/mysql"
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-mysql/driver/include-tables.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": null,
"extra_info": null,
"driver_name": "github.com/go-sql-driver/mysql"
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-mysql/driver/mysql.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -2490,6 +2490,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": [
{
"Type": "TypeMonstersEnumNullable",
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-psql/driver/exclude-tables.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -4578,6 +4578,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": [
{
"Type": "UnicodeEnum",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": [
{
"Type": "UnicodeEnum",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": [
{
"Type": "UnicodeEnum",
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-psql/driver/include-exclude-tables.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": [
{
"Type": "UnicodeEnum",
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-psql/driver/include-tables.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": [
{
"Type": "UnicodeEnum",
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-psql/driver/psql.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -4743,6 +4743,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": [
{
"Type": "UnicodeEnum",
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-sqlite/driver/exclude-tables.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -3093,6 +3093,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": null,
"extra_info": null,
"driver_name": "modernc.org/sqlite"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": null,
"extra_info": null,
"driver_name": "modernc.org/sqlite"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": null,
"extra_info": null,
"driver_name": "modernc.org/sqlite"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": null,
"extra_info": null,
"driver_name": "modernc.org/sqlite"
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-sqlite/driver/include-tables.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": null,
"extra_info": null,
"driver_name": "modernc.org/sqlite"
Expand Down
1 change: 1 addition & 0 deletions gen/bobgen-sqlite/driver/sqlite.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -3403,6 +3403,7 @@
"comment": ""
}
],
"query_folders": null,
"enums": null,
"extra_info": null,
"driver_name": "modernc.org/sqlite"
Expand Down
7 changes: 4 additions & 3 deletions gen/drivers/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ type Types map[string]Type

// DBInfo is the database's table data and dialect.
type DBInfo[DBExtra, ConstraintExtra, IndexExtra any] struct {
Tables []Table[ConstraintExtra, IndexExtra] `json:"tables"`
Enums []Enum `json:"enums"`
ExtraInfo DBExtra `json:"extra_info"`
Tables Tables[ConstraintExtra, IndexExtra] `json:"tables"`
QueryFolders []QueryFolder `json:"query_folders"`
Enums []Enum `json:"enums"`
ExtraInfo DBExtra `json:"extra_info"`
// DriverName is the module name of the underlying `database/sql` driver
DriverName string `json:"driver_name"`
}
Expand Down
53 changes: 53 additions & 0 deletions gen/drivers/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package drivers

type QueryFolder struct {
Path string
Files []QueryFile
}

type QueryFile struct {
Path string
Queries []Query
}

type Query struct {
Name string `yaml:"name"`
SQL string `yaml:"raw"`
RowName string `yaml:"row_name"`
GenerateRow bool `yaml:"generate_row"`

Columns []QueryArg `yaml:"columns"`
Args []QueryArg `yaml:"args"`
}

type QueryArg struct {
Name string `yaml:"name"`
Nullable bool `yaml:"nullable"`
TypeName string `yaml:"type"`
Refs []Ref `yaml:"refs"`
}

type Ref struct {
Key string `yaml:"key"`
Column string `yaml:"column"`
}

type db interface {
GetColumn(key string, col string) Column
}

func (c QueryArg) Type(db db) string {
if len(c.Refs) == 0 {
return c.TypeName
}

ref := db.GetColumn(c.Refs[0].Key, c.Refs[0].Column).Type

for _, r := range c.Refs[1:] {
if ref != db.GetColumn(r.Key, r.Column).Type {
return c.TypeName
}
}

return ref
}
78 changes: 58 additions & 20 deletions gen/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ func Run[T, C, I any](ctx context.Context, s *State[C], driver drivers.Interface
data := &TemplateData[T, C, I]{
Dialect: driver.Dialect(),
Tables: dbInfo.Tables,
QueryFolders: dbInfo.QueryFolders,
Enums: dbInfo.Enums,
ExtraInfo: dbInfo.ExtraInfo,
Aliases: s.Config.Aliases,
Expand Down Expand Up @@ -162,17 +163,14 @@ func generate[T, C, I any](s *State[C], data *TemplateData[T, C, I], goVersion s
templateHeaderByteBuffer := &bytes.Buffer{}

for _, o := range s.Outputs {
if len(o.Templates) == 0 {
continue
}

if _, ok := knownKeys[o.Key]; ok {
return fmt.Errorf("Duplicate output key: %q", o.Key)
}
knownKeys[o.Key] = struct{}{}

// set the package name for this output
data.PkgName = o.PkgName
if len(o.Templates) == 0 {
continue
}

if err := o.initTemplates(s.CustomTemplateFuncs); err != nil {
return fmt.Errorf("unable to initialize templates: %w", err)
Expand All @@ -182,26 +180,66 @@ func generate[T, C, I any](s *State[C], data *TemplateData[T, C, I], goVersion s
continue
}

if err := o.initOutFolders(s.Config.Wipe); err != nil {
return fmt.Errorf("unable to initialize the output folders: %w", err)
}
iterator := slices.Values([]struct{}{{}})

// assign reusable scratch buffers to provided Output
o.templateByteBuffer = templateByteBuffer
o.templateHeaderByteBuffer = templateHeaderByteBuffer
if o.Key == "queries" {
iterator = func(yield func(struct{}) bool) {
for _, folder := range data.QueryFolders {
o.PkgName = filepath.Base(folder.Path)
o.OutFolder = folder.Path
data.QueryFolder = folder

if err := generateSingletonOutput(o, data, goVersion, s.Config.NoTests); err != nil {
return fmt.Errorf("singleton template output: %w", err)
if !yield(struct{}{}) {
return
}
}
}
}

dirExtMap := groupTemplates(o.tableTemplates)
for range iterator {
// set the package name for this output
data.PkgName = o.PkgName

if err := o.initOutFolders(s.Config.Wipe); err != nil {
return fmt.Errorf("unable to initialize the output folders: %w", err)
}

// assign reusable scratch buffers to provided Output
o.templateByteBuffer = templateByteBuffer
o.templateHeaderByteBuffer = templateHeaderByteBuffer

if err := generateSingletonOutput(o, data, goVersion, s.Config.NoTests); err != nil {
return fmt.Errorf("singleton template output: %w", err)
}

dirExtMap := groupTemplates(o.tableTemplates)

for _, table := range data.Tables {
data.Table = table

// Generate the regular templates
if err := generateOutput(o, dirExtMap, o.tableTemplates, data, goVersion, s.Config.NoTests); err != nil {
return fmt.Errorf("unable to generate output: %w", err)
}
}

if len(data.QueryFolder.Files) == 0 {
continue
}

dirExtMap = groupTemplates(o.queryTemplates)
for _, file := range data.QueryFolder.Files {
data.QueryFile = file

for _, table := range data.Tables {
data.Table = table
// We do this so that the name of the file is correct
base := filepath.Base(file.Path)
data.Table = drivers.Table[C, I]{
Name: base[:len(base)-4],
}

// Generate the regular templates
if err := generateOutput(o, dirExtMap, data, goVersion, s.Config.NoTests); err != nil {
return fmt.Errorf("unable to generate output: %w", err)
if err := generateOutput(o, dirExtMap, o.queryTemplates, data, goVersion, s.Config.NoTests); err != nil {
return fmt.Errorf("unable to generate output: %w", err)
}
}
}
}
Expand Down
Loading
Loading