/
api.go
162 lines (144 loc) · 4.49 KB
/
api.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
package anyrow
import (
"context"
"errors"
"github.com/emicklei/anyrow/pb"
pgx "github.com/jackc/pgx/v5"
)
func FilterLimit(limit int) filterOption {
return func(f fetchFilter) fetchFilter {
f.limit = limit
return f
}
}
// Record represents a Table row as a Map.
type Record map[string]any
// FilterRecords queries a table using a WHERE clause. Unless option is given, the limit is 1000.
func FilterRecords(ctx context.Context, conn Querier, metadataCacheKey, tableName string, where string, options ...filterOption) ([]Record, error) {
set, ok := metaCache.Get(metadataCacheKey)
if !ok {
mset, err := getMetadata(ctx, conn, tableName)
if err != nil {
return nil, err
}
metaCache.Set(metadataCacheKey, mset, defaultExpiration)
set = mset
}
collector := &objectCollector{
set: set.(*pb.RowSet),
}
filter := fetchFilter{
where: where,
limit: 1000,
}
if filter.limit <= 0 {
return nil, errors.New("limit parameter must be greater than zero")
}
for _, each := range options {
filter = each(filter)
}
err := fetchValues(ctx, conn, collector.set, filter, collector)
return collector.list, err
}
func FetchSchemas(ctx context.Context, conn Querier) ([]string, error) {
return getSchemaNames(ctx, conn)
}
// FetchTablenames returns a list of public tablenames.
func FetchTableNames(ctx context.Context, conn Querier, schema string) ([]string, error) {
return getTableNames(ctx, conn, schema)
}
// FetchColumns returns a list of column schemas for a public tablename.
func FetchColumns(ctx context.Context, conn Querier, tableName string) ([]*pb.ColumnSchema, error) {
set, err := getMetadata(ctx, conn, tableName)
if err != nil {
return []*pb.ColumnSchema{}, err
}
return set.ColumnSchemas, nil
}
// FetchRecords returns a list of Objects (generic maps) for the given list primary key values.
func FetchRecords(ctx context.Context, conn Querier, metadataCacheKey, tableName string, pkv PrimaryKeysAndValues) ([]Record, error) {
set, ok := metaCache.Get(metadataCacheKey)
if !ok {
mset, err := getMetadata(ctx, conn, tableName)
if err != nil {
return nil, err
}
metaCache.Set(metadataCacheKey, mset, defaultExpiration)
set = mset
}
collector := &objectCollector{
set: set.(*pb.RowSet),
}
filter := fetchFilter{
pkv: pkv,
}
err := fetchValues(ctx, conn, set.(*pb.RowSet), filter, collector)
return collector.list, err
}
// FetchObjects returns a protobuf RowSet for the given list primary key values.
func FetchRowSet(ctx context.Context, conn Querier, metadataCacheKey, tableName string, pkv PrimaryKeysAndValues) (*pb.RowSet, error) {
set, ok := metaCache.Get(metadataCacheKey)
if !ok {
mset, err := getMetadata(ctx, conn, tableName)
if err != nil {
return nil, err
}
metaCache.Set(metadataCacheKey, mset, defaultExpiration)
set = mset
}
tset := set.(*pb.RowSet)
collector := &rowsetCollector{
// create a new with metadata from the cached set
set: &pb.RowSet{
TableName: tset.TableName,
ColumnSchemas: tset.ColumnSchemas,
},
}
filter := fetchFilter{
pkv: pkv,
}
err := fetchValues(ctx, conn, tset, filter, collector)
return collector.set, err
}
// Querier is the interface that is used from a database connection.
// Known implementations are *pgx.Conn and *pgx.Tx and *pgxpool.Conn.
type Querier interface {
Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
}
// PrimaryKeysAndValues is a parameter object holding the column name(s) and one or more values.
type PrimaryKeysAndValues struct {
// either a single column with many values
column string
values []any
// or pairs
pairs []PrimaryKeyAndValue
}
func (pkv PrimaryKeysAndValues) hasValues() bool {
return len(pkv.values) > 0 || len(pkv.pairs) > 0
}
func (pkv PrimaryKeysAndValues) parameterValues() (list []any) {
if pkv.column != "" {
return pkv.values
}
// use pairs
for _, each := range pkv.pairs {
list = append(list, each.Value)
}
return
}
type PrimaryKeyAndValue struct {
Column string
Value any
}
// NewPrimaryKeyAndValue creates a parameter object.
func NewPrimaryKeyAndValue(column string, value any) PrimaryKeyAndValue {
return PrimaryKeyAndValue{Column: column, Value: value}
}
// NewPrimaryKeyAndValues creates a parameter object.
func NewPrimaryKeyAndValues(column string, value ...any) PrimaryKeysAndValues {
return PrimaryKeysAndValues{column: column, values: value}
}
// MewPrimaryKeysAndValues creates a parameter object.
func NewPrimaryKeysAndValues(pairs []PrimaryKeyAndValue) PrimaryKeysAndValues {
return PrimaryKeysAndValues{pairs: pairs}
}