denormalize-field 0.1.3 → 0.2.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/Gemfile +3 -2
- data/Gemfile.lock +6 -2
- data/README.rdoc +10 -7
- data/VERSION +1 -1
- data/config/database.yml +7 -0
- data/denormalize-field.gemspec +12 -5
- data/lib/denormalize-field.rb +24 -3
- data/lib/tasks.rb +5 -0
- data/lib/tasks/denormalize-tasks.rake +11 -0
- data/spec/db_connect.rb +29 -0
- data/spec/denormalize-field_spec.rb +11 -0
- data/spec/spec_helper.rb +9 -5
- metadata +24 -4
data/Gemfile
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
source "http://rubygems.org"
|
|
2
2
|
gem "activerecord", "~> 3.2.0"
|
|
3
3
|
|
|
4
|
-
group :development do
|
|
4
|
+
group :development, :test do
|
|
5
|
+
gem 'em-synchrony'
|
|
5
6
|
gem 'pry'
|
|
6
|
-
gem '
|
|
7
|
+
gem 'pg'
|
|
7
8
|
gem "rspec", "~> 2.8.0"
|
|
8
9
|
gem "rdoc", "~> 3.12"
|
|
9
10
|
gem "jeweler", "~> 1.8.4"
|
data/Gemfile.lock
CHANGED
|
@@ -16,6 +16,9 @@ GEM
|
|
|
16
16
|
builder (3.0.3)
|
|
17
17
|
coderay (1.0.7)
|
|
18
18
|
diff-lcs (1.1.3)
|
|
19
|
+
em-synchrony (1.0.3)
|
|
20
|
+
eventmachine (>= 1.0.0.beta.1)
|
|
21
|
+
eventmachine (1.0.3)
|
|
19
22
|
git (1.2.5)
|
|
20
23
|
i18n (0.6.1)
|
|
21
24
|
jeweler (1.8.4)
|
|
@@ -29,6 +32,7 @@ GEM
|
|
|
29
32
|
mocha (0.10.4)
|
|
30
33
|
metaclass (~> 0.0.1)
|
|
31
34
|
multi_json (1.3.6)
|
|
35
|
+
pg (0.14.1)
|
|
32
36
|
pry (0.9.10)
|
|
33
37
|
coderay (~> 1.0.5)
|
|
34
38
|
method_source (~> 0.8)
|
|
@@ -45,7 +49,6 @@ GEM
|
|
|
45
49
|
diff-lcs (~> 1.1.2)
|
|
46
50
|
rspec-mocks (2.8.0)
|
|
47
51
|
slop (3.3.3)
|
|
48
|
-
sqlite3 (1.3.6)
|
|
49
52
|
tzinfo (0.3.33)
|
|
50
53
|
|
|
51
54
|
PLATFORMS
|
|
@@ -53,9 +56,10 @@ PLATFORMS
|
|
|
53
56
|
|
|
54
57
|
DEPENDENCIES
|
|
55
58
|
activerecord (~> 3.2.0)
|
|
59
|
+
em-synchrony
|
|
56
60
|
jeweler (~> 1.8.4)
|
|
57
61
|
mocha
|
|
62
|
+
pg
|
|
58
63
|
pry
|
|
59
64
|
rdoc (~> 3.12)
|
|
60
65
|
rspec (~> 2.8.0)
|
|
61
|
-
sqlite3
|
data/README.rdoc
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
= denormalize-field
|
|
2
2
|
|
|
3
|
+
Postgres only as of 0.2
|
|
4
|
+
|
|
3
5
|
Denormalizes fields in ActiveRecord models in order to avoid SQL joins and hydrating Ruby Objects to obtain a simple fields.
|
|
4
6
|
|
|
5
7
|
= Usage
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
class Post < ActiveRecord::Base
|
|
10
|
+
belongs_to :category
|
|
11
|
+
denormalizes :category => :name
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
category = Category.create(:name => "News")
|
|
15
|
+
post = Post.create(:category => category)
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
post = Post.create(:category => category)
|
|
17
|
+
post.category_name # "News" (you have to create the migration to add Post#category_name manually)
|
|
14
18
|
|
|
15
|
-
post.category_name # "News" (you have to create the migration to add Post#category_name manually)
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.2.0
|
data/config/database.yml
ADDED
data/denormalize-field.gemspec
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = "denormalize-field"
|
|
8
|
-
s.version = "0.
|
|
8
|
+
s.version = "0.2.0"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Len Smith"]
|
|
12
|
-
s.date = "
|
|
12
|
+
s.date = "2013-05-28"
|
|
13
13
|
s.description = "Denormalize ActiveRecord fields for performance reasons"
|
|
14
14
|
s.email = "len@barrison.com"
|
|
15
15
|
s.extra_rdoc_files = [
|
|
@@ -25,8 +25,12 @@ Gem::Specification.new do |s|
|
|
|
25
25
|
"README.rdoc",
|
|
26
26
|
"Rakefile",
|
|
27
27
|
"VERSION",
|
|
28
|
+
"config/database.yml",
|
|
28
29
|
"denormalize-field.gemspec",
|
|
29
30
|
"lib/denormalize-field.rb",
|
|
31
|
+
"lib/tasks.rb",
|
|
32
|
+
"lib/tasks/denormalize-tasks.rake",
|
|
33
|
+
"spec/db_connect.rb",
|
|
30
34
|
"spec/denormalize-field_spec.rb",
|
|
31
35
|
"spec/schema.rb",
|
|
32
36
|
"spec/spec_helper.rb"
|
|
@@ -42,16 +46,18 @@ Gem::Specification.new do |s|
|
|
|
42
46
|
|
|
43
47
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
44
48
|
s.add_runtime_dependency(%q<activerecord>, ["~> 3.2.0"])
|
|
49
|
+
s.add_development_dependency(%q<em-synchrony>, [">= 0"])
|
|
45
50
|
s.add_development_dependency(%q<pry>, [">= 0"])
|
|
46
|
-
s.add_development_dependency(%q<
|
|
51
|
+
s.add_development_dependency(%q<pg>, [">= 0"])
|
|
47
52
|
s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
|
48
53
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
|
49
54
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
|
50
55
|
s.add_development_dependency(%q<mocha>, [">= 0"])
|
|
51
56
|
else
|
|
52
57
|
s.add_dependency(%q<activerecord>, ["~> 3.2.0"])
|
|
58
|
+
s.add_dependency(%q<em-synchrony>, [">= 0"])
|
|
53
59
|
s.add_dependency(%q<pry>, [">= 0"])
|
|
54
|
-
s.add_dependency(%q<
|
|
60
|
+
s.add_dependency(%q<pg>, [">= 0"])
|
|
55
61
|
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
|
56
62
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
|
57
63
|
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
|
@@ -59,8 +65,9 @@ Gem::Specification.new do |s|
|
|
|
59
65
|
end
|
|
60
66
|
else
|
|
61
67
|
s.add_dependency(%q<activerecord>, ["~> 3.2.0"])
|
|
68
|
+
s.add_dependency(%q<em-synchrony>, [">= 0"])
|
|
62
69
|
s.add_dependency(%q<pry>, [">= 0"])
|
|
63
|
-
s.add_dependency(%q<
|
|
70
|
+
s.add_dependency(%q<pg>, [">= 0"])
|
|
64
71
|
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
|
65
72
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
|
66
73
|
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
data/lib/denormalize-field.rb
CHANGED
|
@@ -2,7 +2,18 @@ require 'active_record'
|
|
|
2
2
|
require 'active_support'
|
|
3
3
|
require 'active_support/inflector'
|
|
4
4
|
|
|
5
|
+
class DenormalizeUpdater
|
|
6
|
+
def self.sync_all
|
|
7
|
+
DenormalizeFields::UPDATE_STATEMENTS.each do |sql|
|
|
8
|
+
DenormalizeFields::CLASSES.first.connection.execute sql
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
5
13
|
module DenormalizeFields
|
|
14
|
+
UPDATE_STATEMENTS = []
|
|
15
|
+
CLASSES = []
|
|
16
|
+
|
|
6
17
|
def denormalizes(hash)
|
|
7
18
|
hash.keys.each do |key|
|
|
8
19
|
_field_name = hash[key]
|
|
@@ -16,13 +27,23 @@ module DenormalizeFields
|
|
|
16
27
|
end
|
|
17
28
|
|
|
18
29
|
_klass = key.to_s.camelize.constantize
|
|
30
|
+
update_sql = "UPDATE #{table_name} SET #{_denormalized_field_name} = c2.#{_field_name} FROM #{table_name} c1 INNER JOIN #{_klass.table_name} c2 on c2.id = c1.#{key}_id"
|
|
31
|
+
|
|
19
32
|
_klass.after_save do
|
|
20
33
|
if self.send "#{_field_name}_changed?"
|
|
21
|
-
self.send(
|
|
22
|
-
|
|
23
|
-
end
|
|
34
|
+
update_sql = "UPDATE #{_original_klass.table_name} SET #{_denormalized_field_name} = '#{self.send(_field_name)}' where #{key}_id = #{self.id}"
|
|
35
|
+
self.connection.execute update_sql
|
|
24
36
|
end
|
|
25
37
|
end
|
|
38
|
+
|
|
39
|
+
self.class.class_eval <<-EVAL
|
|
40
|
+
define_method "#{_klass.table_name}_out_of_sync" do
|
|
41
|
+
#{self.name}.where("id in (SELECT c1.id FROM #{table_name} c1 INNER JOIN #{_klass.table_name} c2 on c2.id = c1.#{key}_id where c1.#{_denormalized_field_name} != c2.#{_field_name})")
|
|
42
|
+
end
|
|
43
|
+
EVAL
|
|
44
|
+
|
|
45
|
+
UPDATE_STATEMENTS.push update_sql
|
|
46
|
+
CLASSES.push self
|
|
26
47
|
end
|
|
27
48
|
end
|
|
28
49
|
end
|
data/lib/tasks.rb
ADDED
data/spec/db_connect.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
require 'erb'
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'em-synchrony/activerecord'
|
|
5
|
+
|
|
6
|
+
class DbConnect
|
|
7
|
+
attr_accessor :config
|
|
8
|
+
def initialize
|
|
9
|
+
@db = URI.parse(ENV['DATABASE_URL'] || 'http://localhost')
|
|
10
|
+
if @db.scheme == 'postgres' # This section makes Heroku work
|
|
11
|
+
ActiveRecord::Base.establish_connection(
|
|
12
|
+
:adapter => @db.scheme == 'postgres' ? 'postgresql' : @db.scheme,
|
|
13
|
+
:host => @db.host,
|
|
14
|
+
:username => @db.user,
|
|
15
|
+
:password => @db.password,
|
|
16
|
+
:database => @db.path[1..-1],
|
|
17
|
+
:encoding => 'utf8'
|
|
18
|
+
)
|
|
19
|
+
else # And this is for my local environment
|
|
20
|
+
environment = ENV['DATABASE_URL'] ? 'production' : 'development'
|
|
21
|
+
@db = YAML.load(ERB.new(File.read('config/database.yml')).result)[environment]
|
|
22
|
+
ActiveRecord::Base.establish_connection(@db)
|
|
23
|
+
@config = ActiveRecord::Base.connection.pool.spec.config
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# connect to the database
|
|
29
|
+
DbConnect.new
|
|
@@ -9,6 +9,17 @@ class Post < ActiveRecord::Base
|
|
|
9
9
|
denormalizes category: :name
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
describe DenormalizeUpdater do
|
|
13
|
+
let(:category) { Category.new(name: "News") }
|
|
14
|
+
let(:post) { Post.create(category: category) }
|
|
15
|
+
|
|
16
|
+
it "syncs all records" do
|
|
17
|
+
post.connection.execute("UPDATE posts set category_name = 'cool story';")
|
|
18
|
+
in_sync_post = Post.create(category: category)
|
|
19
|
+
Post.categories_out_of_sync.should == [post]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
12
23
|
describe "DenormalizeField" do
|
|
13
24
|
let(:category) { Category.new(name: "News") }
|
|
14
25
|
let(:post) { Post.new(category: category) }
|
data/spec/spec_helper.rb
CHANGED
|
@@ -2,6 +2,7 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
|
2
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
3
3
|
require 'rspec'
|
|
4
4
|
require 'denormalize-field'
|
|
5
|
+
require 'db_connect'
|
|
5
6
|
|
|
6
7
|
# Requires supporting files with custom matchers and macros, etc,
|
|
7
8
|
# in ./support/ and its subdirectories.
|
|
@@ -15,18 +16,21 @@ RSpec.configure do |config|
|
|
|
15
16
|
end
|
|
16
17
|
end
|
|
17
18
|
|
|
18
|
-
ActiveRecord::Base.establish_connection
|
|
19
|
-
|
|
19
|
+
ActiveRecord::Base.establish_connection adapter:'postgresql', database: 'denormalizefielddev'
|
|
20
|
+
|
|
21
|
+
begin
|
|
22
|
+
ActiveRecord::Base.connection.drop_table(:categories)
|
|
23
|
+
ActiveRecord::Base.connection.drop_table(:posts)
|
|
24
|
+
rescue
|
|
25
|
+
end
|
|
20
26
|
|
|
21
|
-
ActiveRecord::Base.connection.drop_table(:categories)
|
|
22
|
-
ActiveRecord::Base.connection.drop_table(:posts)
|
|
23
27
|
ActiveRecord::Base.connection.create_table(:categories) do |t|
|
|
24
28
|
t.string :name
|
|
25
29
|
t.timestamps
|
|
26
30
|
end
|
|
27
31
|
|
|
28
32
|
ActiveRecord::Base.connection.create_table(:posts) do |t|
|
|
29
|
-
t.
|
|
33
|
+
t.integer :category_id
|
|
30
34
|
t.string :category_name
|
|
31
35
|
t.timestamps
|
|
32
36
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: denormalize-field
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2013-05-28 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: activerecord
|
|
@@ -27,6 +27,22 @@ dependencies:
|
|
|
27
27
|
- - ~>
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
29
|
version: 3.2.0
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: em-synchrony
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :development
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
30
46
|
- !ruby/object:Gem::Dependency
|
|
31
47
|
name: pry
|
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -44,7 +60,7 @@ dependencies:
|
|
|
44
60
|
- !ruby/object:Gem::Version
|
|
45
61
|
version: '0'
|
|
46
62
|
- !ruby/object:Gem::Dependency
|
|
47
|
-
name:
|
|
63
|
+
name: pg
|
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
|
49
65
|
none: false
|
|
50
66
|
requirements:
|
|
@@ -139,8 +155,12 @@ files:
|
|
|
139
155
|
- README.rdoc
|
|
140
156
|
- Rakefile
|
|
141
157
|
- VERSION
|
|
158
|
+
- config/database.yml
|
|
142
159
|
- denormalize-field.gemspec
|
|
143
160
|
- lib/denormalize-field.rb
|
|
161
|
+
- lib/tasks.rb
|
|
162
|
+
- lib/tasks/denormalize-tasks.rake
|
|
163
|
+
- spec/db_connect.rb
|
|
144
164
|
- spec/denormalize-field_spec.rb
|
|
145
165
|
- spec/schema.rb
|
|
146
166
|
- spec/spec_helper.rb
|
|
@@ -159,7 +179,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
159
179
|
version: '0'
|
|
160
180
|
segments:
|
|
161
181
|
- 0
|
|
162
|
-
hash: -
|
|
182
|
+
hash: -308078005241704715
|
|
163
183
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
184
|
none: false
|
|
165
185
|
requirements:
|