Add ability to select sort order
authorChris Jaekl <chris@localhost>
Mon, 24 Jan 2022 04:24:36 +0000 (23:24 -0500)
committerChris Jaekl <chris@localhost>
Mon, 24 Jan 2022 04:24:36 +0000 (23:24 -0500)
app/index.html
js/src/SearchController.js
main/db.go
main/handler.go

index faa558ccb13d54febd13bbcf2f8621b73f473e1e..af1c79dc6dc080daae2c17437442517a0b1ee968 100644 (file)
@@ -5,15 +5,24 @@
     <meta charset="utf-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
   </head>
-  
-  <body onload="onSearch();"> 
+
+  <body onload="onSearch();">
     <form onmouseenter="ToolTip.stopTooltipTimer();">
-      <input id="search" onclick="onSearch();" type="button" value="Search"/> 
+      <input id="search" onclick="onSearch();" type="button" value="Search"/>
       <span class="term">Author: <input id="aut" type="text"/></span>
       <span class="term">Title: <input id="tit" type="text"/></span>
       <span class="term">Series: <input id="ser" type="text"/></span>
       <span class="term">Language: <input id="lan" type="text"/></span>
       <span class="term">Lists: <input id="lst" type="text"/></span>
+      <span class="term">
+        Sort:
+        <select id="srt">
+          <option value="aut">Author</option>
+          <option value="arr">New Arrivals</option>
+          <!-- <option value="pub">Publication</option> (not yet implemented)-->
+          <option value="tit">Title</option>
+        </select>
+      </span>
     </form>
 
     <div class="pager">
index a02d27bae05f905187ce3306fb9c928e627c72fe..557fc1aa42c02c5ab1bd1116787481023b626a91 100644 (file)
@@ -5,7 +5,8 @@ var SearchController = (function () {
     var my = {},
         booksModel = undefined;
 
-    const terms = ['aut', 'lan', 'lst', 'ser', 'tit'];
+    const textFields = ['aut', 'lan', 'ser', 'tit'];
+    const terms = textFields.concat(['lst', 'srt']);
 
     // ==============
     // Public methods
@@ -13,8 +14,8 @@ var SearchController = (function () {
     my.init = function(linkedBooksModel) {
         booksModel = linkedBooksModel;
         
-        for (var idx in terms) {
-            addEnterListener(terms[idx]);
+        for (var idx in textFields) {
+            addEnterListener(textFields[idx]);
         }
     };
     
@@ -80,11 +81,11 @@ var SearchController = (function () {
                 else {
                     url += '&';
                 }
-                if (term === 'lst') {
-                  url += term + '=' + encodeURIComponent('' + value);
+                if (textFields.includes(term)) {
+                  url += term + '=' + encodeURIComponent('%' + value + '%');
                 }
                 else {
-                  url += term + '=' + encodeURIComponent('%' + value + '%');
+                  url += term + '=' + encodeURIComponent('' + value);
                 }
             }
         }
index 53feb90908e7e6fc3d33bb5d579c602a1a06a238..fbc67c8d235f37ac23bc0c180cf53815107fd51b 100644 (file)
@@ -30,7 +30,7 @@ type Book struct {
 // ---------------------------------------------------------------------------
 type Field string
 const (
-  Author, Language, List, Series, Title Field = "aut", "lan", "lst", "ser", "tit"
+  Author, Language, List, Series, Sort, Title Field = "aut", "lan", "lst", "ser", "srt", "tit"
 )
 
 func (f Field) String() string {
@@ -43,10 +43,29 @@ type SearchTerm struct {
   Text      string
 }
 
+// ---------------------------------------------------------------------------
+type SortOrder string
+const (
+  ByArrival, ByAuthor, ByPublication, ByTitle SortOrder = "arr", "aut", "pub", "tit"
+)
+
+func (so SortOrder) String() string {
+  return string(so)
+}
+
+// ---------------------------------------------------------------------------
 var g_db *sql.DB = nil
 var g_mutex = &sync.Mutex{}
 
 // ============================================================================
+func conditional(count int) (string, int) {
+  if (count == 0) {
+    return "WHERE", 1
+  } else {
+    return "AND", (count + 1)
+  }
+}
+
 func dbShutdown() {
   if nil != g_db {
     g_db.Close()
@@ -190,54 +209,68 @@ func queryIds(criteria []SearchTerm) []int {
            " INNER JOIN Authors a ON a.id=b.author" +
            " LEFT OUTER JOIN Series s ON s.id=b.series" +
            " LEFT OUTER JOIN Lists_Books lb ON b.id=lb.book" +
-           " LEFT OUTER JOIN Lists l ON l.id=lb.list"
+           " LEFT OUTER JOIN Lists l ON l.id=lb.list" +
+           " "
 
   args := make([]interface{}, 0)
-
-  i := 0
+  conjunction := "WHERE"
+  count := 0
+  sort := ByAuthor
 
   for _, criterion := range criteria {
-    if 0 == i {
-      query += " WHERE "
-    } else {
-      query += " AND "
-    }
-
     switch criterion.Attribute {
     case Author:
-      query += " UPPER(a.grouping) LIKE UPPER($" + strconv.Itoa(i + 1) + ")"
+      conjunction, count = conditional(count)
+      query += conjunction + " UPPER(a.grouping) LIKE UPPER($" + strconv.Itoa(count) + ")"
       args = append(args, strings.Replace(criterion.Text, " ", "", -1))
     case Language:
-      query += " UPPER(b.language) LIKE UPPER($" + strconv.Itoa(i + 1) + ")"
+      conjunction, count = conditional(count)
+      query += conjunction + " UPPER(b.language) LIKE UPPER($" + strconv.Itoa(count) + ")"
       args = append(args, criterion.Text)
     case List:
+      conjunction, count = conditional(count)
       codes := strings.Split(criterion.Text, ",")
-      query += " UPPER(l.code) IN ("
+      query += conjunction + " UPPER(l.code) IN ("
 
       for j, code := range codes {
         if j > 0 {
           query += ","
         }
-        query += "UPPER($" + strconv.Itoa(i + j + 1) + ")"
+        query += "UPPER($" + strconv.Itoa(count + j + 1) + ")"
         args = append(args, code)
       }
       query += ")"
-      i += len(codes) - 1
+      count += len(codes) - 1
     case Series:
-      query += " UPPER(s.descr) LIKE UPPER($" + strconv.Itoa(i + 1) + ")"
+      conjunction, count = conditional(count)
+      query += conjunction + " UPPER(s.descr) LIKE UPPER($" + strconv.Itoa(count) + ")"
       args = append(args, criterion.Text)
+    case Sort:
+      sort = SortOrder(criterion.Text)
     case Title:
-      query += " UPPER(b.title) LIKE UPPER($" + strconv.Itoa(i + 1) + ")"
+      conjunction, count = conditional(count)
+      query += conjunction + " UPPER(b.title) LIKE UPPER($" + strconv.Itoa(count) + ")"
       args = append(args, criterion.Text)
     default:
       report("Error:  unrecognized search field in queryIds():  " + criterion.Attribute.String(), nil)
       return nil
     }
-
-    i++
   }
 
-  query += " ORDER BY a.grouping,s.descr,b.volume,b.title,b.path"
+  switch sort {
+  case ByArrival:
+    query += " ORDER BY b.arrived DESC,a.grouping,s.descr,b.volume,b.title,b.path"
+  case ByAuthor:
+    query += " ORDER BY a.grouping,s.descr,b.volume,b.title,b.path,b.arrived DESC"
+  case ByPublication:
+    report("Error: cannot sort by publication (not yet implemented)", nil)
+    return nil
+  case ByTitle:
+    query += " ORDER BY b.title,a.grouping,s.descr,b.volume,b.path,b.arrived DESC"
+  default:
+    report("Error: unrecognized sort order in queryIds(): " + sort.String(), nil)
+    return nil
+  }
 
   res := []int{}
 
index 18366b93dd36d7ac49b2899382572c6e1f3cacdf..bdd6410520896253fc1d68deb76904612adf1ff0 100644 (file)
@@ -190,7 +190,7 @@ func handleInfo(w http.ResponseWriter, r *http.Request) {
 func handleSearch(w http.ResponseWriter, r *http.Request) {
   var err error
 
-  fields := []Field{Author, Language, List, Series, Title}
+  fields := []Field{Author, Language, List, Series, Sort, Title}
 
   terms := make([]SearchTerm, len(fields))