В прошлый раз я защищал свою основу доступа SQLite. Посмотрим, продержится ли он в производстве. Жаль, что я никогда не получу такой большой груз, который должен что-то сломать. Ну ладно, подождем и посмотрим. Может быть, мне повезет, и два печальных параллельных запроса в конечном итоге вызовут панику у моего двоичного кода Go.
Сегодня я сосредоточусь на функциях. Я хочу сделать своего бота умным. Не совсем то, что нравится ИИ, просто звучит немного лучше, чем cmd.exe
, когда вы вводите неправильную команду. Я не собираюсь делать ничего большого, больше похоже на то, чтобы окунуть палец ноги в воду, чтобы посмотреть, как там.
Во-первых, я хочу найти последнее событие с таким же именем, поскольку я сохраняю их в базе данных, и отправляю дату события. Представьте себе такое взаимодействие:
me: eat
bot: Previous 'eat' happened 6 hours ago
Чтобы найти событие с таким же именем, я должен попросить SQLite предоставить мне строку, в которой такой же пользователь, имя события и то же самое, и мне нужна последняя строка после того, как она отсортирована по дате. Конвертируя английский язык в SQL, я получаю:
SELECT date FROM events
WHERE user = ? AND name = ?
ORDER BY date
DESC LIMIT 1
Довольно просто, а? Теперь, преобразовав это в Go и crawshaw.io/sqlite
, я получу следующее:
// Default response
response := fmt.Sprintf("Fist time for '%s'", name)
// Get the last event with the same name and format the response
err := sqlitex.Exec(connection,
"SELECT date FROM events "+
"WHERE user = ? AND name = ? "+
"ORDER BY date "+
"DESC LIMIT 1",
func(s *sqlite.Stmt) error {
response = formatResponse(s.GetInt64("date"), name)
return nil
},
message.From.ID,
name)
// Send the message back to the user
go func() {
bot.Send(tgbotapi.NewMessage(message.Chat.ID, response))
}()
Где formatResponse
очень рудиментарен:
func formatResponse(date int64, name string) string {
last := time.Unix(date, 0)
return fmt.Sprintf("Previous '%s' happened on '%v'", name, last)
}
Теперь взаимодействие выглядит так:
Не совсем умный бот на планете, но мы куда-то идем.
Теперь я хотел бы, чтобы это звучало немного менее глупо и немного более человечно, что не всегда сочетается друг с другом. В этом случае они есть. Я не хочу, чтобы бот говорил что-то вроде happened on '2019-04-04 14:13:57 +0200 CEST'
, а говорил что-то вроде 8 minutes since
или 1 year since
. Вы не поверите, но для этого есть пакет. Добро пожаловать в hako / durafmt. С его помощью очень легко превратить разговор в нечто подобное:
Это намного читабельнее. Чтобы заставить его работать, мне просто нужно было немного изменить функцию formatResponse
(теперь она также должна принимать текущую дату сообщения):
func formatResponse(name string, date int64, prevDate int64) string {
prev := time.Unix(prevDate, 0)
now := time.Unix(date, 0)
duration := durafmt.ParseShort(now.Sub(prev))
return fmt.Sprintf("%s since last '%s'", duration, name)
}
Очень просто. С небольшим количеством строк и менее чем за час работы у меня есть бот, который говорит по-человечески и может сказать мне, когда что-то произошло в последний раз. Отправим его! 🚢
Если вам интересно, код доступен на GitHub. Эта версия помечена тегом day-4
.
Первоначально опубликовано на detunized.net 4 апреля 2019 г.