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

feat: add SetDefaultPrepared which controls query value interpolation #288

Merged
merged 1 commit into from
Aug 3, 2021
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
10 changes: 5 additions & 5 deletions delete_dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var ErrBadFromArgument = errors.New("unsupported DeleteDataset#From argument, a
type DeleteDataset struct {
dialect SQLDialect
clauses exp.DeleteClauses
isPrepared bool
isPrepared prepared
queryFactory exec.QueryFactory
err error
}
Expand All @@ -23,7 +23,7 @@ func newDeleteDataset(d string, queryFactory exec.QueryFactory) *DeleteDataset {
clauses: exp.NewDeleteClauses(),
dialect: GetDialect(d),
queryFactory: queryFactory,
isPrepared: false,
isPrepared: preparedNoPreference,
err: nil,
}
}
Expand All @@ -46,13 +46,13 @@ func (dd *DeleteDataset) Clone() exp.Expression {
// prepared: If true the dataset WILL NOT interpolate the parameters.
func (dd *DeleteDataset) Prepared(prepared bool) *DeleteDataset {
ret := dd.copy(dd.clauses)
ret.isPrepared = prepared
ret.isPrepared = preparedFromBool(prepared)
return ret
}

// Returns true if Prepared(true) has been called on this dataset
func (dd *DeleteDataset) IsPrepared() bool {
return dd.isPrepared
return dd.isPrepared.Bool()
}

// Sets the adapter used to serialize values and create the SQL statement
Expand Down Expand Up @@ -235,7 +235,7 @@ func (dd *DeleteDataset) Executor() exec.QueryExecutor {
}

func (dd *DeleteDataset) deleteSQLBuilder() sb.SQLBuilder {
buf := sb.NewSQLBuilder(dd.isPrepared)
buf := sb.NewSQLBuilder(dd.isPrepared.Bool())
if dd.err != nil {
return buf.SetError(dd.err)
}
Expand Down
15 changes: 15 additions & 0 deletions delete_dataset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ func (dds *deleteDatasetSuite) TestPrepared() {
dds.False(ds.IsPrepared())
// should apply the prepared to any datasets created from the root
dds.True(preparedDs.Where(goqu.Ex{"a": 1}).IsPrepared())

defer goqu.SetDefaultPrepared(false)
goqu.SetDefaultPrepared(true)

// should be prepared by default
ds = goqu.Delete("test")
dds.True(ds.IsPrepared())
}

func (dds *deleteDatasetSuite) TestGetClauses() {
Expand Down Expand Up @@ -445,6 +452,14 @@ func (dds *deleteDatasetSuite) TestExecutor() {
dds.NoError(err)
dds.Equal([]interface{}{int64(10)}, args)
dds.Equal(`DELETE FROM "items" WHERE ("id" > ?)`, dsql)

defer goqu.SetDefaultPrepared(false)
goqu.SetDefaultPrepared(true)

dsql, args, err = ds.Executor().ToSQL()
dds.NoError(err)
dds.Equal([]interface{}{int64(10)}, args)
dds.Equal(`DELETE FROM "items" WHERE ("id" > ?)`, dsql)
}

func (dds *deleteDatasetSuite) TestSetError() {
Expand Down
8 changes: 4 additions & 4 deletions insert_dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
type InsertDataset struct {
dialect SQLDialect
clauses exp.InsertClauses
isPrepared bool
isPrepared prepared
queryFactory exec.QueryFactory
err error
}
Expand All @@ -39,12 +39,12 @@ func Insert(table interface{}) *InsertDataset {
// prepared: If true the dataset WILL NOT interpolate the parameters.
func (id *InsertDataset) Prepared(prepared bool) *InsertDataset {
ret := id.copy(id.clauses)
ret.isPrepared = prepared
ret.isPrepared = preparedFromBool(prepared)
return ret
}

func (id *InsertDataset) IsPrepared() bool {
return id.isPrepared
return id.isPrepared.Bool()
}

// Sets the adapter used to serialize values and create the SQL statement
Expand Down Expand Up @@ -257,7 +257,7 @@ func (id *InsertDataset) Executor() exec.QueryExecutor {
}

func (id *InsertDataset) insertSQLBuilder() sb.SQLBuilder {
buf := sb.NewSQLBuilder(id.isPrepared)
buf := sb.NewSQLBuilder(id.isPrepared.Bool())
if id.err != nil {
return buf.SetError(id.err)
}
Expand Down
15 changes: 15 additions & 0 deletions insert_dataset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ func (ids *insertDatasetSuite) TestPrepared() {
ids.False(ds.IsPrepared())
// should apply the prepared to any datasets created from the root
ids.True(preparedDs.Returning(goqu.C("col")).IsPrepared())

defer goqu.SetDefaultPrepared(false)
goqu.SetDefaultPrepared(true)

// should be prepared by default
ds = goqu.Insert("test")
ids.True(ds.IsPrepared())
}

func (ids *insertDatasetSuite) TestGetClauses() {
Expand Down Expand Up @@ -440,6 +447,14 @@ func (ids *insertDatasetSuite) TestExecutor() {
ids.NoError(err)
ids.Equal([]interface{}{"111 Test Addr", "Test1"}, args)
ids.Equal(`INSERT INTO "items" ("address", "name") VALUES (?, ?)`, isql)

defer goqu.SetDefaultPrepared(false)
goqu.SetDefaultPrepared(true)

isql, args, err = ds.Executor().ToSQL()
ids.NoError(err)
ids.Equal([]interface{}{"111 Test Addr", "Test1"}, args)
ids.Equal(`INSERT INTO "items" ("address", "name") VALUES (?, ?)`, isql)
}

func (ids *insertDatasetSuite) TestInsertStruct() {
Expand Down
48 changes: 48 additions & 0 deletions prepared.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package goqu

var (
// defaultPrepared is controlled by SetDefaultPrepared
defaultPrepared bool
)

type prepared int

const (
// zero value that defers to defaultPrepared
preparedNoPreference prepared = iota

// explicitly enabled via Prepared(true) on a dataset
preparedEnabled

// explicitly disabled via Prepared(false) on a dataset
preparedDisabled
)

// Bool converts the ternary prepared state into a boolean. If the prepared
// state is preparedNoPreference, the value depends on the last value that
// SetDefaultPrepared was called with which is false by default.
func (p prepared) Bool() bool {
if p == preparedNoPreference {
return defaultPrepared
} else if p == preparedEnabled {
return true
}

return false
}

// preparedFromBool converts a bool from e.g. Prepared(true) into a prepared
// const.
func preparedFromBool(prepared bool) prepared {
if prepared {
return preparedEnabled
}

return preparedDisabled
}

// SetDefaultPrepared controls the default Prepared state of all datasets. If
// set to true, any new dataset will use prepared queries by default.
func SetDefaultPrepared(prepared bool) {
defaultPrepared = prepared
}
14 changes: 7 additions & 7 deletions select_dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
type SelectDataset struct {
dialect SQLDialect
clauses exp.SelectClauses
isPrepared bool
isPrepared prepared
queryFactory exec.QueryFactory
err error
}
Expand Down Expand Up @@ -52,12 +52,12 @@ func (sd *SelectDataset) WithDialect(dl string) *SelectDataset {
// prepared: If true the dataset WILL NOT interpolate the parameters.
func (sd *SelectDataset) Prepared(prepared bool) *SelectDataset {
ret := sd.copy(sd.clauses)
ret.isPrepared = prepared
ret.isPrepared = preparedFromBool(prepared)
return ret
}

func (sd *SelectDataset) IsPrepared() bool {
return sd.isPrepared
return sd.isPrepared.Bool()
}

// Returns the current adapter on the dataset
Expand Down Expand Up @@ -101,7 +101,7 @@ func (sd *SelectDataset) copy(clauses exp.SelectClauses) *SelectDataset {
// `ORDER , and `LIMIT`
func (sd *SelectDataset) Update() *UpdateDataset {
u := newUpdateDataset(sd.dialect.Dialect(), sd.queryFactory).
Prepared(sd.isPrepared)
Prepared(sd.isPrepared.Bool())
if sd.clauses.HasSources() {
u = u.Table(sd.GetClauses().From().Columns()[0])
}
Expand All @@ -128,7 +128,7 @@ func (sd *SelectDataset) Update() *UpdateDataset {
// insert.
func (sd *SelectDataset) Insert() *InsertDataset {
i := newInsertDataset(sd.dialect.Dialect(), sd.queryFactory).
Prepared(sd.isPrepared)
Prepared(sd.isPrepared.Bool())
if sd.clauses.HasSources() {
i = i.Into(sd.GetClauses().From().Columns()[0])
}
Expand All @@ -144,7 +144,7 @@ func (sd *SelectDataset) Insert() *InsertDataset {
// `ORDER , and `LIMIT`
func (sd *SelectDataset) Delete() *DeleteDataset {
d := newDeleteDataset(sd.dialect.Dialect(), sd.queryFactory).
Prepared(sd.isPrepared)
Prepared(sd.isPrepared.Bool())
if sd.clauses.HasSources() {
d = d.From(sd.clauses.From().Columns()[0])
}
Expand Down Expand Up @@ -686,7 +686,7 @@ func (sd *SelectDataset) PluckContext(ctx context.Context, i interface{}, col st
}

func (sd *SelectDataset) selectSQLBuilder() sb.SQLBuilder {
buf := sb.NewSQLBuilder(sd.isPrepared)
buf := sb.NewSQLBuilder(sd.isPrepared.Bool())
if sd.err != nil {
return buf.SetError(sd.err)
}
Expand Down
7 changes: 7 additions & 0 deletions select_dataset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ func (sds *selectDatasetSuite) TestPrepared() {
sds.False(ds.IsPrepared())
// should apply the prepared to any datasets created from the root
sds.True(preparedDs.Where(goqu.Ex{"a": 1}).IsPrepared())

defer goqu.SetDefaultPrepared(false)
goqu.SetDefaultPrepared(true)

// should be prepared by default
ds = goqu.From("test")
sds.True(ds.IsPrepared())
}

func (sds *selectDatasetSuite) TestGetClauses() {
Expand Down
8 changes: 4 additions & 4 deletions truncate_dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
type TruncateDataset struct {
dialect SQLDialect
clauses exp.TruncateClauses
isPrepared bool
isPrepared prepared
queryFactory exec.QueryFactory
err error
}
Expand Down Expand Up @@ -39,12 +39,12 @@ func (td *TruncateDataset) WithDialect(dl string) *TruncateDataset {
// prepared: If true the dataset WILL NOT interpolate the parameters.
func (td *TruncateDataset) Prepared(prepared bool) *TruncateDataset {
ret := td.copy(td.clauses)
ret.isPrepared = prepared
ret.isPrepared = preparedFromBool(prepared)
return ret
}

func (td *TruncateDataset) IsPrepared() bool {
return td.isPrepared
return td.isPrepared.Bool()
}

// Returns the current adapter on the dataset
Expand Down Expand Up @@ -160,7 +160,7 @@ func (td *TruncateDataset) Executor() exec.QueryExecutor {
}

func (td *TruncateDataset) truncateSQLBuilder() sb.SQLBuilder {
buf := sb.NewSQLBuilder(td.isPrepared)
buf := sb.NewSQLBuilder(td.isPrepared.Bool())
if td.err != nil {
return buf.SetError(td.err)
}
Expand Down
15 changes: 15 additions & 0 deletions truncate_dataset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ func (tds *truncateDatasetSuite) TestPrepared() {
tds.False(ds.IsPrepared())
// should apply the prepared to any datasets created from the root
tds.True(preparedDs.Restrict().IsPrepared())

defer goqu.SetDefaultPrepared(false)
goqu.SetDefaultPrepared(true)

// should be prepared by default
ds = goqu.Truncate("test")
tds.True(ds.IsPrepared())
}

func (tds *truncateDatasetSuite) TestGetClauses() {
Expand Down Expand Up @@ -274,6 +281,14 @@ func (tds *truncateDatasetSuite) TestExecutor() {
tds.NoError(err)
tds.Empty(args)
tds.Equal(`TRUNCATE "table1", "table2"`, tsql)

defer goqu.SetDefaultPrepared(false)
goqu.SetDefaultPrepared(true)

tsql, args, err = ds.Executor().ToSQL()
tds.NoError(err)
tds.Empty(args)
tds.Equal(`TRUNCATE "table1", "table2"`, tsql)
}

func (tds *truncateDatasetSuite) TestSetError() {
Expand Down
8 changes: 4 additions & 4 deletions update_dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
type UpdateDataset struct {
dialect SQLDialect
clauses exp.UpdateClauses
isPrepared bool
isPrepared prepared
queryFactory exec.QueryFactory
err error
}
Expand All @@ -35,12 +35,12 @@ func Update(table interface{}) *UpdateDataset {
// prepared: If true the dataset WILL NOT interpolate the parameters.
func (ud *UpdateDataset) Prepared(prepared bool) *UpdateDataset {
ret := ud.copy(ud.clauses)
ret.isPrepared = prepared
ret.isPrepared = preparedFromBool(prepared)
return ret
}

func (ud *UpdateDataset) IsPrepared() bool {
return ud.isPrepared
return ud.isPrepared.Bool()
}

// Sets the adapter used to serialize values and create the SQL statement
Expand Down Expand Up @@ -236,7 +236,7 @@ func (ud *UpdateDataset) Executor() exec.QueryExecutor {
}

func (ud *UpdateDataset) updateSQLBuilder() sb.SQLBuilder {
buf := sb.NewSQLBuilder(ud.isPrepared)
buf := sb.NewSQLBuilder(ud.isPrepared.Bool())
if ud.err != nil {
return buf.SetError(ud.err)
}
Expand Down
15 changes: 15 additions & 0 deletions update_dataset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ func (uds *updateDatasetSuite) TestPrepared() {
uds.False(ds.IsPrepared())
// should apply the prepared to any datasets created from the root
uds.True(preparedDs.Where(goqu.Ex{"a": 1}).IsPrepared())

defer goqu.SetDefaultPrepared(false)
goqu.SetDefaultPrepared(true)

// should be prepared by default
ds = goqu.Update("test")
uds.True(ds.IsPrepared())
}

func (uds *updateDatasetSuite) TestGetClauses() {
Expand Down Expand Up @@ -449,6 +456,14 @@ func (uds *updateDatasetSuite) TestExecutor() {
uds.NoError(err)
uds.Equal([]interface{}{"111 Test Addr", "Test1"}, args)
uds.Equal(`UPDATE "items" SET "address"=?,"name"=? WHERE ("name" IS NULL)`, updateSQL)

defer goqu.SetDefaultPrepared(false)
goqu.SetDefaultPrepared(true)

updateSQL, args, err = ds.Executor().ToSQL()
uds.NoError(err)
uds.Equal([]interface{}{"111 Test Addr", "Test1"}, args)
uds.Equal(`UPDATE "items" SET "address"=?,"name"=? WHERE ("name" IS NULL)`, updateSQL)
}

func (uds *updateDatasetSuite) TestSetError() {
Expand Down