package database import ( "bufio" "crypto/rand" "encoding/hex" "encoding/json" "errors" "os" "sort" "time" ) var ( ErrNotFound = errors.New("entry not found") ) type Database struct { path string entries map[string]*Entry } func Load(path string) (*Database, error) { db := &Database{ path: path, entries: make(map[string]*Entry), } file, err := os.Open(path) if err != nil { if os.IsNotExist(err) { return db, nil } return nil, err } defer file.Close() scanner := bufio.NewScanner(file) // Set larger buffer for potentially long clipboard entries buf := make([]byte, 0, 64*1024) scanner.Buffer(buf, 1024*1024) // 1MB max line size for scanner.Scan() { line := scanner.Text() if line == "" { continue } var entry Entry if err := json.Unmarshal([]byte(line), &entry); err != nil { continue } db.entries[entry.ID] = &entry } if err := scanner.Err(); err != nil { return nil, err } return db, nil } func (db *Database) Save() error { file, err := os.Create(db.path) if err != nil { return err } defer file.Close() for _, entry := range db.entries { data, err := json.Marshal(entry) if err != nil { return err } if _, err := file.Write(data); err != nil { return err } if _, err := file.WriteString("\n"); err != nil { return err } } return nil } func generateID() string { bytes := make([]byte, 2) // 2 bytes = 4 hex chars rand.Read(bytes) return hex.EncodeToString(bytes) } func (db *Database) Add(value string) (*Entry, error) { entry := &Entry{ ID: generateID(), Value: value, DateTime: time.Now(), } db.entries[entry.ID] = entry return entry, db.Save() } func (db *Database) Get(id string) (*Entry, error) { entry, exists := db.entries[id] if !exists { return nil, ErrNotFound } return entry, nil } func (db *Database) Delete(id string) error { if _, exists := db.entries[id]; !exists { return ErrNotFound } delete(db.entries, id) return db.Save() } func (db *Database) List(limit int) []*Entry { entries := make([]*Entry, 0, len(db.entries)) for _, entry := range db.entries { entries = append(entries, entry) } // Sort by datetime descending (most recent first) sort.Slice(entries, func(i, j int) bool { return entries[i].DateTime.After(entries[j].DateTime) }) if limit > 0 && limit < len(entries) { entries = entries[:limit] } return entries } func (db *Database) MostRecent() *Entry { entries := db.List(1) if len(entries) == 0 { return nil } return entries[0] } func (db *Database) Count() int { return len(db.entries) }