activerecord-postgres-hstore 0.0.2 → 0.0.3

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
@@ -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