78 lines
2.0 KiB
Go
78 lines
2.0 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"crypto/md5"
|
|
"database/sql"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"math"
|
|
"time"
|
|
)
|
|
|
|
// UpsertRainTile stores a rain tile into table `rain_tiles`.
|
|
// The tiling scheme is equal-angle EPSG:4326 like radar tiles.
|
|
func UpsertRainTile(ctx context.Context, db *sql.DB, product string, dt time.Time, z, y, x int, width, height int, data []byte) error {
|
|
if width == 0 {
|
|
width = 256
|
|
}
|
|
if height == 0 {
|
|
height = 256
|
|
}
|
|
step := 360.0 / math.Pow(2, float64(z))
|
|
west := -180.0 + float64(x)*step
|
|
south := -90.0 + float64(y)*step
|
|
east := west + step
|
|
north := south + step
|
|
res := step / float64(width)
|
|
|
|
sum := md5.Sum(data)
|
|
md5hex := hex.EncodeToString(sum[:])
|
|
|
|
q := `
|
|
INSERT INTO rain_tiles (
|
|
product, dt, z, y, x, width, height,
|
|
west, south, east, north, res_deg,
|
|
data, checksum_md5
|
|
) VALUES (
|
|
$1,$2,$3,$4,$5,$6,$7,
|
|
$8,$9,$10,$11,$12,
|
|
$13,$14
|
|
)
|
|
ON CONFLICT (product, dt, z, y, x)
|
|
DO UPDATE SET
|
|
width = EXCLUDED.width,
|
|
height = EXCLUDED.height,
|
|
west = EXCLUDED.west,
|
|
south = EXCLUDED.south,
|
|
east = EXCLUDED.east,
|
|
north = EXCLUDED.north,
|
|
res_deg = EXCLUDED.res_deg,
|
|
data = EXCLUDED.data,
|
|
checksum_md5 = EXCLUDED.checksum_md5`
|
|
|
|
_, err := db.ExecContext(ctx, q,
|
|
product, dt, z, y, x, width, height,
|
|
west, south, east, north, res,
|
|
data, md5hex,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("upsert rain tile (%s %s z=%d y=%d x=%d): %w", product, dt.Format(time.RFC3339), z, y, x, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// HasRainTile reports whether a rain tile exists for the given key.
|
|
func HasRainTile(ctx context.Context, db *sql.DB, product string, dt time.Time, z, y, x int) (bool, error) {
|
|
const q = `SELECT 1 FROM rain_tiles WHERE product=$1 AND dt=$2 AND z=$3 AND y=$4 AND x=$5 LIMIT 1`
|
|
var one int
|
|
err := db.QueryRowContext(ctx, q, product, dt, z, y, x).Scan(&one)
|
|
if err == sql.ErrNoRows {
|
|
return false, nil
|
|
}
|
|
if err != nil {
|
|
return false, fmt.Errorf("check rain tile exists: %w", err)
|
|
}
|
|
return true, nil
|
|
}
|