mongoid-giza 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +6 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +152 -0
- data/Rakefile +11 -0
- data/lib/mongoid/giza.rb +160 -0
- data/lib/mongoid/giza/configuration.rb +136 -0
- data/lib/mongoid/giza/dynamic_index.rb +37 -0
- data/lib/mongoid/giza/index.rb +101 -0
- data/lib/mongoid/giza/index/attribute.rb +39 -0
- data/lib/mongoid/giza/index/field.rb +27 -0
- data/lib/mongoid/giza/indexer.rb +33 -0
- data/lib/mongoid/giza/models/giza_id.rb +27 -0
- data/lib/mongoid/giza/railtie.rb +17 -0
- data/lib/mongoid/giza/search.rb +83 -0
- data/lib/mongoid/giza/version.rb +5 -0
- data/lib/mongoid/giza/xml_pipe2.rb +67 -0
- data/mongoid-giza.gemspec +32 -0
- data/spec/mongoid/giza/configuration_spec.rb +340 -0
- data/spec/mongoid/giza/dynamic_index_spec.rb +32 -0
- data/spec/mongoid/giza/index/attribute_spec.rb +36 -0
- data/spec/mongoid/giza/index/field_spec.rb +25 -0
- data/spec/mongoid/giza/index_spec.rb +162 -0
- data/spec/mongoid/giza/indexer_spec.rb +87 -0
- data/spec/mongoid/giza/models/giza_id_spec.rb +30 -0
- data/spec/mongoid/giza/search_spec.rb +100 -0
- data/spec/mongoid/giza/xml_pipe2_spec.rb +98 -0
- data/spec/mongoid/giza_spec.rb +282 -0
- data/spec/spec_helper.rb +51 -0
- metadata +227 -0
@@ -0,0 +1,162 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Giza::Index do
|
4
|
+
let(:klass) do
|
5
|
+
klass = double("klass")
|
6
|
+
allow(klass).to receive(:name) { "Klass" }
|
7
|
+
allow(klass).to receive(:all)
|
8
|
+
klass
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:index) { Mongoid::Giza::Index.new(klass) }
|
12
|
+
|
13
|
+
it "should have a list of fields" do
|
14
|
+
expect(index.fields).to be_a_kind_of(Array)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have a list of attributes" do
|
18
|
+
expect(index.attributes).to be_a_kind_of(Array)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should accept a settings hash" do
|
22
|
+
settings = {setting1: 1, setting2: 2}
|
23
|
+
index = Mongoid::Giza::Index.new(klass, settings)
|
24
|
+
expect(index.settings).to be(settings)
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "klass" do
|
28
|
+
it "should be mandatory" do
|
29
|
+
expect { Mongoid::Giza::Index.new }.to raise_error(ArgumentError)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should be set on creation" do
|
33
|
+
expect(index.klass).to be(klass)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "field" do
|
38
|
+
let(:field) { double("field") }
|
39
|
+
|
40
|
+
let(:name) { "field" }
|
41
|
+
|
42
|
+
it "should require a name" do
|
43
|
+
expect { index.field }.to raise_error(ArgumentError)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should create a new Field" do
|
47
|
+
expect(Mongoid::Giza::Index::Field).to receive(:new).with(name, false)
|
48
|
+
index.field(name)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should accept :attribute as an option" do
|
52
|
+
expect(Mongoid::Giza::Index::Field).to receive(:new).with(name, true)
|
53
|
+
index.field(name, attribute: true)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should add the new field to the list of fields" do
|
57
|
+
allow(Mongoid::Giza::Index::Field).to receive(:new) { field }
|
58
|
+
index.field(name)
|
59
|
+
expect(index.fields.first).to be(field)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "attribute" do
|
64
|
+
let(:name) { "attribute" }
|
65
|
+
|
66
|
+
let(:type) { :uint }
|
67
|
+
|
68
|
+
it "should require a name" do
|
69
|
+
expect { index.attribute }.to raise_error(ArgumentError)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should accept a type" do
|
73
|
+
expect(Mongoid::Giza::Index::Attribute).to receive(:new).with(name, type)
|
74
|
+
index.attribute(name, type)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should automatically define the type when it is not supplied" do
|
78
|
+
type = String
|
79
|
+
allow(klass).to receive(:fields) do
|
80
|
+
fields = double("fields")
|
81
|
+
allow(fields).to receive(:[]).with(name) do
|
82
|
+
field = double("field")
|
83
|
+
allow(field).to receive(:type) { type }
|
84
|
+
field
|
85
|
+
end
|
86
|
+
fields
|
87
|
+
end
|
88
|
+
expect(Mongoid::Giza::Index::Attribute).to receive(:new).with(name, Mongoid::Giza::Index::TYPES_MAP[type])
|
89
|
+
index.attribute(name)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should default to the first type when the field is not found" do
|
93
|
+
allow(klass).to receive(:fields) do
|
94
|
+
fields = double("fields")
|
95
|
+
allow(fields).to receive(:[]).with(name) { nil }
|
96
|
+
fields
|
97
|
+
end
|
98
|
+
expect(Mongoid::Giza::Index::Attribute).to receive(:new).with(name, Mongoid::Giza::Index::TYPES_MAP.values.first)
|
99
|
+
index.attribute(name)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should default to the first type when the type is not mapped" do
|
103
|
+
allow(klass).to receive(:fields) do
|
104
|
+
fields = double("fields")
|
105
|
+
allow(fields).to receive(:[]).with(name) do
|
106
|
+
field = double("field")
|
107
|
+
allow(field).to receive(:type) { Object }
|
108
|
+
field
|
109
|
+
end
|
110
|
+
fields
|
111
|
+
end
|
112
|
+
expect(Mongoid::Giza::Index::Attribute).to receive(:new).with(name, Mongoid::Giza::Index::TYPES_MAP.values.first)
|
113
|
+
index.attribute(name)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "name" do
|
118
|
+
it "should be the class name by default" do
|
119
|
+
allow(klass).to receive(:name) { "Klass" }
|
120
|
+
expect(index.name).to eql(:Klass)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should define a new name when supplied" do
|
124
|
+
index.name(:Index)
|
125
|
+
expect(index.name).to eql(:Index)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "generate_xmlpipe2" do
|
130
|
+
let(:xmlpipe2) { double("XMLPipe2") }
|
131
|
+
|
132
|
+
let(:buffer) { double("buffer") }
|
133
|
+
|
134
|
+
it "should create a new XMLPipe2 object" do
|
135
|
+
expect(Mongoid::Giza::XMLPipe2).to receive(:new).with(index, buffer) { xmlpipe2.as_null_object }
|
136
|
+
index.generate_xmlpipe2(buffer)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should generate the xml" do
|
140
|
+
allow(Mongoid::Giza::XMLPipe2).to receive(:new) { xmlpipe2 }
|
141
|
+
expect(xmlpipe2).to receive(:generate!)
|
142
|
+
index.generate_xmlpipe2(buffer)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "criteria" do
|
147
|
+
let(:all) { double("all") }
|
148
|
+
|
149
|
+
let(:criteria) { double("criteria") }
|
150
|
+
|
151
|
+
it "should default to all" do
|
152
|
+
allow(klass).to receive(:all) { all }
|
153
|
+
expect(index.criteria).to be(all)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should accept a new criteria as a parameter" do
|
157
|
+
allow(klass).to receive(:where) { criteria }
|
158
|
+
index.criteria(klass.where(name: "one"))
|
159
|
+
expect(index.criteria).to be(criteria)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Giza::Indexer do
|
4
|
+
before do
|
5
|
+
@controller = double("controller")
|
6
|
+
allow(Riddle::Controller).to receive(:new) { @controller }
|
7
|
+
@indexer = Mongoid::Giza::Indexer.send(:new)
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:config) { Mongoid::Giza::Configuration.instance }
|
11
|
+
|
12
|
+
describe "index!" do
|
13
|
+
it "should create the sphinx configuration file" do
|
14
|
+
allow(@controller).to receive(:index)
|
15
|
+
expect(config).to receive(:render)
|
16
|
+
@indexer.index!
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should execute the sphinx indexer" do
|
20
|
+
allow(config).to receive(:render)
|
21
|
+
expect(@controller).to receive(:index).with(verbose: true)
|
22
|
+
@indexer.index!
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should accept an index list" do
|
26
|
+
allow(config).to receive(:render)
|
27
|
+
expect(@controller).to receive(:index).with(:Person, :Person_2, verbose: true)
|
28
|
+
@indexer.index!(:Person, :Person_2)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "full_index" do
|
33
|
+
let(:klass) { double("class") }
|
34
|
+
|
35
|
+
before do
|
36
|
+
allow(@indexer).to receive(:index!)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should clear the generated indexes from the configuration" do
|
40
|
+
expect(config).to receive(:clear_generated_indexes)
|
41
|
+
allow(@indexer).to receive(:giza_classes) { [klass] }
|
42
|
+
allow(klass).to receive(:regenerate_dynamic_sphinx_indexes)
|
43
|
+
@indexer.full_index
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should regenerate all dynamic indexes of the giza classes" do
|
47
|
+
allow(config).to receive(:clear_generated_indexes)
|
48
|
+
allow(@indexer).to receive(:giza_classes) { [klass] }
|
49
|
+
expect(klass).to receive(:regenerate_dynamic_sphinx_indexes)
|
50
|
+
@indexer.full_index
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should execute the indexer" do
|
54
|
+
allow(config).to receive(:clear_generated_indexes)
|
55
|
+
allow(@indexer).to receive(:giza_classes) { [klass] }
|
56
|
+
allow(klass).to receive(:regenerate_dynamic_sphinx_indexes)
|
57
|
+
expect(@indexer).to receive(:index!).with(no_args)
|
58
|
+
@indexer.full_index
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "giza_classes" do
|
63
|
+
before(:all) do
|
64
|
+
class One
|
65
|
+
include Mongoid::Document
|
66
|
+
include Mongoid::Giza
|
67
|
+
end
|
68
|
+
|
69
|
+
class Two
|
70
|
+
include Mongoid::Document
|
71
|
+
end
|
72
|
+
|
73
|
+
class Three
|
74
|
+
include Mongoid::Document
|
75
|
+
include Mongoid::Giza
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should return all classes that include the Giza module" do
|
80
|
+
expect(@indexer.giza_classes).to include(One, Three)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should not return classes that do not include the Giza module" do
|
84
|
+
expect(@indexer.giza_classes).not_to include(Two)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Giza::GizaID do
|
4
|
+
describe "instance" do
|
5
|
+
let(:giza_id) { Mongoid::Giza::GizaID.new(id: :Person) }
|
6
|
+
|
7
|
+
it "should be valid" do
|
8
|
+
expect(giza_id).to be_valid
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have the specified id" do
|
12
|
+
expect(giza_id.id).to eql(:Person)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have a sequence default to zero" do
|
16
|
+
expect(giza_id.seq).to eql(0)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "next_id" do
|
21
|
+
before do
|
22
|
+
Mongoid::Giza::GizaID.create(id: :Person)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return the next id for the given class" do
|
26
|
+
expect(Mongoid::Giza::GizaID.next_id(:Person)).to eql(1)
|
27
|
+
expect(Mongoid::Giza::GizaID.next_id(:Person)).to eql(2)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Giza::Search do
|
4
|
+
let(:client) do
|
5
|
+
client = double("client")
|
6
|
+
allow(Riddle::Client).to receive(:new).with("localhost", 9132) { client }
|
7
|
+
client
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:search) { Mongoid::Giza::Search.new("localhost", 9132) }
|
11
|
+
|
12
|
+
let(:filters) do
|
13
|
+
filters = double("filters")
|
14
|
+
allow(client).to receive(:filters) { filters }
|
15
|
+
filters
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:filter) { double("filter") }
|
19
|
+
|
20
|
+
describe "initialize" do
|
21
|
+
it "should create a new client with the given host and port" do
|
22
|
+
expect(Riddle::Client).to receive(:new).with("localhost", 9132)
|
23
|
+
search
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should accept a index list" do
|
27
|
+
indexes = Mongoid::Giza::Search.new("localhost", 9132, :index1, :index2).indexes
|
28
|
+
expect(indexes).to eql([:index1, :index2])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "fulltext" do
|
33
|
+
it "should append a query on the specified indexes" do
|
34
|
+
expect(client).to receive(:append_query).with("query", "index1 index2")
|
35
|
+
allow(search).to receive(:indexes) { [:index1, :index2] }
|
36
|
+
search.fulltext("query")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should search all indexes by default" do
|
40
|
+
expect(client).to receive(:append_query).with("query", "*")
|
41
|
+
allow(search).to receive(:indexes) { [] }
|
42
|
+
search.fulltext("query")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "with" do
|
47
|
+
it "should add a filter to the search" do
|
48
|
+
expect(Riddle::Client::Filter).to receive(:new).with("attr", 1, false) { filter }
|
49
|
+
expect(filters).to receive(:<<).with(filter)
|
50
|
+
client
|
51
|
+
search.with(:attr, 1)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "without" do
|
56
|
+
it "should add a filter to the search" do
|
57
|
+
expect(Riddle::Client::Filter).to receive(:new).with("attr", 1, true) { filter }
|
58
|
+
expect(filters).to receive(:<<).with(filter)
|
59
|
+
client
|
60
|
+
search.without(:attr, 1)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "order_by" do
|
65
|
+
it "should set the search order" do
|
66
|
+
expect(client).to receive(:sort_by=).with("attr ASC")
|
67
|
+
search.order_by(:attr, :asc)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "run" do
|
72
|
+
it "should run the query" do
|
73
|
+
expect(client).to receive(:run) { [1, 2] }
|
74
|
+
search.run
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should return the result array" do
|
78
|
+
expect(client).to receive(:run) { [1, 2] }
|
79
|
+
expect(search.run).to eql([1, 2])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "riddle methods mapping" do
|
84
|
+
it "should respond to method from riddle" do
|
85
|
+
allow(client).to receive(:respond_to?).with("offset=") { true }
|
86
|
+
expect(search.respond_to?(:offset)).to eql(true)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should call the equivalent method from riddle" do
|
90
|
+
allow(client).to receive(:respond_to?).with("offset=") { true }
|
91
|
+
expect(client).to receive(:offset=).with(1)
|
92
|
+
search.offset(1)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should raise an error when the equivalent riddle's method does not exists" do
|
96
|
+
allow(client).to receive(:respond_to?).with("idontexist=") { false }
|
97
|
+
expect { search.idontexist }.to raise_error(NoMethodError)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Giza::XMLPipe2 do
|
4
|
+
let(:xmlpipe2) { Mongoid::Giza::XMLPipe2.new(@index, @buffer) }
|
5
|
+
|
6
|
+
before do
|
7
|
+
@buffer = ""
|
8
|
+
@index = double("index")
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "generate_schema" do
|
12
|
+
before do
|
13
|
+
@field = double("field")
|
14
|
+
@attribute = double("attribute")
|
15
|
+
allow(@index).to receive(:fields) { [@field] }
|
16
|
+
allow(@index).to receive(:attributes) { [@attribute] }
|
17
|
+
allow(@field).to receive(:name) { :name }
|
18
|
+
allow(@attribute).to receive(:name) { :age }
|
19
|
+
allow(@attribute).to receive(:type) { :uint }
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should generate the schema of the docset" do
|
23
|
+
allow(@field).to receive(:attribute) { false }
|
24
|
+
xmlpipe2.generate_schema
|
25
|
+
expect(@buffer).to eql('<sphinx:schema><sphinx:field name="name"/><sphinx:attr name="age" type="uint"/></sphinx:schema>')
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should generate a field attribute" do
|
29
|
+
allow(@field).to receive(:attribute) { true }
|
30
|
+
xmlpipe2.generate_schema
|
31
|
+
expect(@buffer).to eql('<sphinx:schema><sphinx:field name="name" attr="string"/><sphinx:attr name="age" type="uint"/></sphinx:schema>')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "generate_docset" do
|
36
|
+
before do
|
37
|
+
field = double("field")
|
38
|
+
attribute = double("attribute")
|
39
|
+
person = double("person")
|
40
|
+
allow(@index).to receive(:fields) { [field] }
|
41
|
+
allow(@index).to receive(:attributes) { [attribute] }
|
42
|
+
allow(@index).to receive(:criteria) { [person] }
|
43
|
+
allow(person).to receive(:giza_id) { 1 }
|
44
|
+
allow(xmlpipe2).to receive(:generate_doc_tags).with([field], person) do
|
45
|
+
@buffer << "<name>Person One</name>"
|
46
|
+
end
|
47
|
+
allow(xmlpipe2).to receive(:generate_doc_tags).with([attribute], person) do
|
48
|
+
@buffer << "<age>25</age>"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "static fields and attributes" do
|
53
|
+
it "should generate the document entries" do
|
54
|
+
xmlpipe2.generate_docset
|
55
|
+
expect(@buffer).to eql('<sphinx:document id="1"><name>Person One</name><age>25</age></sphinx:document>')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "generate_doc_tags" do
|
61
|
+
before do
|
62
|
+
name = double("name")
|
63
|
+
bio = double("bio")
|
64
|
+
@fields = [name, bio]
|
65
|
+
@person = {name: "Person One", bio: "About me"}
|
66
|
+
allow(name).to receive(:name) { :name }
|
67
|
+
allow(name).to receive(:block) do
|
68
|
+
Proc.new { |document| document[:name].upcase }
|
69
|
+
end
|
70
|
+
allow(bio).to receive(:name) { :bio }
|
71
|
+
allow(bio).to receive(:block) { nil }
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should generate all tags for the given fields or attributes" do
|
75
|
+
xmlpipe2.generate_doc_tags(@fields, @person)
|
76
|
+
expect(@buffer).to eql('<name>PERSON ONE</name><bio>About me</bio>')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "generate!" do
|
81
|
+
it "should generate a xml file of the index" do
|
82
|
+
result = '<?xml version="1.0" encoding="utf-8"?>'
|
83
|
+
result << '<sphinx:docset><sphinx:schema>'
|
84
|
+
result << '<sphinx:field name="name"/><sphinx:attr name="age" type="uint"/>'
|
85
|
+
result << '</sphinx:schema>'
|
86
|
+
result << '<sphinx:document id="1"><name>Person One</name><age>25</age></sphinx:document>'
|
87
|
+
result << '</sphinx:docset>'
|
88
|
+
expect(xmlpipe2).to receive(:generate_schema) do
|
89
|
+
@buffer << '<sphinx:schema><sphinx:field name="name"/><sphinx:attr name="age" type="uint"/></sphinx:schema>'
|
90
|
+
end
|
91
|
+
expect(xmlpipe2).to receive(:generate_docset) do
|
92
|
+
@buffer << '<sphinx:document id="1"><name>Person One</name><age>25</age></sphinx:document>'
|
93
|
+
end
|
94
|
+
xmlpipe2.generate!
|
95
|
+
expect(@buffer).to eql(result)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|