Skip to content

Commit 8879fd7

Browse files
committed
feat(sqlc): add skip_queries configuration for selective query generation
The changes introduce a new `skip_queries` configuration option to allow selective query generation in the SQL template. This feature enables users to exclude specific query names from being generated, providing more granular control over the database query template generation process. Key modifications include: - Added `SkipQueries []string` field to the `SQL` struct in config - Implemented `GetSkipQueriesSet()` method to create an efficient lookup map - Updated template generation to conditionally skip queries based on `skip_queries` configuration - Added corresponding tests to verify the new skip queries functionality
1 parent 3259507 commit 8879fd7

6 files changed

Lines changed: 296 additions & 42 deletions

File tree

internal/sqlc/config.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,18 @@ func LoadConfig(path string) (*Config, error) {
5353
// Each SQL block defines the schema files, query files, and database engine
5454
// for a specific code generation target.
5555
type SQL struct {
56-
Schema string `yaml:"schema"`
57-
Queries string `yaml:"queries"`
58-
Engine string `yaml:"engine"`
56+
Schema string `yaml:"schema"`
57+
Engine string `yaml:"engine"`
58+
Queries string `yaml:"queries"`
59+
SkipQueries []string `yaml:"skip_queries,omitempty"`
60+
}
61+
62+
// GetSkipQueriesSet returns a set of query names to skip for efficient lookup.
63+
// The returned map allows O(1) lookup to check if a query should be skipped.
64+
func (s *SQL) GetSkipQueriesSet() map[string]bool {
65+
skipSet := make(map[string]bool, len(s.SkipQueries))
66+
for _, name := range s.SkipQueries {
67+
skipSet[name] = true
68+
}
69+
return skipSet
5970
}

internal/sqlc/config_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ var _ = Describe("Config", func() {
1515
Expect(config).NotTo(BeNil())
1616
})
1717

18+
It("loads a config file with skip_queries", func() {
19+
config, err := sqlc.LoadConfig("./config_test_exclude.yaml")
20+
Expect(err).NotTo(HaveOccurred())
21+
Expect(config).NotTo(BeNil())
22+
Expect(config.SQL).To(HaveLen(1))
23+
Expect(config.SQL[0].SkipQueries).To(HaveLen(3))
24+
Expect(config.SQL[0].SkipQueries).To(ContainElements("DeleteUser", "UpdateAuditLog", "GetUserByEmail"))
25+
})
26+
1827
When("the file does not exist", func() {
1928
It("returns an error", func() {
2029
config, err := sqlc.LoadConfig("./config_test.json")
@@ -31,4 +40,45 @@ var _ = Describe("Config", func() {
3140
})
3241
})
3342
})
43+
44+
Describe("SQL.GetSkipQueriesSet", func() {
45+
It("returns an empty map when skip_queries is nil", func() {
46+
sql := sqlc.SQL{}
47+
skipSet := sql.GetSkipQueriesSet()
48+
Expect(skipSet).NotTo(BeNil())
49+
Expect(skipSet).To(BeEmpty())
50+
})
51+
52+
It("returns an empty map when skip_queries is empty", func() {
53+
sql := sqlc.SQL{
54+
SkipQueries: []string{},
55+
}
56+
skipSet := sql.GetSkipQueriesSet()
57+
Expect(skipSet).NotTo(BeNil())
58+
Expect(skipSet).To(BeEmpty())
59+
})
60+
61+
It("returns a map with correct query names", func() {
62+
sql := sqlc.SQL{
63+
SkipQueries: []string{"DeleteUser", "UpdateAuditLog", "GetUserByEmail"},
64+
}
65+
skipSet := sql.GetSkipQueriesSet()
66+
Expect(skipSet).To(HaveLen(3))
67+
Expect(skipSet["DeleteUser"]).To(BeTrue())
68+
Expect(skipSet["UpdateAuditLog"]).To(BeTrue())
69+
Expect(skipSet["GetUserByEmail"]).To(BeTrue())
70+
Expect(skipSet["OtherQuery"]).To(BeFalse())
71+
})
72+
73+
It("provides O(1) lookup", func() {
74+
sql := sqlc.SQL{
75+
SkipQueries: []string{"Query1", "Query2", "Query3"},
76+
}
77+
skipSet := sql.GetSkipQueriesSet()
78+
_, exists := skipSet["Query2"]
79+
Expect(exists).To(BeTrue())
80+
_, exists = skipSet["NonExistent"]
81+
Expect(exists).To(BeFalse())
82+
})
83+
})
3484
})

internal/sqlc/generator.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ type Generator struct {
2525
func (x *Generator) Generate() error {
2626
// Context holds data for template execution
2727
type Context struct {
28-
Engine string
29-
Schema string
30-
Table *Table
28+
Engine string
29+
Schema string
30+
Table *Table
31+
SkipQueries map[string]bool
3132
}
3233

3334
opts := map[string]any{
@@ -144,6 +145,13 @@ func (x *Generator) Generate() error {
144145
}
145146
return ""
146147
},
148+
// Query skip function
149+
"should_skip": func(ctx Context, queryName string) bool {
150+
if ctx.SkipQueries == nil {
151+
return false
152+
}
153+
return ctx.SkipQueries[queryName]
154+
},
147155
}
148156

149157
// Open the template file
@@ -157,6 +165,8 @@ func (x *Generator) Generate() error {
157165
return err
158166
}
159167

168+
skipQueries := config.GetSkipQueriesSet()
169+
160170
for _, schema := range x.Catalog.Schemas {
161171
for _, table := range schema.Tables {
162172
file, err := os.Create(
@@ -170,9 +180,10 @@ func (x *Generator) Generate() error {
170180
defer file.Close()
171181

172182
ctx := Context{
173-
Engine: config.Engine,
174-
Schema: schema.Name,
175-
Table: &table,
183+
Engine: config.Engine,
184+
Schema: schema.Name,
185+
Table: &table,
186+
SkipQueries: skipQueries,
176187
}
177188
// Execute template
178189
if err := template.Execute(file, ctx); err != nil {

internal/sqlc/generator_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,104 @@ var _ = Describe("Generator", func() {
7070
}
7171
})
7272
})
73+
74+
Context("with skip_queries configuration", func() {
75+
BeforeEach(func() {
76+
dir, err := os.MkdirTemp("", "sqlc-gen-test-exclude-*")
77+
Expect(err).NotTo(HaveOccurred())
78+
79+
catalog, err := sqlc.LoadCatalog("./catalog_test.json")
80+
Expect(err).NotTo(HaveOccurred())
81+
82+
generator = &sqlc.Generator{
83+
Catalog: catalog,
84+
Config: &sqlc.Config{
85+
Version: "2",
86+
SQL: []sqlc.SQL{
87+
{
88+
Schema: "schema.sql",
89+
Engine: "postgresql",
90+
Queries: dir,
91+
SkipQueries: []string{
92+
"GetUser",
93+
"DeleteUser",
94+
"BatchGetUsers",
95+
},
96+
},
97+
},
98+
},
99+
}
100+
})
101+
102+
It("does not generate skipped queries", func() {
103+
Expect(generator.Generate()).NotTo(HaveOccurred())
104+
105+
for _, config := range generator.Config.SQL {
106+
path := filepath.Join(config.Queries, "users.sql")
107+
Expect(path).To(BeAnExistingFile())
108+
content, err := os.ReadFile(path)
109+
Expect(err).NotTo(HaveOccurred())
110+
111+
// Verify excluded queries are not present
112+
Expect(string(content)).NotTo(ContainSubstring("name: GetUser :one"))
113+
Expect(string(content)).NotTo(ContainSubstring("name: DeleteUser :one"))
114+
Expect(string(content)).NotTo(ContainSubstring("name: BatchGetUsers :batchone"))
115+
116+
// Verify other queries are still present
117+
Expect(string(content)).To(ContainSubstring("name: InsertUser :one"))
118+
Expect(string(content)).To(ContainSubstring("name: UpdateUser :one"))
119+
}
120+
})
121+
122+
It("generates all queries when skip_queries is empty", func() {
123+
generator.Config.SQL[0].SkipQueries = []string{}
124+
Expect(generator.Generate()).NotTo(HaveOccurred())
125+
126+
for _, config := range generator.Config.SQL {
127+
path := filepath.Join(config.Queries, "users.sql")
128+
Expect(path).To(BeAnExistingFile())
129+
content, err := os.ReadFile(path)
130+
Expect(err).NotTo(HaveOccurred())
131+
132+
// Verify all queries are present
133+
Expect(string(content)).To(ContainSubstring("name: GetUser :one"))
134+
Expect(string(content)).To(ContainSubstring("name: DeleteUser :one"))
135+
Expect(string(content)).To(ContainSubstring("name: InsertUser :one"))
136+
Expect(string(content)).To(ContainSubstring("name: UpdateUser :one"))
137+
}
138+
})
139+
140+
It("generates all queries when skip_queries is nil", func() {
141+
generator.Config.SQL[0].SkipQueries = nil
142+
Expect(generator.Generate()).NotTo(HaveOccurred())
143+
144+
for _, config := range generator.Config.SQL {
145+
path := filepath.Join(config.Queries, "users.sql")
146+
Expect(path).To(BeAnExistingFile())
147+
content, err := os.ReadFile(path)
148+
Expect(err).NotTo(HaveOccurred())
149+
150+
// Verify all queries are present
151+
Expect(string(content)).To(ContainSubstring("name: GetUser :one"))
152+
Expect(string(content)).To(ContainSubstring("name: DeleteUser :one"))
153+
}
154+
})
155+
156+
It("handles non-existent query names gracefully", func() {
157+
generator.Config.SQL[0].SkipQueries = []string{"NonExistentQuery", "AnotherFakeQuery"}
158+
Expect(generator.Generate()).NotTo(HaveOccurred())
159+
160+
for _, config := range generator.Config.SQL {
161+
path := filepath.Join(config.Queries, "users.sql")
162+
Expect(path).To(BeAnExistingFile())
163+
content, err := os.ReadFile(path)
164+
Expect(err).NotTo(HaveOccurred())
165+
166+
// Verify all real queries are still present
167+
Expect(string(content)).To(ContainSubstring("name: GetUser :one"))
168+
Expect(string(content)).To(ContainSubstring("name: InsertUser :one"))
169+
}
170+
})
171+
})
73172
})
74173
})

0 commit comments

Comments
 (0)