hstore_accessor_rails5 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rubocop.yml +43 -0
- data/.ruby-version +1 -0
- data/Appraisals +11 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +291 -0
- data/Rakefile +10 -0
- data/gemfiles/activerecord_4.0.gemfile +11 -0
- data/gemfiles/activerecord_4.1.gemfile +11 -0
- data/gemfiles/activerecord_4.2.gemfile +11 -0
- data/hstore_accessor.gemspec +34 -0
- data/lib/hstore_accessor.rb +27 -0
- data/lib/hstore_accessor/active_record_4.2/type_helpers.rb +34 -0
- data/lib/hstore_accessor/active_record_5.0/type_helpers.rb +34 -0
- data/lib/hstore_accessor/active_record_pre_4.2/time_helper.rb +29 -0
- data/lib/hstore_accessor/active_record_pre_4.2/type_helpers.rb +42 -0
- data/lib/hstore_accessor/macro.rb +154 -0
- data/lib/hstore_accessor/serialization.rb +49 -0
- data/lib/hstore_accessor/version.rb +3 -0
- data/spec/hstore_accessor_spec.rb +709 -0
- data/spec/spec_helper.rb +48 -0
- metadata +217 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f720dcc6711d9da0adc6cee02b9ecc2d289cc11c
|
4
|
+
data.tar.gz: 57c21b5df60bfbc5e55ac2b26756c4b0aee3adc9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: da7bf66134be0f819dd15ea4295eb0c2704b7daa9f910ba551bd93144c232986a8c2b4ff3d8f8cd4c1412867e59b78837d638c777462bdb149d47b2d3a1902b3
|
7
|
+
data.tar.gz: 5a4509cf56aef71989825d11503fc6d808ac25c5243b66b2b786b58d9fb21402dbfc59be2bec9f69589c3638969d51c4321df655623d3737ae71645e3eb3c195
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
AllCops:
|
2
|
+
Include:
|
3
|
+
- Rakefile
|
4
|
+
Lint/SpaceBeforeFirstArg:
|
5
|
+
Enabled: false
|
6
|
+
Lint/UnusedBlockArgument:
|
7
|
+
Enabled: false
|
8
|
+
Lint/UnusedMethodArgument:
|
9
|
+
Enabled: false
|
10
|
+
Metrics/AbcSize:
|
11
|
+
Enabled: false
|
12
|
+
Metrics/ClassLength:
|
13
|
+
Enabled: false
|
14
|
+
Metrics/CyclomaticComplexity:
|
15
|
+
Enabled: false
|
16
|
+
Metrics/LineLength:
|
17
|
+
Enabled: false
|
18
|
+
Metrics/MethodLength:
|
19
|
+
Enabled: false
|
20
|
+
Metrics/PerceivedComplexity:
|
21
|
+
Enabled: false
|
22
|
+
Style/AlignParameters:
|
23
|
+
Enabled: false
|
24
|
+
Style/ClassAndModuleChildren:
|
25
|
+
Enabled: false
|
26
|
+
Style/ClassVars:
|
27
|
+
Enabled: false
|
28
|
+
Style/Documentation:
|
29
|
+
Enabled: false
|
30
|
+
Style/FileName:
|
31
|
+
Enabled: false
|
32
|
+
Style/GuardClause:
|
33
|
+
Enabled: false
|
34
|
+
Style/IndentHash:
|
35
|
+
Enabled: false
|
36
|
+
Style/RescueModifier:
|
37
|
+
Enabled: false
|
38
|
+
Style/SignalException:
|
39
|
+
Enabled: false
|
40
|
+
Style/SpaceAroundEqualsInParameterDefault:
|
41
|
+
Enabled: false
|
42
|
+
Style/StringLiterals:
|
43
|
+
EnforcedStyle: double_quotes
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.5
|
data/Appraisals
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 JC Grubbs
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
# HstoreAccessor
|
2
|
+
|
3
|
+
Based on (hanselmw's work adding support for rails 5)(https://github.com/hanselmw/hstore_accessor/tree/)add-support-for-rails-5
|
4
|
+
Hstore Accessor allows you to treat fields on an hstore column as though they were actual columns being picked up by ActiveRecord. This is especially handy when trying to avoid sparse columns while making use of [single table inheritence](#single-table-inheritance). Hstore Accessor currently supports ActiveRecord versions 4.0, 4.1, and 4.2.
|
5
|
+
|
6
|
+
Not a fan of hstore? Why not check out [Jsonb Accessor](https://github.com/devmynd/jsonb_accessor)?
|
7
|
+
|
8
|
+
## Table of Contents
|
9
|
+
|
10
|
+
* [Installation](#installation)
|
11
|
+
* [Setup](#setup)
|
12
|
+
* [ActiveRecord methods generated for fields](#activerecord-methods-generated-for-fields)
|
13
|
+
* [Scopes](#scopes)
|
14
|
+
* [String Fields](#string-fields)
|
15
|
+
* [Integer, Float, and Decimal Fields](#integer-float-decimal-fields)
|
16
|
+
* [Datetime Fields](#datetime-fields)
|
17
|
+
* [Date Fields](#date-fields)
|
18
|
+
* [Array Fields](#array-fields)
|
19
|
+
* [Boolean Fields](#boolean-fields)
|
20
|
+
* [Single Table Inheritence](#single-table-inheritance)
|
21
|
+
* [Upgrading](#upgrading)
|
22
|
+
* [Contributing](#contributing)
|
23
|
+
- [Basics](#basics)
|
24
|
+
- [Developing Locally](#developing-locally)
|
25
|
+
|
26
|
+
## Installation
|
27
|
+
|
28
|
+
Add this line to your application's Gemfile:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
gem "hstore_accessor"
|
32
|
+
```
|
33
|
+
|
34
|
+
And then execute:
|
35
|
+
|
36
|
+
$ bundle
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
$ gem install hstore_accessor
|
41
|
+
|
42
|
+
## Setup
|
43
|
+
|
44
|
+
The `hstore_accessor` method accepts the name of the hstore column you'd
|
45
|
+
like to use and a hash with keys representing fields and values
|
46
|
+
indicating the type to be stored in that field. The available types
|
47
|
+
are: `string`, `integer`, `float`, `decimal`, `datetime`, `date`, `boolean`, `array`, and `hash`. It is available on any class that inherits from `ActiveRecord::Base`.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
class Product < ActiveRecord::Base
|
51
|
+
hstore_accessor :options,
|
52
|
+
color: :string,
|
53
|
+
weight: :integer,
|
54
|
+
price: :float,
|
55
|
+
built_at: :datetime,
|
56
|
+
build_date: :date,
|
57
|
+
tags: :array, # deprecated
|
58
|
+
ratings: :hash # deprecated
|
59
|
+
miles: :decimal
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
Now you can interact with the fields stored in the hstore directly.
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
product = Product.new
|
67
|
+
product.color = "green"
|
68
|
+
product.weight = 34
|
69
|
+
product.price = 99.95
|
70
|
+
product.built_at = Time.now - 10.days
|
71
|
+
product.build_date = Date.today
|
72
|
+
product.popular = true
|
73
|
+
product.tags = %w(housewares kitchen) # deprecated
|
74
|
+
product.ratings = { user_a: 3, user_b: 4 } # deprecated
|
75
|
+
product.miles = 3.14
|
76
|
+
```
|
77
|
+
|
78
|
+
Reading these fields works as well.
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
product.color # => "green"
|
82
|
+
product.price # => 99.95
|
83
|
+
```
|
84
|
+
|
85
|
+
In order to reduce the storage overhead of hstore keys (especially when
|
86
|
+
indexed) you can specify an alternate key.
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
hstore_accessor :options,
|
90
|
+
color: { data_type: :string, store_key: "c" },
|
91
|
+
weight: { data_type: :integer, store_key: "w" }
|
92
|
+
```
|
93
|
+
|
94
|
+
In the above example you can continue to interact with the fields using
|
95
|
+
their full name but when saved to the database the field will be set
|
96
|
+
using the `store_key`.
|
97
|
+
|
98
|
+
Additionally, dirty tracking is implemented in the same way that normal
|
99
|
+
`ActiveRecord` fields work.
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
product.color #=> "green"
|
103
|
+
product.color = "blue"
|
104
|
+
product.changed? #=> true
|
105
|
+
product.color_changed? #=> true
|
106
|
+
product.color_was #=> "green"
|
107
|
+
product.color_change #=> ["green", "blue"]
|
108
|
+
```
|
109
|
+
|
110
|
+
## ActiveRecord methods generated for fields
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
class Product < ActiveRecord::Base
|
114
|
+
hstore_accessor :data, field: :string
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
* `field`
|
119
|
+
* `field=`
|
120
|
+
* `field?`
|
121
|
+
* `field_changed?`
|
122
|
+
* `field_was`
|
123
|
+
* `field_change`
|
124
|
+
* `reset_field!`
|
125
|
+
* `restore_field!`
|
126
|
+
* `field_will_change!`
|
127
|
+
|
128
|
+
Overriding methods is supported, with access to the original Hstore Accessor implementation available via `super`.
|
129
|
+
|
130
|
+
Additionally, there is also `hstore_metadata_for_<fields>` on both the class and instances. `column_for_attribute` will also return a column object for an Hstore Accessor defined field. If you're using ActiveRecord 4.2, `type_for_attribute` will return a type object for Hstore Accessor defined fields the same as it does for actual columns.
|
131
|
+
|
132
|
+
## Scopes
|
133
|
+
|
134
|
+
The `hstore_accessor` macro also creates scopes for `string`, `integer`,
|
135
|
+
`float`, `decimal`, `time`, `date`, `boolean`, and `array` fields.
|
136
|
+
|
137
|
+
### String Fields
|
138
|
+
|
139
|
+
For `string` types, a `with_<key>` scope is created which checks for
|
140
|
+
equality.
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
Product.with_color("green")
|
144
|
+
```
|
145
|
+
|
146
|
+
### Integer, Float, Decimal Fields
|
147
|
+
|
148
|
+
For `integer`, `float` and `decimal` types five scopes are created:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
Product.price_lt(240.00) # price less than
|
152
|
+
Product.price_lte(240.00) # price less than or equal to
|
153
|
+
Product.price_eq(240.00) # price equal to
|
154
|
+
Product.price_gte(240.00) # price greater than or equal to
|
155
|
+
Product.price_gt(240.00) # price greater than
|
156
|
+
```
|
157
|
+
|
158
|
+
### Datetime Fields
|
159
|
+
|
160
|
+
For `datetime` fields, three scopes are created:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
Product.built_at_before(Time.now) # built before the given time
|
164
|
+
Product.built_at_eq(Time.now - 10.days) # built at an exact time
|
165
|
+
Product.built_at_after(Time.now - 4.days) # built after the given time
|
166
|
+
```
|
167
|
+
|
168
|
+
### Date Fields
|
169
|
+
|
170
|
+
For `date` fields, three scopes are created:
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
Product.build_date_before(Date.today) # built before the given date
|
174
|
+
Product.build_date_eq(Date.today - 10.days) # built at an exact date
|
175
|
+
Product.built_date_after(Date.today - 4.days) # built after the given date
|
176
|
+
```
|
177
|
+
|
178
|
+
### Array Fields
|
179
|
+
|
180
|
+
*Note: the array field type is deprecated. It is available in version 0.9.0 but not > 1.0.0*
|
181
|
+
|
182
|
+
For `array` types, two scopes are created:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
Product.tags_eq(%w(housewares kitchen)) # tags equaling
|
186
|
+
Product.tags_contains("kitchen") # tags containing a single value
|
187
|
+
Product.tags_contains(%w(housewares kitchen)) # tags containing a number of values
|
188
|
+
```
|
189
|
+
|
190
|
+
### Boolean Fields
|
191
|
+
|
192
|
+
Two scopes are created for `boolean` fields:
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
Product.is_popular # => when popular is set to true
|
196
|
+
Product.not_popular # => when popular is set to false
|
197
|
+
```
|
198
|
+
|
199
|
+
Predicate methods are also available on instances:
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
product = Product.new(popular: true)
|
203
|
+
product.popular? # => true
|
204
|
+
```
|
205
|
+
|
206
|
+
### Single-table Inheritance
|
207
|
+
|
208
|
+
One of the big issues with `ActiveRecord` single-table inheritance (STI)
|
209
|
+
is sparse columns. Essentially, as sub-types of the original table
|
210
|
+
diverge further from their parent more columns are left empty in a given
|
211
|
+
table. Postgres' `hstore` type provides part of the solution in that
|
212
|
+
the values in an `hstore` column does not impose a structure - different
|
213
|
+
rows can have different values.
|
214
|
+
|
215
|
+
We set up our table with an hstore field:
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
# db/migration/<timestamp>_create_vehicles_table.rb
|
219
|
+
class CreateVehiclesTable < ActiveRecord::Migration
|
220
|
+
def change
|
221
|
+
create_table :vehicles do |t|
|
222
|
+
t.string :make
|
223
|
+
t.string :model
|
224
|
+
t.integer :model_year
|
225
|
+
t.string :type
|
226
|
+
t.hstore :data
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
232
|
+
And for our models:
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
# app/models/vehicle.rb
|
236
|
+
class Vehicle < ActiveRecord::Base
|
237
|
+
end
|
238
|
+
|
239
|
+
# app/models/vehicles/automobile.rb
|
240
|
+
class Automobile < Vehicle
|
241
|
+
hstore_accessor :data,
|
242
|
+
axle_count: :integer,
|
243
|
+
weight: :float,
|
244
|
+
engine_details: :hash
|
245
|
+
end
|
246
|
+
|
247
|
+
# app/models/vehicles/airplane.rb
|
248
|
+
class Airplane < Vehicle
|
249
|
+
hstore_accessor :data,
|
250
|
+
engine_type: :string,
|
251
|
+
safety_rating: :integer,
|
252
|
+
features: :hash
|
253
|
+
end
|
254
|
+
```
|
255
|
+
|
256
|
+
From here any attributes specific to any sub-class can be stored in the
|
257
|
+
`hstore` column avoiding sparse data. Indices can also be created on
|
258
|
+
individual fields in an `hstore` column.
|
259
|
+
|
260
|
+
This approach was originally concieved by Joe Hirn in [this blog
|
261
|
+
post](http://www.devmynd.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination).
|
262
|
+
|
263
|
+
## Upgrading
|
264
|
+
Upgrading from version 0.6.0 to 0.9.0 should be fairly painless. If you were previously using a `time` type fields, simply change it to `datetime` like so:
|
265
|
+
|
266
|
+
```ruby
|
267
|
+
# Before...
|
268
|
+
hstore_accessor :data, published_at: :time
|
269
|
+
# After...
|
270
|
+
hstore_accessor :data, published_at: :datetime
|
271
|
+
```
|
272
|
+
|
273
|
+
While the `array` and `hash` types are available in version 0.9.0, they are deprecated and are not available in 1.0.0.
|
274
|
+
|
275
|
+
## Contributing
|
276
|
+
### Basics
|
277
|
+
1. [Fork it](https://github.com/devmynd/hstore_accessor/fork)
|
278
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
279
|
+
3. Write code _and_ tests
|
280
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
281
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
282
|
+
6. Create new Pull Request
|
283
|
+
|
284
|
+
### Developing Locally
|
285
|
+
Before you make your pull requests, please make sure you style is in line with our Rubocop settings and that all of the tests pass.
|
286
|
+
|
287
|
+
1. `bundle install`
|
288
|
+
2. `appraisal install`
|
289
|
+
3. Make sure Postgres is installed and running
|
290
|
+
4. `appraisal rspec` to run all the tests
|
291
|
+
5. `rubocop` to check for style
|
data/Rakefile
ADDED