paulcarey-relaxdb 0.2.8 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+ require 'relaxdb'
3
+ require File.dirname(__FILE__) + '/../../spec/spec_models.rb'
4
+
5
+ RelaxDB.configure :host => "localhost", :port => 5984
6
+ RelaxDB.delete_db "relaxdb_spec" rescue :ok
7
+ RelaxDB.use_db "relaxdb_spec"
8
+
9
+ a1 = Atom.new.save!
10
+ a1_dup = a1.dup
11
+ a1.save!
12
+ begin
13
+ RelaxDB.bulk_save! a1_dup
14
+ puts "Atomic bulk_save _not_ supported"
15
+ rescue RelaxDB::UpdateConflict
16
+ puts "Atomic bulk_save supported"
17
+ end
18
+
@@ -3,65 +3,41 @@ module RelaxDB
3
3
  #
4
4
  # The AllDelegator allows clients to query CouchDB in a natural way
5
5
  # FooDoc.all - returns all docs in CouchDB of type FooDoc
6
- # FooDoc.all.sorted_by(:att1, :att2) - returns all docs in CouchDB of type FooDoc sorted by att1, then att2
7
- # FooDoc.all.sorted_by(:att1) { |q| q.key("bar") } - returns all docs of type FooDoc where att1 equals "bar"
8
- # FooDoc.all.destroy! - does what it says on the tin
9
6
  # FooDoc.all.size - issues a query to a reduce function that returns the total number of docs for that class
7
+ # FooDoc.all.destroy! - TODO - better description
10
8
  #
11
9
  class AllDelegator < Delegator
12
10
 
13
- def initialize(class_name)
11
+ def initialize(class_name, params)
14
12
  super([])
15
13
  @class_name = class_name
14
+ @params = params
16
15
  end
17
16
 
18
17
  def __getobj__
19
- view_path = "_view/#{@class_name}/all?reduce=false"
20
- map, reduce = ViewCreator.all(@class_name)
21
-
22
- RelaxDB.retrieve(view_path, @class_name, "all", map, reduce)
18
+ unless @objs
19
+ @objs = RelaxDB.view "#{@class_name}_all", @params
20
+ end
21
+ @objs
23
22
  end
24
23
 
25
- def sorted_by(*atts)
26
- view = SortedByView.new(@class_name, *atts)
27
-
28
- query = Query.new(@class_name, view.view_name)
29
- yield query if block_given?
30
-
31
- view.query(query)
24
+ def size
25
+ size = RelaxDB.view "#{@class_name}_all", :reduce => true
26
+ size || 0
32
27
  end
33
28
 
34
- # Note that this method leaves the corresponding DesignDoc for the associated class intact
29
+ # TODO: destroy in a bulk_save if feasible
35
30
  def destroy!
36
- each do |o|
31
+ __getobj__
32
+ @objs.each do |o|
37
33
  # A reload is required for deleting objects with a self referential references_many relationship
38
- # This makes all.destroy! very slow. Given that references_many is now deprecated and will
39
- # soon be removed, the required reload is no longer performed.
34
+ # This makes all.destroy! very slow. Change if needed
40
35
  # obj = RelaxDB.load(o._id)
41
36
  # obj.destroy!
42
37
 
43
38
  o.destroy!
44
39
  end
45
- end
46
-
47
- # This is pretty ugly - this pattern is now spread over three
48
- # places (sorted_by_view, relaxdb and here)
49
- # Consolidation needed
50
- def size
51
- view_path = "_view/#{@class_name}/all"
52
- map, reduce = ViewCreator.all(@class_name)
53
-
54
- begin
55
- resp = RelaxDB.db.get(view_path)
56
- rescue => e
57
- DesignDocument.get(@class_name).add_map_view("all", map).
58
- add_reduce_view("all", reduce).save
59
- resp = RelaxDB.db.get(view_path)
60
- end
61
-
62
- data = JSON.parse(resp.body)
63
- data["rows"][0] ? data["rows"][0]["value"] : 0
64
- end
40
+ end
65
41
 
66
42
  end
67
43
 
@@ -1,9 +1,11 @@
1
1
  module RelaxDB
2
2
 
3
3
  class DesignDocument
4
+
5
+ attr_reader :data
4
6
 
5
- def initialize(client_class, data)
6
- @client_class = client_class
7
+ def initialize(design_doc_name, data)
8
+ @design_doc_name = design_doc_name
7
9
  @data = data
8
10
  end
9
11
 
@@ -34,13 +36,13 @@ module RelaxDB
34
36
  self
35
37
  end
36
38
 
37
- def self.get(client_class)
39
+ def self.get(design_doc_name)
38
40
  begin
39
41
  database = RelaxDB.db
40
- resp = database.get("_design/#{client_class}")
41
- DesignDocument.new(client_class, JSON.parse(resp.body))
42
+ resp = database.get("_design/#{design_doc_name}")
43
+ DesignDocument.new(design_doc_name, JSON.parse(resp.body))
42
44
  rescue HTTP_404
43
- DesignDocument.new(client_class, {"_id" => "_design/#{client_class}"} )
45
+ DesignDocument.new(design_doc_name, {"_id" => "_design/#{design_doc_name}"} )
44
46
  end
45
47
  end
46
48
 
@@ -7,16 +7,28 @@ module RelaxDB
7
7
  # Used to store validation messages
8
8
  attr_accessor :errors
9
9
 
10
+ # A call issued to save_all will save this object and the
11
+ # contents of the save_list. This allows secondary object to
12
+ # be saved at the same time as this object.
13
+ attr_accessor :save_list
14
+
10
15
  # Attribute symbols added to this list won't be validated on save
11
16
  attr_accessor :validation_skip_list
12
17
 
13
- # Define properties and property methods
18
+ class_inheritable_accessor :properties, :reader => true
19
+ self.properties = []
20
+
21
+ class_inheritable_accessor :derived_prop_writers
22
+ self.derived_prop_writers = {}
23
+
24
+ class_inheritable_accessor :__view_by_list__
25
+ self.__view_by_list__ = []
14
26
 
27
+ class_inheritable_accessor :belongs_to_rels, :reder => true
28
+ self.belongs_to_rels = {}
29
+
15
30
  def self.property(prop, opts={})
16
- # Class instance varibles are not inherited, so the default properties must be explicitly listed
17
- # Perhaps a better solution exists. Revise. I think extlib contains a solution for this...
18
- @properties ||= [:_id, :_rev]
19
- @properties << prop
31
+ properties << prop
20
32
 
21
33
  define_method(prop) do
22
34
  instance_variable_get("@#{prop}".to_sym)
@@ -45,12 +57,10 @@ module RelaxDB
45
57
  if opts[:derived]
46
58
  add_derived_prop(prop, opts[:derived])
47
59
  end
48
- end
49
-
50
- def self.properties
51
- # Ensure that classes that don't define their own properties still function as CouchDB objects
52
- @properties ||= [:_id, :_rev]
53
- end
60
+ end
61
+
62
+ property :_id
63
+ property :_rev
54
64
 
55
65
  def self.create_validator(att, v)
56
66
  method_name = "validate_#{att}"
@@ -78,15 +88,10 @@ module RelaxDB
78
88
  # See derived_properties_spec.rb for usage
79
89
  def self.add_derived_prop(prop, deriver)
80
90
  source, writer = deriver[0], deriver[1]
81
- @derived_prop_writers ||= {}
82
- @derived_prop_writers[source] ||= {}
83
- @derived_prop_writers[source][prop] = writer
84
- end
85
-
86
- def self.derived_prop_writers
87
- @derived_prop_writers ||= {}
91
+ derived_prop_writers[source] ||= {}
92
+ derived_prop_writers[source][prop] = writer
88
93
  end
89
-
94
+
90
95
  #
91
96
  # The rationale for rescuing the send below is that the lambda for a derived
92
97
  # property shouldn't need to concern itself with checking the validity of
@@ -94,27 +99,19 @@ module RelaxDB
94
99
  # possibility of a writer raising an exception.
95
100
  #
96
101
  def write_derived_props(source)
97
- writers = self.class.derived_prop_writers[source]
102
+ writers = self.class.derived_prop_writers
103
+ writers = writers && writers[source]
98
104
  if writers
99
105
  writers.each do |prop, writer|
100
106
  current_val = send(prop)
101
107
  begin
102
108
  send("#{prop}=", writer.call(current_val, self))
103
109
  rescue => e
104
- RelaxDB.logger.warn "Deriving #{prop} from #{source} raised #{e}"
110
+ RelaxDB.logger.error "Deriving #{prop} from #{source} raised #{e}"
105
111
  end
106
112
  end
107
113
  end
108
114
  end
109
-
110
- def properties
111
- self.class.properties
112
- end
113
-
114
- # Specifying these properties here (after property method has been defined)
115
- # is kinda ugly. Consider a better solution.
116
- property :_id
117
- property :_rev
118
115
 
119
116
  def initialize(hash={})
120
117
  unless hash["_id"]
@@ -122,6 +119,7 @@ module RelaxDB
122
119
  end
123
120
 
124
121
  @errors = Errors.new
122
+ @save_list = []
125
123
  @validation_skip_list = []
126
124
 
127
125
  # Set default properties if this object isn't being loaded from CouchDB
@@ -165,6 +163,7 @@ module RelaxDB
165
163
  s << ", #{relationship}_id: #{id}" if id
166
164
  end
167
165
  s << ", errors: #{errors.inspect}" unless errors.empty?
166
+ s << ", save_list: #{save_list.map { |o| o.inspect }.join ", " }" unless save_list.empty?
168
167
  s << ">"
169
168
  end
170
169
 
@@ -180,7 +179,7 @@ module RelaxDB
180
179
  prop_val = instance_variable_get("@#{prop}".to_sym)
181
180
  data["#{prop}"] = prop_val if prop_val
182
181
  end
183
- data["class"] = self.class.name
182
+ data["relaxdb_class"] = self.class.name
184
183
  data.to_json
185
184
  end
186
185
 
@@ -211,9 +210,9 @@ module RelaxDB
211
210
  end
212
211
 
213
212
  def pre_save
213
+ set_created_at if new_document?
214
214
  return false unless validates?
215
215
  return false unless before_save
216
- set_created_at if new_document?
217
216
  true
218
217
  end
219
218
 
@@ -221,6 +220,15 @@ module RelaxDB
221
220
  after_save
222
221
  end
223
222
 
223
+ # save_all and save_all! are untested
224
+ def save_all
225
+ RelaxDB.bulk_save self, *save_list
226
+ end
227
+
228
+ def save_all!
229
+ RelaxDB.bulk_save! self, *save_list
230
+ end
231
+
224
232
  def save!
225
233
  if save
226
234
  self
@@ -230,21 +238,7 @@ module RelaxDB
230
238
  raise ValidationFailure, self.errors.to_json
231
239
  end
232
240
  end
233
-
234
- def save_all
235
- RelaxDB.bulk_save(self, *all_children)
236
- end
237
-
238
- def save_all!
239
- RelaxDB.bulk_save!(self, *all_children)
240
- end
241
-
242
- def all_children
243
- ho = self.class.has_one_rels.map { |r| send(r) }
244
- hm = self.class.has_many_rels.inject([]) { |m,r| m += send(r).children }
245
- ho + hm
246
- end
247
-
241
+
248
242
  def update_conflict?
249
243
  @update_conflict
250
244
  end
@@ -269,6 +263,7 @@ module RelaxDB
269
263
 
270
264
  total_success
271
265
  end
266
+ alias_method :validate, :validates?
272
267
 
273
268
  def validate_att(att_name, att_val)
274
269
  begin
@@ -286,7 +281,8 @@ module RelaxDB
286
281
  RelaxDB.logger.warn "Validation_msg for #{att_name} with #{att_val} raised #{e}"
287
282
  @errors[att_name] = "validation_msg_exception:invalid:#{att_val}"
288
283
  end
289
- else
284
+ elsif @errors[att_name].nil?
285
+ # Only set a validation message if a validator hasn't already set one
290
286
  @errors[att_name] = "invalid:#{att_val}"
291
287
  end
292
288
  end
@@ -337,6 +333,12 @@ module RelaxDB
337
333
  @references_many_rels << relationship
338
334
 
339
335
  id_arr_sym = "@#{relationship}".to_sym
336
+
337
+ if RelaxDB.create_views?
338
+ target_class = opts[:class]
339
+ relationship_as_viewed_by_target = opts[:known_as].to_s
340
+ ViewCreator.references_many(self.name, relationship, target_class, relationship_as_viewed_by_target).save
341
+ end
340
342
 
341
343
  define_method(relationship) do
342
344
  instance_variable_set(id_arr_sym, []) unless instance_variable_defined? id_arr_sym
@@ -362,6 +364,12 @@ module RelaxDB
362
364
  @has_many_rels ||= []
363
365
  @has_many_rels << relationship
364
366
 
367
+ if RelaxDB.create_views?
368
+ target_class = opts[:class]
369
+ relationship_as_viewed_by_target = (opts[:known_as] || self.name.snake_case).to_s
370
+ ViewCreator.has_n(self.name, relationship, target_class, relationship_as_viewed_by_target).save
371
+ end
372
+
365
373
  define_method(relationship) do
366
374
  create_or_get_proxy(HasManyProxy, relationship, opts)
367
375
  end
@@ -382,6 +390,12 @@ module RelaxDB
382
390
  @has_one_rels ||= []
383
391
  @has_one_rels << relationship
384
392
 
393
+ if RelaxDB.create_views?
394
+ target_class = relationship.to_s.camel_case
395
+ relationship_as_viewed_by_target = self.name.snake_case
396
+ ViewCreator.has_n(self.name, relationship, target_class, relationship_as_viewed_by_target).save
397
+ end
398
+
385
399
  define_method(relationship) do
386
400
  create_or_get_proxy(HasOneProxy, relationship).target
387
401
  end
@@ -398,8 +412,7 @@ module RelaxDB
398
412
  end
399
413
 
400
414
  def self.belongs_to(relationship, opts={})
401
- @belongs_to_rels ||= {}
402
- @belongs_to_rels[relationship] = opts
415
+ belongs_to_rels[relationship] = opts
403
416
 
404
417
  define_method(relationship) do
405
418
  create_or_get_proxy(BelongsToProxy, relationship).target
@@ -417,7 +430,6 @@ module RelaxDB
417
430
  id
418
431
  end
419
432
 
420
- # Allows belongs_to relationships to be used by the paginator
421
433
  define_method("#{relationship}_id") do
422
434
  instance_variable_get("@#{relationship}_id")
423
435
  end
@@ -432,16 +444,14 @@ module RelaxDB
432
444
  alias_method :references, :belongs_to
433
445
  end
434
446
 
435
- def self.belongs_to_rels
436
- @belongs_to_rels ||= {}
437
- end
447
+ self.belongs_to_rels = {}
438
448
 
439
449
  def self.all_relationships
440
450
  belongs_to_rels + has_one_rels + has_many_rels + references_many_rels
441
451
  end
442
452
 
443
- def self.all
444
- @all_delegator ||= AllDelegator.new(self.name)
453
+ def self.all params = {}
454
+ AllDelegator.new self.name, params
445
455
  end
446
456
 
447
457
  # destroy! nullifies all relationships with peers and children before deleting
@@ -482,7 +492,10 @@ module RelaxDB
482
492
  def before_save
483
493
  self.class.before_save_callbacks.each do |callback|
484
494
  resp = callback.is_a?(Proc) ? callback.call(self) : send(callback)
485
- return false unless resp
495
+ if resp == false
496
+ errors[:before_save] = :failed
497
+ return false
498
+ end
486
499
  end
487
500
  end
488
501
 
@@ -499,27 +512,80 @@ module RelaxDB
499
512
  callback.is_a?(Proc) ? callback.call(self) : send(callback)
500
513
  end
501
514
  end
502
-
503
- def self.paginate_by(page_params, *view_keys)
504
- paginate_params = PaginateParams.new
505
- yield paginate_params
506
- raise paginate_params.error_msg if paginate_params.invalid?
507
-
508
- paginator = Paginator.new(paginate_params, page_params)
509
-
510
- design_doc_name = self.name
511
- view = SortedByView.new(design_doc_name, *view_keys)
512
- query = Query.new(design_doc_name, view.view_name)
513
- query.merge(paginate_params)
515
+
516
+ #
517
+ # Creates the corresponding view and stores it in CouchDB
518
+ # Adds by_ and paginate_by_ methods to the class
519
+ #
520
+ def self.view_by *atts
521
+ opts = atts.last.is_a?(Hash) ? atts.pop : {}
522
+ __view_by_list__ << atts
514
523
 
515
- docs = view.query(query)
516
- docs.reverse! if paginate_params.order_inverted?
524
+ if RelaxDB.create_views?
525
+ ViewCreator.by_att_list([self.name], *atts).save
526
+ end
517
527
 
518
- paginator.add_next_and_prev(docs, design_doc_name, view.view_name, view_keys)
528
+ by_name = "by_#{atts.join "_and_"}"
529
+ meta_class.instance_eval do
530
+ define_method by_name do |*params|
531
+ view_name = "#{self.name}_#{by_name}"
532
+ if params.empty?
533
+ res = RelaxDB.view view_name, opts
534
+ elsif params[0].is_a? Hash
535
+ res = RelaxDB.view view_name, opts.merge(params[0])
536
+ else
537
+ res = RelaxDB.view(view_name, :key => params[0]).first
538
+ end
539
+ end
540
+ end
519
541
 
520
- docs
542
+ paginate_by_name = "paginate_by_#{atts.join "_and_"}"
543
+ meta_class.instance_eval do
544
+ define_method paginate_by_name do |params|
545
+ view_name = "#{self.name}_#{by_name}"
546
+ params[:attributes] = atts
547
+ params = opts.merge params
548
+ RelaxDB.paginate_view view_name, params
549
+ end
550
+ end
551
+ end
552
+
553
+ # Create a view allowing all instances of a particular class to be retreived
554
+ def self.create_all_by_class_view
555
+ if RelaxDB.create_views?
556
+ view = ViewCreator.all
557
+ view.save unless view.exists?
558
+ end
559
+ end
560
+
561
+ def self.inherited subclass
562
+ chain = subclass.up_chain
563
+ while k = chain.pop
564
+ k.create_views chain
565
+ end
566
+ end
567
+
568
+ def self.up_chain
569
+ k = self
570
+ kls = [k]
571
+ kls << k while ((k = k.superclass) != RelaxDB::Document)
572
+ kls
573
+ end
574
+
575
+ def self.create_views chain
576
+ # Capture the inheritance hierarchy of this class
577
+ @hierarchy ||= [self]
578
+ @hierarchy += chain
579
+ @hierarchy.uniq!
580
+
581
+ if RelaxDB.create_views?
582
+ ViewCreator.all(@hierarchy).save
583
+ __view_by_list__.each do |atts|
584
+ ViewCreator.by_att_list(@hierarchy, *atts).save
585
+ end
586
+ end
521
587
  end
522
-
588
+
523
589
  end
524
590
 
525
591
  end
@@ -77,11 +77,8 @@ module RelaxDB
77
77
  end
78
78
 
79
79
  def load_children
80
- view_path = "_view/#{@client.class}/#{@relationship}?key=\"#{@client._id}\""
81
- design_doc = @client.class
82
- view_name = @relationship
83
- map_function = ViewCreator.has_n(@target_class, @relationship_as_viewed_by_target)
84
- @children = RelaxDB.retrieve(view_path, design_doc, view_name, map_function)
80
+ view_name = "#{@client.class}_#{@relationship}"
81
+ @children = RelaxDB.view(view_name, :key => @client._id)
85
82
  end
86
83
 
87
84
  def children=(children)
@@ -94,6 +91,10 @@ module RelaxDB
94
91
  def inspect
95
92
  @children.inspect
96
93
  end
94
+
95
+ # Play nice with Merb partials - [ obj ].flatten invokes
96
+ # obj.to_ary if it responds to to_ary
97
+ alias_method :to_ary, :to_a
97
98
 
98
99
  end
99
100
 
@@ -33,11 +33,8 @@ module RelaxDB
33
33
  end
34
34
 
35
35
  def load_target
36
- design_doc = @client.class
37
- view_name = @relationship
38
- view_path = "_view/#{design_doc}/#{view_name}?key=\"#{@client._id}\""
39
- map_function = ViewCreator.has_n(@target_class, @relationship_as_viewed_by_target)
40
- RelaxDB.retrieve(view_path, design_doc, view_name, map_function).first
36
+ view_name = "#{@client.class}_#{@relationship}"
37
+ RelaxDB.view(view_name, :key => @client._id).first
41
38
  end
42
39
 
43
40
  end
@@ -17,11 +17,11 @@ module RelaxDB
17
17
  end
18
18
  end
19
19
 
20
- def initialize
20
+ def initialize(params)
21
+ params.each { |k, v| send(k, v) }
22
+
21
23
  # If a client hasn't explicitly set descending, set it to the CouchDB default
22
24
  @descending = false if @descending.nil?
23
- # CouchDB defaults reduce to true when a reduce func is present
24
- @reduce = false
25
25
  end
26
26
 
27
27
  def update(params)
@@ -44,7 +44,6 @@ module RelaxDB
44
44
 
45
45
  def invalid?
46
46
  # Simply because allowing either to be omitted increases the complexity of the paginator
47
- # This constraint may be removed in future, but don't hold your breath
48
47
  @startkey_set && @endkey_set ? nil : "Both startkey and endkey must be set"
49
48
  end
50
49
  alias error_msg invalid?
@@ -13,21 +13,17 @@ module RelaxDB
13
13
  @paginate_params.update(page_params)
14
14
  end
15
15
 
16
- def total_doc_count(design_doc, view_name)
17
- result = RelaxDB.view(design_doc, view_name) do |q|
18
- q.reduce(true)
19
- q.startkey(@orig_paginate_params.startkey).endkey(@orig_paginate_params.endkey).descending(@orig_paginate_params.descending)
20
- end
21
-
22
- total_docs = RelaxDB.reduce_result(result)
16
+ def total_doc_count(view_name)
17
+ RelaxDB.view view_name, :startkey => @orig_paginate_params.startkey, :endkey => @orig_paginate_params.endkey,
18
+ :descending => @orig_paginate_params.descending, :reduce => true
23
19
  end
24
20
 
25
- def add_next_and_prev(docs, design_doc, view_name, view_keys)
21
+ def add_next_and_prev(docs, view_name, view_keys)
26
22
  unless docs.empty?
27
23
  no_docs = docs.size
28
24
  offset = docs.offset
29
- orig_offset = orig_offset(design_doc, view_name)
30
- total_doc_count = total_doc_count(design_doc, view_name)
25
+ orig_offset = orig_offset(view_name)
26
+ total_doc_count = total_doc_count(view_name)
31
27
 
32
28
  next_exists = !@paginate_params.order_inverted? ? (offset - orig_offset + no_docs < total_doc_count) : true
33
29
  next_params = create_next(docs.last, view_keys) if next_exists
@@ -62,15 +58,15 @@ module RelaxDB
62
58
  prev_params = { :startkey => prev_key, :startkey_docid => prev_key_docid, :descending => !@orig_paginate_params.descending }
63
59
  end
64
60
 
65
- def orig_offset(design_doc, view_name)
66
- query = Query.new(design_doc, view_name)
61
+ def orig_offset(view_name)
67
62
  if @paginate_params.order_inverted?
68
- query.startkey(@orig_paginate_params.endkey).descending(!@orig_paginate_params.descending)
63
+ params = {:startkey => @orig_paginate_params.endkey, :descending => !@orig_paginate_params.descending}
69
64
  else
70
- query.startkey(@orig_paginate_params.startkey).descending(@orig_paginate_params.descending)
65
+ params = {:startkey => @orig_paginate_params.startkey, :descending => @orig_paginate_params.descending}
71
66
  end
72
- query.reduce(false).limit(1)
73
- RelaxDB.retrieve(query.view_path).offset
67
+ params[:limit] = 1
68
+
69
+ RelaxDB.view(view_name, params).offset
74
70
  end
75
71
 
76
72
  end
data/lib/relaxdb/query.rb CHANGED
@@ -3,17 +3,7 @@ module RelaxDB
3
3
  # A Query is used to build the query string made against a view
4
4
  # All parameter values are first JSON encoded and then URL encoded
5
5
  # Nil values are set to the empty string
6
- # All parameter calls return self so calls may be chained => q.startkey("foo").endkey("bar").limit(2)
7
6
 
8
- #
9
- # The query object is currently inconsistent with the RelaxDB object idiom. Consider
10
- # paul = User.new(:name => "paul").save; Event.new(:host=>paul).save
11
- # but an event query requires
12
- # Event.all.sorted_by(:host_id) { |q| q.key(paul._id) }
13
- # rather than
14
- # Event.all.sorted_by(:host) { |q| q.key(paul) }
15
- # I feel that both forms should be supported
16
- #
17
7
  class Query
18
8
 
19
9
  # keys is not included in the standard param as it is significantly different from the others
@@ -32,9 +22,13 @@ module RelaxDB
32
22
  end
33
23
  end
34
24
 
35
- def initialize(design_doc, view_name)
36
- @design_doc = design_doc
25
+ def initialize(view_name, params = {})
26
+ # CouchDB defaults reduce to true when a reduce func is present
27
+ # but returning the map view is typically more useful
28
+ reduce(false)
29
+
37
30
  @view_name = view_name
31
+ params.each { |k, v| send(k, v) }
38
32
  end
39
33
 
40
34
  def keys(keys=nil)
@@ -46,8 +40,18 @@ module RelaxDB
46
40
  end
47
41
  end
48
42
 
43
+ # If set to true RelaxDB.view will return unprocessed data
44
+ def raw(val = nil)
45
+ if val.nil?
46
+ @raw
47
+ else
48
+ @raw = val
49
+ self
50
+ end
51
+ end
52
+
49
53
  def view_path
50
- uri = "_view/#{@design_doc}/#{@view_name}"
54
+ uri = "_design/#{RelaxDB.dd}/_view/#{@view_name}"
51
55
 
52
56
  query = ""
53
57
  @@params.each do |param|