mongoid_denormalize 0.0.1 → 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.
data/README.md CHANGED
@@ -25,8 +25,7 @@ In your model:
25
25
  include Mongoid::Denormalize
26
26
 
27
27
  # Define your denormalized fields
28
- denormalize :title, :from => :post
29
- denormalize :name, :avatar, :from => :user
28
+ denormalize :name, :email, :from => :user
30
29
 
31
30
 
32
31
 
@@ -37,61 +36,54 @@ Example
37
36
  include Mongoid::Document
38
37
  include Mongoid::Denormalize
39
38
 
40
- references_many :posts
39
+ references_many :comments
41
40
 
42
41
  field :name
43
- field :avatar
42
+ field :email
43
+
44
+ denormalize :name, :email, :to => :comments
44
45
  end
45
46
 
46
- def Post
47
+ def Comment
47
48
  include Mongoid::Document
48
49
  include Mongoid::Denormalize
49
50
 
50
51
  referenced_in :user
51
52
 
52
- field :title
53
- denormalize :name, :avatar, :from => :user
53
+ field :body
54
+
55
+ denormalize :name, :email, :from => :user
54
56
  end
55
57
 
56
- >> user = User.create(:name => "John Doe", :avatar => "http://url/to/avatar.png")
57
- >> post = Post.create(:title => "Blog post", :user => user)
58
- >> post.user_name
58
+ >> user = User.create(:name => "John Doe", :email => "john@doe.com")
59
+ >> comment = Comment.create(:body => "Lorem ipsum...", :user => user)
60
+ >> user.comments << comment
61
+ >> comment.user_name
59
62
  "John Doe"
60
- >> post.user_avatar
61
- "http://url/to/avatar.png"
63
+ >> comment.user_email
64
+ "john@doe.com"
62
65
  >> user.update_attributes(:name => "Bill")
63
- >> post.save
64
- >> post.user_name
66
+ >> comment.user_name
65
67
  "Bill"
66
68
 
67
69
 
68
70
  Options
69
71
  -------
70
72
 
71
- Denormalization can happen using an associated object as illustrated above, or using a block. The field type for denormalized fields must
72
- be explicitly set if it is not a `String` value. Examples:
73
+ Denormalization can happen in either or both directions. When using the `:from` option, the associated objects will fetch the values from
74
+ the parent. When using the `:to` option, the parent will push the values to its children.
73
75
 
74
- # Basic denormalization. Will set the user_name attribute with the user name.
76
+ # Basic denormalization. Will set the user_name attribute with the associated user's name.
75
77
  denormalize :name, :from => :user
76
78
 
77
- # Override denormalized field name. Will set the from_email attribute with the user email.
78
- denormalize :email, :from => :user, :to => :from_email
79
-
80
- # Specify denormalized field type. Will set the post_created_at attribute as a Time object.
81
- denormalize :created_at, :type => Time, :from => :post
79
+ # Basic denormalization. Will set the user_name attribute of "self.comments" with "self.name".
80
+ denormalize :name, :to => :comments
82
81
 
83
- # Multiple denormalization fields. Will set the user_name and user_email attributes with values from user.
82
+ # Multiple fields. Will set the user_name and user_email attributes with the associated user's name and email.
84
83
  denormalize :name, :email, :from => :user
85
84
 
86
- # Block denormalization. Will set the comment_count attribute with the blocks return value.
87
- # The block receives the current instance as the first argument.
88
- denormalize(:comment_count, :type => Integer) { |post| post.comments.count }
89
-
90
- # Block denormalization with multiple fields. Will set the post_titles and post_dates attributes with the blocks return value.
91
- # The block receives the current instance as the first argument and the name of the denormalized field as the second argument.
92
- denormalize :post_titles, :post_dates, :type => Array do |user, field|
93
- field == :post_titles ? user.posts.collect(&:title) : user.posts.collect(&:created_at)
94
- end
85
+ # Multiple children. Will set the user_name attribute of "self.posts" and "self.comments" with "self.name".
86
+ denormalize :name, :to => [:posts, :comments]
95
87
 
96
88
 
97
89
  Credits
@@ -6,10 +6,13 @@ module Mongoid::Denormalize
6
6
 
7
7
  included do
8
8
  cattr_accessor :denormalize_definitions
9
+
10
+ before_save :denormalize_from
11
+ after_save :denormalize_to
9
12
  end
10
13
 
11
14
  module ClassMethods
12
- # Set a field or a number of fields to denormalize. Specify the associated object using the :from option.
15
+ # Set a field or a number of fields to denormalize. Specify the associated object using the :from or :to options.
13
16
  #
14
17
  # def Post
15
18
  # include Mongoid::Document
@@ -19,43 +22,40 @@ module Mongoid::Denormalize
19
22
  # references_many :comments
20
23
  #
21
24
  # denormalize :name, :avatar, :from => :user
22
- #
23
- # denormalize :email, :from => :user, :to => :from_email
24
- #
25
- # denormalize :comment_count, :type => Integer do |post|
26
- # post.comments.count
27
- # end
25
+ # denormalize :created_at, :to => :comments
28
26
  # end
29
- def denormalize(*fields, &block)
27
+ def denormalize(*fields)
30
28
  options = fields.pop
31
29
 
32
- (self.denormalize_definitions ||= []) << { :fields => fields, :options => options, :block => block}
30
+ (self.denormalize_definitions ||= []) << { :fields => fields, :options => options }
33
31
 
34
32
  # Define schema
35
- fields.each do |name|
36
- denormalized_name = if block_given?
37
- name
38
- else
39
- options[:to] ? options[:to] : "#{options[:from]}_#{name}"
40
- end
41
-
42
- field denormalized_name, :type => options[:type]
33
+ unless options[:to]
34
+ fields.each { |name| field "#{options[:from]}_#{name}", :type => options[:type] }
43
35
  end
44
-
45
- before_validation :denormalize_fields
46
36
  end
47
37
  end
48
38
 
49
39
  private
50
- def denormalize_fields
40
+ def denormalize_from
51
41
  self.denormalize_definitions.each do |definition|
52
- definition[:fields].each do |name|
53
- if definition[:block]
54
- value = (definition[:fields].length > 1 ? definition[:block].call(self, name) : definition[:block].call(self))
55
- self.send("#{name}=", value)
42
+ next if definition[:options][:to]
43
+
44
+ definition[:fields].each { |name| self.send("#{definition[:options][:from]}_#{name}=", self.send(definition[:options][:from]).try(name)) }
45
+ end
46
+ end
47
+
48
+ def denormalize_to
49
+ self.denormalize_definitions.each do |definition|
50
+ next unless definition[:options][:to]
51
+
52
+ assigns = Hash[*definition[:fields].collect { |name| ["#{self.class.name.underscore}_#{name}", self.send(name)] }.flatten]
53
+
54
+ [definition[:options][:to]].flatten.each do |association|
55
+ if [:embedded_in, :embeds_one, :referenced_in, :references_one].include? self.class.reflect_on_association(association)
56
+ self.send(association).update_attributes(assigns) unless self.send(association).blank?
56
57
  else
57
- attribute_name = (definition[:options][:to] ? definition[:options][:to] : "#{definition[:options][:from]}_#{name}")
58
- self.send("#{attribute_name}=", self.send(definition[:options][:from]).try(name))
58
+ self.send(association).to_a.each { |a| a.update_attributes(assigns) }
59
59
  end
60
60
  end
61
61
  end
@@ -4,10 +4,10 @@ class Comment
4
4
 
5
5
  field :body
6
6
 
7
- referenced_in :post
7
+ embedded_in :post, :inverse_of => :comments
8
8
  referenced_in :user
9
9
 
10
10
  denormalize :name, :from => :user
11
- denormalize :email, :from => :user, :to => :from_email
11
+ denormalize :email, :from => :user
12
12
  denormalize :created_at, :type => Time, :from => :post
13
13
  end
data/spec/models/post.rb CHANGED
@@ -7,8 +7,8 @@ class Post
7
7
  field :created_at, :type => Time
8
8
 
9
9
  referenced_in :user
10
- references_many :comments
10
+ embeds_many :comments
11
11
 
12
12
  denormalize :name, :email, :from => :user
13
- denormalize(:comment_count, :type => Integer) { |post| post.comments.count }
13
+ denormalize :created_at, :to => :comments
14
14
  end
data/spec/models/user.rb CHANGED
@@ -5,10 +5,8 @@ class User
5
5
  field :name
6
6
  field :email
7
7
 
8
- references_many :posts
8
+ references_one :post
9
9
  references_many :comments
10
10
 
11
- denormalize :post_titles, :post_dates, :type => Array do |user, field|
12
- field == :post_titles ? user.posts.collect(&:title) : user.posts.collect(&:created_at).collect { |t| t + 300 }
13
- end
11
+ denormalize :name, :email, :to => [:post, :comments]
14
12
  end
@@ -6,23 +6,21 @@ describe Mongoid::Denormalize do
6
6
  c.drop rescue nil
7
7
  end
8
8
 
9
- @user = User.create!(:name => "John Doe", :email => "john@doe.com")
10
- @post = Post.create!(:title => "Blog post", :body => "Lorem ipsum...", :created_at => Time.parse("Jan 1 2010 12:00"), :user => @user)
11
- @comment = Comment.create!(:body => "This is the comment", :post => @post, :user => @user)
9
+ @post = Post.create!(:title => "Blog post", :body => "Lorem ipsum...", :created_at => Time.parse("Jan 1 2010 12:00"))
10
+ @user = User.create!(:name => "John Doe", :email => "john@doe.com", :post => @post)
11
+ @comment = @post.comments.create(:body => "This is the comment", :user => @user)
12
12
 
13
- @other_user = User.create!(:name => "Bill", :email => "bill@doe.com")
13
+ @user.comments << @comment
14
+
15
+ @other_user = User.create!(:name => "Bill")
14
16
  end
15
17
 
16
- context "denormalize associated object" do
18
+ context "denormalize from" do
17
19
  it "should define multiple fields for association" do
18
20
  @post.fields.should have_key "user_name"
19
21
  @post.fields.should have_key "user_email"
20
22
  end
21
23
 
22
- it "should override the name of the denormalized field" do
23
- @comment.fields.should have_key "from_email"
24
- end
25
-
26
24
  it "should default to string field type for associated fields" do
27
25
  @post.fields["user_name"].type.should eql String
28
26
  end
@@ -33,12 +31,12 @@ describe Mongoid::Denormalize do
33
31
 
34
32
  it "should allow multiple declarations for the same association" do
35
33
  @comment.fields.should have_key "user_name"
36
- @comment.fields.should have_key "from_email"
34
+ @comment.fields.should have_key "user_email"
37
35
  end
38
36
 
39
37
  it "should denormalize fields without specified type" do
40
38
  @comment.user_name.should eql @user.name
41
- @comment.from_email.should eql @user.email
39
+ @comment.user_email.should eql @user.email
42
40
  @post.user_name.should eql @user.name
43
41
  @post.user_email.should eql @user.email
44
42
  end
@@ -47,50 +45,36 @@ describe Mongoid::Denormalize do
47
45
  @comment.post_created_at.should eql @post.created_at
48
46
  end
49
47
 
50
- it "should update denormalized values if changed" do
48
+ it "should update denormalized values if attribute is changed" do
49
+ @user.update_attributes(:name => "Bob Doe")
50
+
51
+ @comment.user_name.should eql @user.name
52
+ end
53
+
54
+ it "should update denormalized values if object is changed" do
51
55
  @other_user = User.create!(:name => "Bill", :email => "bill@doe.com")
52
56
 
53
57
  @comment.user = @other_user
54
58
  @comment.save!
55
59
 
56
60
  @comment.user_name.should eql @other_user.name
57
- @comment.from_email.should eql @other_user.email
61
+ @comment.user_email.should eql @other_user.email
58
62
  end
59
63
  end
60
64
 
61
- context "denormalization with block" do
62
- it "should accept block for denormalization" do
63
- @post.fields.should have_key "comment_count"
64
- end
65
-
66
- it "should accept multiple fields for block" do
67
- @user.fields.should have_key "post_titles"
68
- @user.fields.should have_key "post_dates"
69
- end
70
-
71
- it "should allow setting the field type" do
72
- @user.fields["post_titles"].type.should eql Array
73
- @post.fields["comment_count"].type.should eql Integer
74
- end
75
-
76
- it "should denormalize fields using block" do
77
- @post.save!
78
- @post.comment_count.should eql 1
79
-
65
+ context "denormalize to" do
66
+ it "should push denormalized fields to one-to-one association" do
67
+ @user.name = "Elvis"
80
68
  @user.save!
81
- @user.post_titles.should eql ["Blog post"]
82
- @user.post_dates.should eql [Time.parse("Jan 1 2010 12:00") + 300]
69
+
70
+ @post.user_name.should eql "Elvis"
83
71
  end
84
72
 
85
- it "should update denormalized values if changed" do
86
- @post.user = @other_user
73
+ it "should push denormalized fields to one-to-many association" do
74
+ @post.created_at = Time.parse("Jan 1 2011 12:00")
87
75
  @post.save!
88
76
 
89
- @user.save!
90
- @other_user.save!
91
-
92
- @user.post_titles.should eql []
93
- @other_user.post_titles.should eql ["Blog post"]
77
+ @comment.post_created_at.should eql Time.parse("Jan 1 2011 12:00")
94
78
  end
95
79
  end
96
80
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid_denormalize
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 0
9
8
  - 1
10
- version: 0.0.1
9
+ - 0
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Logan Raarup