activerecord-postgres-hstore 0.0.1 → 0.0.2
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/README.textile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
.
|
1
|
+
h2. Goodbye serialize, hello hstore.
|
2
2
|
|
3
3
|
You need dynamic columns in your tables. What do you do?
|
4
4
|
|
@@ -18,83 +18,113 @@ You need dynamic columns in your tables. What do you do?
|
|
18
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
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
20
|
|
21
|
-
Benchmarks made in my local machine,
|
21
|
+
Benchmarks made in my local machine, with a million records. Time is in milliseconds.
|
22
22
|
|
23
|
-
.
|
23
|
+
h2. Requirements
|
24
24
|
|
25
25
|
Postgresql 8.4 with contrib and Rails 3. (It might work on 2.3.x with minor patches...)
|
26
26
|
|
27
|
-
|
27
|
+
In Ubuntu, this is easy:
|
28
|
+
|
29
|
+
@sudo apt-get install postgresql-8.4 postgresql-contrib-8.4@
|
30
|
+
|
31
|
+
In Mac ...you are screwed. Use a VM.
|
32
|
+
|
33
|
+
h2. Install
|
28
34
|
|
29
35
|
Hstore is a postgres contrib type. Check it out first:
|
30
36
|
|
31
|
-
http://www.postgresql.org/docs/8.4/static/hstore.html
|
37
|
+
"http://www.postgresql.org/docs/8.4/static/hstore.html":http://www.postgresql.org/docs/8.4/static/hstore.html
|
32
38
|
|
33
39
|
Then, just add this to your Gemfile:
|
34
40
|
|
35
|
-
gem 'activerecord-postgres-hstore'
|
41
|
+
@gem 'activerecord-postgres-hstore'@
|
36
42
|
|
37
43
|
And run your bundler:
|
38
44
|
|
39
|
-
bundle install
|
45
|
+
@bundle install@
|
40
46
|
|
41
47
|
Now you need to create a migration that adds hstore support for your postgresql database:
|
42
48
|
|
43
|
-
rails g railtie:hstore
|
49
|
+
@rails g railtie:hstore@
|
44
50
|
|
45
51
|
Run it:
|
46
52
|
|
47
|
-
rake db:migrate
|
53
|
+
@rake db:migrate@
|
48
54
|
|
49
55
|
Finally you can create your own tables using hstore type. It's easy:
|
50
56
|
|
51
|
-
rails g model Person name:string data:hstore
|
57
|
+
@rails g model Person name:string data:hstore@
|
52
58
|
|
53
59
|
You're done.
|
54
60
|
|
55
61
|
Well, not yet. Don't forget to add indexes. Like this:
|
56
62
|
|
57
|
-
CREATE INDEX people_gist_data ON people USING GIST(data)
|
58
|
-
|
59
|
-
CREATE INDEX people_gin_data ON people USING GIN(data)
|
63
|
+
@CREATE INDEX people_gist_data ON people USING GIST(data);@
|
64
|
+
or
|
65
|
+
@CREATE INDEX people_gin_data ON people USING GIN(data);@
|
60
66
|
|
61
67
|
To my experience GIN is faster for searching records.
|
62
68
|
|
63
|
-
.
|
69
|
+
h2. Usage
|
64
70
|
|
65
71
|
Once you have it installed, you just need to learn a little bit of new sqls for selecting stuff (creting and updating is transparent).
|
66
72
|
|
67
73
|
Find records that contains a key named 'foo':
|
68
74
|
|
69
|
-
Person.where("data ? 'foo'")
|
75
|
+
@Person.where("data ? 'foo'")@
|
70
76
|
|
71
77
|
Find records where 'foo' is equal to 'bar':
|
72
78
|
|
73
|
-
Person.where("data -> 'foo' = 'bar'")
|
79
|
+
@Person.where("data -> 'foo' = 'bar'")@
|
74
80
|
|
75
81
|
This same sql is at least twice as fast (using indexes) if you do it that way:
|
76
82
|
|
77
|
-
Person.where("data @> 'foo=>bar'")
|
83
|
+
@Person.where("data @> 'foo=>bar'")@
|
78
84
|
|
79
85
|
Find records where 'foo' is not equal to 'bar':
|
80
86
|
|
81
|
-
Person.where("data -> 'foo' <> 'bar'")
|
82
|
-
|
83
|
-
Person.where("not data @> 'foo=>bar'")
|
87
|
+
@Person.where("data -> 'foo' <> 'bar'")@
|
88
|
+
or
|
89
|
+
@Person.where("not data @> 'foo=>bar'")@
|
84
90
|
|
85
91
|
Find records where 'foo' is like 'bar':
|
86
92
|
|
87
|
-
Person.where("data -> 'foo' LIKE '%bar%'")
|
88
|
-
|
89
|
-
Person.where("data -> 'foo' ILIKE '%bar%'")
|
93
|
+
@Person.where("data -> 'foo' LIKE '%bar%'")@
|
94
|
+
or something like ...
|
95
|
+
@Person.where("data -> 'foo' ILIKE '%bar%'")@
|
96
|
+
|
97
|
+
If you need to delete a key in a record, you can do it that way:
|
98
|
+
|
99
|
+
@person.destroy_key(:data, :foo)@
|
100
|
+
|
101
|
+
This way you'll also save the record:
|
102
|
+
|
103
|
+
@person.destroy_key!(:data, :foo)@
|
104
|
+
|
105
|
+
The destroy_key method returns 'self', so you can chain it:
|
106
|
+
|
107
|
+
@person.destroy_key(:data, :foo).destroy_key(:data, :bar).save@
|
108
|
+
|
109
|
+
But there it a shortcut for that:
|
110
|
+
|
111
|
+
@person.destroy_keys(:data, :foo, :bar)@
|
112
|
+
|
113
|
+
or...
|
114
|
+
|
115
|
+
@person.destroy_keys!(:data, :foo, :bar)@
|
116
|
+
|
117
|
+
And finally, if you need to delete keys in many rows, you can:
|
118
|
+
|
119
|
+
|
90
120
|
|
91
121
|
Have fun.
|
92
122
|
|
93
|
-
.
|
123
|
+
h2. Help
|
94
124
|
|
95
125
|
You can use issues in github for that. Or else you can reach me at twitter: @joaomilho
|
96
126
|
|
97
|
-
.
|
127
|
+
h2. Note on Patches/Pull Requests
|
98
128
|
|
99
129
|
* Fork the project.
|
100
130
|
* Make your feature addition or bug fix.
|
@@ -104,6 +134,6 @@ You can use issues in github for that. Or else you can reach me at twitter: @joa
|
|
104
134
|
(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)
|
105
135
|
* Send me a pull request. Bonus points for topic branches.
|
106
136
|
|
107
|
-
.
|
137
|
+
h2. Copyright
|
108
138
|
|
109
139
|
Copyright (c) 2010 Juan Maiz. See LICENSE for details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
@@ -1,6 +1,51 @@
|
|
1
1
|
# ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('data','','hstore').type
|
2
2
|
module ActiveRecord
|
3
3
|
class Base
|
4
|
+
def self.delete_key attribute, key
|
5
|
+
#UPDATE tab SET h = delete(h, 'k1');
|
6
|
+
unless column_names.include?(attribute.to_s)
|
7
|
+
raise "invalid attribute #{attribute}"
|
8
|
+
end
|
9
|
+
update_all(["#{attribute} = delete(#{attribute},?)",key])
|
10
|
+
end
|
11
|
+
def self.delete_keys attribute, *keys
|
12
|
+
unless column_names.include?(attribute.to_s)
|
13
|
+
raise "invalid attribute #{attribute}"
|
14
|
+
end
|
15
|
+
delete_str = "delete(#{attribute},?)"
|
16
|
+
(keys.count-1).times do
|
17
|
+
delete_str = "delete(#{delete_str},?)"
|
18
|
+
end
|
19
|
+
update_all(["#{attribute} = #{delete_str}", *keys])
|
20
|
+
end
|
21
|
+
|
22
|
+
def destroy_key attribute, key
|
23
|
+
unless self.class.column_names.include?(attribute.to_s)
|
24
|
+
raise "invalid attribute #{attribute}"
|
25
|
+
end
|
26
|
+
new_value = send(attribute)
|
27
|
+
new_value.delete(key.to_s)
|
28
|
+
send("#{attribute}=", new_value)
|
29
|
+
self
|
30
|
+
end
|
31
|
+
def destroy_key! attribute, key
|
32
|
+
destroy_key(attribute, key).save
|
33
|
+
end
|
34
|
+
def destroy_keys attribute, *keys
|
35
|
+
for key in keys
|
36
|
+
new_value = send(attribute)
|
37
|
+
new_value.delete(key.to_s)
|
38
|
+
send("#{attribute}=", new_value)
|
39
|
+
end
|
40
|
+
self
|
41
|
+
end
|
42
|
+
def destroy_keys! attribute, *keys
|
43
|
+
unless self.class.column_names.include?(attribute.to_s)
|
44
|
+
raise "invalid attribute #{attribute}"
|
45
|
+
end
|
46
|
+
destroy_keys(attribute, *keys).save
|
47
|
+
end
|
48
|
+
|
4
49
|
# For Rails 3 compat :D
|
5
50
|
#alias :old_arel_attributes_values :arel_attributes_values
|
6
51
|
def arel_attributes_values(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
|
@@ -1,39 +1,24 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "ActiverecordPostgresHstore" do
|
4
|
-
it "should convert hstore string
|
4
|
+
it "should convert hash to hstore string" do
|
5
5
|
{:a => 1, :b => 2}.to_hstore.should == "('a'=>'1') || ('b'=>'2')"
|
6
6
|
end
|
7
7
|
|
8
|
-
it "should convert
|
8
|
+
it "should convert hstore string to hash" do
|
9
9
|
'"a"=>"1", "b"=>"2"'.from_hstore.should == {'a' => '1', 'b' => '2'}
|
10
10
|
end
|
11
11
|
|
12
12
|
it "should quote correctly" do
|
13
13
|
{:a => "'a'"}.to_hstore.should == "('a'=>'''a''')"
|
14
14
|
end
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
=begin
|
19
15
|
|
20
|
-
|
21
|
-
|
22
|
-
test "should create contact" do
|
23
|
-
assert Contact.make :dynamic_values => {:a => 1, :b => 2}
|
24
|
-
end
|
25
|
-
|
26
|
-
test "should raise HstoreTypeMismatch" do
|
27
|
-
assert_raises ActiveRecord::HstoreTypeMismatch do
|
28
|
-
assert Contact.make :dynamic_values => "bug"
|
29
|
-
end
|
16
|
+
it "should convert empty hash" do
|
17
|
+
{}.to_hstore.should == "''"
|
30
18
|
end
|
31
19
|
|
32
|
-
|
33
|
-
|
34
|
-
assert_equal({'a' => '1', 'b' => 'Lorem ipsum', 'other stuff' => "'''a'''"}, Contact.find(contact.id).dynamic_values)
|
20
|
+
it "should convert empty string" do
|
21
|
+
''.from_hstore.should == {}
|
35
22
|
end
|
36
|
-
|
23
|
+
|
37
24
|
end
|
38
|
-
|
39
|
-
=end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-postgres-hstore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Juan Maiz
|
@@ -14,16 +15,18 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-09-
|
18
|
+
date: 2010-09-09 00:00:00 -03:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: rspec
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
27
30
|
segments:
|
28
31
|
- 1
|
29
32
|
- 2
|
@@ -54,6 +57,7 @@ files:
|
|
54
57
|
- lib/templates/setup_hstore.rb
|
55
58
|
- spec/activerecord-postgres-hstore_spec.rb
|
56
59
|
- README.textile
|
60
|
+
- spec/spec_helper.rb
|
57
61
|
has_rdoc: true
|
58
62
|
homepage: http://github.com/softa/activerecord-postgres-hstore
|
59
63
|
licenses: []
|
@@ -64,26 +68,30 @@ rdoc_options:
|
|
64
68
|
require_paths:
|
65
69
|
- lib
|
66
70
|
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
67
72
|
requirements:
|
68
73
|
- - ">="
|
69
74
|
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
70
76
|
segments:
|
71
77
|
- 0
|
72
78
|
version: "0"
|
73
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
74
81
|
requirements:
|
75
82
|
- - ">="
|
76
83
|
- !ruby/object:Gem::Version
|
84
|
+
hash: 3
|
77
85
|
segments:
|
78
86
|
- 0
|
79
87
|
version: "0"
|
80
88
|
requirements: []
|
81
89
|
|
82
90
|
rubyforge_project:
|
83
|
-
rubygems_version: 1.3.
|
91
|
+
rubygems_version: 1.3.7
|
84
92
|
signing_key:
|
85
93
|
specification_version: 3
|
86
94
|
summary: Goodbye serialize, hello hstore
|
87
95
|
test_files:
|
88
|
-
- spec/spec_helper.rb
|
89
96
|
- spec/activerecord-postgres-hstore_spec.rb
|
97
|
+
- spec/spec_helper.rb
|