branch: externals/rcirc-sqlite
commit a4fd54a0595071655042683544a6db7711713421
Author: Matto Fransen <ma...@matto.nl>
Commit: Matto Fransen <ma...@matto.nl>

    Select a time range to narrow queries
---
 rcirc-sqlite.el | 133 ++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 101 insertions(+), 32 deletions(-)

diff --git a/rcirc-sqlite.el b/rcirc-sqlite.el
index 5abe1cc135..9b46b8df20 100644
--- a/rcirc-sqlite.el
+++ b/rcirc-sqlite.el
@@ -5,7 +5,7 @@
 ;; Author: Matto Fransen <ma...@matto.nl>
 ;; Maintainer: Matto Fransen <ma...@matto.nl>
 ;; Url: https://codeberg.org/mattof/rcirc-sqlite
-;; Version: 0.1.4
+;; Version: 1.0.0
 ;; Keywords: comm
 ;; Package-Requires: ((emacs "30.0"))
 
@@ -46,8 +46,18 @@
 ;; SQLite database:
 ;;   M-x customize-group rcirc-sqlite RET
 
+;;; News:
+
+;; Version 1.0.0 - 2024-04-16
+
+;; * Narrow queries to time range
+;;   Use completion to narrow queries to last 90 days, 60 days,
+;;   30 days, 7 days or a manually selected time range.
+
 ;;; Code:
 
+(require 'org) ;; needed for org-read-date
+
 (defvar rcirc-log-alist)
 (defvar rcirc-log-time-format)
 
@@ -86,6 +96,11 @@ otherwise no connection has been opened.")
 (defconst rcirc-sqlite-nicks-per-channel "Nicks per channel")
 (defconst rcirc-sqlite-channels-per-nick "Channels per nick")
 (defconst rcirc-sqlite-anytime "Anytime")
+(defconst rcirc-sqlite-last-90-days "Last 90 days")
+(defconst rcirc-sqlite-last-60-days "Last 60 days")
+(defconst rcirc-sqlite-last-30-days "Last 30 days")
+(defconst rcirc-sqlite-last-07-days "Last 7 days")
+(defconst rcirc-sqlite-manually-select "manually select range")
 
 (defun rcirc-sqlite--conn ()
   "Return an open database connection, or open one up."
@@ -142,11 +157,15 @@ VALUES (?,?,?,?)"
   (let ((db (rcirc-sqlite--conn)))
     (sqlite-select db "SELECT DISTINCT nick FROM rcirclogs")))
 
-(defun rcirc-sqlite-db-query-months ()
-  "List the year/months from the SQLite database."
-  (let ((db (rcirc-sqlite--conn)))
-    (sqlite-select db "SELECT DISTINCT strftime('%Y-%m', time, 'unixepoch')
-FROM rcirclogs")))
+(defun rcirc-sqlite-create-period-selectstring (when)
+  "Create a select string for the query.
+WHEN is a cons of start-time and end-time."
+  (let ((subquery ""))
+   (unless (= (car when) 0)
+     (setq subquery (concat subquery " time+0 > ?"))
+     (when (> (cdr when) 0)
+       (setq subquery (concat subquery " AND time+0 < ?"))))
+   subquery))
 
 (defun rcirc-sqlite-db-query-stats (arg-list)
   "List the number of rows per channel.
@@ -188,7 +207,7 @@ ARG-LIST is a list with the requested nick and/or channel.
   "Fetch the last N rows of the logs from a specific channel.
 N is defined in `rcirc-sqlite-rows' and is default 200.
 The user can opt for no limit, or a different limit and offset.
-ARG-LIST is a list build from channel, period (year-month), unlimited,
+ARG-LIST is a list build from channel, time range, unlimited,
 offset and limit."
   (let ((db (rcirc-sqlite--conn))
        (dbquery "SELECT * FROM rcirclogs")
@@ -197,12 +216,15 @@ offset and limit."
       (unless (string= channel rcirc-sqlite-all-channels)
        (setq dbquery (concat dbquery " WHERE channel=?"))
        (push channel dbdata))
-      (unless (string= when rcirc-sqlite-anytime)
+      (unless (= (car when) 0)
        (if (string= channel rcirc-sqlite-all-channels)
            (setq dbquery (concat dbquery " WHERE "))
          (setq dbquery (concat dbquery " AND ")))
-       (setq dbquery (concat dbquery "strftime('%Y-%m', time, 'unixepoch')=?"))
-       (push when dbdata))
+       (setq dbquery (concat dbquery
+                             (rcirc-sqlite-create-period-selectstring when)))
+       (push (car when) dbdata)
+       (when (> (cdr when) 0)
+         (push (cdr when) dbdata)))
       (unless unlimited
        (if limit
            (progn
@@ -217,7 +239,7 @@ offset and limit."
 (defun rcirc-sqlite-db-search-log (arg-list)
   "Perform a full text search.
 ARG-LIST describes the search argument and possibly a specific
-channel, month and/or nick to narrow the search to."
+channel, time range, and/or nick to narrow the search to."
   (let ((db (rcirc-sqlite--conn))
        (dbquery "SELECT * FROM rcirclogs WHERE rcirclogs=?"))
     (pcase-let ((`(,query ,channel ,when ,nick) arg-list))
@@ -225,13 +247,17 @@ channel, month and/or nick to narrow the search to."
        (unless (string= channel rcirc-sqlite-all-channels)
          (setq dbquery (concat dbquery " AND channel=?"))
          (push channel dbdata))
-       (unless (string= when rcirc-sqlite-anytime)
-         (setq dbquery (concat dbquery " AND strftime('%Y-%m', time, 
'unixepoch')=?"))
-         (push when dbdata))
+       (unless (= (car when) 0)
+           (setq dbquery (concat dbquery " AND "))
+         (setq dbquery (concat dbquery
+                               (rcirc-sqlite-create-period-selectstring when)))
+         (push (car when) dbdata)
+         (when (> (cdr when) 0)
+           (push (cdr when) dbdata)))
        (unless (string= nick rcirc-sqlite-all-nicks)
          (setq dbquery (concat dbquery " AND nick=?"))
          (push nick dbdata))
-       (setq dbquery (concat dbquery " ORDER BY rank"))
+       (setq dbquery (concat dbquery " ORDER BY rank, time"))
        (sqlite-execute db dbquery
                        (reverse dbdata))))))
 
@@ -254,7 +280,7 @@ ARG-LIST defines which records to select."
        (push nick dbdata)
        (push what dbdata)))
       (sqlite-execute db dbquery dbdata))))
-    
+
 (defun rcirc-sqlite-convert-tabulation-list (list-to-convert)
   "Convert LIST-TO-CONVERT to format for `tabulated-list-mode'.
 Build a vector from the data in LIST-TO-CONVERT and format the
@@ -384,42 +410,85 @@ choices.  This will also be used as the default choice."
    (append wild-card-value (rcirc-sqlite-db-query-nicks))
    nil nil nil nil wild-card-value))
 
-(defun rcirc-sqlite-select-month (wild-card-value)
-  "Provide completion to select a year and month.
-Extend the list of months with WILD-CARD-VALUE to offer the user more
-choices.  This will also be used as the default choice."
-  (completing-read
-   (format-prompt "Select a month" wild-card-value)
-   (cons wild-card-value (rcirc-sqlite-db-query-months))
-   nil nil nil nil wild-card-value))
+(defun rcirc-sqlite-select-time-range ()
+  "Select the start and end in epochseconds of a time range.
+When end is before start, exchange them."
+  (let ((chperiod (completing-read
+                  (format-prompt "Select the search period (use completion): "
+                                 rcirc-sqlite-anytime)
+                  (list rcirc-sqlite-anytime rcirc-sqlite-manually-select
+                    rcirc-sqlite-last-90-days rcirc-sqlite-last-60-days
+                    rcirc-sqlite-last-30-days rcirc-sqlite-last-07-days)
+                  nil nil nil nil rcirc-sqlite-anytime))
+       (end-time 0)
+       (start-time (time-convert (current-time) 'integer)))
+    (cond
+     ((string= chperiod rcirc-sqlite-anytime) (setq start-time 0))
+     ((string= chperiod rcirc-sqlite-last-90-days)
+      (setq start-time (- start-time (* 90 86400))))
+     ((string= chperiod rcirc-sqlite-last-60-days)
+      (setq start-time (- start-time (* 60 86400))))
+     ((string= chperiod rcirc-sqlite-last-30-days)
+      (setq start-time (- start-time (* 30 86400))))
+     ((string= chperiod rcirc-sqlite-last-07-days)
+      (setq start-time (- start-time (* 7 86400))))
+     ((string= chperiod rcirc-sqlite-manually-select)
+      (setq start-time
+           (1- (time-convert
+               (org-read-date t t nil
+                              "Range starts" nil nil) 'integer))
+           end-time
+           (1+ (time-convert
+               (org-read-date t t nil
+                              "Range ends" nil nil) 'integer)))
+      (when (< end-time start-time)
+       (let ((tmp-time end-time))
+         (setq end-time start-time)
+         (setq start-time tmp-time)))))
+    (cons start-time end-time)))
+
+(defun rcirc-sqlite-format-period-string (when)
+  "Create a human readable string from a time range.
+WHEN is a cons of starttime and endtime."
+  (let ((range-string rcirc-sqlite-anytime))
+    (unless (= (car when) 0)
+      (setq range-string (format-time-string "%F %R - " (car when)))
+      (if (= (cdr when) 0)
+         (setq range-string (concat range-string "now"))
+       (setq range-string
+             (concat range-string
+                     (format-time-string "%F %R" (cdr when)))))) range-string))
 
 (defun rcirc-sqlite-view-log (channel when &optional unlimited offset limit)
   "View the logs of a specific CHANNEL.
-WHEN is either `Anytime' or a specific month.
+WHEN is a cons of start time and end time, each possible zero.
 Shows the result in a new buffer.
 When called without OFFSET and LIMIT, show the last 200 rows.
 When called with non-nil UNLIMITED, show all the rows.
 Otherwise offset and limit are used; in that case  both offset
 and limit have to be provided."
   (interactive (list (rcirc-sqlite-select-channel)
-                    (rcirc-sqlite-select-month rcirc-sqlite-anytime)))
+                    (rcirc-sqlite-select-time-range)))
   (let ((searcharg-list (list channel when unlimited offset limit)))
     (rcirc-sqlite-display-tabulation-list
-     (format "View log (%s %s)" channel when)
+     (format "View log (%s %s)" channel
+            (rcirc-sqlite-format-period-string when))
      #'rcirc-sqlite-db-query-log searcharg-list)))
 
 (defun rcirc-sqlite-text-search (query channel when nick)
   "Perform full text search for QUERY.
-WHEN is either `Anytime' or a specific month, to narrow the search.
+WHEN is a cons of start time and end time, each possible zero.
 Optional narrow search in a specific CHANNEL and/or with a specific NICK.
 The results are displayed a new buffer."
   (interactive (list (read-string "Search for: ")
                      (rcirc-sqlite-select-channel)
-                    (rcirc-sqlite-select-month rcirc-sqlite-anytime)
-                    (rcirc-sqlite-select-nick rcirc-sqlite-all-nicks)))
+                    (rcirc-sqlite-select-time-range)
+                    (rcirc-sqlite-select-nick (list rcirc-sqlite-all-nicks))))
   (let ((searcharg-list (list query channel when nick)))
     (rcirc-sqlite-display-tabulation-list
-     (format "Search %s (%s %s %s)" query channel when nick)
+     (format "Search %s (%s %s %s)" query channel
+            (rcirc-sqlite-format-period-string when)
+            nick)
      #'rcirc-sqlite-db-search-log searcharg-list)))
 
 (defun rcirc-sqlite-stats (nick)
@@ -447,7 +516,7 @@ The results are displayed a new buffer."
     (progn
       (advice-remove 'rcirc-log-write #'rcirc-sqlite-store-log)
       (advice-remove 'rcirc-log #'rcirc-sqlite-set-log-time-format))))
-  
+
 (provide 'rcirc-sqlite)
 
 ;;; rcirc-sqlite.el ends here

Reply via email to