hstore_accessor 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b556f080454175cefffda39846659bbc7eb676ea
4
- data.tar.gz: c3b7cecfc960a65db15944e4f8579d941f59a708
3
+ metadata.gz: ed6227f16f31ca2c856584b8e72ae0fb9065f659
4
+ data.tar.gz: f08a8c2cdf12a47e7ed620289fdbf9fa1677e46b
5
5
  SHA512:
6
- metadata.gz: a96e5670fc7ff405146da7f0560bb67af29738ffbae2c209db60d6231cdea90624f8b61c2d8936d88d3c8688a7229ebbd07f6169b9e9816a8583e2a44c066a72
7
- data.tar.gz: fde2a6addc657fe910ff609c087e90673855a88de590256481c36c3a69a797ae2dbc563b8dbf0afa2af259efb2fe53689e4336fedb86d5ed44240e911d2e3299
6
+ metadata.gz: 9617209ac08dd3fbc9a48fdd56866396bb3098e127f66e51c9182f09f565f21f2e9cd084917c9e31f3b60c0e99aec11b312f70d1213df4e80f995d41479267db
7
+ data.tar.gz: fd258525d2f42d3fc42604d000b1302938459d5ad3d65c5d994c11a3209932b0c9181a4058c4144bcbb54c14fcdd3d45aeadd9431655ad3d6a4cf94b4f020819
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ logfile
data/README.md CHANGED
@@ -27,7 +27,7 @@ Or install it yourself as:
27
27
  The `hstore_accessor` method accepts the name of the hstore column you'd
28
28
  like to use and a hash with keys representing fields and values
29
29
  indicating the type to be stored in that field. The available types
30
- are: `string`, `integer`, `float`, `time`, `array`, and `hash`.
30
+ are: `string`, `integer`, `float`, `time`, `boolean`, `array`, and `hash`.
31
31
 
32
32
  ```ruby
33
33
  class Product < ActiveRecord::Base
@@ -51,6 +51,7 @@ p.color = "green"
51
51
  p.weight = 34
52
52
  p.price = 99.95
53
53
  p.built_at = Time.now - 10.days
54
+ p.popular = true
54
55
  p.tags = ["housewares", "kitchen"]
55
56
  p.ratings = { user_a: 3, user_b: 4 }
56
57
  ```
@@ -58,14 +59,14 @@ p.ratings = { user_a: 3, user_b: 4 }
58
59
  Reading these fields works as well.
59
60
 
60
61
  ```ruby
61
- p.color #=> "green
62
+ p.color #=> "green"
62
63
  p.tags #=> ["housewares", "kitchen"]
63
64
  ```
64
65
 
65
66
  ### Scopes
66
67
 
67
68
  The `hstore_accessor` macro also creates scopes for `string`, `integer`,
68
- `float`, `time`, and `array` fields.
69
+ `float`, `time`, `boolean`, and `array` fields.
69
70
 
70
71
  #### String Fields
71
72
 
@@ -108,6 +109,15 @@ Product.tags_contains("kitchen") # tags containing a single val
108
109
  Product.tags_contains(["housewares", "kitchen"]) # tags containing a number of values
109
110
  ```
110
111
 
112
+ #### Boolean Fields
113
+
114
+ Two scopes are created for `boolean` fields:
115
+
116
+ ```ruby
117
+ Product.is_popular # => when populer is set to true
118
+ Product.not_popular # => when populer is set to false
119
+ ```
120
+
111
121
  ### Single-table Inheritance
112
122
 
113
123
  One of the big issues with `ActiveRecord` single-table inheritance (STI)
@@ -165,6 +175,7 @@ individual fields in an `hstore` column.
165
175
  This approach was originally concieved by Joe Hirn in [this blog
166
176
  post](http://www.devmynd.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination).
167
177
 
178
+
168
179
  ## Contributing
169
180
 
170
181
  1. Fork it
@@ -6,7 +6,7 @@ module HstoreAccessor
6
6
 
7
7
  InvalidDataTypeError = Class.new(StandardError)
8
8
 
9
- VALID_TYPES = [:string, :integer, :float, :time, :array, :hash]
9
+ VALID_TYPES = [:string, :integer, :float, :time, :boolean, :array, :hash]
10
10
 
11
11
  SEPARATOR = ";|;"
12
12
 
@@ -14,17 +14,19 @@ module HstoreAccessor
14
14
  DEFAULT_DESERIALIZER = ->(value) { value.to_s }
15
15
 
16
16
  SERIALIZERS = {
17
- :array => ->(value) { value.join(SEPARATOR) },
18
- :hash => ->(value) { value.to_json },
19
- :time => ->(value) { value.to_i }
17
+ :array => -> value { (value && value.join(SEPARATOR)) || "" },
18
+ :hash => -> value { (value && value.to_json) || {} },
19
+ :time => -> value { value.to_i },
20
+ :boolean => -> value { (value == true).to_s }
20
21
  }
21
22
 
22
23
  DESERIALIZERS = {
23
- :array => ->(value) { value.split(SEPARATOR) },
24
- :hash => ->(value) { JSON.parse(value) },
25
- :integer => ->(value) { value.to_i },
26
- :float => ->(value) { value.to_f },
27
- :time => ->(value) { Time.at(value.to_i) }
24
+ :array => -> value { (value && value.split(SEPARATOR)) || [] },
25
+ :hash => -> value { JSON.parse(value) },
26
+ :integer => -> value { value.to_i },
27
+ :float => -> value { value.to_f },
28
+ :time => -> value { Time.at(value.to_i) },
29
+ :boolean => -> value { value == "true" }
28
30
  }
29
31
 
30
32
  def self.included(base)
@@ -59,23 +61,28 @@ module HstoreAccessor
59
61
  deserialize(type, value)
60
62
  end
61
63
 
64
+ query_field = "#{hstore_attribute} -> '#{key}'"
65
+
62
66
  case type
63
67
  when :string
64
- send(:scope, "with_#{key}", -> value { where("#{hstore_attribute} -> '#{key}' = ?", value.to_s) })
68
+ send(:scope, "with_#{key}", -> value { where("#{query_field} = ?", value.to_s) })
65
69
  when :integer, :float
66
- send(:scope, "#{key}_lt", -> value { where("#{hstore_attribute} -> '#{key}' < ?", value.to_s) })
67
- send(:scope, "#{key}_lte", -> value { where("#{hstore_attribute} -> '#{key}' <= ?", value.to_s) })
68
- send(:scope, "#{key}_eq", -> value { where("#{hstore_attribute} -> '#{key}' = ?", value.to_s) })
69
- send(:scope, "#{key}_gte", -> value { where("#{hstore_attribute} -> '#{key}' >= ?", value.to_s) })
70
- send(:scope, "#{key}_gt", -> value { where("#{hstore_attribute} -> '#{key}' > ?", value.to_s) })
70
+ send(:scope, "#{key}_lt", -> value { where("(#{query_field})::#{type} < ?", value.to_s) })
71
+ send(:scope, "#{key}_lte", -> value { where("(#{query_field})::#{type} <= ?", value.to_s) })
72
+ send(:scope, "#{key}_eq", -> value { where("(#{query_field})::#{type} = ?", value.to_s) })
73
+ send(:scope, "#{key}_gte", -> value { where("(#{query_field})::#{type} >= ?", value.to_s) })
74
+ send(:scope, "#{key}_gt", -> value { where("(#{query_field})::#{type} > ?", value.to_s) })
71
75
  when :time
72
- send(:scope, "#{key}_before", -> value { where("to_number(#{hstore_attribute} -> '#{key}', '99999999999') < ?", value.to_i) })
73
- send(:scope, "#{key}_eq", -> value { where("to_number(#{hstore_attribute} -> '#{key}', '99999999999') = ?", value.to_i) })
74
- send(:scope, "#{key}_after", -> value { where("to_number(#{hstore_attribute} -> '#{key}', '99999999999') > ?", value.to_i) })
76
+ send(:scope, "#{key}_before", -> value { where("(#{query_field})::integer < ?", value.to_i) })
77
+ send(:scope, "#{key}_eq", -> value { where("(#{query_field})::integer = ?", value.to_i) })
78
+ send(:scope, "#{key}_after", -> value { where("(#{query_field})::integer > ?", value.to_i) })
79
+ when :boolean
80
+ send(:scope, "is_#{key}", -> { where("#{query_field} = 'true'") })
81
+ send(:scope, "not_#{key}", -> { where("#{query_field} = 'false'") })
75
82
  when :array
76
- send(:scope, "#{key}_eq", -> value { where("#{hstore_attribute} -> '#{key}' = ?", value.join(SEPARATOR)) })
83
+ send(:scope, "#{key}_eq", -> value { where("#{query_field} = ?", value.join(SEPARATOR)) })
77
84
  send(:scope, "#{key}_contains", -> value do
78
- where("string_to_array(#{hstore_attribute} -> '#{key}', '#{SEPARATOR}') @> string_to_array(?, '#{SEPARATOR}')", Array[value].flatten)
85
+ where("string_to_array(#{query_field}, '#{SEPARATOR}') @> string_to_array(?, '#{SEPARATOR}')", Array[value].flatten)
79
86
  end)
80
87
  end
81
88
  end
@@ -1,3 +1,3 @@
1
1
  module HstoreAccessor
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -6,9 +6,10 @@ class Product < ActiveRecord::Base
6
6
  color: :string,
7
7
  price: :integer,
8
8
  weight: :float,
9
+ popular: :boolean,
10
+ build_timestamp: :time,
9
11
  tags: :array,
10
- reviews: :hash,
11
- build_timestamp: :time
12
+ reviews: :hash
12
13
  end
13
14
 
14
15
  describe HstoreAccessor do
@@ -43,9 +44,9 @@ describe HstoreAccessor do
43
44
  describe "scopes" do
44
45
 
45
46
  let!(:timestamp) { Time.now }
46
- let!(:product_a) { Product.create(color: "green", price: 10, weight: 10.1, tags: ["tag1", "tag2", "tag3"], build_timestamp: (timestamp - 10.days)) }
47
- let!(:product_b) { Product.create(color: "orange", price: 20, weight: 20.2, tags: ["tag2", "tag3", "tag4"], build_timestamp: (timestamp - 5.days)) }
48
- let!(:product_c) { Product.create(color: "blue", price: 30, weight: 30.3, tags: ["tag3", "tag4", "tag5"], build_timestamp: timestamp) }
47
+ let!(:product_a) { Product.create(color: "green", price: 10, weight: 10.1, tags: ["tag1", "tag2", "tag3"], popular: true, build_timestamp: (timestamp - 10.days)) }
48
+ let!(:product_b) { Product.create(color: "orange", price: 20, weight: 20.2, tags: ["tag2", "tag3", "tag4"], popular: false, build_timestamp: (timestamp - 5.days)) }
49
+ let!(:product_c) { Product.create(color: "blue", price: 30, weight: 30.3, tags: ["tag3", "tag4", "tag5"], popular: true, build_timestamp: timestamp) }
49
50
 
50
51
  context "for string fields support" do
51
52
 
@@ -132,6 +133,18 @@ describe HstoreAccessor do
132
133
 
133
134
  end
134
135
 
136
+ context "for boolean field support" do
137
+
138
+ it "true" do
139
+ expect(Product.is_popular).to eq [product_a, product_c]
140
+ end
141
+
142
+ it "false" do
143
+ expect(Product.not_popular).to eq [product_b]
144
+ end
145
+
146
+ end
147
+
135
148
  end
136
149
 
137
150
  context "when assigning values it" do
@@ -166,6 +179,13 @@ describe HstoreAccessor do
166
179
  expect(product.tags).to eq ["household", "living room", "kitchen"]
167
180
  end
168
181
 
182
+ it "returns an empty array if an array value is not set" do
183
+ product.tags = nil
184
+ product.save
185
+ product.reload
186
+ expect(product.tags).to eq []
187
+ end
188
+
169
189
  it "correctly stores hash values" do
170
190
  product.reviews = { "user_123" => "4 stars", "user_994" => "3 stars" }
171
191
  product.save
@@ -173,6 +193,13 @@ describe HstoreAccessor do
173
193
  expect(product.reviews).to eq({ "user_123" => "4 stars", "user_994" => "3 stars" })
174
194
  end
175
195
 
196
+ it "returns an empty hash if a hash value is not set" do
197
+ product.reviews = nil
198
+ product.save
199
+ product.reload
200
+ expect(product.reviews).to eq({})
201
+ end
202
+
176
203
  it "correctly stores time values" do
177
204
  timestamp = Time.now - 10.days
178
205
  product.build_timestamp = timestamp
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hstore_accessor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Hirn
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-06-11 00:00:00.000000000 Z
13
+ date: 2013-06-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: pg