activerecord-postgres-hstore 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -116,7 +116,11 @@ or...
116
116
 
117
117
  And finally, if you need to delete keys in many rows, you can:
118
118
 
119
+ @Person.delete_key(:data, :foo)@
119
120
 
121
+ and with many keys:
122
+
123
+ @Person.delete_keys(:data, :foo, :bar)@
120
124
 
121
125
  Have fun.
122
126
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.3
@@ -1,17 +1,29 @@
1
- #raise ActiveRecord::ConnectionAdapters::Column.inspect
2
1
  require 'rails'
3
2
  require 'rails/generators'
4
3
  require 'rails/generators/migration'
5
- class Railtie < Rails::Railtie
4
+
5
+ # = Hstore Railtie
6
+ #
7
+ # Creates a new railtie for 2 reasons:
8
+ #
9
+ # * Initialize ActiveRecord properly
10
+ # * Add hstore:setup generator
11
+ class Hstore < Rails::Railtie
12
+
6
13
  initializer 'activerecord-postgres-hstore' do
7
14
  ActiveSupport.on_load :active_record do
8
15
  require "activerecord-postgres-hstore/activerecord"
9
16
  end
10
17
  end
11
- #rake_tasks do
12
- # load "lib/tasks/hstore.rake"
13
- #end
14
- class HstoreGenerator < Rails::Generators::Base
18
+
19
+ # Creates the hstore:setup generator. This generator creates a migration that
20
+ # adds hstore support for your database. If fact, it's just the sql from the
21
+ # contrib inside a migration. But it' s handy, isn't it?
22
+ #
23
+ # To use your generator, simply run it in your project:
24
+ #
25
+ # rails g hstore:setup
26
+ class Setup < Rails::Generators::Base
15
27
  include Rails::Generators::Migration
16
28
 
17
29
  def self.source_root
@@ -32,11 +44,5 @@ class Railtie < Rails::Railtie
32
44
 
33
45
  end
34
46
  end
35
-
36
-
37
-
38
-
39
-
40
- require "activerecord-postgres-hstore/hstore"
41
47
  require "activerecord-postgres-hstore/string"
42
- require "activerecord-postgres-hstore/hash"
48
+ require "activerecord-postgres-hstore/hash"
@@ -1,36 +1,53 @@
1
- # ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('data','','hstore').type
1
+ # Extends AR to add Hstore functionality.
2
2
  module ActiveRecord
3
+
4
+ # Adds methods for deleting keys in your hstore columns
3
5
  class Base
6
+
7
+ # Deletes all keys from a specific column in a model. E.g.
8
+ # Person.delete_key(:info, :father)
9
+ # The SQL generated will be:
10
+ # UPDATE "people" SET "info" = delete("info",'father');
4
11
  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])
12
+ raise "invalid attribute #{attribute}" unless column_names.include?(attribute.to_s)
13
+ update_all([%(#{attribute} = delete("#{attribute}",?)),key])
10
14
  end
15
+
16
+ # Deletes many keys from a specific column in a model. E.g.
17
+ # Person.delete_key(:info, :father, :mother)
18
+ # The SQL generated will be:
19
+ # UPDATE "people" SET "info" = delete(delete("info",'father'),'mother');
11
20
  def self.delete_keys attribute, *keys
12
- unless column_names.include?(attribute.to_s)
13
- raise "invalid attribute #{attribute}"
14
- end
21
+ raise "invalid attribute #{attribute}" unless column_names.include?(attribute.to_s)
15
22
  delete_str = "delete(#{attribute},?)"
16
- (keys.count-1).times do
17
- delete_str = "delete(#{delete_str},?)"
18
- end
23
+ (keys.count-1).times{ delete_str = "delete(#{delete_str},?)" }
19
24
  update_all(["#{attribute} = #{delete_str}", *keys])
20
25
  end
21
-
26
+
27
+ # Deletes a key in a record. E.g.
28
+ # witt = Person.find_by_name("Ludwig Wittgenstein")
29
+ # witt.destroy_key(:info, :father)
30
+ # It does not save the record, so you'll have to do it.
22
31
  def destroy_key attribute, key
23
- unless self.class.column_names.include?(attribute.to_s)
24
- raise "invalid attribute #{attribute}"
25
- end
32
+ raise "invalid attribute #{attribute}" unless self.class.column_names.include?(attribute.to_s)
26
33
  new_value = send(attribute)
27
34
  new_value.delete(key.to_s)
28
35
  send("#{attribute}=", new_value)
29
36
  self
30
37
  end
38
+
39
+ # Deletes a key in a record. E.g.
40
+ # witt = Person.find_by_name("Ludwig Wittgenstein")
41
+ # witt.destroy_key(:info, :father)
42
+ # It does save the record.
31
43
  def destroy_key! attribute, key
32
44
  destroy_key(attribute, key).save
33
45
  end
46
+
47
+ # Deletes many keys in a record. E.g.
48
+ # witt = Person.find_by_name("Ludwig Wittgenstein")
49
+ # witt.destroy_keys(:info, :father, :mother)
50
+ # It does not save the record, so you'll have to do it.
34
51
  def destroy_keys attribute, *keys
35
52
  for key in keys
36
53
  new_value = send(attribute)
@@ -39,23 +56,27 @@ module ActiveRecord
39
56
  end
40
57
  self
41
58
  end
59
+
60
+ # Deletes many keys in a record. E.g.
61
+ # witt = Person.find_by_name("Ludwig Wittgenstein")
62
+ # witt.destroy_keys!(:info, :father, :mother)
63
+ # It does save the record.
42
64
  def destroy_keys! attribute, *keys
43
- unless self.class.column_names.include?(attribute.to_s)
44
- raise "invalid attribute #{attribute}"
45
- end
65
+ raise "invalid attribute #{attribute}" unless self.class.column_names.include?(attribute.to_s)
46
66
  destroy_keys(attribute, *keys).save
47
67
  end
48
68
 
49
- # For Rails 3 compat :D
50
- #alias :old_arel_attributes_values :arel_attributes_values
69
+ # This method is replaced for Rails 3 compatibility.
70
+ # All I do is add the condition when the field is a hash that converts the value
71
+ # to hstore format.
72
+ # IMHO this should be delegated to the column, so it won't be necessary to rewrite all
73
+ # this method.
51
74
  def arel_attributes_values(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
52
75
  attrs = {}
53
76
  attribute_names.each do |name|
54
77
  if (column = column_for_attribute(name)) && (include_primary_key || !column.primary)
55
-
56
78
  if include_readonly_attributes || (!include_readonly_attributes && !self.class.readonly_attributes.include?(name))
57
79
  value = read_attribute(name)
58
-
59
80
  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))
60
81
  if self.class.columns_hash[name].type == :hstore
61
82
  value = value.to_hstore # Done!
@@ -69,45 +90,62 @@ module ActiveRecord
69
90
  end
70
91
  attrs
71
92
  end
93
+
72
94
  end
95
+
96
+ # This erro class is used when the user passes a wrong value to a hstore column.
97
+ # Hstore columns accepts hashes or hstore valid strings. It is validated with
98
+ # String#valid_hstore? method.
73
99
  class HstoreTypeMismatch < ActiveRecord::ActiveRecordError
74
100
  end
101
+
75
102
  module ConnectionAdapters
76
-
103
+
77
104
  class TableDefinition
78
- # Adds hstore type for migrations
105
+
106
+ # Adds hstore type for migrations. So you can add columns to a table like:
107
+ # create_table :people do |t|
108
+ # ...
109
+ # t.hstore :info
110
+ # ...
111
+ # end
79
112
  def hstore(*args)
80
113
  options = args.extract_options!
81
114
  column_names = args
82
115
  column_names.each { |name| column(name, 'hstore', options) }
83
116
  end
117
+
84
118
  end
85
119
 
86
120
  class PostgreSQLColumn < Column
87
121
  alias :old_type_cast_code :type_cast_code
88
122
  alias :old_simplified_type :simplified_type
89
- alias :old_klass :klass
123
+
124
+ # Does the type casting from hstore columns using String#from_hstore or Hash#from_hstore.
90
125
  def type_cast_code(var_name)
91
126
  type == :hstore ? "#{var_name}.from_hstore" : old_type_cast_code(var_name)
92
127
  end
128
+
129
+ # Adds the hstore type for the column.
93
130
  def simplified_type(field_type)
94
131
  field_type =~ /^hstore$/ ? :hstore : old_simplified_type(field_type)
95
132
  end
96
- def klass
97
- type == :hstore ? Hstore : old_klass
98
- end
133
+
99
134
  end
135
+
100
136
  class PostgreSQLAdapter < AbstractAdapter
137
+
101
138
  alias :old_quote :quote
139
+ alias :old_columns :columns
140
+
141
+ # Quotes correctly a hstore column value.
102
142
  def quote(value, column = nil)
103
143
  if value && column && column.sql_type =~ /^hstore$/
104
- if ! value.kind_of?(Hash) and ! value.valid_hstore?
105
- raise HstoreTypeMismatch, "#{column.name} must have a Hash or a valid hstore value (#{value})"
106
- end
144
+ raise HstoreTypeMismatch, "#{column.name} must have a Hash or a valid hstore value (#{value})" unless value.kind_of?(Hash) || value.valid_hstore?
107
145
  return value.to_hstore
108
146
  end
109
147
  old_quote(value,column)
110
148
  end
111
149
  end
112
150
  end
113
- end
151
+ end
@@ -1,11 +1,14 @@
1
1
  class Hash
2
2
 
3
+ # Generates a single quoted hstore string format. This is the format used
4
+ # to insert or update stuff in the database.
3
5
  def to_hstore
4
6
  return "''" if empty?
5
7
  #@todo DIOGO! Check security issues with this quoting pleaz
6
8
  map{|idx,val| "('#{idx}'=>'#{val.to_s.gsub(/'/,"''")}')" }.join(' || ')
7
9
  end
8
10
 
11
+ # If the method from_hstore is called in a Hash, it just returns self.
9
12
  def from_hstore
10
13
  self
11
14
  end
@@ -1,9 +1,15 @@
1
1
  class String
2
2
 
3
+ # If the value os a column is already a String and it calls to_hstore, it
4
+ # just returns self. Validation occurs afterwards.
3
5
  def to_hstore
4
6
  self
5
7
  end
6
8
 
9
+ # Validates the hstore format. Valid formats are:
10
+ # * An empty string
11
+ # * A string like %("foo"=>"bar"). I'll call it a "double quoted hstore format".
12
+ # * A string like %('foo'=>'bar'). I'll call it a "single quoted hstore format".
7
13
  def valid_hstore?
8
14
  return true if empty? || self == "''"
9
15
  # This is what comes from the database
@@ -16,6 +22,8 @@ class String
16
22
  self.match(dbl_quotes_re) || self.match(sngl_quotes_re)
17
23
  end
18
24
 
25
+ # Creates a hash from a valid double quoted hstore format, 'cause this is the format
26
+ # that postgresql spits out.
19
27
  def from_hstore
20
28
  Hash[ scan(/"([^"]+)"=>"([^"]+)"/) ]
21
29
  end
metadata CHANGED
@@ -1,13 +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
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Juan Maiz
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-09 00:00:00 -03:00
18
+ date: 2010-09-12 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -52,7 +52,6 @@ files:
52
52
  - lib/activerecord-postgres-hstore.rb
53
53
  - lib/activerecord-postgres-hstore/activerecord.rb
54
54
  - lib/activerecord-postgres-hstore/hash.rb
55
- - lib/activerecord-postgres-hstore/hstore.rb
56
55
  - lib/activerecord-postgres-hstore/string.rb
57
56
  - lib/templates/setup_hstore.rb
58
57
  - spec/activerecord-postgres-hstore_spec.rb
@@ -1,2 +0,0 @@
1
- class Hstore < Hash
2
- end