Source file
src/database/sql/example_service_test.go
1
2
3
4
5 package sql_test
6
7 import (
8 "context"
9 "database/sql"
10 "encoding/json"
11 "fmt"
12 "io"
13 "log"
14 "net/http"
15 "time"
16 )
17
18 func Example_openDBService() {
19
20 db, err := sql.Open("driver-name", "database=test1")
21 if err != nil {
22
23
24 log.Fatal(err)
25 }
26 db.SetConnMaxLifetime(0)
27 db.SetMaxIdleConns(50)
28 db.SetMaxOpenConns(50)
29
30 s := &Service{db: db}
31
32 http.ListenAndServe(":8080", s)
33 }
34
35 type Service struct {
36 db *sql.DB
37 }
38
39 func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
40 db := s.db
41 switch r.URL.Path {
42 default:
43 http.Error(w, "not found", http.StatusNotFound)
44 return
45 case "/healthz":
46 ctx, cancel := context.WithTimeout(r.Context(), 1*time.Second)
47 defer cancel()
48
49 err := s.db.PingContext(ctx)
50 if err != nil {
51 http.Error(w, fmt.Sprintf("db down: %v", err), http.StatusFailedDependency)
52 return
53 }
54 w.WriteHeader(http.StatusOK)
55 return
56 case "/quick-action":
57
58
59 ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
60 defer cancel()
61
62 id := 5
63 org := 10
64 var name string
65 err := db.QueryRowContext(ctx, `
66 select
67 p.name
68 from
69 people as p
70 join organization as o on p.organization = o.id
71 where
72 p.id = :id
73 and o.id = :org
74 ;`,
75 sql.Named("id", id),
76 sql.Named("org", org),
77 ).Scan(&name)
78 if err != nil {
79 if err == sql.ErrNoRows {
80 http.Error(w, "not found", http.StatusNotFound)
81 return
82 }
83 http.Error(w, err.Error(), http.StatusInternalServerError)
84 return
85 }
86 io.WriteString(w, name)
87 return
88 case "/long-action":
89
90
91
92
93 ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second)
94 defer cancel()
95
96 var names []string
97 rows, err := db.QueryContext(ctx, "select p.name from people as p where p.active = true;")
98 if err != nil {
99 http.Error(w, err.Error(), http.StatusInternalServerError)
100 return
101 }
102
103 for rows.Next() {
104 var name string
105 err = rows.Scan(&name)
106 if err != nil {
107 break
108 }
109 names = append(names, name)
110 }
111
112
113
114 if closeErr := rows.Close(); closeErr != nil {
115 http.Error(w, closeErr.Error(), http.StatusInternalServerError)
116 return
117 }
118
119
120 if err != nil {
121 http.Error(w, err.Error(), http.StatusInternalServerError)
122 return
123 }
124
125
126 if err = rows.Err(); err != nil {
127 http.Error(w, err.Error(), http.StatusInternalServerError)
128 return
129 }
130
131 json.NewEncoder(w).Encode(names)
132 return
133 case "/async-action":
134
135
136
137
138 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
139 defer cancel()
140
141 var orderRef = "ABC123"
142 tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
143 if err != nil {
144 http.Error(w, err.Error(), http.StatusInternalServerError)
145 return
146 }
147 _, err = tx.ExecContext(ctx, "stored_proc_name", orderRef)
148
149 if err != nil {
150 tx.Rollback()
151 http.Error(w, err.Error(), http.StatusInternalServerError)
152 return
153 }
154 err = tx.Commit()
155 if err != nil {
156 http.Error(w, "action in unknown state, check state before attempting again", http.StatusInternalServerError)
157 return
158 }
159 w.WriteHeader(http.StatusOK)
160 return
161 }
162 }
163
View as plain text