-
Notifications
You must be signed in to change notification settings - Fork 0
/
table.go
120 lines (102 loc) · 2.78 KB
/
table.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
package table
import (
"context"
"github.com/jmoiron/sqlx"
)
// Table provides boilerplate ops for some table with sqlx.
type Table[T any] struct {
name string
pk string
helper *helper
}
// New returns a new Table for the given type.
func New[T any](name, pk string, opts ...Option) *Table[T] {
var t T
return &Table[T]{
helper: newHelper(t, opts...),
name: name,
pk: pk,
}
}
// Find returns a single record with a value matching a given pk.
func (t *Table[T]) Find(ctx context.Context, db *sqlx.DB, id any) (*T, error) {
return t.Fetch(ctx, db, t.pk, id)
}
// Fetch returns a single record with a value matching a given field. Mostly
// useful for fetching by unique values.
func (t *Table[T]) Fetch(ctx context.Context, db *sqlx.DB, col string, val any) (*T, error) {
q := "SELECT " + t.helper.All + " FROM " + t.name + " WHERE " + col + " = ?"
rows, err := db.QueryxContext(ctx, q, val)
if err != nil {
return nil, err
}
defer rows.Close()
var obj T
for rows.Next() {
if err := rows.StructScan(&obj); err != nil {
return nil, err
}
break
}
return &obj, nil
}
// Select fetches all records matching a given query.
func (t *Table[T]) Select(ctx context.Context, db *sqlx.DB, query string, args ...any) ([]*T, error) {
q := "SELECT " + t.helper.All + " FROM " + t.name + " WHERE " + query
rows, err := db.QueryxContext(ctx, q, args...)
if err != nil {
return nil, err
}
defer rows.Close()
var col []*T
for rows.Next() {
var row T
if err := rows.StructScan(&row); err != nil {
return nil, err
}
col = append(col, &row)
}
return col, nil
}
// Insert inserts a single record into the table.
func (t *Table[T]) Insert(ctx context.Context, db *sqlx.DB, obj *T) error {
h := t.helper
q := "INSERT INTO " + t.name + "(" + h.Inserts + ") VALUES (" + h.InsertFields + ") RETURNING " + h.Returning
rows, err := db.NamedQueryContext(ctx, q, obj)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
if err := rows.StructScan(obj); err != nil {
return err
}
break
}
return nil
}
// Replace replaces the given record.
func (t *Table[T]) Replace(ctx context.Context, db *sqlx.DB, obj *T) error {
q := "UPDATE " + t.name + " SET " + t.helper.UpdateValues + " WHERE " + t.pk + " = :" + t.pk + " RETURNING " + t.helper.Returning
rows, err := db.NamedQueryContext(ctx, q, obj)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
if err := rows.StructScan(obj); err != nil {
return err
}
break
}
return nil
}
// Delete deletes records matching the query.
func (t *Table[T]) Delete(ctx context.Context, db *sqlx.DB, query string, args ...any) (int64, error) {
q := "DELETE FROM " + t.name + " WHERE " + query
res, err := db.ExecContext(ctx, q, args...)
if err != nil {
return 0, err
}
return res.RowsAffected()
}