forked from kisielk/sqlstruct
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsqlp.go
173 lines (140 loc) · 6.25 KB
/
sqlp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Copyright 2012 Kamil Kisiel. All rights reserved.
// Modified >2023 by Marius Schmalz
// Use of this source code is governed by the MIT
// license which can be found in the LICENSE file.
/*
Package sqlp provides some convenience functions for using structs with
the Go standard library's database/sql package.
The package matches struct field names to SQL query column names. A field can
also specify a matching column with "sql" tag, if it's different from field
name. Unexported fields or fields marked with `sql:"-"` are ignored, just like
with "encoding/json" package.
For example:
ToDo (See Readme)
*/
package sqlp
import (
"bytes"
"database/sql"
"fmt"
. "github.com/ByteSizedMarius/sqlp/sqlpdb"
"reflect"
"strings"
)
var (
// Global database handle to use for queries
// Used for Insert, QueryBasic,
db *sql.DB
)
// SetDatabase sets the global database handle to be used by the Query function.
func SetDatabase(sqldb *sql.DB) {
db = sqldb
}
// ——————————————————————————————————————————————————————————————————————————————
// Queries
// ——————————————————————————————————————————————————————————————————————————————
func Query[T any](query string, args ...any) (results []T, err error) {
return QueryDb[T](db, query, args...)
}
func QueryRow[T any](query string, args ...any) (result T, err error) {
return QueryRowDb[T](db, query, args...)
}
func QueryBasic[T string | int | int64 | float32 | float64](query string, args ...any) (results []T, err error) {
return QueryBasicDb[T](db, query, args...)
}
func QueryBasicRow[T string | int | int64 | float32 | float64](query string, args ...any) (result T, err error) {
return QueryBasicRowDb[T](db, query, args...)
}
// ——————————————————————————————————————————————————————————————————————————————
// Repo Functions
// ——————————————————————————————————————————————————————————————————————————————
func GetR[T Repo]() ([]T, error) {
query := "SELECT * FROM " + table[T]()
return QueryDb[T](db, query)
}
func GetWhereR[T Repo](where string, args ...any) ([]T, error) {
query, err := whereBuilder("SELECT * FROM "+table[T](), where)
if err != nil {
return nil, err
}
return QueryDb[T](db, query, args...)
}
func GetSingleWhereR[T Repo](where string, args ...any) (res T, err error) {
query, err := whereBuilder("SELECT * FROM "+table[T](), where)
if err != nil {
return
}
return QueryRowDb[T](db, query, args...)
}
func InsertR[T Repo](obj T) (int, error) {
return InsertRdb[T](db, obj)
}
func UpdateR[T Repo](obj T) error {
return UpdateRdb[T](db, obj)
}
func DeleteR[T Repo](obj T) error {
return DeleteRdb[T](db, obj)
}
// ——————————————————————————————————————————————————————————————————————————————
// Deprecated
// ——————————————————————————————————————————————————————————————————————————————
//func In(query string, args ...any) error {
// return InDb(db, query, args...)
//}
// Insert inserts the given object into the table and returns the last inserted id.
// Autogenerated fields can be tagged with `sql-auto:""` (AutoGenTagName) in order for them to be ignored during insert.
// Deprecated
func Insert[T any](obj T, table string) (int, error) {
return InsertDb[T](db, obj, table)
}
// Update
// Deprecated
func Update[T any](obj T, table string) error {
return UpdateDb[T](db, obj, table)
}
// Delete
// Deprecated
func Delete[T any](pk any, table string) error {
return DeleteDb[T](db, pk, table)
}
// ——————————————————————————————————————————————————————————————————————————————
// NameMapper
// ——————————————————————————————————————————————————————————————————————————————
// ToSnakeCase converts a string to snake case, words separated with underscores.
// It's intended to be used with NameMapper to map struct field names to snake case database fields.
func ToSnakeCase(src string) string {
thisUpper := false
prevUpper := false
buf := bytes.NewBufferString("")
for i, v := range src {
if v >= 'A' && v <= 'Z' {
thisUpper = true
} else {
thisUpper = false
}
if i > 0 && thisUpper && !prevUpper {
buf.WriteRune('_')
}
prevUpper = thisUpper
buf.WriteRune(v)
}
return strings.ToLower(buf.String())
}
// ——————————————————————————————————————————————————————————————————————————————
// Helper
// ——————————————————————————————————————————————————————————————————————————————
func table[T Repo]() string {
var instance T
instanceType := reflect.TypeOf(instance)
instanceValue := reflect.New(instanceType).Elem().Interface().(T)
return instanceValue.TableName()
}
func whereBuilder(query string, where string) (string, error) {
if where == "" {
return query, nil
}
if !strings.HasPrefix(where, "WHERE") && !strings.HasPrefix(where, "ORDER") {
return "", fmt.Errorf("where clause must start with WHERE/ORDER " + query)
}
return query + " " + where, nil
}