|
@@ -1,10 +1,13 @@
|
|
package main
|
|
package main
|
|
|
|
|
|
import (
|
|
import (
|
|
|
|
+ "cmp"
|
|
"encoding/json"
|
|
"encoding/json"
|
|
"errors"
|
|
"errors"
|
|
"fmt"
|
|
"fmt"
|
|
"os"
|
|
"os"
|
|
|
|
+ "slices"
|
|
|
|
+ "strings"
|
|
"sync"
|
|
"sync"
|
|
)
|
|
)
|
|
|
|
|
|
@@ -15,7 +18,7 @@ var (
|
|
type (
|
|
type (
|
|
Contacts []Contact
|
|
Contacts []Contact
|
|
ContactsStore struct {
|
|
ContactsStore struct {
|
|
- sync.Mutex
|
|
|
|
|
|
+ sync.RWMutex
|
|
data map[int]Contact
|
|
data map[int]Contact
|
|
}
|
|
}
|
|
)
|
|
)
|
|
@@ -31,11 +34,46 @@ func NewContactsStore() (*ContactsStore, error) {
|
|
}
|
|
}
|
|
|
|
|
|
func (cs *ContactsStore) Get(search string) Contacts {
|
|
func (cs *ContactsStore) Get(search string) Contacts {
|
|
- return make(Contacts, 0)
|
|
|
|
|
|
+ contacts := cs.GetAll()
|
|
|
|
+ if search == "" {
|
|
|
|
+ return contacts
|
|
|
|
+ }
|
|
|
|
+ return slices.DeleteFunc(contacts, func(c Contact) bool {
|
|
|
|
+ return (c.First == "" || !strings.Contains(c.First, search)) &&
|
|
|
|
+ (c.Last == "" || !strings.Contains(c.Last, search)) &&
|
|
|
|
+ (c.Email == "" || !strings.Contains(c.Email, search)) &&
|
|
|
|
+ (c.Phone == "" || !strings.Contains(c.Phone, search))
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func MapValues[M ~map[K]V, K comparable, V any](m M) []V {
|
|
|
|
+ sl := make([]V, 0, len(m))
|
|
|
|
+ for _, v := range m {
|
|
|
|
+ sl = append(sl, v)
|
|
|
|
+ }
|
|
|
|
+ return sl
|
|
}
|
|
}
|
|
|
|
|
|
func (cs *ContactsStore) GetAll() Contacts {
|
|
func (cs *ContactsStore) GetAll() Contacts {
|
|
- return make(Contacts, 0)
|
|
|
|
|
|
+ cs.RLock()
|
|
|
|
+ defer cs.RUnlock()
|
|
|
|
+ contacts := MapValues(cs.data)
|
|
|
|
+ slices.SortStableFunc(contacts, func(a, b Contact) int {
|
|
|
|
+ if sgn := cmp.Compare(a.First, b.First); sgn != 0 {
|
|
|
|
+ return sgn
|
|
|
|
+ }
|
|
|
|
+ if sgn := cmp.Compare(a.Last, b.Last); sgn != 0 {
|
|
|
|
+ return sgn
|
|
|
|
+ }
|
|
|
|
+ if sgn := cmp.Compare(a.Phone, b.Phone); sgn != 0 {
|
|
|
|
+ return sgn
|
|
|
|
+ }
|
|
|
|
+ if sgn := cmp.Compare(a.Email, b.Email); sgn != 0 {
|
|
|
|
+ return sgn
|
|
|
|
+ }
|
|
|
|
+ return cmp.Compare(a.ID, b.ID)
|
|
|
|
+ })
|
|
|
|
+ return contacts
|
|
}
|
|
}
|
|
|
|
|
|
func (cs *ContactsStore) Load() error {
|
|
func (cs *ContactsStore) Load() error {
|
|
@@ -46,6 +84,7 @@ func (cs *ContactsStore) Load() error {
|
|
if err != nil {
|
|
if err != nil {
|
|
return fmt.Errorf("reading file: %w", err)
|
|
return fmt.Errorf("reading file: %w", err)
|
|
}
|
|
}
|
|
|
|
+
|
|
contacts := make(Contacts, 0)
|
|
contacts := make(Contacts, 0)
|
|
if err := json.Unmarshal(bs, &contacts); err != nil {
|
|
if err := json.Unmarshal(bs, &contacts); err != nil {
|
|
return fmt.Errorf("unmarshalling file: %w", err)
|
|
return fmt.Errorf("unmarshalling file: %w", err)
|