mongoid_denormalize 0.0.1 → 0.1.0

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