diff --git a/README.md b/README.md index 2d76d7e..39e506b 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Text Interpolation -- [text/template](https://pkg.go.dev/text/template)-style text interpolation is supported. -To use, call `.WithOptions(map[string]interface{})` on your dotsql instance to +To use, call `.WithData(any)` on your dotsql instance to create a new instance which passes those values into the templating library. ```sql @@ -87,7 +87,7 @@ SELECT count(*) FROM users {{if .exclude_deleted}}WHERE deleted IS NULL{{end}} ``` ```go -dotsql.WithOptions(map[string]interface{}{"exclude_deleted": true}).Query(db, "count-users") +dotsql.WithData(map[string]any{"exclude_deleted": true}).Query(db, "count-users") ``` Embeding diff --git a/dotsql.go b/dotsql.go index 6b91afd..0f149d1 100644 --- a/dotsql.go +++ b/dotsql.go @@ -60,21 +60,14 @@ type ExecerContext interface { // DotSql represents a dotSQL queries holder. type DotSql struct { queries map[string]*template.Template - options map[string]interface{} + data any } -func (d DotSql) WithOptions(additionalOptions map[string]interface{}) DotSql { - options := make(map[string]interface{}) - for k, v := range d.options { - options[k] = v - } - for k, v := range additionalOptions { - options[k] = v - } - return DotSql{queries: d.queries, options: options} +func (d DotSql) WithData(data any) DotSql { + return DotSql{queries: d.queries, data: data} } -func (d DotSql) lookupQuery(name string, options map[string]interface{}) (query string, err error) { +func (d DotSql) lookupQuery(name string, data any) (query string, err error) { template, ok := d.queries[name] if !ok { err = fmt.Errorf("dotsql: '%s' could not be found", name) @@ -84,7 +77,7 @@ func (d DotSql) lookupQuery(name string, options map[string]interface{}) (query if err != nil { return } - err = template.Execute(buffer, options) + err = template.Execute(buffer, data) if err != nil { return } @@ -96,7 +89,7 @@ func (d DotSql) lookupQuery(name string, options map[string]interface{}) (query // Prepare is a wrapper for database/sql's Prepare(), using dotsql named query. func (d DotSql) Prepare(db Preparer, name string) (*sql.Stmt, error) { - query, err := d.lookupQuery(name, d.options) + query, err := d.lookupQuery(name, d.data) if err != nil { return nil, err } @@ -106,7 +99,7 @@ func (d DotSql) Prepare(db Preparer, name string) (*sql.Stmt, error) { // PrepareContext is a wrapper for database/sql's PrepareContext(), using dotsql named query. func (d DotSql) PrepareContext(ctx context.Context, db PreparerContext, name string) (*sql.Stmt, error) { - query, err := d.lookupQuery(name, d.options) + query, err := d.lookupQuery(name, d.data) if err != nil { return nil, err } @@ -116,7 +109,7 @@ func (d DotSql) PrepareContext(ctx context.Context, db PreparerContext, name str // Query is a wrapper for database/sql's Query(), using dotsql named query. func (d DotSql) Query(db Queryer, name string, args ...interface{}) (*sql.Rows, error) { - query, err := d.lookupQuery(name, d.options) + query, err := d.lookupQuery(name, d.data) if err != nil { return nil, err } @@ -126,7 +119,7 @@ func (d DotSql) Query(db Queryer, name string, args ...interface{}) (*sql.Rows, // QueryContext is a wrapper for database/sql's QueryContext(), using dotsql named query. func (d DotSql) QueryContext(ctx context.Context, db QueryerContext, name string, args ...interface{}) (*sql.Rows, error) { - query, err := d.lookupQuery(name, d.options) + query, err := d.lookupQuery(name, d.data) if err != nil { return nil, err } @@ -136,7 +129,7 @@ func (d DotSql) QueryContext(ctx context.Context, db QueryerContext, name string // QueryRow is a wrapper for database/sql's QueryRow(), using dotsql named query. func (d DotSql) QueryRow(db QueryRower, name string, args ...interface{}) (*sql.Row, error) { - query, err := d.lookupQuery(name, d.options) + query, err := d.lookupQuery(name, d.data) if err != nil { return nil, err } @@ -146,7 +139,7 @@ func (d DotSql) QueryRow(db QueryRower, name string, args ...interface{}) (*sql. // QueryRowContext is a wrapper for database/sql's QueryRowContext(), using dotsql named query. func (d DotSql) QueryRowContext(ctx context.Context, db QueryRowerContext, name string, args ...interface{}) (*sql.Row, error) { - query, err := d.lookupQuery(name, d.options) + query, err := d.lookupQuery(name, d.data) if err != nil { return nil, err } @@ -156,7 +149,7 @@ func (d DotSql) QueryRowContext(ctx context.Context, db QueryRowerContext, name // Exec is a wrapper for database/sql's Exec(), using dotsql named query. func (d DotSql) Exec(db Execer, name string, args ...interface{}) (sql.Result, error) { - query, err := d.lookupQuery(name, d.options) + query, err := d.lookupQuery(name, d.data) if err != nil { return nil, err } @@ -166,7 +159,7 @@ func (d DotSql) Exec(db Execer, name string, args ...interface{}) (sql.Result, e // ExecContext is a wrapper for database/sql's ExecContext(), using dotsql named query. func (d DotSql) ExecContext(ctx context.Context, db ExecerContext, name string, args ...interface{}) (sql.Result, error) { - query, err := d.lookupQuery(name, d.options) + query, err := d.lookupQuery(name, d.data) if err != nil { return nil, err } @@ -176,7 +169,7 @@ func (d DotSql) ExecContext(ctx context.Context, db ExecerContext, name string, // Raw returns the query, everything after the --name tag func (d DotSql) Raw(name string) (string, error) { - return d.lookupQuery(name, d.options) + return d.lookupQuery(name, d.data) } // QueryMap returns a map[string]string of loaded queries diff --git a/dotsql_test.go b/dotsql_test.go index ddd1279..e464b08 100644 --- a/dotsql_test.go +++ b/dotsql_test.go @@ -362,7 +362,7 @@ func TestQueryOptions(t *testing.T) { "select": createTemplate(t, "SELECT * from users WHERE name = ?{{if .exclude_deleted}} AND deleted IS NULL{{end}}"), }, } - dotExcludeDeleted := dot.WithOptions(map[string]interface{}{"exclude_deleted": true}) + dotExcludeDeleted := dot.WithData(map[string]any{"exclude_deleted": true}) queryerStub := func(err error) *QueryerMock { return &QueryerMock{ @@ -923,3 +923,13 @@ func TestMergeTakesPresecendeFromLastArgument(t *testing.T) { t.Errorf("Expected query: '%s', got: '%s'", expectedQuery, got) } } + +func TestTemplatesFailQuickly(t *testing.T) { + _, err := LoadFromString("-- name: bad-query\nSELECT * FROM {{if .user}}users{{else}}clients") + expectedErr := errors.New("bad-query:1: unexpected EOF") + if err == nil { + t.Fatalf("expected '%s' error, but didn't get one", expectedErr) + } else if errors.Is(err, expectedErr) { + t.Errorf("expected '%s' error, but got '%s'", expectedErr, err) + } +} diff --git a/integration_test.go b/integration_test.go index 6ebd001..9017c8e 100644 --- a/integration_test.go +++ b/integration_test.go @@ -139,7 +139,7 @@ func countUsers(t *testing.T, dot *DotSql, db QueryRower, name string, expected } } -func TestSelectOption(t *testing.T) { +func TestSelectData(t *testing.T) { db, dotsql := initDotSql() defer db.Close() @@ -153,7 +153,7 @@ func TestSelectOption(t *testing.T) { } countUsers(t, dotsql, db, "count-users", 2) - excludeDeleted := dotsql.WithOptions(map[string]interface{}{"exclude_deleted": true}) + excludeDeleted := dotsql.WithData(map[string]any{"exclude_deleted": true}) countUsers(t, &excludeDeleted, db, "count-users", 2) _, err = dotsql.Exec(db, "soft-delete-user", "foo@bar.com")