Browse Source

Add InsertRow method

Volodymyr Tkach 2 years ago
parent
commit
8aa412b461

+ 33 - 0
gosql/common/common.go

@@ -9,6 +9,7 @@ import (
 	"os"
 	"reflect"
 	"regexp"
+	"strconv"
 	"strings"
 	"time"
 
@@ -28,6 +29,7 @@ type Engine interface {
 	EachPrepared(ctx context.Context, prep *Prepared, logic func(ctx context.Context, rows *Rows) error) error
 	Exec(ctx context.Context, query string, args ...any) (sql.Result, error)
 	ExecPrepared(ctx context.Context, prep *Prepared) (sql.Result, error)
+	InsertRow(ctx context.Context, row any) error
 	Ping(context.Context) error
 	Prepare(ctx context.Context, query string) (*sql.Stmt, error)
 	Query(ctx context.Context, query string, args ...any) (*Rows, error)
@@ -68,6 +70,37 @@ func fixQuery(query string) string {
 	return rSqlParam.ReplaceAllString(query, "?")
 }
 
+func insertRowString(row any) (string, []any) {
+	v := reflect.ValueOf(row).Elem()
+	t := v.Type()
+	var table string
+	fields := []string{}
+	values := []string{}
+	args := []any{}
+	position := 1
+	for i := 0; i < t.NumField(); i++ {
+		if table == "" {
+			if tag := t.Field(i).Tag.Get("table"); tag != "" {
+				table = tag
+			}
+		}
+		if tag := t.Field(i).Tag.Get("field"); tag != "" && tag != "id" {
+			fields = append(fields, tag)
+			values = append(values, "$"+strconv.Itoa(position))
+			switch t.Field(i).Type.Kind() {
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				args = append(args, v.Field(i).Int())
+			case reflect.Float32, reflect.Float64:
+				args = append(args, v.Field(i).Float())
+			case reflect.String:
+				args = append(args, v.Field(i).String())
+			}
+			position++
+		}
+	}
+	return `INSERT INTO ` + table + ` (` + strings.Join(fields, ", ") + `) VALUES (` + strings.Join(values, ", ") + `)`, args
+}
+
 func log(w io.Writer, fname string, start time.Time, err error, tx bool, query string, args ...any) string {
 	var values []string
 

+ 3 - 2
gosql/common/common_export_test.go

@@ -1,8 +1,9 @@
 package common
 
+var DeleteRowByIDString = deleteRowByIDString
 var FixQuery = fixQuery
+var InsertRowString = insertRowString
 var Log = log
-var Scans = scans
 var QueryRowByIDString = queryRowByIDString
 var RowExistsString = rowExistsString
-var DeleteRowByIDString = deleteRowByIDString
+var Scans = scans

+ 24 - 0
gosql/common/common_test.go

@@ -27,6 +27,30 @@ var _ = Describe("common", func() {
 		})
 	})
 
+	Context("insertRow", func() {
+		It("convert struct to SQL query", func() {
+			var row struct {
+				ID       int64  `field:"id" table:"users"`
+				Name     string `field:"name"`
+				Value    string `field:"value"`
+				Position int64  `field:"position"`
+			}
+
+			row.Name = "Name"
+			row.Value = "Value"
+			row.Position = 59
+
+			sql, args := common.InsertRowString(&row)
+
+			Expect(sql).To(Equal(`INSERT INTO users (name, value, position) VALUES ($1, $2, $3)`))
+
+			Expect(len(args)).To(Equal(3))
+			Expect(args[0]).To(Equal("Name"))
+			Expect(args[1]).To(Equal("Value"))
+			Expect(args[2]).To(Equal(int64(59)))
+		})
+	})
+
 	Context("log", func() {
 		Context("time", func() {
 			It("calculate one second", func() {

+ 6 - 0
gosql/common/dbmethods.go

@@ -92,6 +92,12 @@ func (d *DBMethods) ExecPrepared(ctx context.Context, prep *Prepared) (sql.Resul
 	return d.Exec(ctx, prep.Query, prep.Query)
 }
 
+func (d *DBMethods) InsertRow(ctx context.Context, row any) error {
+	query, args := insertRowString(row)
+	_, err := d.Exec(ctx, query, args)
+	return err
+}
+
 func (d *DBMethods) Ping(ctx context.Context) error {
 	start := time.Now()
 	err := d.DB.PingContext(ctx)

+ 6 - 0
gosql/common/tx.go

@@ -86,6 +86,12 @@ func (t *Tx) ExecPrepared(ctx context.Context, prep *Prepared) (sql.Result, erro
 	return t.Exec(ctx, prep.Query, prep.Args...)
 }
 
+func (t *Tx) InsertRow(ctx context.Context, row any) error {
+	query, args := insertRowString(row)
+	_, err := t.Exec(ctx, query, args)
+	return err
+}
+
 func (t *Tx) Query(ctx context.Context, query string, args ...any) (*Rows, error) {
 	start := time.Now()
 	rows, err := t.tx.QueryContext(ctx, t.fixQuery(query), args...)