ar_doc_store 1.0.0 → 1.0.1

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: 119e03286bb8ecf36dfa1d089075188a1979b1cb
4
- data.tar.gz: fc1841751d938d5152c6b902c8925c5c25eac98e
3
+ metadata.gz: 362c4a4c014d334818371ebac25b31607a288644
4
+ data.tar.gz: 58896da6067be1c5a3cf1db37daefc6c9887fce6
5
5
  SHA512:
6
- metadata.gz: fb2485d03e362542372b0a41e2fb4cde66c385731fefd3d437553e82f8c3637bca84ff63b46893a3ccef9be08de23bd299e1abfdac5356120fda85ffab411003
7
- data.tar.gz: 4a0023a148212b537f2b07500641f138ecc870540bbe61c6c79e06ded4e3161fe8528d747ed5989809439399406997cb82550b603c89ad579ead55dd17911c8f
6
+ metadata.gz: a3becf0c88e32a96ad2fd7ff5422e828e53cd3a203485c2bfc19e657bf61ebb3236dbe89e1d2b0ffd0fe59de70cd8de28c8ad4a581040f3c2d02dfcb13985e4f
7
+ data.tar.gz: 2a668359a96d0085c2d37bcede71cd2da2962a1ec4cf334f921956c323b4e2fc53437c3a750f3b3055ff9fe92c7ed8b424babd1037df53fcd522008024388862
data/README.md CHANGED
@@ -153,11 +153,11 @@ We probably have a form for the building, so here goes:
153
153
  ```ruby
154
154
  # in the controller:
155
155
  def new
156
- @building = Building.new
156
+ @building = Building.new
157
157
  end
158
158
 
159
159
  def resource_params
160
- params.require(:building).permit :name, :height, door_attributes: [:door_type]
160
+ params.require(:building).permit :name, :height, door_attributes: [:door_type]
161
161
  end
162
162
 
163
163
  # in the view, with a bonus plug for Slim templates:
@@ -205,10 +205,12 @@ Building.ransack name_cont: 'tall', height_lteq: 20
205
205
 
206
206
  ### Custom attribute types
207
207
 
208
- ArDocStore comes with several basic attribute types: array, boolean, enumeration, float, integer, and string. The implementation and extension points are inspired by SimpleForm. You can either create a new attribute type or overwrite an existing one. Forewarned is forestalled, maybe: as with SimpleForm, the custom input system is way easier to use if you were the one who built it, and it's still a little raw. Let's start with the implementation of :integer :
208
+ ArDocStore comes with several basic attribute types: array, boolean, enumeration, float, integer, and string. The implementation and extension points are inspired by SimpleForm. You can either create a new attribute type or overwrite an existing one. Forewarned is forestalled, maybe: as with SimpleForm, the custom input system is way easier to use if you were the one who built it, and it's still a little raw.
209
+
210
+ All attributes inherit from `AttributeTypes::BaseAttribute` and custom attributes are implemented by overriding that class's methods. Let's start with the implementation of `:integer` :
209
211
 
210
212
  ```ruby
211
- class IntegerAttribute < Base
213
+ class IntegerAttribute < ArDocStore::AttributeTypes::BaseAttribute
212
214
  def conversion
213
215
  :to_i
214
216
  end
@@ -216,15 +218,20 @@ class IntegerAttribute < Base
216
218
  def predicate
217
219
  'int'
218
220
  end
221
+
222
+ def type
223
+ :number
224
+ end
219
225
  end
226
+
220
227
  ```
221
228
 
222
- Note that the data is getting put into a JSON column, so we want to make sure we get it out in the form that we want it. So the conversion method makes sure that it doesn't go in a integer and come back as a string. The predicate method tells postgres (via the ransacker) how to cast the JSON for searching.
229
+ The data is put into a JSON column, so we want to make sure we serialize it correctly. The `conversion` method is a symbol or a string. It is called by the `dump` and `load` (in `BaseAttribute`) methods and is sent to the data when it is written and read. This makes sure that the data doesn't go in a integer and come back as a string. The `predicate` method tells Postgres (via the ransacker) how to cast the JSON for searching.
223
230
 
224
- Not all attribute types are that simple. Sometimes we have to put all the juice in the build method, and take care to define the getter and setter ourselves. In this example, we want to replace the boolean attribute with a similar boolean that can do Yes, No, and N/A, where N/A isn't simply nil but something the user has to choose. Here goes:
231
+ Not all attribute types are that simple. Sometimes we have to put all the juice in the `build` method, and take care to define the getter and setter ourselves. In this example, we want to replace the boolean attribute with a similar boolean that can do Yes, No, and N/A, where N/A isn't simply nil but something the user has to choose. Here goes:
225
232
 
226
233
  ```ruby
227
- class BooleanAttribute < ArDocStore::AttributeTypes::Base
234
+ class BooleanAttribute < ArDocStore::AttributeTypes::BaseAttribute
228
235
  def build
229
236
  key = attribute.to_sym
230
237
  model.class_eval do
@@ -260,6 +267,26 @@ class BooleanInput < SimpleForm::Inputs::CollectionRadioButtonsInput
260
267
  end
261
268
  ```
262
269
 
270
+ #### What if I need different conversions for reading and writing?
271
+
272
+ The `:datetime` attribute requires the data be cast to a string when written, but cast to a `Time` object when read. This overrides the `dump` and `load` methods instead. Here is the implementation:
273
+
274
+ ```ruby
275
+ class DatetimeAttribute < ArDocStore::AttributeTypes::BaseAttribute
276
+ def type
277
+ :datetime
278
+ end
279
+
280
+ def dump
281
+ :to_time
282
+ end
283
+
284
+ def load
285
+ :to_s
286
+ end
287
+ end
288
+ ```
289
+
263
290
  ## Roadmap
264
291
  1. Ransackers for embedded model attributes. Deliberately left out because when you have nested JSON, Postgres searches on any keys within the JSON become 10x slower.
265
292
  2. It would be nice if you could use the AR fluent query API on stored attributes, where is knows to replace, say, "name" with "data->>name" but I don't see how to do that, and Ransack provides a nice enough wrapper around ARel to get the job done another way.
data/Rakefile CHANGED
@@ -16,6 +16,9 @@ namespace :test do
16
16
  create_table :buildings, force: true do |t|
17
17
  t.jsonb :data
18
18
  end
19
+ create_table :purchase_orders, force: true do |t|
20
+ t.jsonb :data
21
+ end
19
22
  end
20
23
  end
21
24
  end
data/lib/ar_doc_store.rb CHANGED
@@ -17,6 +17,7 @@ module ArDocStore
17
17
  autoload :UuidAttribute, "ar_doc_store/attribute_types/uuid_attribute"
18
18
  autoload :EmbedsOneAttribute, "ar_doc_store/attribute_types/embeds_one_attribute"
19
19
  autoload :EmbedsManyAttribute, "ar_doc_store/attribute_types/embeds_many_attribute"
20
+ autoload :DatetimeAttribute, "ar_doc_store/attribute_types/datetime_attribute"
20
21
  end
21
22
 
22
23
  @mappings = Hash.new
@@ -27,6 +28,7 @@ module ArDocStore
27
28
  @mappings[:integer] = 'ArDocStore::AttributeTypes::IntegerAttribute'
28
29
  @mappings[:string] = 'ArDocStore::AttributeTypes::StringAttribute'
29
30
  @mappings[:uuid] = 'ArDocStore::AttributeTypes::UuidAttribute'
31
+ @mappings[:datetime] = 'ArDocStore::AttributeTypes::DatetimeAttribute'
30
32
 
31
33
  def self.mappings
32
34
  @mappings
@@ -20,15 +20,16 @@ module ArDocStore
20
20
  #:nodoc:
21
21
  def store_attribute
22
22
  attribute = @attribute
23
- typecast_method = conversion
24
- predicate = @predicate
23
+ predicate_method = predicate
25
24
  default_value = default
25
+ dump_method = dump
26
+ load_method = load
26
27
  model.class_eval do
27
- add_ransacker(attribute, predicate)
28
+ add_ransacker(attribute, predicate_method)
28
29
  define_method attribute.to_sym, -> {
29
30
  value = read_store_attribute(json_column, attribute)
30
31
  if value
31
- value.public_send(typecast_method)
32
+ value.public_send(load_method)
32
33
  elsif default_value
33
34
  write_default_store_attribute(attribute, default_value)
34
35
  default_value
@@ -38,15 +39,23 @@ module ArDocStore
38
39
  if value == '' || value.nil?
39
40
  write_store_attribute json_column, attribute, nil
40
41
  else
41
- write_store_attribute(json_column, attribute, value.public_send(typecast_method))
42
+ write_store_attribute(json_column, attribute, value.public_send(dump_method))
42
43
  end
43
44
  }
44
45
  end
45
46
  end
46
47
 
48
+ def conversion
49
+ :to_s
50
+ end
47
51
 
52
+ def dump
53
+ conversion
54
+ end
48
55
 
56
+ def load
57
+ conversion
58
+ end
49
59
  end
50
-
51
60
  end
52
61
  end
@@ -0,0 +1,17 @@
1
+ module ArDocStore
2
+ module AttributeTypes
3
+ class DatetimeAttribute < BaseAttribute
4
+ def type
5
+ :datetime
6
+ end
7
+
8
+ def load
9
+ :to_time
10
+ end
11
+
12
+ def dump
13
+ :to_s
14
+ end
15
+ end
16
+ end
17
+ end
@@ -81,8 +81,8 @@ module ArDocStore
81
81
  #:nodoc:
82
82
  def add_ransacker(key, predicate = nil)
83
83
  return unless respond_to?(:ransacker)
84
- ransacker key do
85
- sql = "(data->>'#{key}')"
84
+ ransacker key do |parent|
85
+ sql = "(#{parent.table[:data]}->>'#{key}')"
86
86
  if predicate
87
87
  sql = "#{sql}::#{predicate}"
88
88
  end
@@ -1,3 +1,3 @@
1
1
  module ArDocStore
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -0,0 +1,35 @@
1
+ require_relative './../test_helper'
2
+
3
+ class DatetimeAttributeTest < MiniTest::Test
4
+
5
+ def test_attribute_on_model_init
6
+ approved_at = Time.new(1984, 3, 6)
7
+ po = PurchaseOrder.new approved_at: approved_at
8
+ assert approved_at == po.approved_at
9
+ end
10
+
11
+ def test_attribute_on_existing_model
12
+ approved_at = Time.new(1984, 3, 6)
13
+ po = PurchaseOrder.new
14
+ po.approved_at = approved_at
15
+ assert approved_at == po.approved_at
16
+ assert po.approved_at_changed?
17
+ end
18
+
19
+ def test_question_mark_method
20
+ approved_at = Time.new(1984, 3, 6)
21
+ po = PurchaseOrder.new approved_at: approved_at
22
+ assert_equal true, po.approved_at?
23
+ end
24
+
25
+ def test_conversion
26
+ approved_at = Time.new(1984, 3, 6)
27
+ po = PurchaseOrder.new approved_at: approved_at.to_s
28
+ assert_kind_of Time, po.approved_at
29
+ end
30
+
31
+ def test_no_op
32
+ po = PurchaseOrder.new
33
+ assert_nil po.approved_at
34
+ end
35
+ end
data/test/test_helper.rb CHANGED
@@ -141,3 +141,10 @@ class Building < ActiveRecord::Base
141
141
  embeds_many :entrances
142
142
  embeds_many :restrooms
143
143
  end
144
+
145
+ class PurchaseOrder < ActiveRecord::Base
146
+ include ArDocStore::Model
147
+ attribute :name, :string
148
+ attribute :price, :float
149
+ attribute :approved_at, :datetime
150
+ end
metadata CHANGED
@@ -1,69 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar_doc_store
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Furber
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-15 00:00:00.000000000 Z
11
+ date: 2017-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pg
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0.17'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.17'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.7'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.7'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '10.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: '10.0'
69
69
  description: 'Provides an easy way to do something that is possible in Rails but still
@@ -76,7 +76,7 @@ executables: []
76
76
  extensions: []
77
77
  extra_rdoc_files: []
78
78
  files:
79
- - ".gitignore"
79
+ - .gitignore
80
80
  - Gemfile
81
81
  - LICENSE.txt
82
82
  - README.md
@@ -86,6 +86,7 @@ files:
86
86
  - lib/ar_doc_store/attribute_types/array_attribute.rb
87
87
  - lib/ar_doc_store/attribute_types/base_attribute.rb
88
88
  - lib/ar_doc_store/attribute_types/boolean_attribute.rb
89
+ - lib/ar_doc_store/attribute_types/datetime_attribute.rb
89
90
  - lib/ar_doc_store/attribute_types/embeds_many_attribute.rb
90
91
  - lib/ar_doc_store/attribute_types/embeds_one_attribute.rb
91
92
  - lib/ar_doc_store/attribute_types/enumeration_attribute.rb
@@ -100,6 +101,7 @@ files:
100
101
  - lib/ar_doc_store/version.rb
101
102
  - test/attribute_types/array_attribute_test.rb
102
103
  - test/attribute_types/boolean_attribute_test.rb
104
+ - test/attribute_types/datetime_attribute_test.rb
103
105
  - test/attribute_types/enumeration_attribute_test.rb
104
106
  - test/attribute_types/float_attribute_test.rb
105
107
  - test/attribute_types/integer_attribute_test.rb
@@ -118,23 +120,24 @@ require_paths:
118
120
  - lib
119
121
  required_ruby_version: !ruby/object:Gem::Requirement
120
122
  requirements:
121
- - - ">="
123
+ - - '>='
122
124
  - !ruby/object:Gem::Version
123
125
  version: '0'
124
126
  required_rubygems_version: !ruby/object:Gem::Requirement
125
127
  requirements:
126
- - - ">="
128
+ - - '>='
127
129
  - !ruby/object:Gem::Version
128
130
  version: '0'
129
131
  requirements: []
130
132
  rubyforge_project:
131
- rubygems_version: 2.5.1
133
+ rubygems_version: 2.0.14.1
132
134
  signing_key:
133
135
  specification_version: 4
134
136
  summary: A document storage gem meant for ActiveRecord PostgresQL JSON storage.
135
137
  test_files:
136
138
  - test/attribute_types/array_attribute_test.rb
137
139
  - test/attribute_types/boolean_attribute_test.rb
140
+ - test/attribute_types/datetime_attribute_test.rb
138
141
  - test/attribute_types/enumeration_attribute_test.rb
139
142
  - test/attribute_types/float_attribute_test.rb
140
143
  - test/attribute_types/integer_attribute_test.rb