Skip to content

Commit

Permalink
lib/sql: add new type Meta
Browse files Browse the repository at this point in the history
Meta contains the DML meta data, including driver name, list of column
names, list of column holders, and list of values.

The Meta type replace the Row type.
  • Loading branch information
shuLhan committed Jan 25, 2024
1 parent d686dc5 commit 9021637
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 18 deletions.
84 changes: 84 additions & 0 deletions lib/sql/meta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2024, Shulhan <[email protected]>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sql

import (
"fmt"
"strings"
)

// Meta contains the DML meta data, including driver name, list of column
// names, list of column holders, and list of values.
type Meta struct {
driver string

// ListName contains list of column name.
ListName []string

// ListHolder contains list of column holder, as in "?" or "$x",
// depends on driver.
ListHolder []string

// ListValue contains list of column values, either for insert or
// select.
ListValue []any

// ListWhereValue contains list of values for where condition.
ListWhereValue []any
}

// NewMeta create new Meta using specific driver name.
// The driver affect the ListHolder value.
func NewMeta(driverName string) (meta *Meta) {
meta = &Meta{
driver: driverName,
}
return meta
}

// Add column name and variable.
func (meta *Meta) Add(colName string, val any) {
meta.ListName = append(meta.ListName, colName)

if meta.driver == DriverNamePostgres {
meta.ListHolder = append(meta.ListHolder, fmt.Sprintf(`$%d`, len(meta.ListName)))
} else {
meta.ListHolder = append(meta.ListHolder, DefaultPlaceHolder)
}

meta.ListValue = append(meta.ListValue, val)
}

// AddWhere add value for where condition.
// It return the length of ListWhereValue in list after addition.
func (meta *Meta) AddWhere(val any) int {
meta.ListWhereValue = append(meta.ListWhereValue, val)
return len(meta.ListWhereValue)
}

// Names generate string of column names, for example "col1, col2, ...".
func (meta *Meta) Names() string {
return strings.Join(meta.ListName, `,`)
}

// Holders generate string of holder, for example "$1, $2, ...".
func (meta *Meta) Holders() string {
return strings.Join(meta.ListHolder, `,`)
}

// UpdateFields generate string of "col1=<holder>, col2=<holder>, ...".
func (meta *Meta) UpdateFields() string {
var (
sb strings.Builder
x int
)
for ; x < len(meta.ListName); x++ {
if x > 0 {
sb.WriteByte(',')
}
fmt.Fprintf(&sb, `%s=%s`, meta.ListName[x], meta.ListHolder[x])
}
return sb.String()
}
77 changes: 77 additions & 0 deletions lib/sql/meta_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2024, Shulhan <[email protected]>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sql_test

import (
"fmt"

"github.com/shuLhan/share/lib/sql"
)

func ExampleMeta_Add_mysql() {
type Table struct {
Name string
ID int
}

var (
meta = sql.NewMeta(sql.DriverNameMysql)
t = Table{}
)

meta.Add(`id`, &t.ID)
meta.Add(`name`, &t.Name)

fmt.Println(meta.Names())
fmt.Println(meta.Holders())
fmt.Println(meta.UpdateFields())
// Output:
// id,name
// ?,?
// id=?,name=?
}

func ExampleMeta_Add_postgres() {
type Table struct {
Name string
ID int
}

var (
meta = sql.NewMeta(sql.DriverNamePostgres)
t = Table{}
)

meta.Add(`id`, &t.ID)
meta.Add(`name`, &t.Name)

fmt.Println(meta.Names())
fmt.Println(meta.Holders())
fmt.Println(meta.UpdateFields())
// Output:
// id,name
// $1,$2
// id=$1,name=$2
}

func ExampleMeta_AddWhere() {
var (
meta = sql.NewMeta(sql.DriverNamePostgres)
vals = []any{
int(1000),
string(`name`),
}
idx int
)

idx = meta.AddWhere(vals[0])
fmt.Println(idx, meta.ListWhereValue)

idx = meta.AddWhere(vals[1])
fmt.Println(idx, meta.ListWhereValue)
// Output:
// 1 [1000]
// 2 [1000 name]
}
52 changes: 34 additions & 18 deletions lib/sql/row.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,40 @@ import (
// The map's key is the column name in database and the map's value is
// the column's value.
// This type can be used to create dynamic insert-update fields.
//
// DEPRECATED: use [Meta] instead.
type Row map[string]interface{}

// Meta convert the Row into Meta.
func (row Row) Meta(driverName string) (meta *Meta) {
meta = &Meta{}

if len(row) == 0 {
return meta
}

meta.ListName = make([]string, 0, len(row))
meta.ListHolder = make([]string, 0, len(row))
meta.ListValue = make([]interface{}, 0, len(row))

var colName string
for colName = range row {
meta.ListName = append(meta.ListName, colName)
}
sort.Strings(meta.ListName)

var x int
for x, colName = range meta.ListName {
if driverName == DriverNamePostgres {
meta.ListHolder = append(meta.ListHolder, fmt.Sprintf(`$%d`, x+1))
} else {
meta.ListHolder = append(meta.ListHolder, DefaultPlaceHolder)
}
meta.ListValue = append(meta.ListValue, row[colName])
}
return meta
}

// ExtractSQLFields extract the column's name, column place holder, and column
// values as slices.
//
Expand All @@ -30,23 +62,7 @@ func (row Row) ExtractSQLFields(driverName string) (names, holders []string, val
return nil, nil, nil
}

names = make([]string, 0, len(row))
holders = make([]string, 0, len(row))
values = make([]interface{}, 0, len(row))

for k := range row {
names = append(names, k)
}
sort.Strings(names)

for x, k := range names {
if driverName == DriverNamePostgres {
holders = append(holders, fmt.Sprintf("$%d", x+1))
} else {
holders = append(holders, DefaultPlaceHolder)
}
values = append(values, row[k])
}
var meta = row.Meta(driverName)

return names, holders, values
return meta.ListName, meta.ListHolder, meta.ListValue
}

0 comments on commit 9021637

Please sign in to comment.