@@ -5,16 +5,33 @@ import (
55 "compress/gzip"
66 "encoding/json"
77 "fmt"
8+ "github.com/derekparker/trie"
89 "io"
910 "os"
1011 "path"
1112 "runtime"
13+ "strings"
1214)
1315
1416// Bible contains the old testament and new testament
1517type Bible struct {
1618 OldTestament Testament
1719 NewTestament Testament
20+ searchTree * trie.Trie
21+ }
22+
23+ type SearchNode struct {
24+ Book * Book
25+ Chapter * Chapter
26+ Verse * Verse
27+ }
28+
29+ // String creates a string representation for the SearchNode, ex. Genesis 1:1
30+ func (s * SearchNode ) String () string {
31+ return fmt .Sprintf ("%s %d:%d" ,
32+ s .Book .Title ,
33+ s .Chapter .ChapterNumber ,
34+ s .Verse .VerseNumber )
1835}
1936
2037const bibleTar = "bible.tar.gz"
@@ -26,7 +43,9 @@ func NewBible() *Bible {
2643 _ , currFile , _ , _ := runtime .Caller (0 )
2744 filename := fmt .Sprintf ("%s/%s" , path .Dir (currFile ), bibleTar )
2845
29- bible := & Bible {}
46+ bible := & Bible {
47+ searchTree : trie .New (),
48+ }
3049
3150 f , _ := os .Open (filename )
3251 defer f .Close ()
@@ -36,6 +55,7 @@ func NewBible() *Bible {
3655
3756 tr := tar .NewReader (gzf )
3857
58+ // Build testaments, books, chapters, verses
3959 for {
4060 h , err := tr .Next ()
4161 if err == io .EOF {
@@ -50,6 +70,28 @@ func NewBible() *Bible {
5070 }
5171 }
5272
73+ // Build search tree
74+ var books []Book
75+ books = append (books , bible .OldTestament .Books ... )
76+ books = append (books , bible .NewTestament .Books ... )
77+
78+ for i := range books {
79+ bk := books [i ]
80+
81+ for j := range bk .Chapters {
82+ ch := bk .Chapters [j ]
83+
84+ for k := range ch .Verses {
85+ vr := strings .ToLower (ch .Verses [k ].Text )
86+ bible .searchTree .Add (vr , SearchNode {
87+ Book : & bk ,
88+ Chapter : & ch ,
89+ Verse : & ch .Verses [k ],
90+ })
91+ }
92+ }
93+ }
94+
5395 return bible
5496}
5597
@@ -58,3 +100,22 @@ func decode(r io.Reader) []Book {
58100 json .NewDecoder (r ).Decode (& books )
59101 return books
60102}
103+
104+ // Search finds top matching verses based on the given query.
105+ // The number of search results are restricted by maxResults
106+ func (b * Bible ) Search (query string , maxResults int ) []SearchNode {
107+ t := b .searchTree
108+ keys := t .FuzzySearch (strings .ToLower (query ))
109+ var verses []SearchNode
110+
111+ for k := range keys {
112+ res , _ := t .Find (keys [k ])
113+ verses = append (verses , res .Meta ().(SearchNode ))
114+
115+ if len (verses ) >= maxResults {
116+ break
117+ }
118+ }
119+
120+ return verses
121+ }
0 commit comments