mongoscript 0.0.8

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.
@@ -0,0 +1,157 @@
1
+ require 'spec_helper'
2
+
3
+ describe MongoScript::Execution do
4
+ module ObjectWithExecution
5
+ include MongoScript::ORM::MongoidAdapter
6
+ include MongoScript::Execution
7
+ end
8
+
9
+ before :all do
10
+ @original_script_dirs = ObjectWithExecution.script_dirs
11
+ end
12
+
13
+ before :each do
14
+ ObjectWithExecution.script_dirs = @original_script_dirs
15
+ end
16
+
17
+ it "has a constant for LOADED_SCRIPTS" do
18
+ MongoScript::Execution::LOADED_SCRIPTS.should be_a(Hash)
19
+ end
20
+
21
+ it "defines ScriptNotFound error < Errno::ENOENT" do
22
+ MongoScript::Execution::ScriptNotFound.superclass.should == Errno::ENOENT
23
+ end
24
+
25
+ it "defines ExecutionFailure error < RuntimeError" do
26
+ MongoScript::Execution::ExecutionFailure.superclass.should == RuntimeError
27
+ end
28
+
29
+ it "has a script_dir accessor" do
30
+ stubby = stub("dir")
31
+ ObjectWithExecution.script_dirs = stubby
32
+ ObjectWithExecution.script_dirs.should == stubby
33
+ end
34
+
35
+ it "defaults to the built-in scripts" do
36
+ location_pieces = File.dirname(__FILE__).split("/")
37
+ # strip out /spec/cases to get back to the root directory
38
+ gem_path = location_pieces[0, location_pieces.length - 2].join("/")
39
+ ObjectWithExecution.script_dirs.should == [File.join(gem_path, "lib", "mongoscript", "javascripts")]
40
+ end
41
+
42
+ describe ".code_for" do
43
+ before :all do
44
+ @script_code = File.open(File.join(SCRIPTS_PATH, "sample_script.js")).read
45
+ end
46
+
47
+ before :each do
48
+ ObjectWithExecution.script_dirs = @original_script_dirs + [SCRIPTS_PATH]
49
+ end
50
+
51
+ it "loads and returns the code for a given file" do
52
+ ObjectWithExecution.code_for("sample_script").should == @script_code
53
+ end
54
+
55
+ it "loads and returns the code for a given file by symbol" do
56
+ ObjectWithExecution.code_for(:sample_script).should == @script_code
57
+ end
58
+
59
+ it "stores the value in LOADED_SCRIPTS" do
60
+ ObjectWithExecution.code_for(:sample_script)
61
+ ObjectWithExecution::LOADED_SCRIPTS["sample_script"].should == @script_code
62
+ end
63
+
64
+ it "raises a ScriptNotFound error if the file doesn't exist" do
65
+ File.stubs(:exist?).returns(false)
66
+ expect { ObjectWithExecution.code_for("i don't exist") }.to raise_exception(ObjectWithExecution::ScriptNotFound)
67
+ end
68
+
69
+ it "will look in all the directories provided" do
70
+ dir = "/foo/bar"
71
+ my_script = "a script"
72
+ ObjectWithExecution.script_dirs << dir
73
+ File.stubs(:exists?).returns(*(ObjectWithExecution.script_dirs.map {|f| f == dir}))
74
+
75
+ # make sure that we try to load the script
76
+ stubby = stub("file contents")
77
+ File.expects(:read).with(File.join(dir, "#{my_script}.js")).returns(stubby)
78
+ ObjectWithExecution.code_for(my_script).should == stubby
79
+ end
80
+ end
81
+
82
+ describe ".execute_readonly_routine" do
83
+ it "gets and passes the appropriate code and arguments to be run in readonly mode" do
84
+ args = [1, 2, {}]
85
+ name = "scriptname"
86
+ stubby = stub("code")
87
+ ObjectWithExecution.expects(:code_for).with(name).returns(stubby)
88
+ ObjectWithExecution.expects(:execute_readonly_code).with(stubby, *args)
89
+ ObjectWithExecution.execute_readonly_routine(name, *args)
90
+ end
91
+ end
92
+
93
+ describe ".execute_readwrite_routine" do
94
+ it "gets and passes the appropriate code and arguments to be run in readwrite mode" do
95
+ args = [1, 2, {}]
96
+ name = "scriptname"
97
+ stubby = stub("code")
98
+ ObjectWithExecution.expects(:code_for).with(name).returns(stubby)
99
+ ObjectWithExecution.expects(:execute_readwrite_code).with(stubby, *args)
100
+ ObjectWithExecution.execute_readwrite_routine(name, *args)
101
+ end
102
+ end
103
+
104
+ describe ".execute_readonly_code" do
105
+ it "executes provided code and arguments in with nolock mode" do
106
+ args = [1, 2, {}]
107
+ code = stub("code")
108
+ ObjectWithExecution.expects(:execute).with(code, args, {:nolock => true})
109
+ ObjectWithExecution.execute_readonly_code(code, *args)
110
+ end
111
+ end
112
+
113
+ describe ".execute_readwrite_code" do
114
+ it "executes provided code and arguments with no Mongo options" do
115
+ args = [1, 2, {}]
116
+ code = stub("code")
117
+ ObjectWithExecution.expects(:execute).with(code, args)
118
+ ObjectWithExecution.execute_readwrite_code(code, *args)
119
+ end
120
+ end
121
+
122
+ describe ".execute" do
123
+ it "executes the command via the Mongo database" do
124
+ MongoScript.database.expects(:command).returns({"ok" => 1.0})
125
+ ObjectWithExecution.execute("code")
126
+ end
127
+
128
+ it "executes the code using the eval command" do
129
+ code = stub("code")
130
+ MongoScript.database.expects(:command).with(has_entries(:$eval => code)).returns({"ok" => 1.0})
131
+ ObjectWithExecution.execute(code)
132
+ end
133
+
134
+ it "passes in any arguments provided" do
135
+ args = [:a, :r, :g, :s]
136
+ MongoScript.database.expects(:command).with(has_entries(:args => args)).returns({"ok" => 1.0})
137
+ ObjectWithExecution.execute("code", args)
138
+ end
139
+
140
+ it "merges in any additional options" do
141
+ options = {:a => stub("options")}
142
+ MongoScript.database.expects(:command).with(has_entries(options)).returns({"ok" => 1.0})
143
+ ObjectWithExecution.execute("code", [], options)
144
+ end
145
+
146
+ it "raises an ExecutionFailure error if the result[ok] != 1.0" do
147
+ MongoScript.database.expects(:command).returns({"result" => {}})
148
+ expect { ObjectWithExecution.execute("code") }.to raise_exception(MongoScript::Execution::ExecutionFailure)
149
+ end
150
+
151
+ it "returns the retval" do
152
+ result = stub("result")
153
+ MongoScript.database.expects(:command).returns({"ok" => 1.0, "retval" => result})
154
+ ObjectWithExecution.execute("code").should == result
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+
3
+ describe MongoScript::ORM::MongoidAdapter do
4
+ module ObjectWithMongoidAdapter
5
+ include MongoScript::ORM::MongoidAdapter
6
+ end
7
+
8
+ class AMongoidClass
9
+ include Mongoid::Document
10
+ end
11
+
12
+
13
+ before :all do
14
+ @adapter = ObjectWithMongoidAdapter
15
+ end
16
+
17
+ describe "#database" do
18
+ it "returns Mongo::Config.database" do
19
+ db_stub = stub("database")
20
+ Mongoid::Config.stubs(:database).returns(db_stub)
21
+ @adapter.database.should == db_stub
22
+ end
23
+ end
24
+
25
+ describe "#rehydrate" do
26
+ it "uses Mongoid::Factory to create the Mongoid doc" do
27
+ klass = stub("class")
28
+ hash = stub("document attributes")
29
+ Mongoid::Factory.expects(:from_db).with(klass, hash)
30
+ @adapter.rehydrate(klass, hash)
31
+ end
32
+
33
+ it "returns the rehydrated value" do
34
+ result = stub("document")
35
+ Mongoid::Factory.stubs(:from_db).returns(result)
36
+ @adapter.rehydrate("foo", "bar").should == result
37
+ end
38
+ end
39
+
40
+ describe "#resolve_arguments" do
41
+ it "resolves any hashes in the arguments" do
42
+ args = [{}, 2, 3, [], {:c.in => 2}]
43
+ args.each {|a| @adapter.expects(:resolve_complex_criteria).with(a) if a.is_a?(Hash)}
44
+ @adapter.resolve_arguments(args)
45
+ end
46
+
47
+ it "returns the mapped results" do
48
+ args = [{}, 2, 3, [], {:c.in => 2}]
49
+ stubby = stub("result")
50
+ @adapter.stubs(:resolve_complex_criteria).returns(stubby)
51
+ @adapter.resolve_arguments(args).should == args.map {|a| a.is_a?(Hash) ? stubby : a}
52
+ end
53
+ end
54
+
55
+ describe "#resolve_complex_criteria" do
56
+ it "recursively replaces any hash values with their own resolve_complex_criteria results" do
57
+ hash = {:a.in => [1, 2], :c => {:e.exists => false, :f => {:y.ne => 2}}, :f => 3}
58
+ @adapter.resolve_complex_criteria(hash).should ==
59
+ {:a=>{"$in"=>[1, 2]}, :c=>{:e=>{"$exists"=>false}, :f=>{:y=>{"$ne"=>2}}}, :f=>3}
60
+ end
61
+ end
62
+
63
+ describe "#processable_into_parameters?" do
64
+ it "returns true for Mongoid criteria" do
65
+ ObjectWithMongoidAdapter.processable_into_parameters?(AMongoidClass.all).should be_true
66
+ end
67
+
68
+ it "returns false for everything else" do
69
+ ObjectWithMongoidAdapter.processable_into_parameters?(Hash.new).should be_false
70
+ ObjectWithMongoidAdapter.processable_into_parameters?(Array.new).should be_false
71
+ end
72
+ end
73
+
74
+ describe "#build_multiquery_parameters" do
75
+ # this is a mishmash of stubbing and testing against the values assigned via let :)
76
+
77
+ let(:criteria) {
78
+ AMongoidClass.where(:_ids.in => [1, 2, 3]).only(:_id).ascending(:date).limit(4)
79
+ }
80
+
81
+ it "returns nil if provided something other than a Criteria" do
82
+ ObjectWithMongoidAdapter.build_multiquery_parameters({}).should be_nil
83
+ end
84
+
85
+ it "doesn't change the criteria's options" do
86
+ expect {
87
+ ObjectWithMongoidAdapter.build_multiquery_parameters(criteria)
88
+ }.not_to change(criteria, :options)
89
+ end
90
+
91
+ it "returns the selector as :selector" do
92
+ selecty = stub("selector")
93
+ criteria.stubs(:selector).returns(selecty)
94
+ ObjectWithMongoidAdapter.build_multiquery_parameters(criteria)[:selector].should == selecty
95
+ end
96
+
97
+ it "returns the klass as :klass" do
98
+ ObjectWithMongoidAdapter.build_multiquery_parameters(criteria)[:klass].should == AMongoidClass
99
+ end
100
+
101
+ it "returns the name of the collection as :collection" do
102
+ name = stub("name")
103
+ criteria.collection.stubs(:name).returns(name)
104
+ ObjectWithMongoidAdapter.build_multiquery_parameters(criteria)[:collection].should == name
105
+ end
106
+
107
+ it "returns the fields to get as :fields" do
108
+ ObjectWithMongoidAdapter.build_multiquery_parameters(criteria)[:fields].should == {_id: 1, _type: 1}
109
+ end
110
+
111
+ it "returns all other options as :modifiers" do
112
+ modifiers = criteria.options.dup.delete_if {|k, v| k == :fields}
113
+ ObjectWithMongoidAdapter.build_multiquery_parameters(criteria)[:modifiers].keys.should == modifiers.keys
114
+ end
115
+
116
+ it "uses Mongo::Support to expand the sort criteria" do
117
+ sorts = stub("sorted info")
118
+ Mongo::Support.expects(:array_as_sort_parameters).with(criteria.options[:sort]).returns(sorts)
119
+ ObjectWithMongoidAdapter.build_multiquery_parameters(criteria)[:modifiers][:sort].should == sorts
120
+ end
121
+
122
+ it "works fine with no sort order" do
123
+ ObjectWithMongoidAdapter.build_multiquery_parameters(AMongoidClass.all)[:modifiers][:sort].should == {}
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe MongoScript do
4
+ describe "modules" do
5
+ it "includes Execution" do
6
+ MongoScript.included_modules.should include(MongoScript::Execution)
7
+ end
8
+
9
+ it "includes whatever's determined by orm_adapter" do
10
+ MongoScript.included_modules.should include(MongoScript.orm_adapter)
11
+ end
12
+ end
13
+
14
+ describe ".orm_adapter" do
15
+ it "returns the Mongoid adapter if Mongoid is defined" do
16
+ Object.stubs(:const_defined?).with("Mongoid").returns(true)
17
+ MongoScript.orm_adapter.should == MongoScript::ORM::MongoidAdapter
18
+ end
19
+
20
+ it "raises a NoORMError if no Mongo ORM is available" do
21
+ MongoScript.stubs(:const_defined?).with("Mongoid").returns(false)
22
+ expect { MongoScript.orm_adapter }.to raise_exception(MongoScript::NoORMError)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,295 @@
1
+ require 'spec_helper'
2
+
3
+ describe MongoScript::Multiquery do
4
+ module ObjectWithMultiquery
5
+ include MongoScript::ORM::MongoidAdapter
6
+ include MongoScript::Execution
7
+ include MongoScript::Multiquery
8
+ end
9
+
10
+ let(:results) {
11
+ {
12
+ :cars => 3.times.collect { Car.new.attributes },
13
+ :canines => 3.times.collect { Car.new.attributes }
14
+ }
15
+ }
16
+
17
+ let(:queries) {
18
+ {
19
+ :cars => {:query => {:_id => {:"$in" => [1, 2, 3]}}},
20
+ :canines => {:collection => :dogs, :query => {:deleted_at => Time.now}}
21
+ }
22
+ }
23
+
24
+ let(:normalized_queries) {
25
+ MongoScript.normalize_queries(queries)
26
+ }
27
+
28
+ let(:mongoized_queries) {
29
+ MongoScript.mongoize_queries(normalized_queries)
30
+ }
31
+
32
+ it "defines QueryFailedError error < RuntimeError" do
33
+ MongoScript::Multiquery::QueryFailedError.superclass.should == RuntimeError
34
+ end
35
+
36
+ describe "#multiquery" do
37
+ # here we just want to test the flow of the method
38
+ # further tests ensure that each individual call works as expected
39
+ # we also will have integration tests soon
40
+ let(:normalized_queries) { stub("normalized queries") }
41
+ let(:mongoized_queries) { stub("mongoized queries") }
42
+ let(:raw_results) { stub("raw results") }
43
+ let(:processed_results) { stub("processed results") }
44
+
45
+ before :each do
46
+ MongoScript.stubs(:normalize_queries).returns(normalized_queries)
47
+ MongoScript.stubs(:validate_queries!)
48
+ MongoScript.stubs(:mongoize_queries).returns(mongoized_queries)
49
+ MongoScript.stubs(:execute_readonly_routine).returns(raw_results)
50
+ MongoScript.stubs(:process_results).returns(raw_results)
51
+ end
52
+
53
+ it "returns {} without hitting the database if passed {}" do
54
+ MongoScript.expects(:execute).never
55
+ MongoScript.multiquery({}).should == {}
56
+ end
57
+
58
+ it "normalizes the queries" do
59
+ MongoScript.expects(:normalize_queries).with(queries)
60
+ MongoScript.multiquery(queries)
61
+ end
62
+
63
+ it "validates the normalized queries" do
64
+ MongoScript.expects(:validate_queries!).with(normalized_queries)
65
+ MongoScript.multiquery(queries)
66
+ end
67
+
68
+ it "mongoizes the the normalized queries before execution" do
69
+ MongoScript.expects(:mongoize_queries).with(normalized_queries)
70
+ MongoScript.multiquery(queries)
71
+ end
72
+
73
+ it "executes the multiquery routine with the mongoized results" do
74
+ MongoScript.expects(:execute_readonly_routine).with("multiquery", mongoized_queries).returns({})
75
+ MongoScript.multiquery(queries)
76
+ end
77
+
78
+ it "processes the results and returns them" do
79
+ MongoScript.expects(:process_results).with(raw_results, normalized_queries)
80
+ MongoScript.multiquery(queries)
81
+ end
82
+
83
+ it "processes the results and returns them" do
84
+ MongoScript.stubs(:process_results).returns(processed_results)
85
+ MongoScript.multiquery(queries).should == processed_results
86
+ end
87
+ end
88
+
89
+ describe "#normalize_queries" do
90
+ it "doesn't change the underlying hash" do
91
+ expect {
92
+ MongoScript.normalize_queries(queries)
93
+ # inspect will display all info inside the hash
94
+ # a good proxy to make sure inside values don't change
95
+ }.not_to change(queries, :inspect)
96
+ end
97
+
98
+ context "for hashes" do
99
+ let(:normalized_queries) { MongoScript.normalize_queries(queries) }
100
+
101
+ context "determining collection" do
102
+ it "derives the collection from the name if none is provided" do
103
+ queries[:cars].delete(:collection)
104
+ # normalized_query isn't executed until we call it,
105
+ # so the changes to queries are respected
106
+ normalized_queries[:cars][:collection].to_s.should == "cars"
107
+ end
108
+
109
+ it "leaves the collection alone if it's provided" do
110
+ queries[:canines][:collection] = :dogs
111
+ normalized_queries[:canines][:collection].to_s.should == queries[:canines][:collection].to_s
112
+ end
113
+
114
+ it "checks with indifferent access" do
115
+ queries[:canines].delete(:collection)
116
+ queries[:canines]["collection"] = :dogs
117
+ normalized_queries[:canines][:collection].to_s.should == queries[:canines]["collection"].to_s
118
+ end
119
+ end
120
+
121
+ context "determining the class" do
122
+ it "uses the klass entry if it's provided" do
123
+ queries[:cars][:klass] = Car
124
+ normalized_queries[:cars][:klass].should == Car
125
+ end
126
+
127
+ it "derives the klass (if not provided) from the specified collection (if provided)" do
128
+ queries[:cars].delete(:klass)
129
+ queries[:cars][:collection] = :cars
130
+ normalized_queries[:cars][:klass].should == Car
131
+ end
132
+
133
+ it "derives the klass (if not provided) from the collection (derived from name)" do
134
+ queries[:cars].delete(:klass)
135
+ queries[:cars].delete(:collection)
136
+ normalized_queries[:cars][:klass].should == Car
137
+ end
138
+
139
+ it "sets klass to false if the klass can't be determined from the collection" do
140
+ queries[:canines].delete(:collection)
141
+ queries[:canines].delete(:klass)
142
+ Object.const_defined?("Canine").should be_false
143
+ normalized_queries[:canines][:klass].should be_false
144
+ end
145
+ end
146
+ end
147
+
148
+ context "for objects processable into queries" do
149
+ let(:sample_query) {
150
+ {
151
+ :cars => stub("Mongoid or other object"),
152
+ :canines => stub("another object"),
153
+ :hashy => {:query_type => :hash}
154
+ }.with_indifferent_access
155
+ }
156
+
157
+ before :each do
158
+ MongoScript.stubs(:processable_into_parameters?).returns(true)
159
+ end
160
+
161
+ it "sees if it's processable" do
162
+ MongoScript.stubs(:build_multiquery_parameters)
163
+ sample_query.values.each do |val|
164
+ unless val.is_a?(Hash)
165
+ MongoScript.expects(:processable_into_parameters?).with(val).returns(true)
166
+ else
167
+ MongoScript.expects(:processable_into_parameters?).with(val).never
168
+ end
169
+ end
170
+ MongoScript.normalize_queries(sample_query)
171
+ end
172
+
173
+ it "returns the processed values" do
174
+ # ensure that non-hash values are processed...
175
+ sample_query.inject({}) do |return_vals, (key, val)|
176
+ unless val.is_a?(Hash)
177
+ MongoScript.expects(:build_multiquery_parameters).with(val).returns("my stub value for #{key}")
178
+ end
179
+ end
180
+ # ...and returned appropriately
181
+ MongoScript.normalize_queries(sample_query).each do |k, v|
182
+ unless sample_query[k].is_a?(Hash)
183
+ v.should == "my stub value for #{k}"
184
+ end
185
+ end
186
+ end
187
+ end
188
+
189
+ context "for objects not processable into queries" do
190
+ let(:sample_query) {
191
+ {
192
+ :cars => stub("Mongoid or other object"),
193
+ :canines => stub("another object"),
194
+ :hashy => {:query_type => :hash}
195
+ }.with_indifferent_access
196
+ }
197
+
198
+ it "throws an ArgumentError" do
199
+ MongoScript.stubs(:processable_into_parameters?).returns(false)
200
+ expect { MongoScript.normalize_queries(sample_query) }.to raise_exception(ArgumentError)
201
+ end
202
+ end
203
+ end
204
+
205
+ describe "#validate_queries!" do
206
+ it "throws an error if any of the queries are missing a collection" do
207
+ normalized_queries.first.tap {|k, v| v.delete(:collection) }
208
+ expect { MongoScript.validate_queries!(normalized_queries) }.to raise_exception(ArgumentError)
209
+ end
210
+
211
+ it "throws an error if any of the queries are missing a klass" do
212
+ normalized_queries.first.tap {|k, v| v.delete(:klass) }
213
+ expect { MongoScript.validate_queries!(normalized_queries) }.to raise_exception(ArgumentError)
214
+ end
215
+
216
+ it "has detailed error descriptions"
217
+ end
218
+
219
+ describe "#mongoize_queries" do
220
+ it "returns copy of queries without the klass value" do
221
+ mongoized_queries.each_pair do |k, v|
222
+ v[:klass].should be_nil
223
+ end
224
+ end
225
+
226
+ it "leaves all other values the same" do
227
+ mongoized_queries.each_pair do |k, v|
228
+ # avoid symbol/string differences by using JSON
229
+ MultiJson.encode(v).should == MultiJson.encode(normalized_queries[k].tap {|h| h.delete(:klass) })
230
+ end
231
+ end
232
+
233
+ it "doesn't change the underlying hash" do
234
+ expect {
235
+ MongoScript.mongoize_queries(queries)
236
+ # inspect will display all info inside the hash
237
+ # a good proxy to make sure inside values don't change
238
+ }.not_to change(queries, :inspect)
239
+ end
240
+ end
241
+
242
+ describe "#process_results" do
243
+ def process_results(results, queries)
244
+ results.each_pair do |name, response|
245
+ if response["error"]
246
+ results[name] = QueryFailedError.new(name, queries[name], response)
247
+ else
248
+ # turn all the individual responses into real objects
249
+ response.map! {|data| MongoScript.rehydrate(queries[name][:klass], data)}
250
+ end
251
+ end
252
+ end
253
+
254
+ it "rehydrates all objects" do
255
+ normalized_queries = ObjectWithMultiquery.normalize_queries(queries)
256
+ processed_results = ObjectWithMultiquery.process_results(results, normalized_queries)
257
+
258
+ # in our test case, we could check to make sure that the ids match up
259
+ # in real life, of course, there's no guarantee the database would return
260
+ # all the objects we expect
261
+ processed_results[:canines].each {|d| d.should be_a(Dog)}
262
+ processed_results[:cars].each {|c| c.should be_a(Car)}
263
+ end
264
+
265
+ context "when a query errors" do
266
+ before :each do
267
+ results[:canines] = {"error" => "ssh mongo is sleeping!"}
268
+ end
269
+
270
+ let(:processed_results) {
271
+ ObjectWithMultiquery.process_results(results, normalized_queries)
272
+ }
273
+
274
+ let(:error) {
275
+ processed_results[:canines]
276
+ }
277
+
278
+ it "turns any errors into QueryFailedErrors" do
279
+ error.should be_a(MongoScript::Multiquery::QueryFailedError)
280
+ end
281
+
282
+ it "makes the normalized query available in the error" do
283
+ error.query_parameters.should == normalized_queries[:canines]
284
+ end
285
+
286
+ it "identifies the query name in the error" do
287
+ error.query_name.to_s.should == "canines"
288
+ end
289
+
290
+ it "makes the raw db response available in the error" do
291
+ error.db_response.should == results[:canines]
292
+ end
293
+ end
294
+ end
295
+ end
@@ -0,0 +1,9 @@
1
+ mongoscript_settings: &mongoscript_settings
2
+ host: localhost
3
+ database: mongoscript_dev
4
+
5
+ development:
6
+ <<: *mongoscript_settings
7
+
8
+ test:
9
+ <<: *mongoscript_settings
@@ -0,0 +1,3 @@
1
+ function() {
2
+ return "I am a sample script";
3
+ }
@@ -0,0 +1,82 @@
1
+ // mock a Mongo DB
2
+ // if you're using IE < 9, you'll need to implement map
3
+ // but I doubt that will ever come up :)
4
+
5
+ var MockMongo = function(dbName) {
6
+ var Collection = function(name, data) {
7
+ // we have to declare this as a local var
8
+ // since we need to embed it into the find scope
9
+ var collection = {
10
+ name: name,
11
+ find: function(params, fields) {
12
+ this.findResult = this.findResult || new Query(params, fields, collection);
13
+ return this.findResult;
14
+ },
15
+ data: data || []
16
+ };
17
+ return collection;
18
+ }
19
+
20
+ var Query = function(params, fields, collection) {
21
+ return {
22
+ params: params,
23
+ fields: fields,
24
+ collection: collection,
25
+ limit: function() { this.limitArgs = arguments; return this; },
26
+ sort: function() { this.sortArgs = arguments; return this; },
27
+ toArray: function() {
28
+ // always return the collection's data
29
+ return collection.data;
30
+ },
31
+ map: function() {
32
+ var data = this.toArray();
33
+ return data.map.apply(data, arguments)
34
+ }
35
+ }
36
+ }
37
+
38
+ var prototype = {
39
+ toString: function() {
40
+ return this.name;
41
+ },
42
+
43
+ addCollection: function(name, data) {
44
+ if (!this[name]) {
45
+ this[name] = new Collection(name, data);
46
+
47
+ // set up the system namespaces collection if it doesn't exist
48
+ if (!this["system.namespaces"]) {
49
+ this.addCollection("system.namespaces");
50
+ }
51
+
52
+ // and add the entry to the system.namespace array
53
+ this["system.namespaces"].data.push({
54
+ name: dbName + "." + name
55
+ })
56
+ }
57
+ }
58
+ }
59
+
60
+ var db = Object.create(prototype);
61
+ db.name = dbName;
62
+
63
+ return db;
64
+ }
65
+
66
+ var db;
67
+
68
+ beforeEach(function() {
69
+ db = MockMongo("mongoscript_test");
70
+ db.addCollection("vehicles", [
71
+ {car: 1},
72
+ {truck: 2},
73
+ {spaceship: 100000}
74
+ ])
75
+
76
+ db.addCollection("paths", [
77
+ {road: 1},
78
+ {rail: 2},
79
+ {wormhole: 100000}
80
+ ])
81
+ })
82
+