/
elemcreate.go
183 lines (163 loc) · 4.73 KB
/
elemcreate.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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package polls
import (
"database/sql"
"errors"
"fmt"
"strings"
"sync"
"time"
"github.com/Nv7-Github/Nv7Haven/eod/types"
"github.com/Nv7-Github/Nv7Haven/eod/util"
"github.com/jmoiron/sqlx"
"github.com/lib/pq"
)
var createlock = &sync.Mutex{}
func (e *Polls) elemCreate(p *types.Poll, news func(string)) (err error) {
createlock.Lock()
defer createlock.Unlock()
els := util.Map(p.Data["els"].([]any), func(a any) int { return int(a.(float64)) })
_, exists := p.Data["result"].(float64)
// Check if combo has result
var cmbexists bool
err = e.db.QueryRow(`SELECT EXISTS(SELECT 1 FROM combos WHERE els=$1 AND guild=$2)`, pq.Array(els), p.Guild).Scan(&cmbexists)
if err != nil {
return err
}
if cmbexists {
return errors.New("already has result")
}
// Check if name already exists
if !exists {
var nameid int
err = e.db.QueryRow(`SELECT id FROM elements WHERE LOWER(name)=$1 AND guild=$2`, strings.ToLower(p.Data["result"].(string)), p.Guild).Scan(&nameid)
if err != nil && err != sql.ErrNoRows {
return err
}
if err == nil {
exists = true
p.Data["result"] = float64(nameid)
}
}
// Make tx
var tx *sqlx.Tx
tx, err = e.db.Beginx()
if err != nil {
return
}
defer func() {
if err != nil && tx != nil {
err = tx.Rollback()
return
}
}()
// Create elem if not exists
var id int
var combid int // ID of combo if elem exists for news
var name string
if !exists {
// Get id
err = tx.QueryRow(`SELECT MAX(id) FROM elements WHERE guild=$1`, p.Guild).Scan(&id)
if err != nil {
return
}
id++
// Get parents
var parents []types.Element
err = tx.Select(&parents, `SELECT id, color FROM elements WHERE id=ANY($1) AND guild=$2`, pq.Array(els), p.Guild)
if err != nil {
return
}
col := 0
for _, parent := range parents {
col += parent.Color
}
col /= len(parents)
// Calc treesize
var treeSize int
err = tx.QueryRow(`WITH RECURSIVE parents(els, id) AS (
VALUES($2::integer[], 0)
UNION
(SELECT b.parents els, b.id id FROM elements b INNER JOIN parents p ON b.id=ANY(p.els) where guild=$1)
) SELECT COUNT(*) FROM parents WHERE id>0`, p.Guild, pq.Array(els)).Scan(&treeSize)
if err != nil {
return
}
// Create element
el := types.Element{
ID: id,
Guild: p.Guild,
Name: p.Data["result"].(string),
Color: col,
Creator: p.Creator,
Comment: "None",
CreatedOn: time.Now(),
Parents: pq.Int32Array(util.Map(els, func(a int) int32 { return int32(a) })),
TreeSize: treeSize,
}
name = el.Name
// Insert element
_, err = tx.NamedExec(`INSERT INTO elements (id, guild, name, image, color, comment, creator, createdon, commenter, colorer, imager, parents, treesize) VALUES (:id, :guild, :name, :image, :color, :comment, :creator, :createdon, :commenter, :colorer, :imager, :parents, :treesize)`, el)
if err != nil {
return
}
} else {
id = int(p.Data["result"].(float64))
// Combo ID
err = tx.QueryRow(`SELECT COUNT(*) FROM combos WHERE guild=$1`, p.Guild).Scan(&combid)
if err != nil {
return
}
combid++
// Get name
var currtreesize int
err = tx.QueryRow(`SELECT name, treesize FROM elements WHERE id=$1 AND guild=$2`, id, p.Guild).Scan(&name, &currtreesize)
if err != nil {
return
}
// Check if need to update parents
var treesize int
var loop bool
err = tx.QueryRow(`WITH RECURSIVE parents(els, id) AS (
VALUES($2::integer[], 0)
UNION
(SELECT b.parents els, b.id id FROM elements b INNER JOIN parents p ON b.id=ANY(p.els) where guild=$1)
) SELECT COUNT(*), EXISTS(SELECT 1 FROM parents WHERE id=$3) FROM parents WHERE id>0`, p.Guild, pq.Array(els), id).Scan(&treesize, &loop)
if !loop && treesize < currtreesize {
// Update parents
_, err = tx.Exec(`UPDATE elements SET parents=$1, treesize=$2 WHERE id=$3 AND guild=$4`, pq.Array(els), treesize, id, p.Guild)
if err != nil {
return
}
}
}
// Create combo
_, err = tx.Exec(`INSERT INTO combos (guild, els, result, createdon) VALUES ($1, $2, $3, $4)`, p.Guild, pq.Array(els), id, time.Now())
if err != nil {
return
}
// Commit
err = tx.Commit()
tx = nil
if err != nil {
return
}
// Add to creator's inv if not already in it
var cont bool
err = e.db.QueryRow(`SELECT $3=ANY(inv) FROM inventories WHERE guild=$1 AND "user"=$2`, p.Guild, p.Creator, id).Scan(&cont)
if err != nil {
return
}
if !cont {
_, err = e.db.Exec(`UPDATE inventories SET inv=array_append(inv, $3) WHERE guild=$1 AND "user"=$2`, p.Guild, p.Creator, id)
if err != nil {
return
}
}
// Message
if exists {
news(fmt.Sprintf("🆕 Combination - **%s** %s - Combination **#%d**", name, e.pollContextMsg(p), combid))
} else {
news(fmt.Sprintf("🆕 Element - **%s** %s - Element **#%d**", name, e.pollContextMsg(p), id))
}
return
}