diff options
| author | leshe4ka46 <alex9102naid1@ya.ru> | 2025-10-28 13:42:55 +0300 |
|---|---|---|
| committer | leshe4ka46 <alex9102naid1@ya.ru> | 2025-10-28 13:43:08 +0300 |
| commit | ded279a489631651943b5b65cdb3acb6764cf288 (patch) | |
| tree | 9ea2c846f5efdab6521b4e7236dcbea34c9b544b /pkg/localstore/store.go | |
| parent | bb833561aa74f02970aee13cdc75973b29716491 (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.go | 155 |
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 |
