mongoid_denormalize 0.0.1
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/LICENSE +20 -0
- data/README.md +100 -0
- data/lib/mongoid_denormalize.rb +63 -0
- data/spec/models/comment.rb +13 -0
- data/spec/models/post.rb +14 -0
- data/spec/models/user.rb +14 -0
- data/spec/mongoid_denormalize_spec.rb +96 -0
- data/spec/spec_helper.rb +16 -0
- metadata +95 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Logan Raarup
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
Mongoid::Denormalize
|
2
|
+
====================
|
3
|
+
|
4
|
+
Helper module for denormalizing association attributes in Mongoid models. Why denormalize? Read *[A Note on Denormalization](http://www.mongodb.org/display/DOCS/MongoDB+Data+Modeling+and+Rails#MongoDBDataModelingandRails-ANoteonDenormalization)*.
|
5
|
+
|
6
|
+
|
7
|
+
Installation
|
8
|
+
------------
|
9
|
+
|
10
|
+
Add the gem to your Bundler `Gemfile`:
|
11
|
+
|
12
|
+
gem 'mongoid_denormalize'
|
13
|
+
|
14
|
+
Or install with RubyGems:
|
15
|
+
|
16
|
+
$ gem install mongoid_denormalize
|
17
|
+
|
18
|
+
|
19
|
+
Usage
|
20
|
+
-----
|
21
|
+
|
22
|
+
In your model:
|
23
|
+
|
24
|
+
# Include the helper method
|
25
|
+
include Mongoid::Denormalize
|
26
|
+
|
27
|
+
# Define your denormalized fields
|
28
|
+
denormalize :title, :from => :post
|
29
|
+
denormalize :name, :avatar, :from => :user
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
Example
|
34
|
+
-------
|
35
|
+
|
36
|
+
def User
|
37
|
+
include Mongoid::Document
|
38
|
+
include Mongoid::Denormalize
|
39
|
+
|
40
|
+
references_many :posts
|
41
|
+
|
42
|
+
field :name
|
43
|
+
field :avatar
|
44
|
+
end
|
45
|
+
|
46
|
+
def Post
|
47
|
+
include Mongoid::Document
|
48
|
+
include Mongoid::Denormalize
|
49
|
+
|
50
|
+
referenced_in :user
|
51
|
+
|
52
|
+
field :title
|
53
|
+
denormalize :name, :avatar, :from => :user
|
54
|
+
end
|
55
|
+
|
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
|
59
|
+
"John Doe"
|
60
|
+
>> post.user_avatar
|
61
|
+
"http://url/to/avatar.png"
|
62
|
+
>> user.update_attributes(:name => "Bill")
|
63
|
+
>> post.save
|
64
|
+
>> post.user_name
|
65
|
+
"Bill"
|
66
|
+
|
67
|
+
|
68
|
+
Options
|
69
|
+
-------
|
70
|
+
|
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
|
+
|
74
|
+
# Basic denormalization. Will set the user_name attribute with the user name.
|
75
|
+
denormalize :name, :from => :user
|
76
|
+
|
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
|
82
|
+
|
83
|
+
# Multiple denormalization fields. Will set the user_name and user_email attributes with values from user.
|
84
|
+
denormalize :name, :email, :from => :user
|
85
|
+
|
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
|
95
|
+
|
96
|
+
|
97
|
+
Credits
|
98
|
+
-------
|
99
|
+
|
100
|
+
Copyright (c) 2010 Logan Raarup, released under the MIT license.
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# = Mongoid::Denormalize
|
2
|
+
#
|
3
|
+
# Helper module for denormalizing association attributes in Mongoid models.
|
4
|
+
module Mongoid::Denormalize
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
cattr_accessor :denormalize_definitions
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
# Set a field or a number of fields to denormalize. Specify the associated object using the :from option.
|
13
|
+
#
|
14
|
+
# def Post
|
15
|
+
# include Mongoid::Document
|
16
|
+
# include Mongoid::Denormalize
|
17
|
+
#
|
18
|
+
# referenced_in :user
|
19
|
+
# references_many :comments
|
20
|
+
#
|
21
|
+
# 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
|
28
|
+
# end
|
29
|
+
def denormalize(*fields, &block)
|
30
|
+
options = fields.pop
|
31
|
+
|
32
|
+
(self.denormalize_definitions ||= []) << { :fields => fields, :options => options, :block => block}
|
33
|
+
|
34
|
+
# 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]
|
43
|
+
end
|
44
|
+
|
45
|
+
before_validation :denormalize_fields
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def denormalize_fields
|
51
|
+
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)
|
56
|
+
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))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Comment
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Denormalize
|
4
|
+
|
5
|
+
field :body
|
6
|
+
|
7
|
+
referenced_in :post
|
8
|
+
referenced_in :user
|
9
|
+
|
10
|
+
denormalize :name, :from => :user
|
11
|
+
denormalize :email, :from => :user, :to => :from_email
|
12
|
+
denormalize :created_at, :type => Time, :from => :post
|
13
|
+
end
|
data/spec/models/post.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class Post
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Denormalize
|
4
|
+
|
5
|
+
field :title
|
6
|
+
field :body
|
7
|
+
field :created_at, :type => Time
|
8
|
+
|
9
|
+
referenced_in :user
|
10
|
+
references_many :comments
|
11
|
+
|
12
|
+
denormalize :name, :email, :from => :user
|
13
|
+
denormalize(:comment_count, :type => Integer) { |post| post.comments.count }
|
14
|
+
end
|
data/spec/models/user.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class User
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Denormalize
|
4
|
+
|
5
|
+
field :name
|
6
|
+
field :email
|
7
|
+
|
8
|
+
references_many :posts
|
9
|
+
references_many :comments
|
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
|
14
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Denormalize do
|
4
|
+
before(:all) do
|
5
|
+
Mongoid.master.collections.each do |c|
|
6
|
+
c.drop rescue nil
|
7
|
+
end
|
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)
|
12
|
+
|
13
|
+
@other_user = User.create!(:name => "Bill", :email => "bill@doe.com")
|
14
|
+
end
|
15
|
+
|
16
|
+
context "denormalize associated object" do
|
17
|
+
it "should define multiple fields for association" do
|
18
|
+
@post.fields.should have_key "user_name"
|
19
|
+
@post.fields.should have_key "user_email"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should override the name of the denormalized field" do
|
23
|
+
@comment.fields.should have_key "from_email"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should default to string field type for associated fields" do
|
27
|
+
@post.fields["user_name"].type.should eql String
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should allow setting the field type for associated fields" do
|
31
|
+
@comment.fields["post_created_at"].type.should eql Time
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should allow multiple declarations for the same association" do
|
35
|
+
@comment.fields.should have_key "user_name"
|
36
|
+
@comment.fields.should have_key "from_email"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should denormalize fields without specified type" do
|
40
|
+
@comment.user_name.should eql @user.name
|
41
|
+
@comment.from_email.should eql @user.email
|
42
|
+
@post.user_name.should eql @user.name
|
43
|
+
@post.user_email.should eql @user.email
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should denormalize fields with specified type" do
|
47
|
+
@comment.post_created_at.should eql @post.created_at
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should update denormalized values if changed" do
|
51
|
+
@other_user = User.create!(:name => "Bill", :email => "bill@doe.com")
|
52
|
+
|
53
|
+
@comment.user = @other_user
|
54
|
+
@comment.save!
|
55
|
+
|
56
|
+
@comment.user_name.should eql @other_user.name
|
57
|
+
@comment.from_email.should eql @other_user.email
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
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
|
+
|
80
|
+
@user.save!
|
81
|
+
@user.post_titles.should eql ["Blog post"]
|
82
|
+
@user.post_dates.should eql [Time.parse("Jan 1 2010 12:00") + 300]
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should update denormalized values if changed" do
|
86
|
+
@post.user = @other_user
|
87
|
+
@post.save!
|
88
|
+
|
89
|
+
@user.save!
|
90
|
+
@other_user.save!
|
91
|
+
|
92
|
+
@user.post_titles.should eql []
|
93
|
+
@other_user.post_titles.should eql ["Blog post"]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'mongoid'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
Mongoid.configure do |config|
|
7
|
+
settings = YAML.load(File.read(File.join(File.dirname(__FILE__), "database.yml")))
|
8
|
+
|
9
|
+
db = Mongo::Connection.new(settings['host'], settings['port']).db(settings['database'])
|
10
|
+
db.authenticate(settings['username'], settings['password'])
|
11
|
+
|
12
|
+
config.master = db
|
13
|
+
end
|
14
|
+
|
15
|
+
require File.expand_path("../../lib/mongoid_denormalize", __FILE__)
|
16
|
+
Dir["#{File.dirname(__FILE__)}/models/*.rb"].each { |f| require f }
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mongoid_denormalize
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Logan Raarup
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-09 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: mongoid
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: -1848230043
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
- beta9
|
35
|
+
version: 2.0.0.beta9
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id001
|
38
|
+
description: Helper module for denormalizing association attributes in Mongoid models.
|
39
|
+
email: logan@logan.dk
|
40
|
+
executables: []
|
41
|
+
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
extra_rdoc_files:
|
45
|
+
- LICENSE
|
46
|
+
- README.md
|
47
|
+
files:
|
48
|
+
- LICENSE
|
49
|
+
- README.md
|
50
|
+
- lib/mongoid_denormalize.rb
|
51
|
+
- spec/models/comment.rb
|
52
|
+
- spec/models/post.rb
|
53
|
+
- spec/models/user.rb
|
54
|
+
- spec/mongoid_denormalize_spec.rb
|
55
|
+
- spec/spec_helper.rb
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: http://github.com/logandk/mongoid_denormalize
|
58
|
+
licenses: []
|
59
|
+
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options:
|
62
|
+
- --charset=UTF-8
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 3
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.3.7
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Mongoid denormalization helper.
|
90
|
+
test_files:
|
91
|
+
- spec/models/comment.rb
|
92
|
+
- spec/models/post.rb
|
93
|
+
- spec/models/user.rb
|
94
|
+
- spec/mongoid_denormalize_spec.rb
|
95
|
+
- spec/spec_helper.rb
|