Skip to content

Commit 819f197

Browse files
authored
Override globs (#1189)
1 parent c8bf991 commit 819f197

File tree

12 files changed

+187
-30
lines changed

12 files changed

+187
-30
lines changed

internal/codegen/golang/go_type.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ func goType(r *compiler.Result, col *compiler.Column, settings config.CombinedSe
1111
if oride.GoTypeName == "" {
1212
continue
1313
}
14-
sameTable := sameTableName(col.Table, oride.Table, r.Catalog.DefaultSchema)
15-
if oride.Column != "" && oride.ColumnName == col.Name && sameTable {
14+
sameTable := oride.Matches(col.Table, r.Catalog.DefaultSchema)
15+
if oride.Column != "" && oride.ColumnName.MatchString(col.Name) && sameTable {
1616
return oride.GoTypeName
1717
}
1818
}

internal/codegen/python/gen.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,8 @@ func pyInnerType(r *compiler.Result, col *compiler.Column, settings config.Combi
181181
if !oride.PythonType.IsSet() {
182182
continue
183183
}
184-
sameTable := sameTableName(col.Table, oride.Table, r.Catalog.DefaultSchema)
185-
if oride.Column != "" && oride.ColumnName == col.Name && sameTable {
184+
sameTable := oride.Matches(col.Table, r.Catalog.DefaultSchema)
185+
if oride.Column != "" && oride.ColumnName.MatchString(col.Name) && sameTable {
186186
return oride.PythonType.TypeString()
187187
}
188188
if oride.DBType != "" && oride.DBType == col.DataType && oride.Nullable != (col.NotNull || col.IsArray) {

internal/config/config.go

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import (
99
"os"
1010
"strings"
1111

12-
"github.com/kyleconroy/sqlc/internal/core"
12+
"github.com/kyleconroy/sqlc/internal/sql/ast"
13+
1314
yaml "gopkg.in/yaml.v3"
1415
)
1516

@@ -165,15 +166,50 @@ type Override struct {
165166
// fully qualified name of the column, e.g. `accounts.id`
166167
Column string `json:"column" yaml:"column"`
167168

168-
ColumnName string
169-
Table core.FQN
169+
ColumnName *Match
170+
TableCatalog *Match
171+
TableSchema *Match
172+
TableRel *Match
170173
GoImportPath string
171174
GoPackage string
172175
GoTypeName string
173176
GoBasicType bool
174177
}
175178

176-
func (o *Override) Parse() error {
179+
func (o *Override) Matches(n *ast.TableName, defaultSchema string) bool {
180+
if n == nil {
181+
return false
182+
}
183+
184+
schema := n.Schema
185+
if n.Schema == "" {
186+
schema = defaultSchema
187+
}
188+
189+
if o.TableCatalog != nil && !o.TableCatalog.MatchString(n.Catalog) {
190+
return false
191+
}
192+
193+
if o.TableSchema == nil && schema != "" {
194+
return false
195+
}
196+
197+
if o.TableSchema != nil && !o.TableSchema.MatchString(schema) {
198+
return false
199+
}
200+
201+
if o.TableRel == nil && n.Name != "" {
202+
return false
203+
}
204+
205+
if o.TableRel != nil && !o.TableRel.MatchString(n.Name) {
206+
return false
207+
}
208+
209+
return true
210+
}
211+
212+
func (o *Override) Parse() (err error) {
177213

178214
// validate deprecated postgres_type field
179215
if o.Deprecated_PostgresType != "" {
@@ -203,16 +239,40 @@ func (o *Override) Parse() error {
203239
colParts := strings.Split(o.Column, ".")
204240
switch len(colParts) {
205241
case 2:
206-
o.ColumnName = colParts[1]
207-
o.Table = core.FQN{Schema: "public", Rel: colParts[0]}
242+
if o.ColumnName, err = MatchCompile(colParts[1]); err != nil {
243+
return err
244+
}
245+
if o.TableRel, err = MatchCompile(colParts[0]); err != nil {
246+
return err
247+
}
248+
if o.TableSchema, err = MatchCompile("public"); err != nil {
249+
return err
250+
}
208251
case 3:
209-
o.ColumnName = colParts[2]
210-
o.Table = core.FQN{Schema: colParts[0], Rel: colParts[1]}
252+
if o.ColumnName, err = MatchCompile(colParts[2]); err != nil {
253+
return err
254+
}
255+
if o.TableRel, err = MatchCompile(colParts[1]); err != nil {
256+
return err
257+
}
258+
if o.TableSchema, err = MatchCompile(colParts[0]); err != nil {
259+
return err
260+
}
211261
case 4:
212-
o.ColumnName = colParts[3]
213-
o.Table = core.FQN{Catalog: colParts[0], Schema: colParts[1], Rel: colParts[2]}
262+
if o.ColumnName, err = MatchCompile(colParts[3]); err != nil {
263+
return err
264+
}
265+
if o.TableRel, err = MatchCompile(colParts[2]); err != nil {
266+
return err
267+
}
268+
if o.TableSchema, err = MatchCompile(colParts[1]); err != nil {
269+
return err
270+
}
271+
if o.TableCatalog, err = MatchCompile(colParts[0]); err != nil {
272+
return err
273+
}
214274
default:
215-
return fmt.Errorf("Override `column` specifier %q is not the proper format, expected '[catalog.][schema.]colname.tablename'", o.Column)
275+
return fmt.Errorf("Override `column` specifier %q is not the proper format, expected '[catalog.][schema.]tablename.colname'", o.Column)
216276
}
217277
}
218278

internal/config/match.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
)
7+
8+
// Match is a wrapper of *regexp.Regexp.
9+
// It contains the match pattern compiled into a regular expression.
10+
type Match struct {
11+
*regexp.Regexp
12+
}
13+
14+
// Compile takes our match expression as a string, and compiles it into a *Match object.
15+
// Will return an error on an invalid pattern.
16+
func MatchCompile(pattern string) (match *Match, err error) {
17+
regex := ""
18+
escaped := false
19+
arr := []byte(pattern)
20+
21+
for i := 0; i < len(arr); i++ {
22+
if escaped {
23+
escaped = false
24+
switch arr[i] {
25+
case '*', '?', '\\':
26+
regex += "\\" + string(arr[i])
27+
default:
28+
return nil, fmt.Errorf("Invalid escaped character '%c'", arr[i])
29+
}
30+
} else {
31+
switch arr[i] {
32+
case '\\':
33+
escaped = true
34+
case '*':
35+
regex += ".*"
36+
case '?':
37+
regex += "."
38+
case '.', '(', ')', '+', '|', '^', '$', '[', ']', '{', '}':
39+
regex += "\\" + string(arr[i])
40+
default:
41+
regex += string(arr[i])
42+
}
43+
}
44+
}
45+
46+
if escaped {
47+
return nil, fmt.Errorf("Unterminated escape at end of pattern")
48+
}
49+
50+
var r *regexp.Regexp
51+
52+
if r, err = regexp.Compile("^" + regex + "$"); err != nil {
53+
return nil, err
54+
}
55+
56+
return &Match{r}, nil
57+
}

internal/core/fqn.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,3 @@ type FQN struct {
77
Schema string
88
Rel string
99
}
10-
11-
func (f FQN) String() string {
12-
s := f.Rel
13-
if f.Schema != "" {
14-
s = f.Schema + "." + s
15-
}
16-
if f.Catalog != "" {
17-
s = f.Catalog + "." + s
18-
}
19-
return s
20-
}

internal/endtoend/testdata/overrides_go_types/mysql/go/models.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/overrides_go_types/mysql/schema.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,15 @@ CREATE TABLE foo (
33
total bigint NOT NULL,
44
retyped text NOT NULL
55
);
6+
7+
CREATE TABLE bar (
8+
other text NOT NULL,
9+
total bigint NOT NULL,
10+
also_retyped text NOT NULL
11+
);
12+
13+
CREATE TABLE baz (
14+
other text NOT NULL,
15+
total bigint NOT NULL,
16+
also_retyped text NOT NULL
17+
);

internal/endtoend/testdata/overrides_go_types/mysql/sqlc.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
{
1212
"go_type": "github.com/kyleconroy/sqlc-testdata/pkg.CustomType",
1313
"column": "foo.retyped"
14+
},
15+
{
16+
"go_type": "github.com/kyleconroy/sqlc-testdata/pkg.CustomType",
17+
"column": "*.also_retyped"
1418
}
1519
]
1620
}

internal/endtoend/testdata/overrides_go_types/postgresql/pgx/go/models.go

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/overrides_go_types/postgresql/pgx/go/query.sql.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/overrides_go_types/postgresql/pgx/schema.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,13 @@ CREATE TABLE foo (
66
bio text,
77
about text
88
);
9+
10+
CREATE TABLE bar (
11+
id uuid NOT NULL,
12+
other_id uuid NOT NULL,
13+
more_id uuid NOT NULL,
14+
age integer,
15+
balance double,
16+
bio text,
17+
about text
18+
);

internal/endtoend/testdata/overrides_go_types/postgresql/pgx/sqlc.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
"queries": "query.sql",
1111
"overrides": [
1212
{
13-
"column": "foo.id",
13+
"column": "*.id",
1414
"go_type": {
1515
"import": "github.com/gofrs/uuid",
16+
"package": "uuid",
1617
"type": "UUID"
1718
},
1819
},
1920
{
20-
"column": "foo.other_id",
21+
"column": "*.*_id",
2122
"go_type": {
2223
"import": "github.com/gofrs/uuid",
2324
"package": "fuid",

0 commit comments

Comments
 (0)