Skip to content

Commit ecce80d

Browse files
committed
small refactor + db work on various units
1 parent 7afd6bc commit ecce80d

22 files changed

+780
-183
lines changed

Makefile

+4-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,7 @@ build:
2020
go build --ldflags "-X main.buildVersion=source"
2121

2222
build_all:
23-
xgo -out build/twitch --targets "darwin/amd64,windows/amd64,linux/amd64" --ldflags "-X main.buildVersion=source" ./
23+
xgo -out build/twitch --targets "darwin/amd64,windows/amd64,linux/amd64" --ldflags "-X main.buildVersion=source" ./
24+
25+
clean:
26+
rm -rf ~/.twitch-cli/eventCache.db

internal/database/_schema.sql

+12
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ create table bans (
3535
foreign key (broadcaster_id) references users(id),
3636
foreign key (user_id) references users(id)
3737
);
38+
create table ban_events (
39+
id text not null primary key,
40+
event_timestamp text not null,
41+
event_type text not null,
42+
event_version text not null default '1.0',
43+
broadcaster_id text not null,
44+
user_id text not null,
45+
expires_at text,
46+
foreign key (broadcaster_id) references users(id),
47+
foreign key (user_id) references users(id)
48+
);
3849
create table moderators (
3950
broadcaster_id text not null,
4051
user_id text not null,
@@ -163,6 +174,7 @@ create table subscriptions (
163174
is_gift boolean not null default false,
164175
gifter_id text,
165176
tier text not null default '1000',
177+
created_at text not null,
166178
primary key (broadcaster_id, user_id),
167179
foreign key (broadcaster_id) references users(id),
168180
foreign key (user_id) references users(id),

internal/database/_template.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,22 @@ import "log"
77
type Principle struct {
88
}
99

10-
func (c CLIDatabase) GetPrincipleById(id string) (Principle, error) {
10+
func (c CLIDatabase) GetPrinciple(p Principle) (Principle, error) {
1111
var r Principle
1212

13-
err := c.DB.Get(&r, "select * from principle where id = $1", id)
13+
sql := generateSQL("select * from principle", u, SEP_AND)
14+
sql = fmt.Sprintf("%v LIMIT 1", sql)
15+
rows, err := c.DB.NamedQuery(sql, u)
1416
if err != nil {
1517
return r, err
1618
}
17-
log.Printf("%#v", r)
19+
20+
for rows.Next() {
21+
err := rows.StructScan(&r)
22+
if err != nil {
23+
return r, err
24+
}
25+
}
1826

1927
return r, err
2028
}

internal/database/api.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package database
4+
5+
type DBResposne struct {
6+
Cursor string
7+
Total string
8+
Limit int
9+
Data interface{}
10+
}
11+
12+
type DBPagination struct {
13+
Limit int
14+
Cursor string
15+
}

internal/database/categories.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,24 @@
22
// SPDX-License-Identifier: Apache-2.0
33
package database
44

5-
import "log"
6-
75
type Category struct {
8-
ID string `db:"id"`
9-
Name string `db:"category_name"`
6+
ID string `db:"id" json:"id"`
7+
Name string `db:"category_name" json:"name"`
108
}
119

12-
func (c CLIDatabase) GetCategoryByID(id string) (Category, error) {
10+
func (c CLIDatabase) GetCategory(cat Category) (Category, error) {
1311
var r Category
14-
err := c.DB.Get(&r, "select * from categories where id = $1", id)
12+
rows, err := c.DB.NamedQuery(generateSQL("select * from categories", cat, SEP_AND), cat)
1513
if err != nil {
1614
return r, err
1715
}
18-
log.Printf("%#v", r)
16+
17+
for rows.Next() {
18+
err := rows.StructScan(&r)
19+
if err != nil {
20+
return r, err
21+
}
22+
}
1923

2024
return r, err
2125
}

internal/database/init.go

+2-2
Large diffs are not rendered by default.

internal/database/moderation.go

+39-6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313

1414
const MOD_ADD = "moderation.moderator.add"
1515
const MOD_REMOVE = "moderation.moderator.remove"
16+
const BAN_ADD = "moderation.user.ban"
17+
const BAN_REMOVE = "moderation.user.unban"
1618

1719
type Moderator struct {
1820
UserID string `db:"user_id" json:"user_id"`
@@ -37,6 +39,11 @@ type ModeratorActionEvent struct {
3739
UserName string `db:"user_name" json:"user_name"`
3840
}
3941

42+
type BanEvent struct {
43+
ModeratorAction
44+
ExpiresAt *sql.NullString `db:"expires_at" json:"expires_at"`
45+
}
46+
4047
func (c CLIDatabase) GetModerationActionsByBroadcaster(broadcaster string) ([]ModeratorAction, error) {
4148
var r []ModeratorAction
4249

@@ -49,21 +56,23 @@ func (c CLIDatabase) GetModerationActionsByBroadcaster(broadcaster string) ([]Mo
4956
return r, err
5057
}
5158

52-
func (c CLIDatabase) AddModerator(broadcaster string, user string) error {
59+
func (c CLIDatabase) AddModerator(p UserRequestParams) error {
60+
stmt := generateInsertSQL("moderators", "id", p, false)
61+
p.CreatedAt = util.GetTimestamp().UTC().Format(time.RFC3339)
62+
5363
ma := ModeratorAction{
5464
ID: util.RandomGUID(),
5565
EventType: MOD_ADD,
5666
EventVersion: "1.0",
5767
EventTimestamp: util.GetTimestamp().Format(time.RFC3339),
5868
ModeratorActionEvent: ModeratorActionEvent{
59-
UserID: user,
60-
BroadcasterID: broadcaster,
69+
UserID: p.UserID,
70+
BroadcasterID: p.BroadcasterID,
6171
},
6272
}
6373

6474
tx := c.DB.MustBegin()
65-
tx.Exec(`insert into moderators values($1, $2, $3)`, broadcaster, user, util.GetTimestamp().UTC().Format(time.RFC3339))
66-
75+
tx.NamedExec(stmt, p)
6776
tx.NamedExec(`INSERT INTO moderator_actions VALUES(:id, :event_type, :event_timestamp, :event_version, :broadcaster_id, :user_id)`, ma)
6877
return tx.Commit()
6978
}
@@ -84,7 +93,7 @@ func (c CLIDatabase) GetModeratorsForBroadcaster(broadcasterID string, userID st
8493
func (c CLIDatabase) RemoveModerator(broadcaster string, user string) error {
8594
ma := ModeratorAction{
8695
ID: util.RandomGUID(),
87-
EventType: MOD_REMOVE,
96+
EventType: BAN_ADD,
8897
EventVersion: "1.0",
8998
EventTimestamp: util.GetTimestamp().Format(time.RFC3339),
9099
ModeratorActionEvent: ModeratorActionEvent{
@@ -98,3 +107,27 @@ func (c CLIDatabase) RemoveModerator(broadcaster string, user string) error {
98107
tx.NamedExec(`INSERT INTO moderator_actions VALUES(:id, :event_type, :event_timestamp, :event_version, :broadcaster_id, :user_id)`, ma)
99108
return tx.Commit()
100109
}
110+
111+
func (c CLIDatabase) InsertBan(p UserRequestParams) error {
112+
stmt := generateInsertSQL("bans", "id", p, false)
113+
p.CreatedAt = util.GetTimestamp().UTC().Format(time.RFC3339)
114+
115+
ma := BanEvent{
116+
ModeratorAction: ModeratorAction{
117+
ID: util.RandomGUID(),
118+
EventType: BAN_ADD,
119+
EventVersion: "1.0",
120+
EventTimestamp: util.GetTimestamp().Format(time.RFC3339),
121+
ModeratorActionEvent: ModeratorActionEvent{
122+
UserID: p.UserID,
123+
BroadcasterID: p.BroadcasterID,
124+
},
125+
},
126+
ExpiresAt: &sql.NullString{String: ""},
127+
}
128+
129+
tx := c.DB.MustBegin()
130+
tx.NamedExec(stmt, p)
131+
tx.NamedExec(`INSERT INTO ban_events VALUES(:id, :event_type, :event_timestamp, :event_version, :broadcaster_id, :user_id, :expires_at)`, ma)
132+
return tx.Commit()
133+
}

internal/database/sql_gen.go

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package database
4+
5+
import (
6+
"encoding/base64"
7+
"encoding/json"
8+
"fmt"
9+
"log"
10+
"reflect"
11+
"strings"
12+
)
13+
14+
const SEP_AND = "and"
15+
const SEP_OR = "or"
16+
17+
type InternalPagination struct {
18+
SQL string
19+
InternalCursor
20+
PaginationCursor string
21+
}
22+
23+
type InternalCursor struct {
24+
Offset int `json:"o"`
25+
Limit int `json:"l"`
26+
}
27+
28+
func generateSQL(s string, i interface{}, seperator string) string {
29+
if seperator == "" {
30+
seperator = "and"
31+
}
32+
33+
t := reflect.TypeOf(i)
34+
v := reflect.ValueOf(i)
35+
36+
whereClause := []string{}
37+
for index := 0; index < t.NumField(); index++ {
38+
field := v.Field(index)
39+
40+
db := t.Field(index).Tag.Get("db")
41+
if db == "" {
42+
continue
43+
}
44+
45+
switch field.Kind() {
46+
case reflect.String:
47+
if field.Interface().(string) == "" {
48+
continue
49+
}
50+
break
51+
case reflect.Ptr:
52+
if !field.Elem().IsValid() {
53+
continue
54+
}
55+
break
56+
case reflect.Bool:
57+
if field.Interface() == false {
58+
continue
59+
}
60+
break
61+
default:
62+
println(v.Field(index).Kind())
63+
}
64+
65+
whereClause = append(whereClause, fmt.Sprintf("%v = :%v", db, db))
66+
}
67+
w := strings.Join(whereClause, fmt.Sprintf(" %v ", seperator))
68+
s = fmt.Sprintf("%v where %v", s, w)
69+
return s
70+
}
71+
72+
func generateInsertSQL(table string, pk string, i interface{}, upsert bool) string {
73+
t := reflect.TypeOf(i)
74+
75+
insertClause := []string{}
76+
valuesClause := []string{}
77+
upsertClause := []string{}
78+
for index := 0; index < t.NumField(); index++ {
79+
field := t.Field(index)
80+
81+
db := field.Tag.Get("db")
82+
if db == "" {
83+
continue
84+
}
85+
insertClause = append(insertClause, fmt.Sprintf("%v", db))
86+
valuesClause = append(valuesClause, fmt.Sprintf(":%v", db))
87+
if upsert {
88+
upsertClause = append(upsertClause, fmt.Sprintf("%v=:%v", db, db))
89+
}
90+
}
91+
s := fmt.Sprintf("insert into %v (%v) values(%v)", table, strings.Join(insertClause, ", "), strings.Join(valuesClause, ", "))
92+
if upsert {
93+
s = fmt.Sprintf("%v on conflict(%v) do update set %v", s, pk, strings.Join(upsertClause, ", "))
94+
}
95+
96+
return s
97+
}
98+
99+
func generatePaginationSQLAndResponse(limit int, prev_cursor string, is_before bool) InternalPagination {
100+
ic := InternalCursor{}
101+
if limit == 0 {
102+
limit = 20
103+
}
104+
105+
if prev_cursor != "" {
106+
b, err := base64.RawStdEncoding.DecodeString(prev_cursor)
107+
if err != nil {
108+
log.Print(err)
109+
}
110+
json.Unmarshal(b, &ic)
111+
if is_before {
112+
ic.Offset -= limit
113+
} else {
114+
ic.Offset += limit
115+
}
116+
}
117+
118+
ic.Limit = limit
119+
120+
if ic.Offset < 0 {
121+
return InternalPagination{}
122+
}
123+
124+
b, _ := json.Marshal(ic)
125+
126+
ip := InternalPagination{
127+
InternalCursor: ic,
128+
PaginationCursor: base64.RawURLEncoding.EncodeToString(b),
129+
SQL: fmt.Sprintf(" LIMIT %v OFFSET %v", ic.Limit, ic.Offset),
130+
}
131+
132+
return ip
133+
}

0 commit comments

Comments
 (0)