aboutsummaryrefslogtreecommitdiff
path: root/pkg/localstore/store.go
diff options
context:
space:
mode:
authorleshe4ka46 <alex9102naid1@ya.ru>2025-10-28 13:42:55 +0300
committerleshe4ka46 <alex9102naid1@ya.ru>2025-10-28 13:43:08 +0300
commitded279a489631651943b5b65cdb3acb6764cf288 (patch)
tree9ea2c846f5efdab6521b4e7236dcbea34c9b544b /pkg/localstore/store.go
parentbb833561aa74f02970aee13cdc75973b29716491 (diff)
unmarshal all formats, merge them in the single table, users are truly unique
Diffstat (limited to 'pkg/localstore/store.go')
-rw-r--r--pkg/localstore/store.go155
1 files changed, 36 insertions, 119 deletions
diff --git a/pkg/localstore/store.go b/pkg/localstore/store.go
index 151b2b4..dad2ffe 100644
--- a/pkg/localstore/store.go
+++ b/pkg/localstore/store.go
@@ -7,6 +7,7 @@ import (
"time"
"unicode/utf8"
+ "airlines/pkg/airports"
"airlines/pkg/model"
)
@@ -51,7 +52,6 @@ type flightDayKey struct {
DateYMD int32
}
-
type Store struct {
mu sync.RWMutex
@@ -97,7 +97,6 @@ func NewLocalStore() *Store {
}
}
-
func isZeroCoord(c model.LatLong) bool { return c.Lat == 0 && c.Long == 0 }
func ymdUTC(t time.Time) int32 {
@@ -122,8 +121,6 @@ func ensureSet(m map[uint64]map[uint64]struct{}, k uint64) map[uint64]struct{} {
return s
}
-/* ============================== users ============================= */
-
func fatherInitial(s string) string {
s = strings.TrimSpace(s)
if s == "" {
@@ -133,7 +130,7 @@ func fatherInitial(s string) string {
if r == utf8.RuneError {
return ""
}
- return string(r) // your pipeline keeps it UPPER
+ return string(r)
}
func addUserInitIndex(m map[userInitKey]uint64, u *model.User) {
@@ -148,7 +145,6 @@ func delUserInitIndex(m map[userInitKey]uint64, u *model.User) {
delete(m, k)
}
-// --- merge helper (unchanged; keeps initial→full, birthday, nick, sex upgrades) ---
func (s *Store) mergeUserFields(id uint64, in *model.User) *model.User {
ex := s.users[id]
// fathersname: initial -> full (same initial), move indexes
@@ -186,12 +182,12 @@ func (s *Store) mergeUserFields(id uint64, in *model.User) *model.User {
return ex
}
-// --- FIXED SaveUser: initial-key lookup tries BOTH (birth, 0) ---
func (s *Store) SaveUser(u *model.User) (*model.User, error) {
if u == nil {
return nil, errors.New("nil user")
}
- // normalize (names already UPPER)
+
+ // normalize just for sure
u.Nick = strings.TrimSpace(u.Nick)
u.Name = strings.TrimSpace(u.Name)
u.Surname = strings.TrimSpace(u.Surname)
@@ -205,14 +201,14 @@ func (s *Store) SaveUser(u *model.User) (*model.User, error) {
s.mu.Lock()
defer s.mu.Unlock()
- // 1) by Nick
+ // by Nick
if u.Nick != "" {
if id, ok := s.nickToUID[u.Nick]; ok {
return s.mergeUserFields(id, u), nil
}
}
- // 2) exact tuple
+ // exact tuple
if id, ok := s.nameToUID[inKey]; ok {
if u.Nick != "" && s.users[id].Nick == "" {
s.users[id].Nick = u.Nick
@@ -221,7 +217,7 @@ func (s *Store) SaveUser(u *model.User) (*model.User, error) {
return s.mergeUserFields(id, u), nil
}
- // 3) initial-based match (try with incoming birth, then with 0)
+ // try with incoming birth, then with 0
init := fatherInitial(u.Fathersname)
tryInits := []userInitKey{
{Surname: u.Surname, Name: u.Name, Init: init, BirthYMD: inBirth},
@@ -233,14 +229,14 @@ func (s *Store) SaveUser(u *model.User) (*model.User, error) {
if id, ok := s.nameInitToUID[ik]; ok {
ex := s.users[id]
- // If ex has initial-only and incoming has full (same initial) → upgrade fathers + move indexes
+ // If ex has initial-only and incoming has full → upgrade fathers + move indexes
if ex.Fathersname == fatherInitial(ex.Fathersname) &&
u.Fathersname != "" &&
fatherInitial(u.Fathersname) == fatherInitial(ex.Fathersname) {
// move name index
oldNameKey := userNameKey{Surname: ex.Surname, Name: ex.Name, Fathersname: ex.Fathersname, BirthYMD: ymdUTC(ex.Birthday)}
delete(s.nameToUID, oldNameKey)
- // remove old init index (birth may differ)
+ // remove old init index
delUserInitIndex(s.nameInitToUID, ex)
ex.Fathersname = u.Fathersname
@@ -276,7 +272,7 @@ func (s *Store) SaveUser(u *model.User) (*model.User, error) {
}
}
- // 4) relaxed: fathersname empty, same birth
+ // fathersname empty, same birth
if id, ok := s.nameToUID[userNameKey{Surname: u.Surname, Name: u.Name, Fathersname: "", BirthYMD: inBirth}]; ok {
ex := s.users[id]
if ex.Fathersname == "" && u.Fathersname != "" {
@@ -298,7 +294,7 @@ func (s *Store) SaveUser(u *model.User) (*model.User, error) {
return ex, nil
}
- // 5) same fathersname, no birth
+ // same fathersname, no birth
if id, ok := s.nameToUID[userNameKey{Surname: u.Surname, Name: u.Name, Fathersname: u.Fathersname, BirthYMD: 0}]; ok {
delete(s.nameToUID, userNameKey{Surname: u.Surname, Name: u.Name, Fathersname: u.Fathersname, BirthYMD: 0})
ex := s.users[id]
@@ -316,7 +312,7 @@ func (s *Store) SaveUser(u *model.User) (*model.User, error) {
return ex, nil
}
- // 6) fully unspecific existing (fathers="", birth=0)
+ // fathers="", birth=0
if id, ok := s.nameToUID[userNameKey{Surname: u.Surname, Name: u.Name, Fathersname: "", BirthYMD: 0}]; ok {
ex := s.users[id]
delete(s.nameToUID, userNameKey{Surname: ex.Surname, Name: ex.Name, Fathersname: "", BirthYMD: 0})
@@ -338,7 +334,7 @@ func (s *Store) SaveUser(u *model.User) (*model.User, error) {
return ex, nil
}
- // 7) create
+ // not found -> create
u.ID = uint64(len(s.users))
s.users = append(s.users, u)
if u.Nick != "" {
@@ -349,15 +345,6 @@ func (s *Store) SaveUser(u *model.User) (*model.User, error) {
return u, nil
}
-/* ============================== cards ============================= */
-/*
-Match order:
- 1) exact (Prefix, Number, Bonus)
- 2) pair (Prefix, Number) → if stored bonus=="" and incoming bonus!="", upgrade in place (move triple index)
- 3) else create new
-Never steal UserID: only set if existing has 0 and incoming non-zero.
-*/
-
func (s *Store) SaveCard(c *model.Card) (*model.Card, error) {
if c == nil {
return nil, errors.New("nil card")
@@ -404,7 +391,7 @@ func (s *Store) SaveCard(c *model.Card) (*model.Card, error) {
s.cardsByUser[ex.UserID] = v
switch {
case ex.Bonusprogramm == "" && c.Bonusprogramm != "":
- // move triple index from empty -> new bonus
+ // move index from empty -> new bonus
oldTri := cardKey{Prefix: ex.Prefix, Number: ex.Number, Bonus: ex.Bonusprogramm}
delete(s.cardToCID, oldTri)
ex.Bonusprogramm = c.Bonusprogramm
@@ -415,8 +402,8 @@ func (s *Store) SaveCard(c *model.Card) (*model.Card, error) {
return ex, nil
case ex.Bonusprogramm != "" && c.Bonusprogramm == "":
return ex, nil
- case ex.Bonusprogramm != "" && c.Bonusprogramm != "" && ex.Bonusprogramm != c.Bonusprogramm:
- // different program → create new card record
+ // different program → create new card record
+ // case ex.Bonusprogramm != "" && c.Bonusprogramm != "" && ex.Bonusprogramm != c.Bonusprogramm:
default:
return ex, nil
}
@@ -426,7 +413,7 @@ func (s *Store) SaveCard(c *model.Card) (*model.Card, error) {
c.ID = uint64(len(s.cards))
s.cards = append(s.cards, c)
s.cardPairToCID[pair] = c.ID
- s.cardToCID[tri] = c.ID // even if bonus == "", we still index triple
+ s.cardToCID[tri] = c.ID
if s.cardsByUser[c.UserID] == nil {
s.cardsByUser[c.UserID] = make(map[uint64]struct{}, 1024)
@@ -438,18 +425,6 @@ func (s *Store) SaveCard(c *model.Card) (*model.Card, error) {
return c, nil
}
-/* ============================== flights =========================== */
-/*
-Identity:
- - date-only: (Number, From, To, DateYMD, false, 0)
- - timed : (Number, From, To, DateYMD, true, SecSinceMidnight)
-Upgrade:
- - if a date-only exists and a timed arrives for the same day, upgrade in place
-Merge:
- - coords: fill when missing
- - relations: add (dedup via sets)
-*/
-
func (s *Store) SaveFlight(f *model.Flight) (*model.Flight, error) {
if f == nil {
return nil, errors.New("nil flight")
@@ -474,14 +449,14 @@ func (s *Store) SaveFlight(f *model.Flight) (*model.Flight, error) {
s.mu.Lock()
defer s.mu.Unlock()
- // 1) exact (precise) key
+ // precise key
if id, ok := s.flightToFID[pKey]; ok {
ex := s.flights[id]
s.mergeFlightFields(id, ex, f)
return ex, nil
}
- // 2) same day exists -> maybe upgrade date-only to timed
+ // same day exists -> maybe upgrade date-only to timed
if id, ok := s.flightByDay[dayKey]; ok {
ex := s.flights[id]
exKey := s.keyOfFlight(ex)
@@ -489,7 +464,7 @@ func (s *Store) SaveFlight(f *model.Flight) (*model.Flight, error) {
// move map key to timed
delete(s.flightToFID, exKey)
ex.HasTime = true
- // set clock from incoming (keep same calendar date)
+ // set clock from incoming
ex.Date = time.Date(dayUTC.Year(), dayUTC.Month(), dayUTC.Day(),
f.Date.Hour(), f.Date.Minute(), f.Date.Second(), f.Date.Nanosecond(), f.Date.Location())
s.flightToFID[s.keyOfFlight(ex)] = id
@@ -500,20 +475,20 @@ func (s *Store) SaveFlight(f *model.Flight) (*model.Flight, error) {
return ex, nil
}
- // 3) brand new
+ // brand new
f.ID = uint64(len(s.flights))
s.flights = append(s.flights, f)
s.flightToFID[pKey] = f.ID
s.flightByDay[dayKey] = f.ID
- // if s.countriesByUser[f.UserID] == nil {
- // s.countriesByUser[f.UserID] = make(map[string]struct{}, 1024)
- // }
+ if s.countriesByUser[f.UserID] == nil {
+ s.countriesByUser[f.UserID] = make(map[string]struct{}, 1024)
+ }
- // v := s.countriesByUser[f.UserID]
- // dd, _ := airports.LookupIATA(f.From)
- // v[dd.Country] = struct{}{}
- // s.countriesByUser[f.UserID] = v
+ v := s.countriesByUser[f.UserID]
+ dd, _ := airports.LookupIATA(f.From)
+ v[dd.Country] = struct{}{}
+ s.countriesByUser[f.UserID] = v
if f.Code != "" {
if s.codesByUser[f.UserID] == nil {
@@ -543,7 +518,7 @@ func (s *Store) keyOfFlight(f *model.Flight) flightKey {
}
func (s *Store) mergeFlightFields(id uint64, ex, in *model.Flight) {
- // coords: fill when empty
+ // coords fill when empty
if isZeroCoord(ex.FromCoords) && !isZeroCoord(in.FromCoords) {
ex.FromCoords = in.FromCoords
}
@@ -560,17 +535,15 @@ func (s *Store) mergeFlightFields(id uint64, ex, in *model.Flight) {
if in.Code != "" && ex.Code == "" {
ex.Code = in.Code
- // if s.codesByUser[in.UserID] == nil {
- // s.codesByUser[in.UserID] = make(map[string]struct{}, 1024)
- // }
- // codesByUser := s.codesByUser[in.UserID]
- // codesByUser[in.Code] = struct{}{}
- // s.codesByUser[in.UserID] = codesByUser
+ if s.codesByUser[in.UserID] == nil {
+ s.codesByUser[in.UserID] = make(map[string]struct{}, 1024)
+ }
+ codesByUser := s.codesByUser[in.UserID]
+ codesByUser[in.Code] = struct{}{}
+ s.codesByUser[in.UserID] = codesByUser
}
}
-/* ============================== finders =========================== */
-
func (s *Store) FindUserByNick(nick string) (*model.User, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
@@ -579,60 +552,4 @@ func (s *Store) FindUserByNick(nick string) (*model.User, bool) {
return nil, false
}
return s.users[id], true
-}
-
-func (s *Store) FindUserByName(name, surname, fathers string, bday time.Time) (*model.User, bool) {
- key := userNameKey{
- Surname: strings.TrimSpace(surname),
- Name: strings.TrimSpace(name),
- Fathersname: strings.TrimSpace(fathers),
- BirthYMD: ymdUTC(bday),
- }
- s.mu.RLock()
- defer s.mu.RUnlock()
- id, ok := s.nameToUID[key]
- if !ok || id == 0 || int(id) >= len(s.users) {
- return nil, false
- }
- return s.users[id], true
-}
-
-func (s *Store) FindCard(prefix string, number uint64, bonus string) (*model.Card, bool) {
- tri := cardKey{Prefix: strings.TrimSpace(prefix), Number: number, Bonus: strings.TrimSpace(bonus)}
- s.mu.RLock()
- defer s.mu.RUnlock()
- if id, ok := s.cardToCID[tri]; ok && id != 0 && int(id) < len(s.cards) {
- return s.cards[id], true
- }
- // fall back to pair if no exact
- pair := cardPairKey{Prefix: strings.TrimSpace(prefix), Number: number}
- if id, ok := s.cardPairToCID[pair]; ok && id != 0 && int(id) < len(s.cards) {
- return s.cards[id], true
- }
- return nil, false
-}
-
-func (s *Store) FindFlight(number, from, to string, date time.Time, hasTime bool) (*model.Flight, bool) {
- number = strings.TrimSpace(number)
- from = strings.TrimSpace(from)
- to = strings.TrimSpace(to)
-
- ymd := ymdUTC(time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, time.UTC))
- var k flightKey
- if hasTime {
- k = flightKey{Number: number, From: from, To: to, DateYMD: ymd, HasTime: true, Sec: secSinceMidnight(date)}
- } else {
- k = flightKey{Number: number, From: from, To: to, DateYMD: ymd, HasTime: false, Sec: 0}
- }
-
- s.mu.RLock()
- defer s.mu.RUnlock()
- if id, ok := s.flightToFID[k]; ok && id != 0 && int(id) < len(s.flights) {
- return s.flights[id], true
- }
- // day-level fallback (returns best precision for the day if exact key absent)
- if id, ok := s.flightByDay[flightDayKey{Number: number, From: from, To: to, DateYMD: ymd}]; ok && id != 0 && int(id) < len(s.flights) {
- return s.flights[id], true
- }
- return nil, false
-}
+} \ No newline at end of file