activerecord-postgres-hstore 0.3.0 → 0.4.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/.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.