Skip to content

Commit 7f8ff2b

Browse files
author
Matthew Borders
committed
Added search functionality to find paragraphs based on a query string
1 parent 9db44b1 commit 7f8ff2b

File tree

2 files changed

+68
-3
lines changed

2 files changed

+68
-3
lines changed

parse.go

+61-3
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,36 @@ import (
99
"os"
1010
"path"
1111
"runtime"
12+
"strings"
1213

1314
"github.com/derekparker/trie"
1415
)
1516

17+
type SearchNode struct {
18+
Part *Part
19+
Article *Article
20+
Section *Section
21+
Paragraph *Paragraph
22+
}
23+
24+
// String creates a string representation for the SearchNode,
25+
// ex. Part 1, Article 1, Section 1, Paragraph 1
26+
func (s *SearchNode) String() string {
27+
return fmt.Sprintf("Part %d, Article %d, Section %d, Paragraph %d",
28+
s.Part.PartNumber,
29+
s.Article.ArticleNumber,
30+
s.Section.SectionNumber,
31+
s.Paragraph.ParagraphNumber);
32+
}
33+
1634
const catechismTar = "catechism.tar.gz"
1735
const catechismFilename = "catechism.json"
1836

1937
func NewCatechism() *Catechism {
2038
_, currFile, _, _ := runtime.Caller(0)
2139
filename := fmt.Sprintf("%s/%s", path.Dir(currFile), catechismTar)
2240

23-
c := &Catechism{
41+
catechism := &Catechism{
2442
searchTree: trie.New(),
2543
}
2644

@@ -41,15 +59,55 @@ func NewCatechism() *Catechism {
4159

4260
switch h.Name {
4361
case catechismFilename:
44-
c.Parts = decode(tr)
62+
catechism.Parts = decode(tr)
4563
}
4664
}
4765

48-
return c
66+
// Build search tree
67+
for i := range catechism.Parts {
68+
p := catechism.Parts[i]
69+
for j := range p.Articles {
70+
a := p.Articles[j]
71+
for k := range a.Sections {
72+
s := a.Sections[k]
73+
for l := range s.Paragraphs {
74+
par := s.Paragraphs[l]
75+
t := strings.ToLower(par.Text)
76+
catechism.searchTree.Add(t, SearchNode{
77+
Part: &p,
78+
Article: &a,
79+
Section: &s,
80+
Paragraph: &par,
81+
})
82+
}
83+
}
84+
}
85+
}
86+
87+
return catechism
4988
}
5089

5190
func decode(r io.Reader) []Part {
5291
var parts []Part
5392
json.NewDecoder(r).Decode(&parts)
5493
return parts
5594
}
95+
96+
// Search finds top matching verses based on the given query.
97+
// The number of search results are restricted by maxResults
98+
func (c *Catechism) Search(query string, maxResults int) []SearchNode {
99+
t := c.searchTree
100+
keys := t.FuzzySearch(strings.ToLower(query))
101+
var nodes []SearchNode
102+
103+
for k := range keys {
104+
res, _ := t.Find(keys[k])
105+
nodes = append(nodes, res.Meta().(SearchNode))
106+
107+
if len(nodes) >= maxResults {
108+
break
109+
}
110+
}
111+
112+
return nodes
113+
}

parse_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,10 @@ func TestCatechism_GetParagraph_InvalidParagraph(t *testing.T) {
8080
_, err := c.GetParagraph(1, 1, 1, 100)
8181
assert.Equal(t, "invalid paragraph number", err.Error())
8282
}
83+
84+
func TestCatechism_Search(t *testing.T) {
85+
p := c.Search("I believe", 10)
86+
87+
assert.NotEmpty(t, p)
88+
assert.Equal(t, "Part 4, Article 3, Section 4, Paragraph 1", p[0].String())
89+
}

0 commit comments

Comments
 (0)