From 1d2cff0b603a9dc9dbc652382c9d5f080dc084a4 Mon Sep 17 00:00:00 2001 From: Okan YILDIRIM <63511519+ragokan@users.noreply.github.com> Date: Wed, 10 Jun 2026 11:18:39 +0300 Subject: [PATCH 1/2] Add insert column exclusion option --- README.md | 11 +++++++ internal/sqlc/config.go | 35 ++++++++++++++++++-- internal/sqlc/config_test.go | 36 +++++++++++++++++++++ internal/sqlc/config_test_exclude.yaml | 5 +++ internal/sqlc/generator.go | 32 ++++++++++++------ internal/sqlc/generator_test.go | 41 ++++++++++++++++++++++++ internal/sqlc/template/template.sql.tmpl | 20 ++++++------ internal/sqlc/template/template_test.go | 2 ++ 8 files changed, 160 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 3b92e6b..71a2996 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,11 @@ sql: - "CopyUsers" exclude: - "DeleteUser" + insert_columns: + exclude: + - "id" + - "created_at" + - "updated_at" ``` Use `options.tables` to control which tables get query files. Entries may be @@ -95,6 +100,12 @@ are query names (e.g. `GetUser`, `ListPostsByTitle`). > list form (`queries: ["CopyUsers"]`) is no longer supported — move those > entries under `queries.include`. +Use `options.insert_columns.exclude` to remove database-owned columns from +generated `INSERT`, batch insert, and `COPY` queries. Entries may be plain +column names (`id`), table-qualified names (`users.id`), or schema-qualified +names (`auth.users.id`). This is useful for columns with database defaults such +as generated IDs and timestamps. + ### Default queries (always generated) Primary key CRUD operations, List queries (including FK-index-based list diff --git a/internal/sqlc/config.go b/internal/sqlc/config.go index c5e0c26..276d74b 100644 --- a/internal/sqlc/config.go +++ b/internal/sqlc/config.go @@ -71,8 +71,9 @@ type Codegen struct { // CodegenOptions holds plugin-specific options for the gen-queries plugin. type CodegenOptions struct { - Queries QueryOptions `yaml:"queries,omitempty"` - Tables TableOptions `yaml:"tables,omitempty"` + Queries QueryOptions `yaml:"queries,omitempty"` + Tables TableOptions `yaml:"tables,omitempty"` + InsertColumns ColumnOptions `yaml:"insert_columns,omitempty"` } // QueryOptions holds query-level filtering options for the gen-queries plugin. @@ -92,6 +93,11 @@ type TableOptions struct { Exclude []string `yaml:"exclude,omitempty"` } +// ColumnOptions holds column-level filtering options. +type ColumnOptions struct { + Exclude []string `yaml:"exclude,omitempty"` +} + // GetOptions returns the CodegenOptions for the gen-queries plugin. // If no matching codegen entry is found, returns an empty CodegenOptions. func (s *SQL) GetOptions() CodegenOptions { @@ -148,6 +154,18 @@ func (s *SQL) GetExcludeSet() map[string]bool { return excludeSet } +// GetInsertColumnExcludeSet returns the deny-list of columns to skip in +// generated INSERT/COPY statements. Entries may be column names, table-qualified +// column names, or schema-qualified table column names. +func (s *SQL) GetInsertColumnExcludeSet() map[string]bool { + opts := s.GetOptions() + excludeSet := make(map[string]bool, len(opts.InsertColumns.Exclude)) + for _, name := range opts.InsertColumns.Exclude { + excludeSet[name] = true + } + return excludeSet +} + // tableSelected reports whether a table should have query files generated. // Exclude always takes precedence over include; an empty include set matches // every table. Both sets are checked against the unqualified table name and @@ -162,3 +180,16 @@ func tableSelected(includeSet, excludeSet map[string]bool, schema, table string) } return includeSet[table] || includeSet[qualified] } + +func insertColumnSelected(excludeSet map[string]bool, schema, table, column string) bool { + if excludeSet[column] { + return false + } + if excludeSet[table+"."+column] { + return false + } + if excludeSet[schema+"."+table+"."+column] { + return false + } + return true +} diff --git a/internal/sqlc/config_test.go b/internal/sqlc/config_test.go index 835268e..6468995 100644 --- a/internal/sqlc/config_test.go +++ b/internal/sqlc/config_test.go @@ -27,6 +27,7 @@ var _ = Describe("Config", func() { Expect(opts.Queries.Include).To(HaveLen(2)) Expect(opts.Queries.Include).To(ContainElements("CopyUsers", "GetUserByEmail")) Expect(opts.Tables.Exclude).To(ContainElement("posts")) + Expect(opts.InsertColumns.Exclude).To(ContainElements("id", "users.created_at", "public.users.updated_at")) }) When("the file does not exist", func() { @@ -74,6 +75,9 @@ var _ = Describe("Config", func() { Options: sqlc.CodegenOptions{ Queries: sqlc.QueryOptions{Include: []string{"ListUsers", "CopyUsers"}}, Tables: sqlc.TableOptions{Exclude: []string{"audit_logs"}}, + InsertColumns: sqlc.ColumnOptions{ + Exclude: []string{"id", "created_at", "updated_at"}, + }, }, }, }, @@ -82,6 +86,7 @@ var _ = Describe("Config", func() { Expect(opts.Queries.Include).To(HaveLen(2)) Expect(opts.Queries.Include).To(ContainElements("ListUsers", "CopyUsers")) Expect(opts.Tables.Exclude).To(ContainElement("audit_logs")) + Expect(opts.InsertColumns.Exclude).To(ContainElements("id", "created_at", "updated_at")) }) }) @@ -242,4 +247,35 @@ var _ = Describe("Config", func() { Expect(includeSet["posts"]).To(BeFalse()) }) }) + + Describe("SQL.GetInsertColumnExcludeSet", func() { + It("returns an empty map when codegen is nil", func() { + sql := sqlc.SQL{} + excludeSet := sql.GetInsertColumnExcludeSet() + Expect(excludeSet).NotTo(BeNil()) + Expect(excludeSet).To(BeEmpty()) + }) + + It("returns a map with excluded insert column names", func() { + sql := sqlc.SQL{ + Codegen: []sqlc.Codegen{ + { + Plugin: "gen-queries", + Out: "out", + Options: sqlc.CodegenOptions{ + InsertColumns: sqlc.ColumnOptions{ + Exclude: []string{"id", "todos.created_at", "public.todos.updated_at"}, + }, + }, + }, + }, + } + excludeSet := sql.GetInsertColumnExcludeSet() + Expect(excludeSet).To(HaveLen(3)) + Expect(excludeSet["id"]).To(BeTrue()) + Expect(excludeSet["todos.created_at"]).To(BeTrue()) + Expect(excludeSet["public.todos.updated_at"]).To(BeTrue()) + Expect(excludeSet["title"]).To(BeFalse()) + }) + }) }) diff --git a/internal/sqlc/config_test_exclude.yaml b/internal/sqlc/config_test_exclude.yaml index 4642237..24d8b79 100644 --- a/internal/sqlc/config_test_exclude.yaml +++ b/internal/sqlc/config_test_exclude.yaml @@ -18,3 +18,8 @@ sql: include: - "CopyUsers" - "GetUserByEmail" + insert_columns: + exclude: + - "id" + - "users.created_at" + - "public.users.updated_at" diff --git a/internal/sqlc/generator.go b/internal/sqlc/generator.go index 3e27725..2555c74 100644 --- a/internal/sqlc/generator.go +++ b/internal/sqlc/generator.go @@ -30,11 +30,12 @@ type Generator struct { func (x *Generator) Generate() error { // Context holds data for template execution type Context struct { - Engine string - Schema string - Table *Table - QueryInclude map[string]bool - QueryExclude map[string]bool + Engine string + Schema string + Table *Table + QueryInclude map[string]bool + QueryExclude map[string]bool + InsertColumnExclude map[string]bool } opts := map[string]any{ @@ -153,6 +154,15 @@ func (x *Generator) Generate() error { } return isDefault || ctx.QueryInclude[queryName] }, + "insert_columns": func(ctx Context) []Column { + columns := make([]Column, 0, len(ctx.Table.Columns)) + for _, column := range ctx.Table.Columns { + if insertColumnSelected(ctx.InsertColumnExclude, ctx.Schema, ctx.Table.Name, column.Name) { + columns = append(columns, column) + } + } + return columns + }, } // Open the template file @@ -168,6 +178,7 @@ func (x *Generator) Generate() error { queryInclude := config.GetQueryIncludeSet() queryExclude := config.GetQueryExcludeSet() + insertColumnExclude := config.GetInsertColumnExcludeSet() include := config.GetIncludeSet() exclude := config.GetExcludeSet() @@ -188,11 +199,12 @@ func (x *Generator) Generate() error { defer file.Close() ctx := Context{ - Engine: config.Engine, - Schema: schema.Name, - Table: &table, - QueryInclude: queryInclude, - QueryExclude: queryExclude, + Engine: config.Engine, + Schema: schema.Name, + Table: &table, + QueryInclude: queryInclude, + QueryExclude: queryExclude, + InsertColumnExclude: insertColumnExclude, } // Execute template into buffer, then squeeze blank lines var buffer bytes.Buffer diff --git a/internal/sqlc/generator_test.go b/internal/sqlc/generator_test.go index 99eaba5..05afdbe 100644 --- a/internal/sqlc/generator_test.go +++ b/internal/sqlc/generator_test.go @@ -231,6 +231,47 @@ var _ = Describe("Generator", func() { } }) + It("excludes configured columns from insert queries", func() { + dir := generator.Config.SQL[0].Queries + generator.Config.SQL[0].Codegen = []sqlc.Codegen{ + { + Plugin: "gen-queries", + Out: dir, + Options: sqlc.CodegenOptions{ + InsertColumns: sqlc.ColumnOptions{ + Exclude: []string{"id"}, + }, + }, + }, + } + + Expect(generator.Generate()).NotTo(HaveOccurred()) + + content, err := os.ReadFile(filepath.Join(dir, "users.sql")) + Expect(err).NotTo(HaveOccurred()) + + Expect(string(content)).To(ContainSubstring(`-- name: InsertUser :one +INSERT INTO users ( + email, + name +) VALUES ( + sqlc.arg(email), + sqlc.narg(name) +) +RETURNING *;`)) + Expect(string(content)).To(ContainSubstring(`-- name: ExecInsertUser :exec +INSERT INTO users ( + email, + name +) VALUES ( + sqlc.arg(email), + sqlc.narg(name) +);`)) + Expect(string(content)).NotTo(ContainSubstring(`-- name: InsertUser :one +INSERT INTO users ( + id,`)) + }) + When("the queries directory does not exist", func() { It("returns an error", func() { for index := range generator.Config.SQL { diff --git a/internal/sqlc/template/template.sql.tmpl b/internal/sqlc/template/template.sql.tmpl index c60244b..a40746a 100644 --- a/internal/sqlc/template/template.sql.tmpl +++ b/internal/sqlc/template/template.sql.tmpl @@ -201,11 +201,11 @@ WHERE -- Returns the inserted row with all fields populated. -- name: {{$query_name}} :one INSERT INTO {{.Table.Name}} ( -{{ range $i, $column := .Table.Columns}}{{if $i}}, +{{ range $i, $column := insert_columns $}}{{if $i}}, {{end}} {{$column.Name}} {{- end}} ) VALUES ( -{{ range $i, $column := .Table.Columns}}{{if $i}}, +{{ range $i, $column := insert_columns $}}{{if $i}}, {{end}} {{query_argument $column}} {{- end}} ) @@ -219,11 +219,11 @@ RETURNING *; -- Returns number of affected rows (should always be 1 on success). -- name: {{$query_name}} :exec INSERT INTO {{.Table.Name}} ( -{{ range $i, $column := .Table.Columns}}{{if $i}}, +{{ range $i, $column := insert_columns $}}{{if $i}}, {{end}} {{$column.Name}} {{- end}} ) VALUES ( -{{ range $i, $column := .Table.Columns}}{{if $i}}, +{{ range $i, $column := insert_columns $}}{{if $i}}, {{end}} {{query_argument $column}} {{- end}} ); @@ -236,11 +236,11 @@ INSERT INTO {{.Table.Name}} ( -- Executes the insert once for each provided set of values and returns inserted rows. -- name: {{$query_name}} :batchone INSERT INTO {{.Table.Name}} ( -{{ range $i, $column := .Table.Columns}}{{if $i}}, +{{ range $i, $column := insert_columns $}}{{if $i}}, {{end}} {{$column.Name}} {{- end}} ) VALUES ( -{{ range $i, $column := .Table.Columns}}{{if $i}}, +{{ range $i, $column := insert_columns $}}{{if $i}}, {{end}} {{query_argument $column}} {{- end}} ) @@ -254,11 +254,11 @@ RETURNING *; -- Executes the insert once for each provided set of values and returns number of affected rows. -- name: {{$query_name}} :batchexec INSERT INTO {{.Table.Name}} ( -{{ range $i, $column := .Table.Columns}}{{if $i}}, +{{ range $i, $column := insert_columns $}}{{if $i}}, {{end}} {{$column.Name}} {{- end}} ) VALUES ( -{{ range $i, $column := .Table.Columns}}{{if $i}}, +{{ range $i, $column := insert_columns $}}{{if $i}}, {{end}} {{query_argument $column}} {{- end}} ); @@ -270,11 +270,11 @@ INSERT INTO {{.Table.Name}} ( -- This is the fastest way to insert large amounts of data. Does not return inserted rows. -- name: {{$query_name}} :copyfrom INSERT INTO {{.Table.Name}} ( -{{ range $i, $column := .Table.Columns}}{{if $i}}, +{{ range $i, $column := insert_columns $}}{{if $i}}, {{end}} {{$column.Name}} {{- end}} ) VALUES ( -{{ range $i, $column := .Table.Columns}}{{if $i}}, +{{ range $i, $column := insert_columns $}}{{if $i}}, {{end}} {{query_argument $column}} {{- end}} ); diff --git a/internal/sqlc/template/template_test.go b/internal/sqlc/template/template_test.go index f41d66b..80fa215 100644 --- a/internal/sqlc/template/template_test.go +++ b/internal/sqlc/template/template_test.go @@ -27,6 +27,8 @@ var _ = Describe("Template", func() { "is_fk_index": func(args ...any) bool { return false }, // Query selection function "should_generate": func(args ...any) bool { return false }, + // Insert column filtering + "insert_columns": func(args ...any) []any { return nil }, } It("opens and parses template successfully", func() { From 66555539fc0bbfc8ed73211993feff21e93dd728 Mon Sep 17 00:00:00 2001 From: Okan YILDIRIM <63511519+ragokan@users.noreply.github.com> Date: Wed, 10 Jun 2026 12:35:30 +0300 Subject: [PATCH 2/2] Add update column exclusion option --- README.md | 9 ++++++ internal/sqlc/config.go | 15 +++++++++- internal/sqlc/config_test.go | 36 ++++++++++++++++++++++++ internal/sqlc/config_test_exclude.yaml | 5 ++++ internal/sqlc/generator.go | 15 +++++++++- internal/sqlc/generator_test.go | 33 ++++++++++++++++++++++ internal/sqlc/template/template.sql.tmpl | 32 ++++++++++----------- internal/sqlc/template/template_test.go | 2 ++ 8 files changed, 129 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 71a2996..99a133c 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,10 @@ sql: - "id" - "created_at" - "updated_at" + update_columns: + exclude: + - "created_at" + - "updated_at" ``` Use `options.tables` to control which tables get query files. Entries may be @@ -106,6 +110,11 @@ column names (`id`), table-qualified names (`users.id`), or schema-qualified names (`auth.users.id`). This is useful for columns with database defaults such as generated IDs and timestamps. +Use `options.update_columns.exclude` to remove columns from generated `UPDATE` +queries. Entries support the same plain, table-qualified, and schema-qualified +forms. Generated update masks are cast to `text[]`, so sqlc emits strongly typed +`[]string` update masks for PostgreSQL targets. + ### Default queries (always generated) Primary key CRUD operations, List queries (including FK-index-based list diff --git a/internal/sqlc/config.go b/internal/sqlc/config.go index 276d74b..00bec5a 100644 --- a/internal/sqlc/config.go +++ b/internal/sqlc/config.go @@ -74,6 +74,7 @@ type CodegenOptions struct { Queries QueryOptions `yaml:"queries,omitempty"` Tables TableOptions `yaml:"tables,omitempty"` InsertColumns ColumnOptions `yaml:"insert_columns,omitempty"` + UpdateColumns ColumnOptions `yaml:"update_columns,omitempty"` } // QueryOptions holds query-level filtering options for the gen-queries plugin. @@ -166,6 +167,18 @@ func (s *SQL) GetInsertColumnExcludeSet() map[string]bool { return excludeSet } +// GetUpdateColumnExcludeSet returns the deny-list of columns to skip in +// generated UPDATE statements. Entries may be column names, table-qualified +// column names, or schema-qualified table column names. +func (s *SQL) GetUpdateColumnExcludeSet() map[string]bool { + opts := s.GetOptions() + excludeSet := make(map[string]bool, len(opts.UpdateColumns.Exclude)) + for _, name := range opts.UpdateColumns.Exclude { + excludeSet[name] = true + } + return excludeSet +} + // tableSelected reports whether a table should have query files generated. // Exclude always takes precedence over include; an empty include set matches // every table. Both sets are checked against the unqualified table name and @@ -181,7 +194,7 @@ func tableSelected(includeSet, excludeSet map[string]bool, schema, table string) return includeSet[table] || includeSet[qualified] } -func insertColumnSelected(excludeSet map[string]bool, schema, table, column string) bool { +func columnSelected(excludeSet map[string]bool, schema, table, column string) bool { if excludeSet[column] { return false } diff --git a/internal/sqlc/config_test.go b/internal/sqlc/config_test.go index 6468995..407e40e 100644 --- a/internal/sqlc/config_test.go +++ b/internal/sqlc/config_test.go @@ -28,6 +28,7 @@ var _ = Describe("Config", func() { Expect(opts.Queries.Include).To(ContainElements("CopyUsers", "GetUserByEmail")) Expect(opts.Tables.Exclude).To(ContainElement("posts")) Expect(opts.InsertColumns.Exclude).To(ContainElements("id", "users.created_at", "public.users.updated_at")) + Expect(opts.UpdateColumns.Exclude).To(ContainElements("created_at", "users.updated_at", "public.users.deleted_at")) }) When("the file does not exist", func() { @@ -78,6 +79,9 @@ var _ = Describe("Config", func() { InsertColumns: sqlc.ColumnOptions{ Exclude: []string{"id", "created_at", "updated_at"}, }, + UpdateColumns: sqlc.ColumnOptions{ + Exclude: []string{"created_at", "updated_at"}, + }, }, }, }, @@ -87,6 +91,7 @@ var _ = Describe("Config", func() { Expect(opts.Queries.Include).To(ContainElements("ListUsers", "CopyUsers")) Expect(opts.Tables.Exclude).To(ContainElement("audit_logs")) Expect(opts.InsertColumns.Exclude).To(ContainElements("id", "created_at", "updated_at")) + Expect(opts.UpdateColumns.Exclude).To(ContainElements("created_at", "updated_at")) }) }) @@ -278,4 +283,35 @@ var _ = Describe("Config", func() { Expect(excludeSet["title"]).To(BeFalse()) }) }) + + Describe("SQL.GetUpdateColumnExcludeSet", func() { + It("returns an empty map when codegen is nil", func() { + sql := sqlc.SQL{} + excludeSet := sql.GetUpdateColumnExcludeSet() + Expect(excludeSet).NotTo(BeNil()) + Expect(excludeSet).To(BeEmpty()) + }) + + It("returns a map with excluded update column names", func() { + sql := sqlc.SQL{ + Codegen: []sqlc.Codegen{ + { + Plugin: "gen-queries", + Out: "out", + Options: sqlc.CodegenOptions{ + UpdateColumns: sqlc.ColumnOptions{ + Exclude: []string{"created_at", "todos.updated_at", "public.todos.user_id"}, + }, + }, + }, + }, + } + excludeSet := sql.GetUpdateColumnExcludeSet() + Expect(excludeSet).To(HaveLen(3)) + Expect(excludeSet["created_at"]).To(BeTrue()) + Expect(excludeSet["todos.updated_at"]).To(BeTrue()) + Expect(excludeSet["public.todos.user_id"]).To(BeTrue()) + Expect(excludeSet["title"]).To(BeFalse()) + }) + }) }) diff --git a/internal/sqlc/config_test_exclude.yaml b/internal/sqlc/config_test_exclude.yaml index 24d8b79..8216cff 100644 --- a/internal/sqlc/config_test_exclude.yaml +++ b/internal/sqlc/config_test_exclude.yaml @@ -23,3 +23,8 @@ sql: - "id" - "users.created_at" - "public.users.updated_at" + update_columns: + exclude: + - "created_at" + - "users.updated_at" + - "public.users.deleted_at" diff --git a/internal/sqlc/generator.go b/internal/sqlc/generator.go index 2555c74..3b0629c 100644 --- a/internal/sqlc/generator.go +++ b/internal/sqlc/generator.go @@ -36,6 +36,7 @@ func (x *Generator) Generate() error { QueryInclude map[string]bool QueryExclude map[string]bool InsertColumnExclude map[string]bool + UpdateColumnExclude map[string]bool } opts := map[string]any{ @@ -157,7 +158,17 @@ func (x *Generator) Generate() error { "insert_columns": func(ctx Context) []Column { columns := make([]Column, 0, len(ctx.Table.Columns)) for _, column := range ctx.Table.Columns { - if insertColumnSelected(ctx.InsertColumnExclude, ctx.Schema, ctx.Table.Name, column.Name) { + if columnSelected(ctx.InsertColumnExclude, ctx.Schema, ctx.Table.Name, column.Name) { + columns = append(columns, column) + } + } + return columns + }, + "update_columns": func(ctx Context) []Column { + tableColumns := ctx.Table.GetNonPrimaryKeyColumns() + columns := make([]Column, 0, len(tableColumns)) + for _, column := range tableColumns { + if columnSelected(ctx.UpdateColumnExclude, ctx.Schema, ctx.Table.Name, column.Name) { columns = append(columns, column) } } @@ -179,6 +190,7 @@ func (x *Generator) Generate() error { queryInclude := config.GetQueryIncludeSet() queryExclude := config.GetQueryExcludeSet() insertColumnExclude := config.GetInsertColumnExcludeSet() + updateColumnExclude := config.GetUpdateColumnExcludeSet() include := config.GetIncludeSet() exclude := config.GetExcludeSet() @@ -205,6 +217,7 @@ func (x *Generator) Generate() error { QueryInclude: queryInclude, QueryExclude: queryExclude, InsertColumnExclude: insertColumnExclude, + UpdateColumnExclude: updateColumnExclude, } // Execute template into buffer, then squeeze blank lines var buffer bytes.Buffer diff --git a/internal/sqlc/generator_test.go b/internal/sqlc/generator_test.go index 05afdbe..79f0fd7 100644 --- a/internal/sqlc/generator_test.go +++ b/internal/sqlc/generator_test.go @@ -272,6 +272,39 @@ INSERT INTO users ( id,`)) }) + It("excludes configured columns from update queries", func() { + dir := generator.Config.SQL[0].Queries + generator.Config.SQL[0].Codegen = []sqlc.Codegen{ + { + Plugin: "gen-queries", + Out: dir, + Options: sqlc.CodegenOptions{ + UpdateColumns: sqlc.ColumnOptions{ + Exclude: []string{"name"}, + }, + }, + }, + } + + Expect(generator.Generate()).NotTo(HaveOccurred()) + + content, err := os.ReadFile(filepath.Join(dir, "users.sql")) + Expect(err).NotTo(HaveOccurred()) + + Expect(string(content)).To(ContainSubstring(`-- name: UpdateUser :one +UPDATE users +SET + email = CASE + WHEN 'email' = any(sqlc.arg(update_mask)::text[]) + THEN sqlc.arg(email) + ELSE email + END +WHERE + id = sqlc.arg(id) +RETURNING *;`)) + Expect(string(content)).NotTo(ContainSubstring("name = CASE")) + }) + When("the queries directory does not exist", func() { It("returns an error", func() { for index := range generator.Config.SQL { diff --git a/internal/sqlc/template/template.sql.tmpl b/internal/sqlc/template/template.sql.tmpl index a40746a..57a9adb 100644 --- a/internal/sqlc/template/template.sql.tmpl +++ b/internal/sqlc/template/template.sql.tmpl @@ -76,9 +76,9 @@ WHERE -- name: {{$query_name}} :one UPDATE {{$.Table.Name}} SET -{{ range $i, $column := $.Table.GetNonPrimaryKeyColumns}}{{if $i}}, +{{ range $i, $column := update_columns $}}{{if $i}}, {{end}} {{$column.Name}} = CASE - WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)) + WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)::text[]) THEN {{query_argument $column}} ELSE {{$column.Name}} END @@ -96,9 +96,9 @@ RETURNING *; -- name: {{$query_name}} :exec UPDATE {{$.Table.Name}} SET -{{ range $i, $column := $.Table.GetNonPrimaryKeyColumns}}{{if $i}}, +{{ range $i, $column := update_columns $}}{{if $i}}, {{end}} {{$column.Name}} = CASE - WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)) + WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)::text[]) THEN {{query_argument $column}} ELSE {{$column.Name}} END @@ -115,9 +115,9 @@ WHERE -- name: {{$query_name}} :batchone UPDATE {{$.Table.Name}} SET -{{ range $i, $column := $.Table.GetNonPrimaryKeyColumns}}{{if $i}}, +{{ range $i, $column := update_columns $}}{{if $i}}, {{end}} {{$column.Name}} = CASE - WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)) + WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)::text[]) THEN {{query_argument $column}} ELSE {{$column.Name}} END @@ -135,9 +135,9 @@ RETURNING *; -- name: {{$query_name}} :batchexec UPDATE {{$.Table.Name}} SET -{{ range $i, $column := $.Table.GetNonPrimaryKeyColumns}}{{if $i}}, +{{ range $i, $column := update_columns $}}{{if $i}}, {{end}} {{$column.Name}} = CASE - WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)) + WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)::text[]) THEN {{query_argument $column}} ELSE {{$column.Name}} END @@ -350,9 +350,9 @@ OFFSET -- name: {{$query_name}} :many UPDATE {{$.Table.Name}} SET -{{ range $i, $column := $.Table.Columns}}{{if $i}}, +{{ range $i, $column := update_columns $}}{{if $i}}, {{end}} {{$column.Name}} = CASE - WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)) + WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)::text[]) THEN {{query_argument $column}} ELSE {{$column.Name}} END @@ -373,9 +373,9 @@ RETURNING *; -- name: {{$query_name}} :execrows UPDATE {{$.Table.Name}} SET -{{ range $i, $column := $.Table.Columns}}{{if $i}}, +{{ range $i, $column := update_columns $}}{{if $i}}, {{end}} {{$column.Name}} = CASE - WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)) + WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)::text[]) THEN {{query_argument $column}} ELSE {{$column.Name}} END @@ -395,9 +395,9 @@ WHERE -- name: {{$query_name}} :batchmany UPDATE {{$.Table.Name}} SET -{{ range $i, $column := $.Table.Columns}}{{if $i}}, +{{ range $i, $column := update_columns $}}{{if $i}}, {{end}} {{$column.Name}} = CASE - WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)) + WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)::text[]) THEN {{query_argument $column}} ELSE {{$column.Name}} END @@ -418,9 +418,9 @@ RETURNING *; -- name: {{$query_name}} :batchexec UPDATE {{$.Table.Name}} SET -{{ range $i, $column := $.Table.Columns}}{{if $i}}, +{{ range $i, $column := update_columns $}}{{if $i}}, {{end}} {{$column.Name}} = CASE - WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)) + WHEN '{{$column.Name}}' = any(sqlc.arg(update_mask)::text[]) THEN {{query_argument $column}} ELSE {{$column.Name}} END diff --git a/internal/sqlc/template/template_test.go b/internal/sqlc/template/template_test.go index 80fa215..f12074a 100644 --- a/internal/sqlc/template/template_test.go +++ b/internal/sqlc/template/template_test.go @@ -29,6 +29,8 @@ var _ = Describe("Template", func() { "should_generate": func(args ...any) bool { return false }, // Insert column filtering "insert_columns": func(args ...any) []any { return nil }, + // Update column filtering + "update_columns": func(args ...any) []any { return nil }, } It("opens and parses template successfully", func() {