activerecord-postgres-hstore 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+
5
+ branches:
6
+ only:
7
+ - master
data/Gemfile CHANGED
@@ -1,14 +1,16 @@
1
1
  source "http://rubygems.org"
2
2
  # Add dependencies required to use your gem here.
3
- gem 'activerecord'
3
+ gem 'rails'
4
4
  gem 'rake'
5
+ gem 'pg'
5
6
 
6
7
  # Add dependencies to develop your gem here.
7
8
  # Include everything needed to run rake, tests, features, etc.
8
- group :development do
9
+ group :development, :test do
9
10
  gem "shoulda", ">= 0"
10
- gem "bundler", "~> 1.0.0"
11
- gem "jeweler", "~> 1.6.4"
12
- gem "rcov", ">= 0"
11
+ gem "bundler", "~> 1.1.3"
12
+ gem "jeweler", "~> 1.8.3"
13
13
  gem "rdoc"
14
+ gem "rspec"
15
+ gem "rcov"
14
16
  end
data/Gemfile.lock CHANGED
@@ -1,38 +1,115 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- activemodel (3.0.9)
5
- activesupport (= 3.0.9)
6
- builder (~> 2.1.2)
7
- i18n (~> 0.5.0)
8
- activerecord (3.0.9)
9
- activemodel (= 3.0.9)
10
- activesupport (= 3.0.9)
11
- arel (~> 2.0.10)
12
- tzinfo (~> 0.3.23)
13
- activesupport (3.0.9)
14
- arel (2.0.10)
15
- builder (2.1.2)
4
+ actionmailer (3.2.3)
5
+ actionpack (= 3.2.3)
6
+ mail (~> 2.4.4)
7
+ actionpack (3.2.3)
8
+ activemodel (= 3.2.3)
9
+ activesupport (= 3.2.3)
10
+ builder (~> 3.0.0)
11
+ erubis (~> 2.7.0)
12
+ journey (~> 1.0.1)
13
+ rack (~> 1.4.0)
14
+ rack-cache (~> 1.2)
15
+ rack-test (~> 0.6.1)
16
+ sprockets (~> 2.1.2)
17
+ activemodel (3.2.3)
18
+ activesupport (= 3.2.3)
19
+ builder (~> 3.0.0)
20
+ activerecord (3.2.3)
21
+ activemodel (= 3.2.3)
22
+ activesupport (= 3.2.3)
23
+ arel (~> 3.0.2)
24
+ tzinfo (~> 0.3.29)
25
+ activeresource (3.2.3)
26
+ activemodel (= 3.2.3)
27
+ activesupport (= 3.2.3)
28
+ activesupport (3.2.3)
29
+ i18n (~> 0.6)
30
+ multi_json (~> 1.0)
31
+ arel (3.0.2)
32
+ builder (3.0.0)
33
+ diff-lcs (1.1.3)
34
+ erubis (2.7.0)
16
35
  git (1.2.5)
17
- i18n (0.5.0)
18
- jeweler (1.6.4)
36
+ hike (1.2.1)
37
+ i18n (0.6.0)
38
+ jeweler (1.8.3)
19
39
  bundler (~> 1.0)
20
40
  git (>= 1.2.5)
21
41
  rake
22
- rake (0.9.2)
23
- rcov (0.9.9)
24
- rdoc (3.9.1)
25
- shoulda (2.11.3)
26
- tzinfo (0.3.29)
42
+ rdoc
43
+ journey (1.0.3)
44
+ json (1.7.3)
45
+ mail (2.4.4)
46
+ i18n (>= 0.4.0)
47
+ mime-types (~> 1.16)
48
+ treetop (~> 1.4.8)
49
+ mime-types (1.18)
50
+ multi_json (1.3.5)
51
+ pg (0.13.2)
52
+ polyglot (0.3.3)
53
+ rack (1.4.1)
54
+ rack-cache (1.2)
55
+ rack (>= 0.4)
56
+ rack-ssl (1.3.2)
57
+ rack
58
+ rack-test (0.6.1)
59
+ rack (>= 1.0)
60
+ rails (3.2.3)
61
+ actionmailer (= 3.2.3)
62
+ actionpack (= 3.2.3)
63
+ activerecord (= 3.2.3)
64
+ activeresource (= 3.2.3)
65
+ activesupport (= 3.2.3)
66
+ bundler (~> 1.0)
67
+ railties (= 3.2.3)
68
+ railties (3.2.3)
69
+ actionpack (= 3.2.3)
70
+ activesupport (= 3.2.3)
71
+ rack-ssl (~> 1.3.2)
72
+ rake (>= 0.8.7)
73
+ rdoc (~> 3.4)
74
+ thor (~> 0.14.6)
75
+ rake (0.9.2.2)
76
+ rcov (0.9.11)
77
+ rdoc (3.12)
78
+ json (~> 1.4)
79
+ rspec (2.10.0)
80
+ rspec-core (~> 2.10.0)
81
+ rspec-expectations (~> 2.10.0)
82
+ rspec-mocks (~> 2.10.0)
83
+ rspec-core (2.10.1)
84
+ rspec-expectations (2.10.0)
85
+ diff-lcs (~> 1.1.3)
86
+ rspec-mocks (2.10.1)
87
+ shoulda (3.0.1)
88
+ shoulda-context (~> 1.0.0)
89
+ shoulda-matchers (~> 1.0.0)
90
+ shoulda-context (1.0.0)
91
+ shoulda-matchers (1.0.0)
92
+ sprockets (2.1.3)
93
+ hike (~> 1.2)
94
+ rack (~> 1.0)
95
+ tilt (~> 1.1, != 1.3.0)
96
+ thor (0.14.6)
97
+ tilt (1.3.3)
98
+ treetop (1.4.10)
99
+ polyglot
100
+ polyglot (>= 0.3.1)
101
+ tzinfo (0.3.33)
27
102
 
28
103
  PLATFORMS
29
104
  ruby
30
105
 
31
106
  DEPENDENCIES
32
- activerecord
33
- bundler (~> 1.0.0)
34
- jeweler (~> 1.6.4)
107
+ bundler (~> 1.1.3)
108
+ jeweler (~> 1.8.3)
109
+ pg
110
+ rails
35
111
  rake
36
112
  rcov
37
113
  rdoc
114
+ rspec
38
115
  shoulda
data/README.md ADDED
@@ -0,0 +1,163 @@
1
+ [![Build Status](https://secure.travis-ci.org/softa/activerecord-postgres-hstore.png?branch=master)](http://travis-ci.org/softa/activerecord-postgres-hstore)
2
+
3
+ Goodbye serialize, hello hstore.
4
+ --------------------------------
5
+
6
+ You need dynamic columns in your tables. What do you do?
7
+
8
+ * Create lots of tables to handle it. Nice, now you’ll need more models and lots of additional sqls. Insertion and selection will be slow as hell.
9
+ * Use a noSQL database just for this issue. Good luck.
10
+ * Create a serialized column. Nice, insertion will be fine, and reading data from a record too. But, what if you have a condition in your select that includes serialized data? Yeah, regular expressions.
11
+
12
+ Requirements
13
+ ------------
14
+
15
+ Postgresql 8.4+ (also tested with 9.0) with contrib and Rails 3. (It
16
+ might work on 2.3.x with minor patches…)
17
+ On Ubuntu, this is easy: `sudo apt-get install postgresql-contrib-9.0`
18
+
19
+ On Mac <del> …you are screwed. Use a VM. </del> you should use [the binary package kindly provided by EnterpriseDB](http://www.enterprisedb.com/products-services-training/pgdownload#osx)
20
+ [Homebrew’s](https://github.com/mxcl/homebrew) Postgres installation also includes the contrib packages: `brew install postgres`
21
+
22
+ Notes for Rails 3.1 and above
23
+ -----------------------------
24
+
25
+ The master branch already support a custom serialization coder.
26
+ If you want to use it just put in your Gemfile:
27
+
28
+ gem 'activerecord-postgres-hstore', git: 'git://github.com/softa/activerecord-postgres-hstore.git'
29
+
30
+ If you install them gem from the master branch you also have to insert a
31
+ line in each model that uses hstore.
32
+ Assuming a model called **Person**, with a **data** field on it, the
33
+ code should look like:
34
+
35
+ class Person < ActiveRecord::Base
36
+ serialize :data, ActiveRecord::Coders::Hstore
37
+ end
38
+
39
+ Install
40
+ -------
41
+
42
+ Hstore is a PostgreSQL contrib type, [check it out first](http://www.postgresql.org/docs/9.2/static/hstore.html).
43
+
44
+ Then, just add this to your Gemfile:
45
+
46
+ `gem 'activerecord-postgres-hstore'`
47
+
48
+ And run your bundler:
49
+
50
+ `bundle install`
51
+
52
+ Make sure that you have the desired database, if not create it as the
53
+ desired user:
54
+
55
+ `createdb hstorage_dev`
56
+
57
+ Add the parameters to your database.yml (these are system dependant),
58
+ e.g.:
59
+
60
+ development:
61
+ adapter: postgresql
62
+ host: 127.0.0.1
63
+ database: hstorage_dev
64
+ encoding: unicode
65
+ username: postgres
66
+ password:
67
+ pool: 5
68
+
69
+ Now you need to create a migration that adds hstore support for your
70
+ PostgreSQL database:
71
+
72
+ `rails g hstore:setup`
73
+
74
+ Run it:
75
+
76
+ `rake db:migrate`
77
+
78
+ Finally you can create your own tables using hstore type. It’s easy:
79
+
80
+ rails g model Person name:string data:hstore
81
+ rake db:migrate
82
+
83
+ You’re done.
84
+ Well, not yet. Don’t forget to add indexes. Like this:
85
+
86
+ `CREATE INDEX people_gist_data ON people USING GIST(data);`
87
+ or
88
+ `CREATE INDEX people_gin_data ON people USING GIN(data);`
89
+
90
+ To understand the difference between the two types of indexes take a
91
+ look at [PostgreSQL docs](http://www.postgresql.org/docs/9.2/static/textsearch-indexes.html).
92
+
93
+ Usage
94
+ -----
95
+
96
+ Once you have it installed, you just need to learn a little bit of new
97
+ sqls for selecting stuff (creating and updating is transparent).
98
+ Find records that contains a key named 'foo’:
99
+
100
+ Person.where("data ? 'foo'")
101
+
102
+ Find records where 'foo’ is equal to 'bar’:
103
+
104
+ Person.where("data -> 'foo' = 'bar'")
105
+
106
+ This same sql is at least twice as fast (using indexes) if you do it
107
+ that way:
108
+
109
+ Person.where("data > 'foo=>bar’")
110
+
111
+ Find records where 'foo’ is not equal to 'bar’:
112
+
113
+ Person.where("data -> 'foo' <> 'bar'")
114
+
115
+ Find records where 'foo’ is like 'bar’:
116
+
117
+ Person.where("data -> 'foo' LIKE '%bar%'")
118
+
119
+ If you need to delete a key in a record, you can do it that way:
120
+
121
+ person.destroy_key(:data, :foo)
122
+
123
+ This way you’ll also save the record:
124
+
125
+ person.destroy_key!(:data, :foo)
126
+
127
+ The destroy\_key method returns 'self’, so you can chain it:
128
+
129
+ person.destroy_key(:data, :foo).destroy_key(:data, :bar).save
130
+
131
+ But there is a shortcuts for that:
132
+
133
+ person.destroy_keys(:data, :foo, :bar)
134
+
135
+ And finally, if you need to delete keys in many rows, you can:
136
+
137
+ Person.delete_key(:data, :foo)
138
+
139
+ and with many keys:
140
+
141
+ Person.delete_keys(:data, :foo, :bar)
142
+
143
+ Have fun.
144
+
145
+ Help
146
+ ----
147
+
148
+ You can use issues in github for that. Or else you can reach us at
149
+ twitter: [@dbiazus](https://twitter.com/#!/dbiazus) or [@joaomilho](https://twitter.com/#!/joaomilho)
150
+
151
+ Note on Patches/Pull Requests
152
+ -----------------------------
153
+
154
+ * Fork the project.
155
+ * Make your feature addition or bug fix.
156
+ * Add tests for it. This is important so I don’t break it in a future version unintentionally.
157
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
158
+ * Send me a pull request. Bonus points for topic branches.
159
+
160
+ Copyright
161
+ ---------
162
+
163
+ Copyright © 2010 Juan Maiz. See LICENSE for details.
data/Rakefile CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'bundler'
5
+ require 'rake'
6
+ require 'jeweler'
7
+ require 'rspec/core/rake_task'
8
+ require 'rdoc/task'
9
+
10
+ task :default => :spec
11
+
5
12
  begin
6
13
  Bundler.setup(:default, :development)
7
14
  rescue Bundler::BundlerError => e
@@ -9,9 +16,15 @@ rescue Bundler::BundlerError => e
9
16
  $stderr.puts "Run `bundle install` to install missing gems"
10
17
  exit e.status_code
11
18
  end
12
- require 'rake'
13
19
 
14
- require 'jeweler'
20
+ RSpec::Core::RakeTask.new(:spec)
21
+
22
+ RSpec::Core::RakeTask.new(:coverage) do |t|
23
+ t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
24
+ t.rcov = true
25
+ t.rcov_opts = ['--exclude', 'spec']
26
+ end
27
+
15
28
  Jeweler::Tasks.new do |gem|
16
29
  # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
30
  gem.name = "activerecord-postgres-hstore"
@@ -25,29 +38,11 @@ Jeweler::Tasks.new do |gem|
25
38
  end
26
39
  Jeweler::RubygemsDotOrgTasks.new
27
40
 
28
- require 'rake/testtask'
29
- Rake::TestTask.new(:test) do |test|
30
- test.libs << 'lib' << 'test'
31
- test.pattern = 'test/**/test_*.rb'
32
- test.verbose = true
33
- end
34
-
35
- require 'rcov/rcovtask'
36
- Rcov::RcovTask.new do |test|
37
- test.libs << 'test'
38
- test.pattern = 'test/**/test_*.rb'
39
- test.verbose = true
40
- test.rcov_opts << '--exclude "gems/*"'
41
- end
42
-
43
- task :default => :test
44
-
45
- require 'rdoc/task'
46
41
  RDoc::Task.new do |rdoc|
47
42
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
-
49
43
  rdoc.rdoc_dir = 'rdoc'
50
44
  rdoc.title = "activerecord-postgres-hstore #{version}"
51
45
  rdoc.rdoc_files.include('README*')
52
46
  rdoc.rdoc_files.include('lib/**/*.rb')
53
47
  end
48
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.0
@@ -4,25 +4,26 @@
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = %q{activerecord-postgres-hstore}
8
- s.version = "0.3.0"
7
+ s.name = "activerecord-postgres-hstore"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Juan Maiz", "Diogo Biazus"]
12
- s.date = %q{2011-12-28}
13
- s.description = %q{This gem adds support for the postgres hstore type. It is the _just right_ alternative for storing hashes instead of using seralization or dynamic tables.}
14
- s.email = %q{juanmaiz@gmail.com}
12
+ s.date = "2012-06-14"
13
+ s.description = "This gem adds support for the postgres hstore type. It is the _just right_ alternative for storing hashes instead of using seralization or dynamic tables."
14
+ s.email = "juanmaiz@gmail.com"
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.textile"
17
+ "README.md"
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
21
  ".rspec",
22
+ ".travis.yml",
22
23
  "Gemfile",
23
24
  "Gemfile.lock",
24
25
  "LICENSE",
25
- "README.textile",
26
+ "README.md",
26
27
  "Rakefile",
27
28
  "VERSION",
28
29
  "activerecord-postgres-hstore.gemspec",
@@ -81,48 +82,56 @@ Gem::Specification.new do |s|
81
82
  "app/vendor/plugins/.gitkeep",
82
83
  "lib/activerecord-postgres-hstore.rb",
83
84
  "lib/activerecord-postgres-hstore/activerecord.rb",
85
+ "lib/activerecord-postgres-hstore/coder.rb",
84
86
  "lib/activerecord-postgres-hstore/hash.rb",
87
+ "lib/activerecord-postgres-hstore/railties.rb",
85
88
  "lib/activerecord-postgres-hstore/string.rb",
86
89
  "lib/templates/setup_hstore.rb",
87
90
  "lib/templates/setup_hstore91.rb",
91
+ "spec/activerecord-coders-hstore.rb",
88
92
  "spec/activerecord-postgres-hstore_spec.rb",
89
93
  "spec/spec_helper.rb"
90
94
  ]
91
- s.homepage = %q{http://github.com/softa/activerecord-postgres-hstore}
95
+ s.homepage = "http://github.com/softa/activerecord-postgres-hstore"
92
96
  s.licenses = ["MIT"]
93
97
  s.require_paths = ["lib"]
94
- s.rubygems_version = %q{1.3.7}
95
- s.summary = %q{Goodbye serialize, hello hstore}
98
+ s.rubygems_version = "1.8.15"
99
+ s.summary = "Goodbye serialize, hello hstore"
96
100
 
97
101
  if s.respond_to? :specification_version then
98
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
99
102
  s.specification_version = 3
100
103
 
101
104
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
102
- s.add_runtime_dependency(%q<activerecord>, [">= 0"])
105
+ s.add_runtime_dependency(%q<rails>, [">= 0"])
103
106
  s.add_runtime_dependency(%q<rake>, [">= 0"])
107
+ s.add_runtime_dependency(%q<pg>, [">= 0"])
104
108
  s.add_development_dependency(%q<shoulda>, [">= 0"])
105
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
106
- s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
107
- s.add_development_dependency(%q<rcov>, [">= 0"])
109
+ s.add_development_dependency(%q<bundler>, ["~> 1.1.3"])
110
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
108
111
  s.add_development_dependency(%q<rdoc>, [">= 0"])
112
+ s.add_development_dependency(%q<rspec>, [">= 0"])
113
+ s.add_development_dependency(%q<rcov>, [">= 0"])
109
114
  else
110
- s.add_dependency(%q<activerecord>, [">= 0"])
115
+ s.add_dependency(%q<rails>, [">= 0"])
111
116
  s.add_dependency(%q<rake>, [">= 0"])
117
+ s.add_dependency(%q<pg>, [">= 0"])
112
118
  s.add_dependency(%q<shoulda>, [">= 0"])
113
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
114
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
115
- s.add_dependency(%q<rcov>, [">= 0"])
119
+ s.add_dependency(%q<bundler>, ["~> 1.1.3"])
120
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
116
121
  s.add_dependency(%q<rdoc>, [">= 0"])
122
+ s.add_dependency(%q<rspec>, [">= 0"])
123
+ s.add_dependency(%q<rcov>, [">= 0"])
117
124
  end
118
125
  else
119
- s.add_dependency(%q<activerecord>, [">= 0"])
126
+ s.add_dependency(%q<rails>, [">= 0"])
120
127
  s.add_dependency(%q<rake>, [">= 0"])
128
+ s.add_dependency(%q<pg>, [">= 0"])
121
129
  s.add_dependency(%q<shoulda>, [">= 0"])
122
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
123
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
124
- s.add_dependency(%q<rcov>, [">= 0"])
130
+ s.add_dependency(%q<bundler>, ["~> 1.1.3"])
131
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
125
132
  s.add_dependency(%q<rdoc>, [">= 0"])
133
+ s.add_dependency(%q<rspec>, [">= 0"])
134
+ s.add_dependency(%q<rcov>, [">= 0"])
126
135
  end
127
136
  end
128
137
 
@@ -1,54 +1,4 @@
1
- require 'rails'
2
- require 'rails/generators'
3
- require 'rails/generators/migration'
4
- require 'pg'
5
-
6
- # = Hstore Railtie
7
- #
8
- # Creates a new railtie for 2 reasons:
9
- #
10
- # * Initialize ActiveRecord properly
11
- # * Add hstore:setup generator
12
- class Hstore < Rails::Railtie
13
-
14
- initializer 'activerecord-postgres-hstore' do
15
- ActiveSupport.on_load :active_record do
16
- require "activerecord-postgres-hstore/activerecord"
17
- end
18
- end
19
-
20
- # Creates the hstore:setup generator. This generator creates a migration that
21
- # adds hstore support for your database. If fact, it's just the sql from the
22
- # contrib inside a migration. But it' s handy, isn't it?
23
- #
24
- # To use your generator, simply run it in your project:
25
- #
26
- # rails g hstore:setup
27
- class Setup < Rails::Generators::Base
28
- include Rails::Generators::Migration
29
-
30
- def self.source_root
31
- @source_root ||= File.join(File.dirname(__FILE__), 'templates')
32
- end
33
-
34
- def self.next_migration_number(dirname)
35
- if ActiveRecord::Base.timestamped_migrations
36
- Time.now.utc.strftime("%Y%m%d%H%M%S")
37
- else
38
- "%.3d" % (current_migration_number(dirname) + 1)
39
- end
40
- end
41
-
42
- def create_migration_file
43
- pgversion = ActiveRecord::Base.connection.send(:postgresql_version)
44
- if pgversion < 90100
45
- migration_template 'setup_hstore.rb', 'db/migrate/setup_hstore.rb'
46
- else
47
- migration_template 'setup_hstore91.rb', 'db/migrate/setup_hstore.rb'
48
- end
49
- end
50
-
51
- end
52
- end
1
+ require "activerecord-postgres-hstore/railties"
53
2
  require "activerecord-postgres-hstore/string"
54
3
  require "activerecord-postgres-hstore/hash"
4
+ require "activerecord-postgres-hstore/coder"
@@ -66,6 +66,7 @@ module ActiveRecord
66
66
  destroy_keys(attribute, *keys).save
67
67
  end
68
68
 
69
+ if Rails.version < '3.1.0'
69
70
  # This method is replaced for Rails 3 compatibility.
70
71
  # All I do is add the condition when the field is a hash that converts the value
71
72
  # to hstore format.
@@ -88,6 +89,7 @@ module ActiveRecord
88
89
  end
89
90
  attrs
90
91
  end
92
+ end
91
93
 
92
94
  end
93
95
 
@@ -0,0 +1,26 @@
1
+ module ActiveRecord
2
+ module Coders
3
+ class Hstore
4
+ def self.load(hstore)
5
+ new.load(hstore)
6
+ end
7
+
8
+ def self.dump(hstore)
9
+ new.dump(hstore)
10
+ end
11
+
12
+ def initialize(default=nil)
13
+ @default=default
14
+ end
15
+
16
+ def dump(obj)
17
+ obj.nil? ? (@default.nil? ? nil : @default.to_hstore) : obj.to_hstore
18
+ end
19
+
20
+ def load(hstore)
21
+ hstore.nil? ? nil : hstore.from_hstore
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,53 @@
1
+ require 'rails'
2
+ require 'rails/generators'
3
+ require 'rails/generators/migration'
4
+ require 'pg'
5
+
6
+ # = Hstore Railtie
7
+ #
8
+ # Creates a new railtie for 2 reasons:
9
+ #
10
+ # * Initialize ActiveRecord properly
11
+ # * Add hstore:setup generator
12
+ class Hstore < Rails::Railtie
13
+
14
+ initializer 'activerecord-postgres-hstore' do
15
+ ActiveSupport.on_load :active_record do
16
+ require "activerecord-postgres-hstore/activerecord"
17
+ end
18
+ end
19
+
20
+ # Creates the hstore:setup generator. This generator creates a migration that
21
+ # adds hstore support for your database. If fact, it's just the sql from the
22
+ # contrib inside a migration. But it' s handy, isn't it?
23
+ #
24
+ # To use your generator, simply run it in your project:
25
+ #
26
+ # rails g hstore:setup
27
+ class Setup < Rails::Generators::Base
28
+ include Rails::Generators::Migration
29
+
30
+ def self.source_root
31
+ @source_root ||= File.join(File.dirname(__FILE__), '../templates')
32
+ end
33
+
34
+ def self.next_migration_number(dirname)
35
+ if ActiveRecord::Base.timestamped_migrations
36
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
37
+ else
38
+ "%.3d" % (current_migration_number(dirname) + 1)
39
+ end
40
+ end
41
+
42
+ def create_migration_file
43
+ pgversion = ActiveRecord::Base.connection.send(:postgresql_version)
44
+ if pgversion < 90100
45
+ migration_template 'setup_hstore.rb', 'db/migrate/setup_hstore.rb'
46
+ else
47
+ migration_template 'setup_hstore91.rb', 'db/migrate/setup_hstore.rb'
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+
@@ -1,9 +1,9 @@
1
1
  class SetupHstore < ActiveRecord::Migration
2
2
  def self.up
3
- execute "CREATE EXTENSION hstore"
3
+ execute "CREATE EXTENSION IF NOT EXISTS hstore"
4
4
  end
5
5
 
6
6
  def self.down
7
- execute "DROP EXTENSION hstore"
7
+ execute "DROP EXTENSION IF EXISTS hstore"
8
8
  end
9
9
  end
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "ActiverecordCodersHstore" do
4
+ it 'should load nil' do
5
+ ActiveRecord::Coders::Hstore.load(nil).should be_nil
6
+ end
7
+
8
+ it 'should load an hstore' do
9
+ ActiveRecord::Coders::Hstore.load("a=>a").should == { 'a' => 'a' }
10
+ end
11
+
12
+ it 'should dump an hstore' do
13
+ ActiveRecord::Coders::Hstore.dump({'a'=>'a'}).should == {'a'=>'a'}.to_hstore
14
+ end
15
+
16
+ it 'should dump nil' do
17
+ ActiveRecord::Coders::Hstore.dump(nil).should be_nil
18
+ end
19
+
20
+ it 'should dump the default given nil' do
21
+ ActiveRecord::Coders::Hstore.new({'a'=>'a'}).dump(nil).should == {'a'=>'a'}.to_hstore
22
+ end
23
+ end
metadata CHANGED
@@ -1,142 +1,132 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: activerecord-postgres-hstore
3
- version: !ruby/object:Gem::Version
4
- hash: 19
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 3
9
- - 0
10
- version: 0.3.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Juan Maiz
14
9
  - Diogo Biazus
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2011-12-28 00:00:00 -02:00
20
- default_executable:
21
- dependencies:
22
- - !ruby/object:Gem::Dependency
23
- name: activerecord
13
+ date: 2012-06-14 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: &2159228940 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
24
23
  type: :runtime
25
24
  prerelease: false
26
- version_requirements: &id001 !ruby/object:Gem::Requirement
27
- none: false
28
- requirements:
29
- - - ">="
30
- - !ruby/object:Gem::Version
31
- hash: 3
32
- segments:
33
- - 0
34
- version: "0"
35
- requirement: *id001
36
- - !ruby/object:Gem::Dependency
25
+ version_requirements: *2159228940
26
+ - !ruby/object:Gem::Dependency
37
27
  name: rake
28
+ requirement: &2159228300 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
- version_requirements: &id002 !ruby/object:Gem::Requirement
36
+ version_requirements: *2159228300
37
+ - !ruby/object:Gem::Dependency
38
+ name: pg
39
+ requirement: &2159227720 !ruby/object:Gem::Requirement
41
40
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- hash: 3
46
- segments:
47
- - 0
48
- version: "0"
49
- requirement: *id002
50
- - !ruby/object:Gem::Dependency
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *2159227720
48
+ - !ruby/object:Gem::Dependency
51
49
  name: shoulda
50
+ requirement: &2159227100 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
52
56
  type: :development
53
57
  prerelease: false
54
- version_requirements: &id003 !ruby/object:Gem::Requirement
55
- none: false
56
- requirements:
57
- - - ">="
58
- - !ruby/object:Gem::Version
59
- hash: 3
60
- segments:
61
- - 0
62
- version: "0"
63
- requirement: *id003
64
- - !ruby/object:Gem::Dependency
58
+ version_requirements: *2159227100
59
+ - !ruby/object:Gem::Dependency
65
60
  name: bundler
61
+ requirement: &2159226380 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ version: 1.1.3
66
67
  type: :development
67
68
  prerelease: false
68
- version_requirements: &id004 !ruby/object:Gem::Requirement
69
+ version_requirements: *2159226380
70
+ - !ruby/object:Gem::Dependency
71
+ name: jeweler
72
+ requirement: &2159225720 !ruby/object:Gem::Requirement
69
73
  none: false
70
- requirements:
74
+ requirements:
71
75
  - - ~>
72
- - !ruby/object:Gem::Version
73
- hash: 23
74
- segments:
75
- - 1
76
- - 0
77
- - 0
78
- version: 1.0.0
79
- requirement: *id004
80
- - !ruby/object:Gem::Dependency
81
- name: jeweler
76
+ - !ruby/object:Gem::Version
77
+ version: 1.8.3
82
78
  type: :development
83
79
  prerelease: false
84
- version_requirements: &id005 !ruby/object:Gem::Requirement
80
+ version_requirements: *2159225720
81
+ - !ruby/object:Gem::Dependency
82
+ name: rdoc
83
+ requirement: &2159224880 !ruby/object:Gem::Requirement
85
84
  none: false
86
- requirements:
87
- - - ~>
88
- - !ruby/object:Gem::Version
89
- hash: 7
90
- segments:
91
- - 1
92
- - 6
93
- - 4
94
- version: 1.6.4
95
- requirement: *id005
96
- - !ruby/object:Gem::Dependency
97
- name: rcov
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
98
89
  type: :development
99
90
  prerelease: false
100
- version_requirements: &id006 !ruby/object:Gem::Requirement
91
+ version_requirements: *2159224880
92
+ - !ruby/object:Gem::Dependency
93
+ name: rspec
94
+ requirement: &2159223860 !ruby/object:Gem::Requirement
101
95
  none: false
102
- requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- hash: 3
106
- segments:
107
- - 0
108
- version: "0"
109
- requirement: *id006
110
- - !ruby/object:Gem::Dependency
111
- name: rdoc
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
112
100
  type: :development
113
101
  prerelease: false
114
- version_requirements: &id007 !ruby/object:Gem::Requirement
102
+ version_requirements: *2159223860
103
+ - !ruby/object:Gem::Dependency
104
+ name: rcov
105
+ requirement: &2159223260 !ruby/object:Gem::Requirement
115
106
  none: false
116
- requirements:
117
- - - ">="
118
- - !ruby/object:Gem::Version
119
- hash: 3
120
- segments:
121
- - 0
122
- version: "0"
123
- requirement: *id007
124
- description: This gem adds support for the postgres hstore type. It is the _just right_ alternative for storing hashes instead of using seralization or dynamic tables.
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: *2159223260
114
+ description: This gem adds support for the postgres hstore type. It is the _just right_
115
+ alternative for storing hashes instead of using seralization or dynamic tables.
125
116
  email: juanmaiz@gmail.com
126
117
  executables: []
127
-
128
118
  extensions: []
129
-
130
- extra_rdoc_files:
119
+ extra_rdoc_files:
131
120
  - LICENSE
132
- - README.textile
133
- files:
121
+ - README.md
122
+ files:
134
123
  - .document
135
124
  - .rspec
125
+ - .travis.yml
136
126
  - Gemfile
137
127
  - Gemfile.lock
138
128
  - LICENSE
139
- - README.textile
129
+ - README.md
140
130
  - Rakefile
141
131
  - VERSION
142
132
  - activerecord-postgres-hstore.gemspec
@@ -195,45 +185,41 @@ files:
195
185
  - app/vendor/plugins/.gitkeep
196
186
  - lib/activerecord-postgres-hstore.rb
197
187
  - lib/activerecord-postgres-hstore/activerecord.rb
188
+ - lib/activerecord-postgres-hstore/coder.rb
198
189
  - lib/activerecord-postgres-hstore/hash.rb
190
+ - lib/activerecord-postgres-hstore/railties.rb
199
191
  - lib/activerecord-postgres-hstore/string.rb
200
192
  - lib/templates/setup_hstore.rb
201
193
  - lib/templates/setup_hstore91.rb
194
+ - spec/activerecord-coders-hstore.rb
202
195
  - spec/activerecord-postgres-hstore_spec.rb
203
196
  - spec/spec_helper.rb
204
- has_rdoc: true
205
197
  homepage: http://github.com/softa/activerecord-postgres-hstore
206
- licenses:
198
+ licenses:
207
199
  - MIT
208
200
  post_install_message:
209
201
  rdoc_options: []
210
-
211
- require_paths:
202
+ require_paths:
212
203
  - lib
213
- required_ruby_version: !ruby/object:Gem::Requirement
204
+ required_ruby_version: !ruby/object:Gem::Requirement
214
205
  none: false
215
- requirements:
216
- - - ">="
217
- - !ruby/object:Gem::Version
218
- hash: 3
219
- segments:
206
+ requirements:
207
+ - - ! '>='
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ segments:
220
211
  - 0
221
- version: "0"
222
- required_rubygems_version: !ruby/object:Gem::Requirement
212
+ hash: -2838359693870553945
213
+ required_rubygems_version: !ruby/object:Gem::Requirement
223
214
  none: false
224
- requirements:
225
- - - ">="
226
- - !ruby/object:Gem::Version
227
- hash: 3
228
- segments:
229
- - 0
230
- version: "0"
215
+ requirements:
216
+ - - ! '>='
217
+ - !ruby/object:Gem::Version
218
+ version: '0'
231
219
  requirements: []
232
-
233
220
  rubyforge_project:
234
- rubygems_version: 1.3.7
221
+ rubygems_version: 1.8.15
235
222
  signing_key:
236
223
  specification_version: 3
237
224
  summary: Goodbye serialize, hello hstore
238
225
  test_files: []
239
-
data/README.textile DELETED
@@ -1,161 +0,0 @@
1
- h2. Goodbye serialize, hello hstore.
2
-
3
- You need dynamic columns in your tables. What do you do?
4
-
5
- * Create lots of tables to handle it.
6
- Nice, now you'll need more models and lots of additional sqls. Insertion and selection will be slow as hell.
7
-
8
- * Use a noSQL database just for this issue.
9
- Good luck.
10
-
11
- * Create a serialized column.
12
- Nice, insertion will be fine, and reading data from a record too. But, what if you have a condition in your select that includes serialized data? Yeah, regular expressions.
13
-
14
- !https://spreadsheets.google.com/oimg?key=0AoQcKrACYfGjdGRVV3cyTDZYQkJMa255VkxxQW9LTHc&oid=1&zx=ksfsz3-j87df5!
15
-
16
- |action|serialize|hstore|serialize sql|hstore sql|
17
- |count all with condition|10114,575|1830,444|SELECT count(*) FROM foos WHERE data ~ 'foo: bar';|SELECT count(*) FROM bars WHERE data @> 'foo=>bar';|
18
- |count all with negative condition|18722,149|1677,948|SELECT count(*) FROM foos WHERE data !~ 'another key: 9999990';|SELECT count(*) FROM bars WHERE not data @> '"another key"=>9999990';|
19
- |find one with condition|17740,307|130,227|SELECT count(*) FROM foos WHERE data ~ 'another key: 9999990';|SELECT * FROM bars WHERE data @> '"another key"=>9999990'|
20
-
21
- Benchmarks made in my local machine, with a million records. Time is in milliseconds.
22
-
23
- h2. Requirements
24
-
25
- Postgresql 8.4+ (also tested with 9.0) with contrib and Rails 3. (It might work on 2.3.x with minor patches...)
26
-
27
- On Ubuntu, this is easy:
28
-
29
- @sudo apt-get install postgresql-contrib-9.0@
30
-
31
- On Mac <del>...you are screwed. Use a VM.</del> you should use "the binary package kindly provided by EnterpriseDB":http://www.enterprisedb.com/products-services-training/pgdownload#osx
32
-
33
- "Homebrew's":https://github.com/mxcl/homebrew Postgres installation also includes the contrib packages. @brew install postgres@
34
-
35
- h2. Install
36
-
37
- Hstore is a postgres contrib type. Check it out first:
38
-
39
- "http://www.postgresql.org/docs/9.0/static/hstore.html":http://www.postgresql.org/docs/9.0/static/hstore.html
40
-
41
- Then, just add this to your Gemfile:
42
-
43
- @gem 'activerecord-postgres-hstore'@
44
-
45
- And run your bundler:
46
-
47
- @bundle install@
48
-
49
- Make sure that you have the desired database, if not create it as the desired user:
50
-
51
- @createdb hstorage_dev@
52
-
53
- Add the parameters to your database.yml (these are system dependant), e.g.:
54
-
55
- bc. development:
56
- adapter: postgresql
57
- host: 127.0.0.1
58
- database: hstorage_dev
59
- encoding: unicode
60
- username: postgres
61
- password:
62
- pool: 5
63
-
64
- Now you need to create a migration that adds hstore support for your postgresql database:
65
-
66
- @rails g hstore:setup@
67
-
68
- Run it:
69
-
70
- @rake db:migrate@
71
-
72
- Finally you can create your own tables using hstore type. It's easy:
73
-
74
- @rails g model Person name:string data:hstore@
75
- @rake db:migrate@
76
-
77
- You're done.
78
-
79
- Well, not yet. Don't forget to add indexes. Like this:
80
-
81
- @CREATE INDEX people_gist_data ON people USING GIST(data);@
82
- or
83
- @CREATE INDEX people_gin_data ON people USING GIN(data);@
84
-
85
- To my experience GIN is faster for searching records.
86
-
87
- h2. Usage
88
-
89
- Once you have it installed, you just need to learn a little bit of new sqls for selecting stuff (creating and updating is transparent).
90
-
91
- Find records that contains a key named 'foo':
92
-
93
- @Person.where("data ? 'foo'")@
94
-
95
- Find records where 'foo' is equal to 'bar':
96
-
97
- @Person.where("data -> 'foo' = 'bar'")@
98
-
99
- This same sql is at least twice as fast (using indexes) if you do it that way:
100
-
101
- @Person.where("data @> 'foo=>bar'")@
102
-
103
- Find records where 'foo' is not equal to 'bar':
104
-
105
- @Person.where("data -> 'foo' <> 'bar'")@
106
- or
107
- @Person.where("not data @> 'foo=>bar'")@
108
-
109
- Find records where 'foo' is like 'bar':
110
-
111
- @Person.where("data -> 'foo' LIKE '%bar%'")@
112
- or something like ...
113
- @Person.where("data -> 'foo' ILIKE '%bar%'")@
114
-
115
- If you need to delete a key in a record, you can do it that way:
116
-
117
- @person.destroy_key(:data, :foo)@
118
-
119
- This way you'll also save the record:
120
-
121
- @person.destroy_key!(:data, :foo)@
122
-
123
- The destroy_key method returns 'self', so you can chain it:
124
-
125
- @person.destroy_key(:data, :foo).destroy_key(:data, :bar).save@
126
-
127
- But there it a shortcut for that:
128
-
129
- @person.destroy_keys(:data, :foo, :bar)@
130
-
131
- or...
132
-
133
- @person.destroy_keys!(:data, :foo, :bar)@
134
-
135
- And finally, if you need to delete keys in many rows, you can:
136
-
137
- @Person.delete_key(:data, :foo)@
138
-
139
- and with many keys:
140
-
141
- @Person.delete_keys(:data, :foo, :bar)@
142
-
143
- Have fun.
144
-
145
- h2. Help
146
-
147
- You can use issues in github for that. Or else you can reach me at twitter: @joaomilho
148
-
149
- h2. Note on Patches/Pull Requests
150
-
151
- * Fork the project.
152
- * Make your feature addition or bug fix.
153
- * Add tests for it. This is important so I don't break it in a
154
- future version unintentionally.
155
- * Commit, do not mess with rakefile, version, or history.
156
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
157
- * Send me a pull request. Bonus points for topic branches.
158
-
159
- h2. Copyright
160
-
161
- Copyright (c) 2010 Juan Maiz. See LICENSE for details.