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
|
package service
import (
"context"
"database/sql"
"git.neonxp.ru/neonxp/guessr/pkg/model"
"github.com/uptrace/bun"
)
type Places struct {
db *bun.DB
}
func New(db *bun.DB) *Places {
return &Places{db: db}
}
func (p *Places) GetNext(ctx context.Context) (*model.Place, error) {
r := new(model.Place)
btx, err := p.db.BeginTx(ctx, &sql.TxOptions{})
if err != nil {
return nil, err
}
err = btx.NewSelect().
ColumnExpr(`p.guid, p.img`).
Model(r).
Where(`p.count = (SELECT MIN(pl.count) FROM places pl WHERE pl.deleted_at IS NULL)`).
OrderExpr(`RANDOM()`).
Limit(1).
Scan(ctx, r)
if err != nil {
return nil, err
}
_, err = btx.NewUpdate().
Model(r).
Set(`count = count + 1`).
WherePK("guid").
Exec(ctx)
if err != nil {
return nil, err
}
return r, btx.Commit()
}
func (p *Places) Guess(ctx context.Context, guid string, lat, lon float32) (*GuessResult, error) {
r := &GuessResult{}
err := p.db.NewSelect().
Model(&model.Place{GUID: guid}).
WherePK("guid").
ColumnExpr(`p.name, p.guid, p.img,
ST_Distance(ST_MakePoint(?, ?)::geography, p.position::geography)::int AS distance,
ST_AsGeoJSON(ST_MakeLine(
ST_SetSRID(ST_MakePoint(?, ?), 4326),
ST_SetSRID(p.position, 4326)
)) AS geojson`, lon, lat, lon, lat).
Scan(ctx, r)
return r, err
}
type GuessResult struct {
GUID string `json:"guid"`
Img string `json:"img"`
Name string `json:"name"`
Geojson any `json:"geojson"`
Distance int `json:"distance"`
}
|