add insert statement
This commit is contained in:
@@ -5,23 +5,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// https://www.sqlite.org/lang_delete.html
|
// https://www.sqlite.org/lang_delete.html
|
||||||
type DeleteQuery struct {
|
type DeleteStatement struct {
|
||||||
table SelectTable
|
table SelectTable
|
||||||
|
|
||||||
where []Where
|
where []Where
|
||||||
args []any
|
args []any
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *DeleteQuery) Args() []any {
|
func (s *DeleteStatement) Args() []any {
|
||||||
return q.args
|
return s.args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *DeleteQuery) IsValid() bool {
|
func (s *DeleteStatement) IsValid() bool {
|
||||||
if !q.table.IsValid() {
|
if !s.table.IsValid() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, w := range q.where {
|
for _, w := range s.where {
|
||||||
if !w.IsValid() {
|
if !w.IsValid() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -30,13 +30,13 @@ func (q *DeleteQuery) IsValid() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *DeleteQuery) String() string {
|
func (s *DeleteStatement) String() string {
|
||||||
strs := []string{"delete", q.table.String()}
|
strs := []string{"delete", s.table.String()}
|
||||||
|
|
||||||
if len(q.where) > 0 {
|
if len(s.where) > 0 {
|
||||||
strs = append(strs, "where")
|
strs = append(strs, "where")
|
||||||
|
|
||||||
for _, w := range q.where {
|
for _, w := range s.where {
|
||||||
strs = append(strs, w.String())
|
strs = append(strs, w.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,26 +44,26 @@ func (q *DeleteQuery) String() string {
|
|||||||
return strings.Join(strs, " ")
|
return strings.Join(strs, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *DeleteQuery) Where(def string, args ...any) *DeleteQuery {
|
func (s *DeleteStatement) Where(def string, args ...any) *DeleteStatement {
|
||||||
q.where = append(q.where, Where(def))
|
s.where = append(s.where, Where(def))
|
||||||
|
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
if q.args == nil {
|
if s.args == nil {
|
||||||
q.args = []any{}
|
s.args = []any{}
|
||||||
}
|
}
|
||||||
|
|
||||||
q.args = append(q.args, args...)
|
s.args = append(s.args, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return q
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func Delete(from string) *DeleteQuery {
|
func Delete(from string) *DeleteStatement {
|
||||||
q := &DeleteQuery{
|
s := &DeleteStatement{
|
||||||
table: From(from),
|
table: From(from),
|
||||||
|
|
||||||
where: []Where{},
|
where: []Where{},
|
||||||
}
|
}
|
||||||
|
|
||||||
return q
|
return s
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
func TestDelete(t *testing.T) {
|
func TestDelete(t *testing.T) {
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
In *DeleteQuery
|
In *DeleteStatement
|
||||||
Args []any
|
Args []any
|
||||||
String string
|
String string
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ func TestDelete(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
In: Delete("customer as c"),
|
In: Delete("customer as c"),
|
||||||
String: "select c.id, c.name from customer as c",
|
String: "delete from customer as c",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
In: Delete("customer").Where("id = ?", 1234),
|
In: Delete("customer").Where("id = ?", 1234),
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package sqimple
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://www.sqlite.org/lang_delete.html
|
||||||
|
type InsertStatement struct {
|
||||||
|
table InsertTable
|
||||||
|
or string
|
||||||
|
|
||||||
|
columns []string
|
||||||
|
values []Values
|
||||||
|
|
||||||
|
selectValues *SelectQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InsertStatement) Args() []any {
|
||||||
|
if s.selectValues != nil {
|
||||||
|
return s.selectValues.Args()
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []any{}
|
||||||
|
for _, row := range s.values {
|
||||||
|
for _, column := range s.columns {
|
||||||
|
args = append(args, row[column])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InsertStatement) IsValid() bool {
|
||||||
|
if !s.table.IsValid() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InsertStatement) Columns(columns ...string) *InsertStatement {
|
||||||
|
if s.columns == nil {
|
||||||
|
s.columns = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, column := range columns {
|
||||||
|
if !slices.Contains(s.columns, column) {
|
||||||
|
s.columns = append(s.columns, columns...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InsertStatement) Or(or string) *InsertStatement {
|
||||||
|
s.or = or
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InsertStatement) Select(q *SelectQuery) *InsertStatement {
|
||||||
|
s.selectValues = q
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InsertStatement) String() string {
|
||||||
|
strs := []string{"insert"}
|
||||||
|
|
||||||
|
if s.or != "" {
|
||||||
|
strs = append(strs, "or", s.or)
|
||||||
|
}
|
||||||
|
|
||||||
|
strs = append(strs, s.table.String())
|
||||||
|
|
||||||
|
if len(s.columns) > 0 {
|
||||||
|
strs = append(strs, fmt.Sprintf("(%s)", strings.Join(s.columns, ", ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.selectValues != nil {
|
||||||
|
strs = append(strs, s.selectValues.String())
|
||||||
|
} else {
|
||||||
|
strs = append(strs, "values")
|
||||||
|
|
||||||
|
valueStrs := []string{}
|
||||||
|
for range s.values {
|
||||||
|
marks := []string{}
|
||||||
|
for range s.columns {
|
||||||
|
marks = append(marks, "?")
|
||||||
|
}
|
||||||
|
|
||||||
|
valueStrs = append(valueStrs, fmt.Sprintf("(%s)", strings.Join(marks, ", ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
strs = append(strs, strings.Join(valueStrs, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(strs, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InsertStatement) Values(values ...Values) *InsertStatement {
|
||||||
|
if s.values == nil {
|
||||||
|
s.values = []Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, row := range values {
|
||||||
|
s.values = append(s.values, row)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func Insert(into string) *InsertStatement {
|
||||||
|
s := &InsertStatement{
|
||||||
|
table: Into(into),
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package sqimple
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/alecthomas/assert/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInsert(t *testing.T) {
|
||||||
|
type TestCase struct {
|
||||||
|
In *InsertStatement
|
||||||
|
Args []any
|
||||||
|
String string
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []TestCase{
|
||||||
|
{
|
||||||
|
In: Insert("customer").Columns("name").Values(Values{"name": "Adam"}),
|
||||||
|
Args: []any{"Adam"},
|
||||||
|
String: "insert into customer (name) values (?)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: Insert("customer").Columns("name").Values(Values{"name": "Adam"}, Values{"name": "Bernard"}),
|
||||||
|
Args: []any{"Adam", "Bernard"},
|
||||||
|
String: "insert into customer (name) values (?), (?)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: Insert("customer").Or("update").Columns("id", "name").Values(Values{"id": 1234, "name": "Adam"}),
|
||||||
|
Args: []any{1234, "Adam"},
|
||||||
|
String: "insert or update into customer (id, name) values (?, ?)",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,46 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var selectTableRegexp = regexp.MustCompile("^(from|left join|inner join|right join) ([^ ]+)( (as) ([^ ]+))?( (on) ([^ ]+) (=|!=|>|>=|<|<=) ([^ ]+)( (and) ([^ ]+) (=|!=|>|>=|<|<=) ([^ ]+))*)?$")
|
var (
|
||||||
|
insertTableRegexp = regexp.MustCompile("^into ([^ ]+)( (as) ([^ ]+))?$")
|
||||||
|
selectTableRegexp = regexp.MustCompile("^(from|left join|inner join|right join) ([^ ]+)( (as) ([^ ]+))?( (on) ([^ ]+) (=|!=|>|>=|<|<=) ([^ ]+)( (and) ([^ ]+) (=|!=|>|>=|<|<=) ([^ ]+))*)?$")
|
||||||
|
)
|
||||||
|
|
||||||
|
type InsertTable string
|
||||||
|
|
||||||
|
func (t InsertTable) IsValid() bool {
|
||||||
|
return insertTableRegexp.MatchString(string(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t InsertTable) 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 InsertTable) String() string {
|
||||||
|
return string(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Into(def string) InsertTable {
|
||||||
|
if strings.Index(def, "into ") == 0 {
|
||||||
|
return InsertTable(def)
|
||||||
|
}
|
||||||
|
|
||||||
|
return InsertTable(fmt.Sprintf("into %s", def))
|
||||||
|
}
|
||||||
|
|
||||||
type SelectTable string
|
type SelectTable string
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,40 @@ import (
|
|||||||
"github.com/alecthomas/assert/v2"
|
"github.com/alecthomas/assert/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestInsertTable(t *testing.T) {
|
||||||
|
type TestCase struct {
|
||||||
|
In string
|
||||||
|
IsValid bool
|
||||||
|
Table string
|
||||||
|
As string
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []TestCase{
|
||||||
|
{
|
||||||
|
In: "into customer",
|
||||||
|
IsValid: true,
|
||||||
|
Table: "customer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: "into customer as c",
|
||||||
|
IsValid: true,
|
||||||
|
Table: "customer",
|
||||||
|
As: "c",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.In, func(t *testing.T) {
|
||||||
|
it := InsertTable(testCase.In)
|
||||||
|
table, as, ok := it.Parse()
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.IsValid, ok, "incorrect test case")
|
||||||
|
assert.Equal(t, testCase.Table, table, "parsed table incorrectly")
|
||||||
|
assert.Equal(t, testCase.As, as, "parsed as incorrectly")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSelectTable(t *testing.T) {
|
func TestSelectTable(t *testing.T) {
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
In string
|
In string
|
||||||
|
|||||||
Reference in New Issue
Block a user