activerecord-postgres-hstore 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Juan Maiz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,109 @@
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, time in milliseconds.
22
+
23
+ .h2 Requirements
24
+
25
+ Postgresql 8.4 with contrib and Rails 3. (It might work on 2.3.x with minor patches...)
26
+
27
+ .h2 Install
28
+
29
+ Hstore is a postgres contrib type. Check it out first:
30
+
31
+ http://www.postgresql.org/docs/8.4/static/hstore.html
32
+
33
+ Then, just add this to your Gemfile:
34
+
35
+ gem 'activerecord-postgres-hstore'
36
+
37
+ And run your bundler:
38
+
39
+ bundle install
40
+
41
+ Now you need to create a migration that adds hstore support for your postgresql database:
42
+
43
+ rails g railtie:hstore
44
+
45
+ Run it:
46
+
47
+ rake db:migrate
48
+
49
+ Finally you can create your own tables using hstore type. It's easy:
50
+
51
+ rails g model Person name:string data:hstore
52
+
53
+ You're done.
54
+
55
+ Well, not yet. Don't forget to add indexes. Like this:
56
+
57
+ CREATE INDEX people_gist_data ON people USING GIST(data);
58
+ -- or
59
+ CREATE INDEX people_gin_data ON people USING GIN(data);
60
+
61
+ To my experience GIN is faster for searching records.
62
+
63
+ .h2 Usage
64
+
65
+ 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
+
67
+ Find records that contains a key named 'foo':
68
+
69
+ Person.where("data ? 'foo'")
70
+
71
+ Find records where 'foo' is equal to 'bar':
72
+
73
+ Person.where("data -> 'foo' = 'bar'")
74
+
75
+ This same sql is at least twice as fast (using indexes) if you do it that way:
76
+
77
+ Person.where("data @> 'foo=>bar'")
78
+
79
+ Find records where 'foo' is not equal to 'bar':
80
+
81
+ Person.where("data -> 'foo' <> 'bar'")
82
+ # or
83
+ Person.where("not data @> 'foo=>bar'")
84
+
85
+ Find records where 'foo' is like 'bar':
86
+
87
+ Person.where("data -> 'foo' LIKE '%bar%'")
88
+ # or something like ...
89
+ Person.where("data -> 'foo' ILIKE '%bar%'")
90
+
91
+ Have fun.
92
+
93
+ .h2 Help
94
+
95
+ You can use issues in github for that. Or else you can reach me at twitter: @joaomilho
96
+
97
+ .h2 Note on Patches/Pull Requests
98
+
99
+ * Fork the project.
100
+ * Make your feature addition or bug fix.
101
+ * Add tests for it. This is important so I don't break it in a
102
+ future version unintentionally.
103
+ * Commit, do not mess with rakefile, version, or history.
104
+ (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
+ * Send me a pull request. Bonus points for topic branches.
106
+
107
+ .h2 Copyright
108
+
109
+ Copyright (c) 2010 Juan Maiz. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "activerecord-postgres-hstore"
8
+ gem.summary = %Q{Goodbye serialize, hello hstore}
9
+ gem.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.}
10
+ gem.email = "juanmaiz@gmail.com"
11
+ gem.homepage = "http://github.com/softa/activerecord-postgres-hstore"
12
+ gem.authors = ["Juan Maiz"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.files = FileList['.document', '.gitignore', 'LICENSE', 'README.rdoc', 'Rakefile', 'VERSION', 'spec/**/*_spec.rb', 'lib/**/*.rb'].to_a
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'spec/rake/spectask'
23
+ Spec::Rake::SpecTask.new(:spec) do |spec|
24
+ spec.libs << 'lib' << 'spec'
25
+ spec.spec_files = FileList['spec/**/*_spec.rb']
26
+ end
27
+
28
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.pattern = 'spec/**/*_spec.rb'
31
+ spec.rcov = true
32
+ end
33
+
34
+ task :spec => :check_dependencies
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+ rdoc.rdoc_dir = 'rdoc'
41
+ rdoc.title = "activerecord-postgres-hstore #{version}"
42
+ rdoc.rdoc_files.include('README*')
43
+ rdoc.rdoc_files.include('lib/**/*.rb')
44
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,42 @@
1
+ #raise ActiveRecord::ConnectionAdapters::Column.inspect
2
+ require 'rails'
3
+ require 'rails/generators'
4
+ require 'rails/generators/migration'
5
+ class Railtie < Rails::Railtie
6
+ initializer 'activerecord-postgres-hstore' do
7
+ ActiveSupport.on_load :active_record do
8
+ require "activerecord-postgres-hstore/activerecord"
9
+ end
10
+ end
11
+ #rake_tasks do
12
+ # load "lib/tasks/hstore.rake"
13
+ #end
14
+ class HstoreGenerator < Rails::Generators::Base
15
+ include Rails::Generators::Migration
16
+
17
+ def self.source_root
18
+ @source_root ||= File.join(File.dirname(__FILE__), 'templates')
19
+ end
20
+
21
+ def self.next_migration_number(dirname)
22
+ if ActiveRecord::Base.timestamped_migrations
23
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
24
+ else
25
+ "%.3d" % (current_migration_number(dirname) + 1)
26
+ end
27
+ end
28
+
29
+ def create_migration_file
30
+ migration_template 'setup_hstore.rb', 'db/migrate/setup_hstore.rb'
31
+ end
32
+
33
+ end
34
+ end
35
+
36
+
37
+
38
+
39
+
40
+ require "activerecord-postgres-hstore/hstore"
41
+ require "activerecord-postgres-hstore/string"
42
+ require "activerecord-postgres-hstore/hash"
@@ -0,0 +1,68 @@
1
+ # ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('data','','hstore').type
2
+ module ActiveRecord
3
+ class Base
4
+ # For Rails 3 compat :D
5
+ #alias :old_arel_attributes_values :arel_attributes_values
6
+ def arel_attributes_values(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
7
+ attrs = {}
8
+ attribute_names.each do |name|
9
+ if (column = column_for_attribute(name)) && (include_primary_key || !column.primary)
10
+
11
+ if include_readonly_attributes || (!include_readonly_attributes && !self.class.readonly_attributes.include?(name))
12
+ value = read_attribute(name)
13
+
14
+ if value && ((self.class.serialized_attributes.has_key?(name) && (value.acts_like?(:date) || value.acts_like?(:time))) || value.is_a?(Hash) || value.is_a?(Array))
15
+ if self.class.columns_hash[name].type == :hstore
16
+ value = value.to_hstore # Done!
17
+ else
18
+ value = value.to_yaml
19
+ end
20
+ end
21
+ attrs[self.class.arel_table[name]] = value
22
+ end
23
+ end
24
+ end
25
+ attrs
26
+ end
27
+ end
28
+ class HstoreTypeMismatch < ActiveRecord::ActiveRecordError
29
+ end
30
+ module ConnectionAdapters
31
+
32
+ class TableDefinition
33
+ # Adds hstore type for migrations
34
+ def hstore(*args)
35
+ options = args.extract_options!
36
+ column_names = args
37
+ column_names.each { |name| column(name, 'hstore', options) }
38
+ end
39
+ end
40
+
41
+ class PostgreSQLColumn < Column
42
+ alias :old_type_cast_code :type_cast_code
43
+ alias :old_simplified_type :simplified_type
44
+ alias :old_klass :klass
45
+ def type_cast_code(var_name)
46
+ type == :hstore ? "#{var_name}.from_hstore" : old_type_cast_code(var_name)
47
+ end
48
+ def simplified_type(field_type)
49
+ field_type =~ /^hstore$/ ? :hstore : old_simplified_type(field_type)
50
+ end
51
+ def klass
52
+ type == :hstore ? Hstore : old_klass
53
+ end
54
+ end
55
+ class PostgreSQLAdapter < AbstractAdapter
56
+ alias :old_quote :quote
57
+ def quote(value, column = nil)
58
+ if value && column && column.sql_type =~ /^hstore$/
59
+ if ! value.kind_of?(Hash) and ! value.valid_hstore?
60
+ raise HstoreTypeMismatch, "#{column.name} must have a Hash or a valid hstore value (#{value})"
61
+ end
62
+ return value.to_hstore
63
+ end
64
+ old_quote(value,column)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,12 @@
1
+ class Hash
2
+
3
+ def to_hstore
4
+ #@todo DIOGO! Check security issues with this quoting pleaz
5
+ map{|idx,val| "('#{idx}'=>'#{val.to_s.gsub(/'/,"''")}')" }.join(' || ')
6
+ end
7
+
8
+ def from_hstore
9
+ self
10
+ end
11
+
12
+ end
@@ -0,0 +1,2 @@
1
+ class Hstore < Hash
2
+ end
@@ -0,0 +1,22 @@
1
+ class String
2
+
3
+ def to_hstore
4
+ self
5
+ end
6
+
7
+ def valid_hstore?
8
+ # This is what comes from the database
9
+ dbl_quotes_re = /"([^"]+)"=>"([^"]+)"/
10
+ # TODO
11
+ # This is what comes from the plugin
12
+ # this is a big problem, 'cause regexes does not know how to count...
13
+ # how should i very values quoted with two single quotes? using .+ sux.
14
+ sngl_quotes_re = /'(.+)'=>'(.+)'/
15
+ self.match(dbl_quotes_re) || self.match(sngl_quotes_re)
16
+ end
17
+
18
+ def from_hstore
19
+ Hash[ scan(/"([^"]+)"=>"([^"]+)"/) ]
20
+ end
21
+
22
+ end
@@ -0,0 +1,277 @@
1
+ class SetupHstore < ActiveRecord::Migration
2
+ def self.up
3
+ sql = <<-HSTORE_SQL
4
+ /* $PostgreSQL: pgsql/contrib/hstore/hstore.sql.in,v 1.11 2009/06/11 18:30:03 tgl Exp $ */
5
+
6
+ -- Adjust this setting to control where the objects get created.
7
+ SET search_path = public;
8
+
9
+ CREATE TYPE hstore;
10
+
11
+ CREATE OR REPLACE FUNCTION hstore_in(cstring)
12
+ RETURNS hstore
13
+ AS '$libdir/hstore'
14
+ LANGUAGE C STRICT;
15
+
16
+ CREATE OR REPLACE FUNCTION hstore_out(hstore)
17
+ RETURNS cstring
18
+ AS '$libdir/hstore'
19
+ LANGUAGE C STRICT;
20
+
21
+ CREATE TYPE hstore (
22
+ INTERNALLENGTH = -1,
23
+ INPUT = hstore_in,
24
+ OUTPUT = hstore_out,
25
+ STORAGE = extended
26
+ );
27
+
28
+ CREATE OR REPLACE FUNCTION fetchval(hstore,text)
29
+ RETURNS text
30
+ AS '$libdir/hstore'
31
+ LANGUAGE C STRICT IMMUTABLE;
32
+
33
+ CREATE OPERATOR -> (
34
+ LEFTARG = hstore,
35
+ RIGHTARG = text,
36
+ PROCEDURE = fetchval
37
+ );
38
+
39
+ CREATE OR REPLACE FUNCTION isexists(hstore,text)
40
+ RETURNS bool
41
+ AS '$libdir/hstore','exists'
42
+ LANGUAGE C STRICT IMMUTABLE;
43
+
44
+ CREATE OR REPLACE FUNCTION exist(hstore,text)
45
+ RETURNS bool
46
+ AS '$libdir/hstore','exists'
47
+ LANGUAGE C STRICT IMMUTABLE;
48
+
49
+ CREATE OPERATOR ? (
50
+ LEFTARG = hstore,
51
+ RIGHTARG = text,
52
+ PROCEDURE = exist,
53
+ RESTRICT = contsel,
54
+ JOIN = contjoinsel
55
+ );
56
+
57
+ CREATE OR REPLACE FUNCTION isdefined(hstore,text)
58
+ RETURNS bool
59
+ AS '$libdir/hstore','defined'
60
+ LANGUAGE C STRICT IMMUTABLE;
61
+
62
+ CREATE OR REPLACE FUNCTION defined(hstore,text)
63
+ RETURNS bool
64
+ AS '$libdir/hstore','defined'
65
+ LANGUAGE C STRICT IMMUTABLE;
66
+
67
+ CREATE OR REPLACE FUNCTION delete(hstore,text)
68
+ RETURNS hstore
69
+ AS '$libdir/hstore','delete'
70
+ LANGUAGE C STRICT IMMUTABLE;
71
+
72
+ CREATE OR REPLACE FUNCTION hs_concat(hstore,hstore)
73
+ RETURNS hstore
74
+ AS '$libdir/hstore'
75
+ LANGUAGE C STRICT IMMUTABLE;
76
+
77
+ CREATE OPERATOR || (
78
+ LEFTARG = hstore,
79
+ RIGHTARG = hstore,
80
+ PROCEDURE = hs_concat
81
+ );
82
+
83
+ CREATE OR REPLACE FUNCTION hs_contains(hstore,hstore)
84
+ RETURNS bool
85
+ AS '$libdir/hstore'
86
+ LANGUAGE C STRICT IMMUTABLE;
87
+
88
+ CREATE OR REPLACE FUNCTION hs_contained(hstore,hstore)
89
+ RETURNS bool
90
+ AS '$libdir/hstore'
91
+ LANGUAGE C STRICT IMMUTABLE;
92
+
93
+ CREATE OPERATOR @> (
94
+ LEFTARG = hstore,
95
+ RIGHTARG = hstore,
96
+ PROCEDURE = hs_contains,
97
+ COMMUTATOR = '<@',
98
+ RESTRICT = contsel,
99
+ JOIN = contjoinsel
100
+ );
101
+
102
+ CREATE OPERATOR <@ (
103
+ LEFTARG = hstore,
104
+ RIGHTARG = hstore,
105
+ PROCEDURE = hs_contained,
106
+ COMMUTATOR = '@>',
107
+ RESTRICT = contsel,
108
+ JOIN = contjoinsel
109
+ );
110
+
111
+ -- obsolete:
112
+ CREATE OPERATOR @ (
113
+ LEFTARG = hstore,
114
+ RIGHTARG = hstore,
115
+ PROCEDURE = hs_contains,
116
+ COMMUTATOR = '~',
117
+ RESTRICT = contsel,
118
+ JOIN = contjoinsel
119
+ );
120
+
121
+ CREATE OPERATOR ~ (
122
+ LEFTARG = hstore,
123
+ RIGHTARG = hstore,
124
+ PROCEDURE = hs_contained,
125
+ COMMUTATOR = '@',
126
+ RESTRICT = contsel,
127
+ JOIN = contjoinsel
128
+ );
129
+
130
+ CREATE OR REPLACE FUNCTION tconvert(text,text)
131
+ RETURNS hstore
132
+ AS '$libdir/hstore'
133
+ LANGUAGE C IMMUTABLE; -- not STRICT
134
+
135
+ CREATE OPERATOR => (
136
+ LEFTARG = text,
137
+ RIGHTARG = text,
138
+ PROCEDURE = tconvert
139
+ );
140
+
141
+ CREATE OR REPLACE FUNCTION akeys(hstore)
142
+ RETURNS _text
143
+ AS '$libdir/hstore'
144
+ LANGUAGE C STRICT IMMUTABLE;
145
+
146
+ CREATE OR REPLACE FUNCTION avals(hstore)
147
+ RETURNS _text
148
+ AS '$libdir/hstore'
149
+ LANGUAGE C STRICT IMMUTABLE;
150
+
151
+ CREATE OR REPLACE FUNCTION skeys(hstore)
152
+ RETURNS setof text
153
+ AS '$libdir/hstore'
154
+ LANGUAGE C STRICT IMMUTABLE;
155
+
156
+ CREATE OR REPLACE FUNCTION svals(hstore)
157
+ RETURNS setof text
158
+ AS '$libdir/hstore'
159
+ LANGUAGE C STRICT IMMUTABLE;
160
+
161
+ CREATE OR REPLACE FUNCTION each(IN hs hstore,
162
+ OUT key text,
163
+ OUT value text)
164
+ RETURNS SETOF record
165
+ AS '$libdir/hstore'
166
+ LANGUAGE C STRICT IMMUTABLE;
167
+
168
+
169
+
170
+ -- define the GiST support methods
171
+
172
+ CREATE TYPE ghstore;
173
+
174
+ CREATE OR REPLACE FUNCTION ghstore_in(cstring)
175
+ RETURNS ghstore
176
+ AS '$libdir/hstore'
177
+ LANGUAGE C STRICT;
178
+
179
+ CREATE OR REPLACE FUNCTION ghstore_out(ghstore)
180
+ RETURNS cstring
181
+ AS '$libdir/hstore'
182
+ LANGUAGE C STRICT;
183
+
184
+ CREATE TYPE ghstore (
185
+ INTERNALLENGTH = -1,
186
+ INPUT = ghstore_in,
187
+ OUTPUT = ghstore_out
188
+ );
189
+
190
+ CREATE OR REPLACE FUNCTION ghstore_compress(internal)
191
+ RETURNS internal
192
+ AS '$libdir/hstore'
193
+ LANGUAGE C IMMUTABLE STRICT;
194
+
195
+ CREATE OR REPLACE FUNCTION ghstore_decompress(internal)
196
+ RETURNS internal
197
+ AS '$libdir/hstore'
198
+ LANGUAGE C IMMUTABLE STRICT;
199
+
200
+ CREATE OR REPLACE FUNCTION ghstore_penalty(internal,internal,internal)
201
+ RETURNS internal
202
+ AS '$libdir/hstore'
203
+ LANGUAGE C IMMUTABLE STRICT;
204
+
205
+ CREATE OR REPLACE FUNCTION ghstore_picksplit(internal, internal)
206
+ RETURNS internal
207
+ AS '$libdir/hstore'
208
+ LANGUAGE C IMMUTABLE STRICT;
209
+
210
+ CREATE OR REPLACE FUNCTION ghstore_union(internal, internal)
211
+ RETURNS internal
212
+ AS '$libdir/hstore'
213
+ LANGUAGE C IMMUTABLE STRICT;
214
+
215
+ CREATE OR REPLACE FUNCTION ghstore_same(internal, internal, internal)
216
+ RETURNS internal
217
+ AS '$libdir/hstore'
218
+ LANGUAGE C IMMUTABLE STRICT;
219
+
220
+ CREATE OR REPLACE FUNCTION ghstore_consistent(internal,internal,int,oid,internal)
221
+ RETURNS bool
222
+ AS '$libdir/hstore'
223
+ LANGUAGE C IMMUTABLE STRICT;
224
+
225
+ -- register the opclass for indexing (not as default)
226
+ CREATE OPERATOR CLASS gist_hstore_ops
227
+ DEFAULT FOR TYPE hstore USING gist
228
+ AS
229
+ OPERATOR 7 @> ,
230
+ OPERATOR 9 ?(hstore,text) ,
231
+ --OPERATOR 8 <@ ,
232
+ OPERATOR 13 @ ,
233
+ --OPERATOR 14 ~ ,
234
+ FUNCTION 1 ghstore_consistent (internal, internal, int, oid, internal),
235
+ FUNCTION 2 ghstore_union (internal, internal),
236
+ FUNCTION 3 ghstore_compress (internal),
237
+ FUNCTION 4 ghstore_decompress (internal),
238
+ FUNCTION 5 ghstore_penalty (internal, internal, internal),
239
+ FUNCTION 6 ghstore_picksplit (internal, internal),
240
+ FUNCTION 7 ghstore_same (internal, internal, internal),
241
+ STORAGE ghstore;
242
+
243
+ -- define the GIN support methods
244
+
245
+ CREATE OR REPLACE FUNCTION gin_extract_hstore(internal, internal)
246
+ RETURNS internal
247
+ AS '$libdir/hstore'
248
+ LANGUAGE C IMMUTABLE STRICT;
249
+
250
+ CREATE OR REPLACE FUNCTION gin_extract_hstore_query(internal, internal, int2, internal, internal)
251
+ RETURNS internal
252
+ AS '$libdir/hstore'
253
+ LANGUAGE C IMMUTABLE STRICT;
254
+
255
+ CREATE OR REPLACE FUNCTION gin_consistent_hstore(internal, int2, internal, int4, internal, internal)
256
+ RETURNS bool
257
+ AS '$libdir/hstore'
258
+ LANGUAGE C IMMUTABLE STRICT;
259
+
260
+ CREATE OPERATOR CLASS gin_hstore_ops
261
+ DEFAULT FOR TYPE hstore USING gin
262
+ AS
263
+ OPERATOR 7 @> ,
264
+ OPERATOR 9 ?(hstore,text),
265
+ FUNCTION 1 bttextcmp(text,text),
266
+ FUNCTION 2 gin_extract_hstore(internal, internal),
267
+ FUNCTION 3 gin_extract_hstore_query(internal, internal, int2, internal, internal),
268
+ FUNCTION 4 gin_consistent_hstore(internal, int2, internal, int4, internal, internal),
269
+ STORAGE text;
270
+ HSTORE_SQL
271
+ execute sql
272
+ end
273
+
274
+ def self.down
275
+ # Kinda... hard.
276
+ end
277
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "ActiverecordPostgresHstore" do
4
+ it "should convert hstore string to hash" do
5
+ {:a => 1, :b => 2}.to_hstore.should == "('a'=>'1') || ('b'=>'2')"
6
+ end
7
+
8
+ it "should convert hash to hstore string" do
9
+ '"a"=>"1", "b"=>"2"'.from_hstore.should == {'a' => '1', 'b' => '2'}
10
+ end
11
+
12
+ it "should quote correctly" do
13
+ {:a => "'a'"}.to_hstore.should == "('a'=>'''a''')"
14
+ end
15
+
16
+ end
17
+
18
+ =begin
19
+
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
30
+ end
31
+
32
+ test "should read values from contact" do
33
+ contact = Contact.make :dynamic_values => {:a => 1, :b => "Lorem ipsum", 'other stuff' => "'''a'''"}
34
+ assert_equal({'a' => '1', 'b' => 'Lorem ipsum', 'other stuff' => "'''a'''"}, Contact.find(contact.id).dynamic_values)
35
+ end
36
+
37
+ end
38
+
39
+ =end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'activerecord-postgres-hstore'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activerecord-postgres-hstore
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Juan Maiz
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-09-08 00:00:00 -03:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
31
+ version: 1.2.9
32
+ type: :development
33
+ version_requirements: *id001
34
+ 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.
35
+ email: juanmaiz@gmail.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - LICENSE
42
+ - README.textile
43
+ files:
44
+ - .document
45
+ - .gitignore
46
+ - LICENSE
47
+ - Rakefile
48
+ - VERSION
49
+ - lib/activerecord-postgres-hstore.rb
50
+ - lib/activerecord-postgres-hstore/activerecord.rb
51
+ - lib/activerecord-postgres-hstore/hash.rb
52
+ - lib/activerecord-postgres-hstore/hstore.rb
53
+ - lib/activerecord-postgres-hstore/string.rb
54
+ - lib/templates/setup_hstore.rb
55
+ - spec/activerecord-postgres-hstore_spec.rb
56
+ - README.textile
57
+ has_rdoc: true
58
+ homepage: http://github.com/softa/activerecord-postgres-hstore
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --charset=UTF-8
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.3.6
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Goodbye serialize, hello hstore
87
+ test_files:
88
+ - spec/spec_helper.rb
89
+ - spec/activerecord-postgres-hstore_spec.rb