DB 적재 초기구조

This commit is contained in:
Lectom C Han
2025-12-09 13:51:25 +09:00
parent fa1a7a057e
commit ecaca02400
11 changed files with 498 additions and 73 deletions

View File

@@ -0,0 +1,98 @@
package geo
import (
"context"
"database/sql"
"errors"
"net"
"time"
_ "github.com/jackc/pgx/v5/stdlib"
)
const defaultLookupQuery = `
SELECT
ip::text,
country,
region,
city,
latitude,
longitude
FROM geoip.lookup_city($1);
`
type postgresResolver struct {
db *sql.DB
lookupQuery string
}
func newPostgresResolver(databaseURL, lookupQuery string) (Resolver, error) {
if databaseURL == "" {
return nil, errors.New("database url is required for postgres backend")
}
db, err := sql.Open("pgx", databaseURL)
if err != nil {
return nil, err
}
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(2)
db.SetConnMaxIdleTime(5 * time.Minute)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
_ = db.Close()
return nil, err
}
if lookupQuery == "" {
lookupQuery = defaultLookupQuery
}
return &postgresResolver{
db: db,
lookupQuery: lookupQuery,
}, nil
}
func (r *postgresResolver) Close() error {
return r.db.Close()
}
func (r *postgresResolver) Lookup(ipStr string) (Location, error) {
ip := net.ParseIP(ipStr)
if ip == nil {
return Location{}, ErrInvalidIP
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
row := r.db.QueryRowContext(ctx, r.lookupQuery, ip.String())
var (
resolvedIP string
country, region sql.NullString
city sql.NullString
latitude, longitude sql.NullFloat64
)
if err := row.Scan(&resolvedIP, &country, &region, &city, &latitude, &longitude); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return Location{}, ErrNotFound
}
return Location{}, err
}
return Location{
IP: resolvedIP,
Country: country.String,
Region: region.String,
City: city.String,
Address: buildAddress(city.String, region.String, country.String),
Latitude: latitude.Float64,
Longitude: longitude.Float64,
}, nil
}