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 +7 -0
- data/Gemfile +7 -5
- data/Gemfile.lock +99 -22
- data/README.md +163 -0
- data/Rakefile +16 -21
- data/VERSION +1 -1
- data/activerecord-postgres-hstore.gemspec +32 -23
- data/lib/activerecord-postgres-hstore.rb +2 -52
- data/lib/activerecord-postgres-hstore/activerecord.rb +2 -0
- data/lib/activerecord-postgres-hstore/coder.rb +26 -0
- data/lib/activerecord-postgres-hstore/railties.rb +53 -0
- data/lib/templates/setup_hstore91.rb +2 -2
- data/spec/activerecord-coders-hstore.rb +23 -0
- metadata +108 -122
- data/README.textile +0 -161
data/.travis.yml
ADDED
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 '
|
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.
|
11
|
-
gem "jeweler", "~> 1.
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
18
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
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
|
+
[](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
|
-
|
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.
|
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 =
|
8
|
-
s.version = "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 =
|
13
|
-
s.description =
|
14
|
-
s.email =
|
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.
|
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.
|
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 =
|
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 =
|
95
|
-
s.summary =
|
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<
|
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.
|
106
|
-
s.add_development_dependency(%q<jeweler>, ["~> 1.
|
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<
|
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.
|
114
|
-
s.add_dependency(%q<jeweler>, ["~> 1.
|
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<
|
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.
|
123
|
-
s.add_dependency(%q<jeweler>, ["~> 1.
|
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
|
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
|
+
|
@@ -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
|
-
|
5
|
-
prerelease:
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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:
|
27
|
-
|
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:
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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:
|
55
|
-
|
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:
|
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
|
-
|
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:
|
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
|
-
|
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:
|
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
|
-
|
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:
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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.
|
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.
|
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
|
-
|
219
|
-
segments:
|
206
|
+
requirements:
|
207
|
+
- - ! '>='
|
208
|
+
- !ruby/object:Gem::Version
|
209
|
+
version: '0'
|
210
|
+
segments:
|
220
211
|
- 0
|
221
|
-
|
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
|
-
|
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.
|
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.
|