From 7746bfd32abd3d18468e2d45cf3b6a9efda163c1 Mon Sep 17 00:00:00 2001 From: Paddy Carver Date: Sat, 11 Feb 2023 20:11:35 -0800 Subject: [PATCH] Upgrade to Go 1.18, add SQLiteString. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upgrade to Go 1.18, adding a go.mod and go.sum. Change all instances of `interface{}` to `any`. Update `Insert` to use generics so we no longer need to convert to a `[]pan.SQLTableNamer` before passing slices in, slices of any type that fills the `pan.SQLTableNamer` interface will now work. Should be backwards-compatible. It also has the benefit of enforcing that all values need to be of the same type, which was implied by the comment prior to this, so I'm not considering it a breaking change. Add an SQLiteString method to Query, returning a string that can be used for SQLite. Technically, this is the same as MySQLString. But it feels weird using MySQLString in SQLite code, and now if we discover any special handling we need to do for SQLite, we can just put it in this method. 🎵 Now Playing: Better Than That 🎵 Artist: Sub-Radio 🎵 Album: Better Than That --- go.mod | 5 +++++ go.sum | 2 ++ query.go | 36 +++++++++++++++++++++++++----------- reflect_test.go | 2 +- 4 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d3722cd --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module darlinggo.co/pan + +go 1.18 + +require github.com/mattn/go-sqlite3 v1.14.16 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7878efc --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= diff --git a/query.go b/query.go index 0b4c61b..6eed841 100644 --- a/query.go +++ b/query.go @@ -33,7 +33,7 @@ var ( // goroutines, you need to coordinate that access yourself. type Query struct { sql string - args []interface{} + args []any expressions []string includesWhere bool includesOrder bool @@ -56,14 +56,13 @@ type Flag int func New(query string) *Query { return &Query{ sql: query, - args: []interface{}{}, + args: []any{}, } } // Insert returns a Query instance containing SQL that will insert the passed `values` into -// the database. All `values` will be inserted into the same table, so invalid SQL will be -// generated if all `values` are not the same type. -func Insert(values ...SQLTableNamer) *Query { +// the database. +func Insert[Type SQLTableNamer](values ...Type) *Query { columns := Columns(values[0]) query := New("INSERT INTO " + Table(values[0]) + " (" + columns.String() + ") VALUES") @@ -106,7 +105,7 @@ func (q *Query) String() string { var res string toCheck := q.sql for i := strings.Index(toCheck, "?"); i >= 0; argPos++ { - var arg interface{} + var arg any arg = "!{MISSING}" if len(q.args) > argPos { arg = q.args[argPos] @@ -135,6 +134,21 @@ func (q *Query) MySQLString() (string, error) { return q.sql + ";", nil } +// SQLiteString returns a SQL string that can be passed to SQLite to execute +// your query. If the number of placeholders do not match the number of +// arguments provided to your Query, an ErrWrongNumberArgs error will be +// returned. If there are still expressions left in the buffer (meaning the +// Flush method wasn't called) an ErrNeedsFlush error will be returned. +func (q *Query) SQLiteString() (string, error) { + if len(q.expressions) != 0 { + return "", ErrNeedsFlush + } + if err := q.checkCounts(); err != nil { + return "", err + } + return q.sql + ";", nil +} + // PostgreSQLString returns an SQL string that can be passed to PostgreSQL to execute // your query. If the number of placeholders do not match the number of arguments // provided to your Query, an ErrWrongNumberArgs error will be returned. If there are @@ -176,7 +190,7 @@ func (q *Query) Flush(join string) *Query { } // Expression adds a raw string and optional values to the Query’s buffer. -func (q *Query) Expression(key string, values ...interface{}) *Query { +func (q *Query) Expression(key string, values ...any) *Query { q.expressions = append(q.expressions, key) q.args = append(q.args, values...) return q @@ -202,7 +216,7 @@ func (q *Query) Where() *Query { // determined by finding the column name for the passed property on the passed SQLTableNamer. // The passed property must be a string that matches, identically, the property name; if it // does not, it will panic. -func (q *Query) Comparison(obj SQLTableNamer, property, operator string, value interface{}) *Query { +func (q *Query) Comparison(obj SQLTableNamer, property, operator string, value any) *Query { return q.Expression(Column(obj, property)+" "+operator+" ?", value) } @@ -210,14 +224,14 @@ func (q *Query) Comparison(obj SQLTableNamer, property, operator string, value i // `values` are the variables to match against, and `obj` and `property` are used to determine // the column. `property` must exactly match the name of a property on `obj`, or the call will // panic. -func (q *Query) In(obj SQLTableNamer, property string, values ...interface{}) *Query { +func (q *Query) In(obj SQLTableNamer, property string, values ...any) *Query { return q.Expression(Column(obj, property)+" IN("+Placeholders(len(values))+")", values...) } // Assign adds an expression to the Query’s buffer in the form of "column = ?", and adds `value` // to the arguments for this query. `obj` and `property` are used to determine the column. // `property` must exactly match the name of a property on `obj`, or the call will panic. -func (q *Query) Assign(obj SQLTableNamer, property string, value interface{}) *Query { +func (q *Query) Assign(obj SQLTableNamer, property string, value any) *Query { return q.Expression(Column(obj, property)+" = ?", value) } @@ -258,6 +272,6 @@ func (q *Query) Offset(offset int64) *Query { // // Note that Args returns its internal slice; you should copy the returned slice over before modifying // it. -func (q *Query) Args() []interface{} { +func (q *Query) Args() []any { return q.args } diff --git a/reflect_test.go b/reflect_test.go index 8428cfb..6346f86 100644 --- a/reflect_test.go +++ b/reflect_test.go @@ -190,7 +190,7 @@ func TestUnmarshal(t *testing.T) { t.Error(err) } q := Insert(dummy) - mysql, err := q.MySQLString() + mysql, err := q.SQLiteString() if err != nil { t.Error(err) }