-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsql.go
165 lines (139 loc) · 3.23 KB
/
sql.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
package main
import (
"database/sql"
"log"
"os"
"time"
_ "github.com/lib/pq"
)
// initDB connects to the DB and creates the tables if they don't exist
func initDB() *sql.DB {
// Connect to DB
dbInfo := os.Getenv("DATABASE_URL")
if dbInfo == "" {
dbInfo = "host=localhost port=5432 user=dev password=dev dbname=chat_dev sslmode=disable"
}
db, err := sql.Open("postgres", dbInfo)
if err != nil {
log.Fatalf("Error: %v", err)
}
err = db.Ping()
if err != nil {
log.Fatalf("Error: %v", err)
}
log.Println("Connected to DB.")
// Create tables if not exists
_, err = db.Exec("CREATE EXTENSION IF NOT EXISTS \"pgcrypto\"")
if err != nil {
log.Fatalf("Error: %v", err)
}
_, err = db.Exec(`
CREATE TABLE IF NOT EXISTS messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id VARCHAR(255),
user_name VARCHAR(255),
user_avatar VARCHAR(255),
type VARCHAR(255),
content TEXT,
date_post TIMESTAMP
)
`)
if err != nil {
log.Fatalf("Error: %v", err)
}
log.Println("Tables created or already existing.")
// All good!
return db
}
// insertMessage inserts a single message into the database
// and returns either the id or an error
func insertMessage(db *sql.DB, msg Message) (string, error) {
stmt := `
INSERT INTO messages (
user_id,
user_name,
user_avatar,
type,
content,
date_post
)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id
`
var id string
err := db.QueryRow(stmt, msg.UserID, msg.UserName, msg.UserAvatar, msg.Type, msg.Content, msg.Date).Scan(&id)
if err != nil {
return "", err
}
return id, nil
}
func selectPreviousMessage(db *sql.DB, userID string) (*sql.Rows, error) {
stmt := `
(SELECT *
FROM messages
WHERE type = 'message'
ORDER BY date_post DESC
LIMIT 10)
UNION
(SELECT *
FROM messages
WHERE type = 'message'
AND user_id != $1
AND date_post > (
SELECT date_post
FROM messages
WHERE type = 'logout'
AND user_id = $1
ORDER BY date_post DESC
LIMIT 1
)
)
`
rows, err := db.Query(stmt, userID)
if err != nil {
return &sql.Rows{}, err
}
return rows, nil
}
func selectConnectedUsers(db *sql.DB, userID string) (*sql.Rows, error) {
stmt := `
SELECT DISTINCT m.user_id, users_login.user_name, users_login.user_avatar
FROM messages m
INNER JOIN
(SELECT DISTINCT user_id, user_name, user_avatar, MAX(date_post)
FROM messages
WHERE type = 'login'
GROUP BY user_id, user_name, user_avatar) users_login
ON m.user_id = users_login.user_id
LEFT JOIN
(SELECT DISTINCT user_id, user_name, user_avatar, MAX(date_post)
FROM messages
WHERE type = 'logout'
GROUP BY user_id, user_name, user_avatar) users_logout
ON m.user_id = users_logout.user_id
WHERE m.user_id != $1
AND users_login.max > users_logout.max
OR users_logout.max IS NULL
ORDER BY users_login.user_name
`
rows, err := db.Query(stmt, userID)
if err != nil {
return &sql.Rows{}, err
}
return rows, nil
}
func selectOlderMessages(db *sql.DB, date time.Time) (*sql.Rows, error) {
stmt := `
SELECT *
FROM messages
WHERE type = 'message'
AND date_post < $1
ORDER BY date_post DESC
LIMIT 10
`
rows, err := db.Query(stmt, date)
if err != nil {
return &sql.Rows{}, err
}
return rows, nil
}