Skip to content

Сховище

m.DB — постійне key-value сховище, яке пишеться на диск і переживає перезапуски.

Власник і ключ

Кожне значення живе під власником — використовуйте m.Name(), щоб ваші дані залишалися вашими:

go
m.DB.SetString(m.Name(), "last_city", "Київ")
city := m.DB.GetString(m.Name(), "last_city", "")

Геттери приймають значення за замовчуванням, яке повернеться за відсутності ключа, тож танців «а чи є такий ключ» не потрібно.

Типізований доступ

go
m.DB.SetString(m.Name(), "city", "Київ")
m.DB.SetInt(m.Name(), "count", 42)
m.DB.SetInt64(m.Name(), "user_id", 123456789)
m.DB.SetBool(m.Name(), "enabled", true)
m.DB.SetStringSlice(m.Name(), "cities", []string{"Київ", "Львів"})
m.DB.SetInt64Slice(m.Name(), "admins", []int64{1, 2, 3})
m.DB.SetStringMap(m.Name(), "labels", map[string]string{"ua": "Київ"})
m.DB.SetAnyMap(m.Name(), "state", map[string]any{"n": 1})

У кожного є парний геттер зі значенням за замовчуванням:

go
city    := m.DB.GetString(m.Name(), "city", "Київ")
count   := m.DB.GetInt(m.Name(), "count", 0)
enabled := m.DB.GetBool(m.Name(), "enabled", false)
cities  := m.DB.GetStringSlice(m.Name(), "cities", nil)

Обробляйте помилки запису

Запис іде на диск і може не вдатися. Проігнорувати помилку — означає мовчки втратити дані:

go
if err := m.DB.SetString(m.Name(), "city", city); err != nil {
	return fmt.Errorf("збереження міста: %w", err)
}

Читання впасти не може — для цього й потрібне значення за замовчуванням.

Дані за чатами й користувачами

Складіть ключ:

go
func chatKey(chatID int64) string {
	return "chat:" + strconv.FormatInt(chatID, 10)
}

m.DB.SetString(m.Name(), chatKey(msg.ChatID), "Київ")

Якщо дрібних значень багато, мапа під одним ключем дешевша за багато ключів:

go
cities := m.DB.GetStringMap(m.Name(), "cities_by_chat", nil)
if cities == nil {
	cities = map[string]string{}
}
cities[strconv.FormatInt(msg.ChatID, 10)] = city
if err := m.DB.SetStringMap(m.Name(), "cities_by_chat", cities); err != nil {
	return fmt.Errorf("збереження міст: %w", err)
}

Що можна зберігати

Лише те, що серіалізується в JSON: рядки, числа, булеві значення, а також слайси та мапи з них. Спроба зберегти щось інше поверне помилку, а не зіпсує файл.

Геттери повертають копію, тому зміна отриманої мапи не змінює збережене — записуйте її назад.

Ціна

Кожен запис серіалізує базу й перезаписує файл. За звичайної частоти це нормально, але не пишіть по разу на кожне вхідне повідомлення у вотчері. Накопичуйте в пам'яті й скидайте періодично:

go
type Counter struct {
	goroku.Base
	mu     sync.Mutex
	counts map[int64]int
}

func (m *Counter) flush() error {
	m.mu.Lock()
	snapshot := make(map[string]int, len(m.counts))
	for id, n := range m.counts {
		snapshot[strconv.FormatInt(id, 10)] = n
	}
	m.mu.Unlock()
	return m.DB.SetStringMapInt(m.Name(), "counts", snapshot)
}

Секрети

Значення, яких не має бути в бекапі, оголошуйте полем налаштування з Secret: true — див. Налаштування. Звичайні значення в DB потрапляють у бекап як є.

Released under the GNU AGPL v3 License.