| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- (in-package #:chatikbot)
- (defvar *db-name* "db.sqlite" "SQLite database name")
- (defun db-path ()
- (merge-pathnames *db-name*
- (asdf:component-pathname
- (asdf:find-system '#:chatikbot))))
- (defmacro with-db ((db) &body body)
- `(sqlite:with-open-database (,db (db-path) :busy-timeout 10)
- ,@body))
- (defun db-init ()
- (sqlite:with-open-database (db (db-path))
- ;; Finance
- (sqlite:execute-non-query db "create table if not exists finance (ts, usd, eur, gbp, brent)")
- (sqlite:execute-non-query db "create index if not exists fin_ts_ids on finance (ts)")
- ;; Foursquare
- (sqlite:execute-non-query db "create table if not exists fsq_chat_users (chat_id, user_id)")
- (sqlite:execute-non-query db "create index if not exists fsq_chat_users_chat_idx on fsq_chat_users (chat_id)")
- (sqlite:execute-non-query db "create index if not exists fsq_chat_users_user_idx on fsq_chat_users (user_id)")
- (sqlite:execute-non-query db "create table if not exists fsq_seen (id, created_at)")
- (sqlite:execute-non-query db "create index if not exists fsq_seen_idx on fsq_seen (id)")))
- ;; Finance
- (defun db-add-finance (ts usd eur gbp brent)
- (sqlite:with-open-database (db (db-path) :busy-timeout 10)
- (sqlite:execute-non-query db "insert into finance (ts, usd, eur, gbp, brent) values (?, ?, ?, ?, ?)"
- ts usd eur gbp brent)))
- (defun db-get-last-finance ()
- (sqlite:with-open-database (db (db-path) :busy-timeout 10)
- (sqlite:execute-one-row-m-v db "select ts, usd, eur, gbp, brent from finance order by ts desc limit 1")))
- (defun %finance-alist (statement)
- (let ((names (sqlite:statement-column-names statement))
- (map '(("usd" . "USD/RUB") ("eur" . "EUR/RUB") ("gbp" . "GBP/RUB") ("brent" . "Brent"))))
- (cons (sqlite:statement-column-value statement 0)
- (loop
- for i from 1 below (length names)
- for col in (rest names)
- collect (cons (aget col map) (sqlite:statement-column-value statement i))))))
- (defun db-get-series (after-ts &optional usd eur gbp brent (avg 60))
- (let ((sql (format nil
- "select ts/~a*~a~:[~;,avg(usd) as usd~]~:[~;,avg(eur) as eur~]~:[~;,avg(gbp) as gbp~]~:[~;,avg(brent) as brent~] from finance where ts >= ? group by ts/~a order by ts"
- avg avg usd eur gbp brent avg)))
- (sqlite:with-open-database (db (db-path) :busy-timeout 10)
- (loop
- with statement = (sqlite:prepare-statement db sql)
- initially (sqlite:bind-parameter statement 1 (local-time:timestamp-to-unix after-ts))
- while (sqlite:step-statement statement)
- collect (%finance-alist statement)
- finally (sqlite:finalize-statement statement)))))
- ;; Foursquare
- (defun db-fsq-get-chat-users (chat-id)
- (flatten (with-db (db)
- (sqlite:execute-to-list db "select user_id from fsq_chat_users where chat_id = ?" chat-id))))
- (defun db-fsq-get-user-chats (user-id)
- (flatten (with-db (db)
- (sqlite:execute-to-list db "select chat_id from fsq_chat_users where user_id = ?" user-id))))
- (defun db-fsq-set-chat-users (chat-id users)
- (with-db (db)
- (sqlite:with-transaction db
- (sqlite:execute-non-query db "delete from fsq_chat_users where chat_id = ?" chat-id)
- (dolist (user-id users)
- (sqlite:execute-non-query db "insert into fsq_chat_users (chat_id, user_id) values (?, ?)" chat-id user-id)))))
- (defun db-fsq-add-seen (id created-at)
- (with-db (db)
- (sqlite:execute-non-query db "insert into fsq_seen (id, created_at) values (?, ?)" id created-at)))
- (defun db-fsq-has-seen (id)
- (with-db (db)
- (sqlite:execute-single db "select id from fsq_seen where id = ? limit 1" id)))
- (defun db-fsq-last-created ()
- (with-db (db)
- (sqlite:execute-single db "select created_at from fsq_seen order by created_at desc limit 1")))
|