mongoscript 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+