summaryrefslogtreecommitdiff
path: root/pkg/service/places.go
blob: d0888368a470a03f0f836f689710c8bae2618728 (plain) (blame)
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"`
}