forked from jonbodner/proteus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
145 lines (126 loc) · 6.81 KB
/
main.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
package main
import (
"context"
"database/sql"
"fmt"
"github.com/jonbodner/dbtimer"
"github.com/jonbodner/proteus"
"github.com/jonbodner/proteus/logger"
_ "github.com/lib/pq"
)
type Product struct {
Id int `prof:"id"`
Name string `prof:"name"`
Cost *float64 `prof:"cost"`
}
func (p Product) String() string {
c := "<nil>"
if p.Cost != nil {
c = fmt.Sprintf("%f", *p.Cost)
}
return fmt.Sprintf("%d: %s(%s)", p.Id, p.Name, c)
}
type ProductDAO struct {
FindByID func(ctx context.Context, e proteus.ContextQuerier, id int) (Product, error) `proq:"select * from Product where id = :id:" prop:"id"`
Update func(ctx context.Context, e proteus.ContextExecutor, p Product) (int64, error) `proq:"update Product set name = :p.Name:, cost = :p.Cost: where id = :p.Id:" prop:"p"`
FindByNameAndCost func(ctx context.Context, e proteus.ContextQuerier, name string, cost float64) ([]Product, error) `proq:"select * from Product where name=:name: and cost=:cost:" prop:"name,cost"`
FindByIDMap func(ctx context.Context, e proteus.ContextQuerier, id int) (map[string]interface{}, error) `proq:"select * from Product where id = :id:" prop:"id"`
UpdateMap func(ctx context.Context, e proteus.ContextExecutor, p map[string]interface{}) (int64, error) `proq:"update Product set name = :p.Name:, cost = :p.Cost: where id = :p.Id:" prop:"p"`
FindByNameAndCostMap func(ctx context.Context, e proteus.ContextQuerier, name string, cost float64) ([]map[string]interface{}, error) `proq:"select * from Product where name=:name: and cost=:cost:" prop:"name,cost"`
Insert func(ctx context.Context, e proteus.ContextExecutor, id int, name string, cost *float64) (int64, error) `proq:"insert into product(id, name, cost) values(:id:, :name:, :cost:)" prop:"id,name,cost"`
FindByIDSlice func(ctx context.Context, e proteus.ContextQuerier, ids []int) ([]Product, error) `proq:"select * from Product where id in (:ids:)" prop:"ids"`
FindByIDSliceAndName func(ctx context.Context, e proteus.ContextQuerier, ids []int, name string) ([]Product, error) `proq:"select * from Product where name = :name: and id in (:ids:)" prop:"ids,name"`
FindByIDSliceNameAndCost func(ctx context.Context, e proteus.ContextQuerier, ids []int, name string, cost *float64) ([]Product, error) `proq:"select * from Product where name = :name: and id in (:ids:) and (cost is null or cost = :cost:)" prop:"ids,name,cost"`
FindByIDSliceCostAndNameSlice func(ctx context.Context, e proteus.ContextQuerier, ids []int, names []string, cost *float64) ([]Product, error) `proq:"select * from Product where id in (:ids:) and (cost is null or cost = :cost:) and name in (:names:)" prop:"ids,names,cost"`
FindByNameAndCostUnlabeled func(ctx context.Context, e proteus.ContextQuerier, name string, cost float64) ([]Product, error) `proq:"select * from Product where name=:$1: and cost=:$2:"`
}
type setupDb func(c context.Context, p ProductDAO) *sql.DB
func main() {
dbtimer.SetTimerLoggerFunc(func(ti dbtimer.TimerInfo) {
fmt.Printf("%s %s %v %v %d\n", ti.Method, ti.Query, ti.Args, ti.Err, ti.End.Sub(ti.Start).Nanoseconds()/1000)
})
logger.Config(logger.LoggerFunc(func(vals ...interface{}) error {
fmt.Printf("%s: (%s) - %+v\n", vals[1], vals[3], vals[5])
return nil
}))
ctx := context.Background()
var productDAO ProductDAO
err := proteus.ShouldBuild(ctx, &productDAO, proteus.Postgres)
if err != nil {
panic(err)
}
run(setupDbPostgres, productDAO)
}
func run(setupDb setupDb, productDAO ProductDAO) {
ctx := logger.WithLevel(context.Background(), logger.DEBUG)
db := setupDb(ctx, productDAO)
defer db.Close()
tx, err := db.Begin()
if err != nil {
panic(err)
}
defer tx.Commit()
logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByID(ctx, tx, 10)))
cost := new(float64)
*cost = 56.23
p := Product{10, "Thingie", cost}
logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.Update(ctx, tx, p)))
logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByID(ctx, tx, 10)))
logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByNameAndCost(ctx, tx, "fred", 54.10)))
logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByNameAndCost(ctx, tx, "Thingie", 56.23)))
//using a map of [string]interface{} works too!
logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDMap(ctx, tx, 10))))
logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByNameAndCostMap(ctx, tx, "Thingie", 56.23))))
logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByID(ctx, tx, 11))))
m := map[string]interface{}{
"Id": 11,
"Name": "bobbo",
"Cost": 12.94,
}
logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.UpdateMap(ctx, tx, m))))
logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByID(ctx, tx, 11))))
//searching using a slice
logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSlice(ctx, tx, []int{1, 3, 5}))))
logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSliceAndName(ctx, tx, []int{1, 3, 5}, "person1"))))
logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSliceNameAndCost(ctx, tx, []int{1, 3, 5}, "person3", nil))))
logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSliceCostAndNameSlice(ctx, tx, []int{1, 3, 5}, []string{"person3", "person5"}, nil))))
//using positional parameters instead of names
logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByNameAndCostUnlabeled(ctx, tx, "Thingie", 56.23))))
}
func setupDbPostgres(ctx context.Context, productDAO ProductDAO) *sql.DB {
//db, err := sql.Open("postgres", "postgres://pro_user:pro_pwd@localhost/proteus?sslmode=disable")
db, err := sql.Open("timer", "postgres postgres://pro_user:pro_pwd@localhost/proteus?sslmode=disable")
if err != nil {
logger.Log(ctx, logger.FATAL, fmt.Sprintln(err))
}
sqlStmt := `
drop table if exists product;
create table product (id integer not null primary key, name text, cost real);
`
_, err = db.Exec(sqlStmt)
if err != nil {
logger.Log(ctx, logger.FATAL, fmt.Sprintf("%q: %s\n", err, sqlStmt))
return nil
}
populate(ctx, db, productDAO)
return db
}
func populate(ctx context.Context, db *sql.DB, productDao ProductDAO) {
tx, err := db.Begin()
if err != nil {
logger.Log(ctx, logger.FATAL, fmt.Sprintln(err))
}
defer tx.Commit()
for i := 0; i < 100; i++ {
var cost *float64
if i%2 == 0 {
c := 1.1 * float64(i)
cost = &c
}
rowCount, err := productDao.Insert(ctx, tx, i, fmt.Sprintf("person%d", i), cost)
if err != nil {
logger.Log(ctx, logger.FATAL, fmt.Sprintln(err))
}
logger.Log(ctx, logger.DEBUG, fmt.Sprintln(rowCount))
}
}