replace sql mostly with sqlc

This commit is contained in:
2025-07-16 22:10:49 +02:00
parent a3440326e8
commit 7c29f64f6d
14 changed files with 418 additions and 741 deletions

View File

@@ -10,7 +10,6 @@ import (
"os"
"path"
"path/filepath"
"strconv"
"github.com/juli0n21/go-osu-parser/parser"
_ "modernc.org/sqlite"
@@ -49,7 +48,9 @@ func initDB(connectionString string, osuDb *parser.OsuDB, osuroot string) (*sql.
return nil, nil, err
}
if err = checkhealth(db, osuDB); err != nil {
sqlcQueries := sqlcdb.New(db)
if err = checkhealth(sqlcQueries, osuDB); err != nil {
if err = rebuildBeatmapDb(db, osuDB); err != nil {
return nil, nil, err
}
@@ -70,8 +71,6 @@ func initDB(connectionString string, osuDb *parser.OsuDB, osuroot string) (*sql.
}
}
sqlcQueries := sqlcdb.New(db)
return db, sqlcQueries, nil
}
@@ -90,13 +89,13 @@ func createDB(db *sql.DB) error {
MD5Hash TEXT DEFAULT '00000000000000000000000000000000',
File TEXT DEFAULT 'unknown.osu',
RankedStatus TEXT DEFAULT Unknown,
LastModifiedTime DATETIME DEFAULT '0001-01-01 00:00:00',
LastModifiedTime INTEGER DEFAULT 0,
TotalTime INTEGER DEFAULT 0,
AudioPreviewTime INTEGER DEFAULT 0,
BeatmapSetId INTEGER DEFAULT -1,
Source TEXT DEFAULT '',
Tags TEXT DEFAULT '',
LastPlayed DATETIME DEFAULT '0001-01-01 00:00:00',
LastPlayed INTEGER DEFAULT 0,
Folder TEXT DEFAULT 'Unknown Folder',
UNIQUE (Artist, Title, MD5Hash, Difficulty)
);
@@ -146,34 +145,24 @@ func createCollectionDB(db *sql.DB) error {
return nil
}
func checkhealth(db *sql.DB, osuDb *parser.OsuDB) error {
func checkhealth(db *sqlcdb.Queries, osuDb *parser.OsuDB) error {
rows, err := db.Query(`SELECT COUNT(*) FROM Beatmap GROUP BY BeatmapSetId;`)
count, err := db.GetBeatmapSetCount(context.TODO())
if err != nil {
return err
}
defer rows.Close()
var count int
if err = rows.Scan(&count); err != nil {
return err
}
if count != int(osuDb.FolderCount) {
if count != int64(osuDb.FolderCount) {
log.Println("Folder count missmatch rebuilding db...")
return ErrBeatmapCountNotMatch
}
rows, err = db.Query(`SELECT COUNT(*) FROM Beatmap;`)
count, err = db.GetBeatmapCount(context.TODO())
if err != nil {
return err
}
if err = rows.Scan(&count); err != nil {
return err
}
if count != int(osuDb.NumberOfBeatmaps) {
if count != int64(osuDb.NumberOfBeatmaps) {
log.Println("Beatmap count missmatch rebuilding db...")
return ErrBeatmapCountNotMatch
}
@@ -310,268 +299,6 @@ func rebuildCollectionDb(db *sql.DB, collectionDb *parser.Collections) error {
return tx.Commit()
}
func getBeatmapCount(db *sql.DB) int {
rows, err := db.Query("SELECT COUNT(*) FROM Beatmap")
if err != nil {
log.Println(err)
return 0
}
defer rows.Close()
var count int
if rows.Next() {
err = rows.Scan(&count)
if err != nil {
log.Println(err)
return 0
}
} else {
return 0
}
return count
}
func getRecent(ctx context.Context, q *sqlcdb.Queries, limit, offset int) ([]Song, error) {
rows, err := q.GetRecentBeatmaps(ctx, sqlcdb.GetRecentBeatmapsParams{
Limit: int64(limit), Offset: int64(offset),
})
if err != nil {
return nil, err
}
var songs []Song
for _, song := range rows {
songs = append(songs, convertToSong(song))
}
return songs, nil
}
func getSearch(db *sql.DB, q string, limit, offset int) (ActiveSearch, error) {
rows, err := db.Query(
`
SELECT
BeatmapId,
MD5Hash,
Title,
Artist,
Creator,
Folder,
File,
Audio,
TotalTime
FROM Beatmap WHERE Title LIKE ? OR Artist LIKE ? LIMIT ? OFFSET ?
`, "%"+q+"%", "%"+q+"%", limit, offset)
if err != nil {
return ActiveSearch{}, err
}
defer rows.Close()
s, err := scanSongs(rows)
if err != nil {
return ActiveSearch{}, err
}
return ActiveSearch{Songs: s}, nil
}
func getArtists(db *sql.DB, q string, limit, offset int) ([]Artist, error) {
rows, err := db.Query("SELECT Artist, COUNT(Artist) FROM Beatmap WHERE Artist LIKE ? OR Title LIKE ? GROUP BY Artist LIMIT ? OFFSET ?", "%"+q+"%", "%"+q+"%", limit, offset)
if err != nil {
return []Artist{}, err
}
defer rows.Close()
artist := []Artist{}
for rows.Next() {
var a string
var c int
err := rows.Scan(&a, &c)
if err != nil {
return []Artist{}, err
}
artist = append(artist, Artist{Artist: a, Count: c})
}
return artist, nil
}
func getFavorites(db *sql.DB, q string, limit, offset int) ([]Song, error) {
rows, err := db.Query("SELECT * FROM Songs WHERE IsFavorite = 1 LIMIT ? OFFSET ?", limit, offset)
if err != nil {
return nil, err
}
defer rows.Close()
return scanSongs(rows)
}
func getCollection(db *sql.DB, limit, offset, index int) (Collection, error) {
rows, err := db.Query(`
WITH cols AS (
SELECT
c.Name,
ROW_NUMBER() OVER (ORDER BY c.Name) AS RowNumber
FROM Collection c
GROUP BY c.Name
)
SELECT
c.Name, b.BeatmapId, b.MD5Hash, b.Title, b.Artist,
b.Creator, b.Folder, b.File, b.Audio, b.TotalTime
FROM Collection c
Join Beatmap b ON c.MD5Hash = b.MD5Hash
WHERE c.Name = (SELECT Name FROM cols WHERE RowNumber = ?)
LIMIT ?
OFFSET ?;`, index, limit, offset)
if err != nil {
return Collection{}, err
}
defer rows.Close()
var c Collection
for rows.Next() {
s := Song{}
if err := rows.Scan(&c.Name, &s.BeatmapID, &s.MD5Hash, &s.Title, &s.Artist, &s.Creator, &s.Folder, &s.File, &s.Audio, &s.TotalTime); err != nil {
return Collection{}, err
}
s.Image = extractImageFromFile(osuRoot, s.Folder, s.File)
c.Songs = append(c.Songs, s)
}
row := db.QueryRow(`SELECT COUNT(*) FROM Collection WHERE Name = ?`, c.Name)
var count string
row.Scan(&count)
if i, err := strconv.Atoi(count); err == nil {
c.Items = i
}
return c, nil
}
func getCollectionByName(db *sql.DB, limit, offset int, name string) (Collection, error) {
rows, err := db.Query(`
SELECT
c.Name, b.BeatmapId, b.MD5Hash, b.Title, b.Artist,
b.Creator, b.Folder, b.File, b.Audio, b.TotalTime
FROM Collection c
Join Beatmap b ON c.MD5Hash = b.MD5Hash
WHERE c.Name = ?
LIMIT ?
OFFSET ?;`, name, limit, offset)
if err != nil {
return Collection{}, err
}
defer rows.Close()
var c Collection
for rows.Next() {
s := Song{}
if err := rows.Scan(&c.Name, &s.BeatmapID, &s.MD5Hash, &s.Title, &s.Artist, &s.Creator, &s.Folder, &s.File, &s.Audio, &s.TotalTime); err != nil {
return Collection{}, err
}
s.Image = extractImageFromFile(osuRoot, s.Folder, s.File)
c.Songs = append(c.Songs, s)
}
row := db.QueryRow(`SELECT COUNT(*) FROM Collection WHERE Name = ?`, c.Name)
var count string
row.Scan(&count)
if i, err := strconv.Atoi(count); err == nil {
c.Items = i
} else {
return Collection{}, err
}
return c, nil
}
func getCollections(db *sql.DB, q string, limit, offset int) ([]CollectionPreview, error) {
rows, err := db.Query(`
SELECT
c.Name,
COUNT(b.MD5Hash) AS Count,
MIN(b.Folder) AS Folder,
MIN(b.File) AS File
FROM Collection c
JOIN Beatmap b ON c.MD5Hash = b.MD5Hash
WHERE c.Name LIKE ?
GROUP BY c.Name
LIMIT ?
OFFSET ?`, "%"+q+"%", limit, offset)
if err != nil {
return []CollectionPreview{}, err
}
defer rows.Close()
var collections []CollectionPreview
for rows.Next() {
var c CollectionPreview
var folder, file, count string
if err := rows.Scan(&c.Name, &count, &folder, &file); err != nil {
return []CollectionPreview{}, err
}
if i, err := strconv.Atoi(count); err == nil {
c.Items = i
}
c.Image = extractImageFromFile(osuRoot, folder, file)
collections = append(collections, c)
}
return collections, nil
}
func getSong(db *sql.DB, hash string) (Song, error) {
row := db.QueryRow("SELECT BeatmapId, MD5Hash, Title, Artist, Creator, Folder, File, Audio, TotalTime FROM Beatmap WHERE MD5Hash = ?", hash)
s, err := scanSong(row)
return s, err
}
func scanSongs(rows *sql.Rows) ([]Song, error) {
songs := []Song{}
for rows.Next() {
var s Song
if err := rows.Scan(&s.BeatmapID, &s.MD5Hash, &s.Title, &s.Artist, &s.Creator, &s.Folder, &s.File, &s.Audio, &s.TotalTime); err != nil {
return nil, err
}
bm, err := parser.ParseOsuFile(fmt.Sprintf("%sSongs/%s/%s", osuRoot, s.Folder, s.File))
if err != nil {
fmt.Println(err)
s.Image = "404.png"
} else {
if bgImage := bm.BackgroundImage(); bgImage != "" {
s.Image = fmt.Sprintf("%s/%s", s.Folder, bgImage)
} else {
s.Image = "404.png"
}
}
songs = append(songs, s)
}
return songs, nil
}
func scanSong(row *sql.Row) (Song, error) {
s := Song{}
if err := row.Scan(&s.BeatmapID, &s.MD5Hash, &s.Title, &s.Artist, &s.Creator, &s.Folder, &s.File, &s.Audio, &s.TotalTime); err != nil {
return Song{}, err
}
s.Image = extractImageFromFile(osuRoot, s.Folder, s.File)
return s, nil
}
func extractImageFromFile(osuRoot, folder, file string) string {
bm, err := parser.ParseOsuFile(filepath.Join(osuRoot, "Songs", folder, file))
if err != nil {
@@ -586,67 +313,3 @@ func extractImageFromFile(osuRoot, folder, file string) string {
return "404.png"
}
func scanCollections(rows *sql.Rows) ([]Collection, error) {
var collection []Collection
for rows.Next() {
var c Collection
if err := rows.Scan(&c); err != nil {
return []Collection{}, err
}
collection = append(collection, c)
}
return collection, nil
}
func scanCollectionPreviews(rows *sql.Rows) ([]CollectionPreview, error) {
var collection []CollectionPreview
for rows.Next() {
var c CollectionPreview
if err := rows.Scan(&c); err != nil {
return []CollectionPreview{}, err
}
collection = append(collection, c)
}
return collection, nil
}
func scanCollectionPreview(row *sql.Row) (CollectionPreview, error) {
var c CollectionPreview
if err := row.Scan(&c); err != nil {
return CollectionPreview{}, err
}
return c, nil
}
func convertToSong(r sqlcdb.GetRecentBeatmapsRow) Song {
return Song{
BeatmapID: safeInt64(r.Beatmapid),
MD5Hash: safeString(r.Md5hash),
Title: safeString(r.Title),
Artist: safeString(r.Artist),
Creator: safeString(r.Creator),
Folder: safeString(r.Folder),
File: safeString(r.File),
Audio: safeString(r.Audio),
TotalTime: int64(safeInt64(r.Totaltime)),
Image: extractImageFromFile(osuRoot, safeString(r.Folder), safeString(r.File)),
}
}
func safeString(ns sql.NullString) string {
if ns.Valid {
return ns.String
}
return ""
}
func safeInt64(n sql.NullInt64) int {
if n.Valid {
return int(n.Int64)
}
return 0
}