add update statement

This commit is contained in:
2026-07-07 22:07:50 +01:00
parent 87517d247a
commit f2ebd5b53f
5 changed files with 209 additions and 4 deletions
+4
View File
@@ -29,6 +29,10 @@ func TestInsert(t *testing.T) {
Args: []any{1234, "Adam"},
String: "insert or update into customer (id, name) values (?, ?)",
},
{
In: Insert("customer").Columns("name").Select(Select("baby_names").Columns("name")),
String: "insert into customer (name) select name from baby_names",
},
}
for _, testCase := range testCases {
+9 -4
View File
@@ -30,6 +30,10 @@ func (q *SelectQuery) Args() []any {
}
func (q *SelectQuery) Columns(defs ...string) *SelectQuery {
if q.columns == nil {
q.columns = []Column{}
}
for _, def := range defs {
q.columns = append(q.columns, Column(def))
}
@@ -157,6 +161,10 @@ func (q *SelectQuery) String() string {
}
func (q *SelectQuery) Where(def string, args ...any) *SelectQuery {
if q.where == nil {
q.where = []Where{}
}
q.where = append(q.where, Where(def))
if len(args) > 0 {
@@ -172,10 +180,7 @@ func (q *SelectQuery) Where(def string, args ...any) *SelectQuery {
func Select(from string) *SelectQuery {
q := &SelectQuery{
columns: []Column{},
tables: []SelectTable{From(from)},
where: []Where{},
tables: []SelectTable{From(from)},
}
return q
+29
View File
@@ -9,6 +9,7 @@ import (
var (
insertTableRegexp = regexp.MustCompile("^into ([^ ]+)( (as) ([^ ]+))?$")
selectTableRegexp = regexp.MustCompile("^(from|left join|inner join|right join) ([^ ]+)( (as) ([^ ]+))?( (on) ([^ ]+) (=|!=|>|>=|<|<=) ([^ ]+)( (and) ([^ ]+) (=|!=|>|>=|<|<=) ([^ ]+))*)?$")
updateTableRegexp = regexp.MustCompile("^([^ ]+)( (as) ([^ ]+))?$")
)
type InsertTable string
@@ -120,3 +121,31 @@ func RightJoin(def string) SelectTable {
return SelectTable(fmt.Sprintf("right join %s", def))
}
type UpdateTable string
func (t UpdateTable) IsValid() bool {
return insertTableRegexp.MatchString(string(t))
}
func (t UpdateTable) Parse() (table, as string, ok bool) {
if insertTableRegexp.MatchString(string(t)) {
ok = true
result := insertTableRegexp.FindAllStringSubmatch(string(t), -1)
for _, r := range result {
table = r[1]
if r[3] == "as" {
as = r[4]
}
}
}
return
}
func (t UpdateTable) String() string {
return string(t)
}
+126
View File
@@ -0,0 +1,126 @@
package sqimple
import (
"slices"
"strings"
)
// https://www.sqlite.org/lang_update.html
type UpdateStatement struct {
table UpdateTable
or string
columns []string
set map[string]any
where []Where
args []any
}
func (s *UpdateStatement) Args() []any {
args := []any{}
for _, column := range s.columns {
args = append(args, s.set[column])
}
for _, arg := range s.args {
args = append(args, arg)
}
return args
}
func (s *UpdateStatement) IsValid() bool {
if !s.table.IsValid() {
return false
}
for _, w := range s.where {
if !w.IsValid() {
return false
}
}
return false
}
func (s *UpdateStatement) Or(or string) *UpdateStatement {
s.or = or
return s
}
func (s *UpdateStatement) Set(column string, value any) *UpdateStatement {
if s.columns == nil {
s.columns = []string{}
}
if s.set == nil {
s.set = map[string]any{}
}
if !slices.Contains(s.columns, column) {
s.columns = append(s.columns, column)
}
s.set[column] = value
return s
}
func (s *UpdateStatement) SetMap(data map[string]any) *UpdateStatement {
for column, value := range data {
s.Set(column, value)
}
return s
}
func (s *UpdateStatement) String() string {
strs := []string{"update"}
if s.or != "" {
strs = append(strs, "or", s.or)
}
strs = append(strs, s.table.String(), "set")
for i, column := range s.columns {
if i < len(s.columns)-1 {
strs = append(strs, column, "= ?,")
} else {
strs = append(strs, column, "= ?")
}
}
if len(s.where) > 0 {
strs = append(strs, "where")
for _, w := range s.where {
strs = append(strs, w.String())
}
}
return strings.Join(strs, " ")
}
func (s *UpdateStatement) Where(def string, args ...any) *UpdateStatement {
s.where = append(s.where, Where(def))
if len(args) > 0 {
if s.args == nil {
s.args = []any{}
}
s.args = append(s.args, args...)
}
return s
}
func Update(table string) *UpdateStatement {
s := &UpdateStatement{
table: UpdateTable(table),
}
return s
}
+41
View File
@@ -0,0 +1,41 @@
package sqimple
import (
"testing"
"github.com/alecthomas/assert/v2"
)
func TestUpdate(t *testing.T) {
type TestCase struct {
In *UpdateStatement
Args []any
String string
}
testCases := []TestCase{
{
In: Update("customer").Set("name", "Adam"),
Args: []any{"Adam"},
String: "update customer set name = ?",
},
{
In: Update("customer").Set("name", "Adam").Where("id = ?", 1234),
Args: []any{"Adam", 1234},
String: "update customer set name = ? where id = ?",
},
{
// Same as previous, but backwards
In: Update("customer").Where("id = ?", 1234).Set("name", "Adam"),
Args: []any{"Adam", 1234},
String: "update customer set name = ? where id = ?",
},
}
for _, testCase := range testCases {
t.Run(testCase.String, func(t *testing.T) {
assert.Equal(t, testCase.Args, testCase.In.Args(), "collected arguments incorrectly")
assert.Equal(t, testCase.String, testCase.In.String(), "stringified incorrectly")
})
}
}