12 // ---------------------------------------------------------------------------
15 Age string // recommended age, e.g. "beginner", "junior", "ya" (Young Adult), "adult"
16 AuthorGrouping string // unique rendering of the author's name, used for internal grouping
17 AuthorReading string // reading order of author's name, e.g. "Charles Dickens"
18 AuthorSort string // sort order of author's name, e.g. "Dickens, Charles"
19 CoverId int // index into EFS table for cover, if there is one
20 DDC string // Dewey Decimal Classification
21 Description string // Back cover / inside flap blurb, describing the book
22 Genre string // e.g. "adventure", "historical", "mystery", "romance", "sf" (Science Fiction)
23 LCC string // Library of Congress Classification
29 // ---------------------------------------------------------------------------
32 Author, Series, Title Field = "aut", "ser", "tit"
35 func (f Field) String() string {
39 // ---------------------------------------------------------------------------
40 type SearchTerm struct {
45 var g_db *sql.DB = nil
46 var g_mutex = &sync.Mutex{}
48 // ============================================================================
55 func getDb() (*sql.DB) {
58 defer g_mutex.Unlock()
61 g_db = openDb(config.user, config.pass, config.dbName)
68 func niVal(ni sql.NullInt64) int {
75 func nsVal(ns sql.NullString) string {
82 func openDb(user, pass, dbName string) (*sql.DB) {
83 db, err := sql.Open("postgres","user=" + user + " password=" + pass + " dbname=" + dbName + " sslmode=disable")
85 report("Error: DB arguments incorrect?", err)
91 report("Error: could not connect to DB.", err)
99 func queryBooksByIds(ids []int) []Book {
100 query := `SELECT s.age,a.grouping,a.reading,a.sort,b.cover,c.ddc,b.description,s.genre,c.lcc,s.descr,b.title,b.volume
102 INNER JOIN Books b ON a.id=b.author
103 LEFT OUTER JOIN Classifications c ON c.id=b.classification
104 LEFT OUTER JOIN Series s ON s.id=b.series
107 ps, err := getDb().Prepare(query)
109 report("Error: failed to prepare statement: " + query, err)
115 for _, id := range ids {
121 res := make([]Book, count)
124 for _, id := range ids {
129 row := ps.QueryRow(id)
131 var age, grouping, reading, sort, ddc, description, genre, lcc, name, title, volume sql.NullString
132 var cover sql.NullInt64
134 err = row.Scan(&age, &grouping, &reading, &sort, &cover, &ddc, &description, &genre, &lcc, &name, &title, &volume)
136 report("Error: Failed to read book:" + strconv.Itoa(id) + ":", err)
141 b.AuthorGrouping = nsVal(grouping)
142 b.AuthorReading = nsVal(reading)
143 b.AuthorSort = nsVal(sort)
144 b.CoverId = niVal(cover)
146 b.Description = nsVal(description)
147 b.Genre = nsVal(genre)
149 b.SeriesName = nsVal(name)
150 b.Title = nsVal(title)
151 b.Volume = nsVal(volume)
158 if count < len(res) {
165 func queryBookPathById(id int) (string) {
166 query := "SELECT b.path FROM Books b WHERE b.id=$1"
168 ps, err := getDb().Prepare(query)
170 report("Failed to Prepare query: " + query, err)
175 row := ps.QueryRow(id)
176 var path sql.NullString
177 err = row.Scan(&path)
179 report(fmt.Sprintf("Failed to retrieve path for book id %v: ", id), err)
186 func queryIds(criteria []SearchTerm) []int {
187 query := "SELECT b.id FROM Books b" +
188 " INNER JOIN Authors a ON a.id=b.author" +
189 " LEFT OUTER JOIN Series s ON s.id=b.series"
191 args := make([]interface{}, len(criteria))
193 for i, criterion := range criteria {
200 text := criterion.Text
202 switch criterion.Attribute {
204 query += " UPPER(a.grouping) LIKE UPPER($" + strconv.Itoa(i + 1) + ")"
205 text = strings.Replace(text, " ", "", -1) // Remove spaces
207 query += " UPPER(s.descr) LIKE UPPER($" + strconv.Itoa(i + 1) + ")"
209 query += " UPPER(b.title) LIKE UPPER($" + strconv.Itoa(i + 1) + ")"
211 report("Error: unrecognized search field in queryIds(): " + criterion.Attribute.String(), nil)
217 query += " ORDER BY b.path"
221 ps, err := getDb().Prepare(query)
223 report("Failed to Prepare query: " + query, err)
229 rows, err = ps.Query(args...)
231 report("Failed to execute query: " + query, err)
239 res = append(res, id)
245 func queryMimeTypeByEfsId(efsId int) string {
246 const query = "SELECT mimeType FROM Efs WHERE id=$1"
248 ps, err := getDb().Prepare(query)
250 report("Failed to Prepare query: " + query, err)
255 row := ps.QueryRow(efsId)
256 var mimeType sql.NullString
257 err = row.Scan(&mimeType)
259 report(fmt.Sprintf("Failed to retrieve mimeType for id %v: ", efsId), err)
263 return nsVal(mimeType)
266 func report(msg string, err error) {
267 fmt.Println("Error: " + msg, err)