jsonb_accessor 1.3.7-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +153 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +62 -0
- data/.ruby-version +1 -0
- data/Appraisals +25 -0
- data/CHANGELOG.md +28 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Dockerfile +12 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +355 -0
- data/Rakefile +33 -0
- data/UPGRADE_GUIDE.md +67 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/db/config.yml +8 -0
- data/db/migrate/20150407031737_set_up_testing_db.rb +24 -0
- data/db/schema.rb +36 -0
- data/docker-compose.yml +29 -0
- data/gemfiles/activerecord_5.0.0.gemfile +7 -0
- data/gemfiles/activerecord_5.1.0.gemfile +7 -0
- data/gemfiles/activerecord_5.2.0.gemfile +7 -0
- data/gemfiles/activerecord_6.0.0.gemfile +7 -0
- data/gemfiles/activerecord_6.1.0.gemfile +7 -0
- data/gemfiles/activerecord_7.0.1.gemfile +7 -0
- data/jsonb_accessor.gemspec +45 -0
- data/lib/jsonb_accessor/attribute_query_methods.rb +42 -0
- data/lib/jsonb_accessor/helpers.rb +37 -0
- data/lib/jsonb_accessor/macro.rb +124 -0
- data/lib/jsonb_accessor/query_builder.rb +86 -0
- data/lib/jsonb_accessor/query_helper.rb +103 -0
- data/lib/jsonb_accessor/version.rb +5 -0
- data/lib/jsonb_accessor.rb +22 -0
- metadata +263 -0
data/README.md
ADDED
@@ -0,0 +1,355 @@
|
|
1
|
+
# JSONb Accessor
|
2
|
+
|
3
|
+
Created by [<img src="https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/tandem-logo.png" alt="Tandem Logo" />](https://www.madeintandem.com/)
|
4
|
+
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/jsonb_accessor.svg)](http://badge.fury.io/rb/jsonb_accessor) ![CI](https://github.com/madeintandem/jsonb_accessor/actions/workflows/ci.yml/badge.svg) <img src="https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/json-bee.png" alt="JSONb Accessor Logo" align="right" />
|
6
|
+
|
7
|
+
Adds typed `jsonb` backed fields as first class citizens to your `ActiveRecord` models. This gem is similar in spirit to [HstoreAccessor](https://github.com/madeintandem/hstore_accessor), but the `jsonb` column in PostgreSQL has a few distinct advantages, mostly around nested documents and support for collections.
|
8
|
+
|
9
|
+
It also adds generic scopes for querying `jsonb` columns.
|
10
|
+
|
11
|
+
## Table of Contents
|
12
|
+
|
13
|
+
- [Installation](#installation)
|
14
|
+
- [Usage](#usage)
|
15
|
+
- [Scopes](#scopes)
|
16
|
+
- [Single-Table Inheritance](#single-table-inheritance)
|
17
|
+
- [Dependencies](#dependencies)
|
18
|
+
- [Validations](#validations)
|
19
|
+
- [Upgrading](#upgrading)
|
20
|
+
- [Development](#development)
|
21
|
+
- [Contributing](#contributing)
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
Add this line to your application's `Gemfile`:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
gem "jsonb_accessor"
|
29
|
+
```
|
30
|
+
|
31
|
+
And then execute:
|
32
|
+
|
33
|
+
$ bundle install
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
First we must create a model which has a `jsonb` column available to store data into it:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
class CreateProducts < ActiveRecord::Migration
|
41
|
+
def change
|
42
|
+
create_table :products do |t|
|
43
|
+
t.jsonb :data
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
We can then declare the `jsonb` fields we wish to expose via the accessor:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
class Product < ActiveRecord::Base
|
53
|
+
jsonb_accessor :data,
|
54
|
+
title: :string,
|
55
|
+
external_id: :integer,
|
56
|
+
reviewed_at: :datetime
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
Any type the [`attribute` API](http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute) supports. You can also implement your own type by following the example in the `attribute` documentation.
|
61
|
+
|
62
|
+
To pass through options like `default` and `array` to the `attribute` API, just put them in an array.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
class Product < ActiveRecord::Base
|
66
|
+
jsonb_accessor :data,
|
67
|
+
title: [:string, default: "Untitled"],
|
68
|
+
previous_titles: [:string, array: true, default: []]
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
The `default` option works pretty much as you would expect in practice; if no values are set for the attributes, a hash of the specified default values is saved to the jsonb column.
|
73
|
+
|
74
|
+
You can also pass in a `store_key` option.
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
class Product < ActiveRecord::Base
|
78
|
+
jsonb_accessor :data, title: [:string, store_key: :t]
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
This allows you to use `title` for your getters and setters, but use `t` as the key in the `jsonb` column.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
product = Product.new(title: "Foo")
|
86
|
+
product.title #=> "Foo"
|
87
|
+
product.data #=> { "t" => "Foo" }
|
88
|
+
```
|
89
|
+
|
90
|
+
## Scopes
|
91
|
+
|
92
|
+
Jsonb Accessor provides several scopes to make it easier to query `jsonb` columns. `jsonb_contains`, `jsonb_number_where`, `jsonb_time_where`, and `jsonb_where` are available on all `ActiveRecord::Base` subclasses and don't require that you make use of the `jsonb_accessor` declaration.
|
93
|
+
|
94
|
+
If a class does have a `jsonb_accessor` declaration, then we define one custom scope. So, let's say we have a class that looks like this:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
class Product < ActiveRecord::Base
|
98
|
+
jsonb_accessor :data,
|
99
|
+
name: :string,
|
100
|
+
price: [:integer, store_key: :p],
|
101
|
+
price_in_cents: :integer,
|
102
|
+
reviewed_at: :datetime
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
Jsonb Accessor will add a `scope` to `Product` called like the json column with `_where` suffix, in our case `data_where`.
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
Product.all.data_where(name: "Granite Towel", price: 17)
|
110
|
+
```
|
111
|
+
|
112
|
+
Similarly, it will also add a `data_where_not` `scope` to `Product`.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
Product.all.data_where_not(name: "Plasma Fork")
|
116
|
+
```
|
117
|
+
|
118
|
+
For number fields you can query using `<` or `>`or use plain english if that's what you prefer.
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
Product.all.data_where(price: { <: 15 })
|
122
|
+
Product.all.data_where(price: { <=: 15 })
|
123
|
+
Product.all.data_where(price: { less_than: 15 })
|
124
|
+
Product.all.data_where(price: { less_than_or_equal_to: 15 })
|
125
|
+
|
126
|
+
Product.all.data_where(price: { >: 15 })
|
127
|
+
Product.all.data_where(price: { >=: 15 })
|
128
|
+
Product.all.data_where(price: { greater_than: 15 })
|
129
|
+
Product.all.data_where(price: { greater_than_or_equal_to: 15 })
|
130
|
+
|
131
|
+
Product.all.data_where(price: { greater_than: 15, less_than: 30 })
|
132
|
+
```
|
133
|
+
|
134
|
+
For time related fields you can query using `before` and `after`.
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
Product.all.data_where(reviewed_at: { before: Time.current.beginning_of_week, after: 4.weeks.ago })
|
138
|
+
```
|
139
|
+
|
140
|
+
If you want to search for records within a certain time, date, or number range, just pass in the range (Note: this is just shorthand for the above mentioned `before`/`after`/`less_than`/`less_than_or_equal_to`/`greater_than_or_equal_to`/etc options).
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
Product.all.data_where(price: 10..20)
|
144
|
+
Product.all.data_where(price: 10...20)
|
145
|
+
Product.all.data_where(reviewed_at: Time.current..3.days.from_now)
|
146
|
+
```
|
147
|
+
|
148
|
+
This scope is a convenient wrapper around the `jsonb_where` `scope` that saves you from having to convert the given keys to the store keys and from specifying the column.
|
149
|
+
|
150
|
+
### `jsonb_where`
|
151
|
+
|
152
|
+
Works just like the [`scope` above](#scopes) except that it does not convert the given keys to store keys and you must specify the column name. For example:
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
Product.all.jsonb_where(:data, reviewed_at: { before: Time.current }, p: { greater_than: 5 })
|
156
|
+
|
157
|
+
# instead of
|
158
|
+
|
159
|
+
Product.all.data_where(reviewed_at: { before: Time.current }, price: { greater_than: 5 })
|
160
|
+
```
|
161
|
+
|
162
|
+
This scope makes use of the `jsonb_contains`, `jsonb_number_where`, and `jsonb_time_where` `scope`s.
|
163
|
+
|
164
|
+
### `jsonb_where_not`
|
165
|
+
|
166
|
+
Just the opposite of `jsonb_where`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
Product.all.jsonb_where_not(:data, reviewed_at: { before: Time.current }, p: { greater_than: 5 })
|
170
|
+
```
|
171
|
+
|
172
|
+
### `<jsonb_attribute>_order`
|
173
|
+
|
174
|
+
Orders your query according to values in the Jsonb Accessor fields similar to ActiveRecord's `order`.
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
Product.all.data_order(:price)
|
178
|
+
Product.all.data_order(:price, :reviewed_at)
|
179
|
+
Product.all.data_order(:price, reviewed_at: :desc)
|
180
|
+
```
|
181
|
+
|
182
|
+
It will convert your given keys into store keys if necessary.
|
183
|
+
|
184
|
+
### `jsonb_order`
|
185
|
+
|
186
|
+
Allows you to order by a Jsonb Accessor field.
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
Product.all.jsonb_order(:data, :price, :asc)
|
190
|
+
Product.all.jsonb_order(:data, :price, :desc)
|
191
|
+
```
|
192
|
+
|
193
|
+
### `jsonb_contains`
|
194
|
+
|
195
|
+
Returns all records that contain the given JSON paths.
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
Product.all.jsonb_contains(:data, title: "foo")
|
199
|
+
Product.all.jsonb_contains(:data, reviewed_at: 10.minutes.ago, p: 12) # Using the store key
|
200
|
+
```
|
201
|
+
|
202
|
+
**Note:** Under the hood, `jsonb_contains` uses the [`@>` operator in Postgres](https://www.postgresql.org/docs/9.5/static/functions-json.html) so when you include an array query, the stored array and the array used for the query do not need to match exactly. For example, when queried with `[1, 2]`, records that have arrays of `[2, 1, 3]` will be returned.
|
203
|
+
|
204
|
+
### `jsonb_excludes`
|
205
|
+
|
206
|
+
Returns all records that exclude the given JSON paths. Pretty much the opposite of `jsonb_contains`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
Product.all.jsonb_excludes(:data, title: "foo")
|
210
|
+
Product.all.jsonb_excludes(:data, reviewed_at: 10.minutes.ago, p: 12) # Using the store key
|
211
|
+
```
|
212
|
+
|
213
|
+
### `jsonb_number_where`
|
214
|
+
|
215
|
+
Returns all records that match the given criteria.
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
Product.all.jsonb_number_where(:data, :price_in_cents, :greater_than, 300)
|
219
|
+
```
|
220
|
+
|
221
|
+
It supports:
|
222
|
+
|
223
|
+
- `>`
|
224
|
+
- `>=`
|
225
|
+
- `greater_than`
|
226
|
+
- `greater_than_or_equal_to`
|
227
|
+
- `<`
|
228
|
+
- `<=`
|
229
|
+
- `less_than`
|
230
|
+
- `less_than_or_equal_to`
|
231
|
+
|
232
|
+
and it is indifferent to strings/symbols.
|
233
|
+
|
234
|
+
### `jsonb_number_where_not`
|
235
|
+
|
236
|
+
Returns all records that do not match the given criteria. It's the opposite of `jsonb_number_where`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).
|
237
|
+
|
238
|
+
```ruby
|
239
|
+
Product.all.jsonb_number_where_not(:data, :price_in_cents, :greater_than, 300)
|
240
|
+
```
|
241
|
+
|
242
|
+
### `jsonb_time_where`
|
243
|
+
|
244
|
+
Returns all records that match the given criteria.
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
Product.all.jsonb_time_where(:data, :reviewed_at, :before, 2.days.ago)
|
248
|
+
```
|
249
|
+
|
250
|
+
It supports `before` and `after` and is indifferent to strings/symbols.
|
251
|
+
|
252
|
+
### `jsonb_time_where_not`
|
253
|
+
|
254
|
+
Returns all records that match the given criteria. The opposite of `jsonb_time_where`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).
|
255
|
+
|
256
|
+
```ruby
|
257
|
+
Product.all.jsonb_time_where_not(:data, :reviewed_at, :before, 2.days.ago)
|
258
|
+
```
|
259
|
+
|
260
|
+
## Single-Table Inheritance
|
261
|
+
|
262
|
+
One of the big issues with `ActiveRecord` single-table inheritance (STI)
|
263
|
+
is sparse columns. Essentially, as sub-types of the original table
|
264
|
+
diverge further from their parent more columns are left empty in a given
|
265
|
+
table. Postgres' `jsonb` type provides part of the solution in that
|
266
|
+
the values in an `jsonb` column does not impose a structure - different
|
267
|
+
rows can have different values.
|
268
|
+
|
269
|
+
We set up our table with an `jsonb` field:
|
270
|
+
|
271
|
+
```ruby
|
272
|
+
# db/migration/<timestamp>_create_players.rb
|
273
|
+
class CreateVehicles < ActiveRecord::Migration
|
274
|
+
def change
|
275
|
+
create_table :vehicles do |t|
|
276
|
+
t.string :make
|
277
|
+
t.string :model
|
278
|
+
t.integer :model_year
|
279
|
+
t.string :type
|
280
|
+
t.jsonb :data
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
```
|
285
|
+
|
286
|
+
And for our models:
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
# app/models/vehicle.rb
|
290
|
+
class Vehicle < ActiveRecord::Base
|
291
|
+
end
|
292
|
+
|
293
|
+
# app/models/vehicles/automobile.rb
|
294
|
+
class Automobile < Vehicle
|
295
|
+
jsonb_accessor :data,
|
296
|
+
axle_count: :integer,
|
297
|
+
weight: :float
|
298
|
+
end
|
299
|
+
|
300
|
+
# app/models/vehicles/airplane.rb
|
301
|
+
class Airplane < Vehicle
|
302
|
+
jsonb_accessor :data,
|
303
|
+
engine_type: :string,
|
304
|
+
safety_rating: :integer
|
305
|
+
end
|
306
|
+
```
|
307
|
+
|
308
|
+
From here any attributes specific to any sub-class can be stored in the
|
309
|
+
`jsonb` column avoiding sparse data. Indices can also be created on
|
310
|
+
individual fields in an `jsonb` column.
|
311
|
+
|
312
|
+
This approach was originally conceived by Joe Hirn in [this blog
|
313
|
+
post](https://madeintandem.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination/).
|
314
|
+
|
315
|
+
## Validations
|
316
|
+
|
317
|
+
Because this gem promotes attributes nested into the JSON column to first level attributes, most validations should just work. Please leave us feedback if they're not working as expected.
|
318
|
+
|
319
|
+
## Dependencies
|
320
|
+
|
321
|
+
- ActiveRecord >= 5.0
|
322
|
+
- Postgres >= 9.4 (in order to use the [jsonb column type](http://www.postgresql.org/docs/9.4/static/datatype-json.html)).
|
323
|
+
|
324
|
+
## Upgrading
|
325
|
+
|
326
|
+
See the [upgrade guide](UPGRADE_GUIDE.md).
|
327
|
+
|
328
|
+
## Development
|
329
|
+
|
330
|
+
### On your local machine
|
331
|
+
|
332
|
+
After checking out the repo, run `bin/setup` to install dependencies (make sure postgres is running first).
|
333
|
+
|
334
|
+
Run `bin/console` for an interactive prompt that will allow you to experiment.
|
335
|
+
|
336
|
+
`rake` will run Rubocop and the specs.
|
337
|
+
|
338
|
+
### With Docker
|
339
|
+
|
340
|
+
```
|
341
|
+
# setup
|
342
|
+
docker-compose build
|
343
|
+
docker-compose run ruby rake db:migrate
|
344
|
+
# run test suite
|
345
|
+
docker-compose run ruby rake spec
|
346
|
+
```
|
347
|
+
|
348
|
+
## Contributing
|
349
|
+
|
350
|
+
1. [Fork it](https://github.com/madeintandem/jsonb_accessor/fork)
|
351
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
352
|
+
3. Add tests and changes (run the tests with `rake`)
|
353
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
354
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
355
|
+
6. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "bundler/setup"
|
5
|
+
require "bundler/gem_tasks"
|
6
|
+
require "rspec/core/rake_task"
|
7
|
+
require "rubocop/rake_task"
|
8
|
+
require "active_record"
|
9
|
+
require "erb"
|
10
|
+
|
11
|
+
RSpec::Core::RakeTask.new
|
12
|
+
RuboCop::RakeTask.new
|
13
|
+
|
14
|
+
# rubocop:disable Style/MixinUsage
|
15
|
+
include ActiveRecord::Tasks
|
16
|
+
# rubocop:enable Style/MixinUsage
|
17
|
+
|
18
|
+
root = File.expand_path __dir__
|
19
|
+
db_dir = File.join(root, "db")
|
20
|
+
DatabaseTasks.root = root
|
21
|
+
DatabaseTasks.db_dir = db_dir
|
22
|
+
DatabaseTasks.database_configuration = YAML.safe_load(ERB.new(File.read(File.join(db_dir, "config.yml"))).result, aliases: true)
|
23
|
+
DatabaseTasks.migrations_paths = [File.join(db_dir, "migrate")]
|
24
|
+
DatabaseTasks.env = "test"
|
25
|
+
|
26
|
+
task :environment do
|
27
|
+
ActiveRecord::Base.configurations = DatabaseTasks.database_configuration
|
28
|
+
ActiveRecord::Base.establish_connection DatabaseTasks.env.to_sym
|
29
|
+
end
|
30
|
+
|
31
|
+
load "active_record/railties/databases.rake"
|
32
|
+
|
33
|
+
task(default: %i[rubocop spec])
|
data/UPGRADE_GUIDE.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Upgrading from 0.X.X to 1.0.0
|
2
|
+
|
3
|
+
## Jsonb Accessor declaration
|
4
|
+
|
5
|
+
In 0.X.X you would write:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
class Product < ActiveRecord::Base
|
9
|
+
jsonb_accessor :data,
|
10
|
+
:count, # doesn't specify a type
|
11
|
+
title: :string,
|
12
|
+
external_id: :integer,
|
13
|
+
reviewed_at: :date_time, # snake cased
|
14
|
+
previous_rankings: :integer_array, # `:type_array` key
|
15
|
+
external_rankings: :array # plain array
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
In 1.0.0 you would write:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
class Product < ActiveRecord::Base
|
23
|
+
jsonb_accessor :data,
|
24
|
+
count: :value, # all fields must specify a type
|
25
|
+
title: :string,
|
26
|
+
external_id: :integer,
|
27
|
+
reviewed_at: :datetime, # `:date_time` is now `:datetime`
|
28
|
+
previous_rankings: [:integer, array: true], # now just the type followed by `array: true`
|
29
|
+
external_rankings: [:value, array: true] # now the value type is specified as well as `array: true`
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
There are several important differences. All fields must now specify a type, `:date_time` is now `:datetime`, and arrays are specified using a type and `array: true` instead of `type_array`.
|
34
|
+
|
35
|
+
Also, in order to use the `value` type you need to register it:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
# in an initializer
|
39
|
+
ActiveRecord::Type.register(:value, ActiveRecord::Type::Value)
|
40
|
+
```
|
41
|
+
|
42
|
+
### Deeply nested objects
|
43
|
+
|
44
|
+
In 0.X.X you could write:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
class Product < ActiveRecord::Base
|
48
|
+
jsonb_accessor :data,
|
49
|
+
ranking_info: {
|
50
|
+
original_rank: :integer,
|
51
|
+
current_rank: :integer,
|
52
|
+
metadata: {
|
53
|
+
ranked_on: :date
|
54
|
+
}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
Which would allow you to use getter and setter methods at any point in the structure.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
Product.new(ranking_info: { original_rank: 3, current_rank: 5, metadata: { ranked_on: Date.today } })
|
63
|
+
product.ranking_info.original_rank # 3
|
64
|
+
product.ranking_info.metadata.ranked_on # Date.today
|
65
|
+
```
|
66
|
+
|
67
|
+
1.0.0 does not support this syntax. If you need these sort of methods, you can create your own type `class` and register it with `ActiveRecord::Type`. [Here's an example](http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute).
|
data/bin/console
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "jsonb_accessor"
|
6
|
+
require "rspec"
|
7
|
+
require File.expand_path("../spec/spec_helper.rb", __dir__)
|
8
|
+
|
9
|
+
dbconfig = YAML.safe_load(ERB.new(File.read(File.join("db", "config.yml"))).result, aliases: true)
|
10
|
+
ActiveRecord::Base.establish_connection(dbconfig["development"])
|
11
|
+
|
12
|
+
# rubocop:disable Lint/UselessAssignment
|
13
|
+
x = Product.new
|
14
|
+
# rubocop:enable Lint/UselessAssignment
|
15
|
+
|
16
|
+
Pry.start
|
data/bin/setup
ADDED
data/db/config.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class SetUpTestingDb < ActiveRecord::Migration[5.0]
|
4
|
+
def change
|
5
|
+
create_table :products do |t|
|
6
|
+
t.jsonb :options
|
7
|
+
t.jsonb :data
|
8
|
+
|
9
|
+
t.string :string_type
|
10
|
+
t.integer :integer_type
|
11
|
+
t.integer :product_category_id
|
12
|
+
t.boolean :boolean_type
|
13
|
+
t.float :float_type
|
14
|
+
t.time :time_type
|
15
|
+
t.date :date_type
|
16
|
+
t.datetime :datetime_type
|
17
|
+
t.decimal :decimal_type
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table :product_categories do |t|
|
21
|
+
t.jsonb :options
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/db/schema.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file is auto-generated from the current state of the database. Instead
|
4
|
+
# of editing this file, please use the migrations feature of Active Record to
|
5
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
6
|
+
#
|
7
|
+
# Note that this schema.rb definition is the authoritative source for your
|
8
|
+
# database schema. If you need to create the application database on another
|
9
|
+
# system, you should be using db:schema:load, not running all the migrations
|
10
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
11
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
12
|
+
#
|
13
|
+
# It's strongly recommended that you check this file into your version control system.
|
14
|
+
|
15
|
+
ActiveRecord::Schema.define(version: 20_150_407_031_737) do
|
16
|
+
# These are extensions that must be enabled in order to support this database
|
17
|
+
enable_extension "plpgsql"
|
18
|
+
|
19
|
+
create_table "product_categories", id: :serial, force: :cascade do |t|
|
20
|
+
t.jsonb "options"
|
21
|
+
end
|
22
|
+
|
23
|
+
create_table "products", id: :serial, force: :cascade do |t|
|
24
|
+
t.jsonb "options"
|
25
|
+
t.jsonb "data"
|
26
|
+
t.string "string_type"
|
27
|
+
t.integer "integer_type"
|
28
|
+
t.integer "product_category_id"
|
29
|
+
t.boolean "boolean_type"
|
30
|
+
t.float "float_type"
|
31
|
+
t.time "time_type"
|
32
|
+
t.date "date_type"
|
33
|
+
t.datetime "datetime_type"
|
34
|
+
t.decimal "decimal_type"
|
35
|
+
end
|
36
|
+
end
|
data/docker-compose.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
version: '3'
|
2
|
+
|
3
|
+
services:
|
4
|
+
ruby:
|
5
|
+
environment:
|
6
|
+
- DATABASE_HOST=postgres
|
7
|
+
build:
|
8
|
+
args:
|
9
|
+
- RUBY_VERSION=${RUBY_VERSION:-2.7.2}
|
10
|
+
context: .
|
11
|
+
volumes:
|
12
|
+
- '.:/usr/src/app'
|
13
|
+
depends_on:
|
14
|
+
- postgres
|
15
|
+
|
16
|
+
|
17
|
+
postgres:
|
18
|
+
image: postgres:12
|
19
|
+
environment:
|
20
|
+
- POSTGRES_HOST_AUTH_METHOD=trust
|
21
|
+
- POSTGRES_DB=jsonb_accessor
|
22
|
+
- PGDATA=/var/lib/postgresql/data/pgdata
|
23
|
+
volumes:
|
24
|
+
- pg_data:/var/lib/postgresql/data/pgdata
|
25
|
+
ports:
|
26
|
+
- 5432:5432
|
27
|
+
|
28
|
+
volumes:
|
29
|
+
pg_data:
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "jsonb_accessor/version"
|
6
|
+
|
7
|
+
is_java = RUBY_PLATFORM == "java"
|
8
|
+
|
9
|
+
Gem::Specification.new do |spec|
|
10
|
+
spec.name = "jsonb_accessor"
|
11
|
+
spec.version = JsonbAccessor::VERSION
|
12
|
+
spec.authors = ["Michael Crismali", "Joe Hirn", "Jason Haruska"]
|
13
|
+
spec.email = ["michael@crismali.com", "joe@devmynd.com", "jason@haruska.com"]
|
14
|
+
spec.platform = "java" if is_java
|
15
|
+
|
16
|
+
spec.summary = "Adds typed jsonb backed fields to your ActiveRecord models."
|
17
|
+
spec.description = "Adds typed jsonb backed fields to your ActiveRecord models."
|
18
|
+
spec.homepage = "https://github.com/devmynd/jsonb_accessor"
|
19
|
+
spec.license = "MIT"
|
20
|
+
spec.required_ruby_version = ">= 2"
|
21
|
+
|
22
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) || f.match(/png\z/) }
|
23
|
+
spec.bindir = "exe"
|
24
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
|
+
spec.require_paths = ["lib"]
|
26
|
+
|
27
|
+
spec.add_dependency "activerecord", ">= 5.0"
|
28
|
+
spec.add_dependency "activesupport", ">= 5.0"
|
29
|
+
if is_java
|
30
|
+
spec.add_dependency "activerecord-jdbcpostgresql-adapter", ">= 50.0"
|
31
|
+
else
|
32
|
+
spec.add_dependency "pg", ">= 0.18.1"
|
33
|
+
end
|
34
|
+
|
35
|
+
spec.add_development_dependency "appraisal", "~> 2.2.0"
|
36
|
+
spec.add_development_dependency "awesome_print"
|
37
|
+
spec.add_development_dependency "database_cleaner", "~> 1.6.0"
|
38
|
+
spec.add_development_dependency "pry"
|
39
|
+
spec.add_development_dependency "pry-doc"
|
40
|
+
spec.add_development_dependency "pry-nav"
|
41
|
+
spec.add_development_dependency "psych", "~> 3"
|
42
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
43
|
+
spec.add_development_dependency "rspec", "~> 3.6.0"
|
44
|
+
spec.add_development_dependency "rubocop", "~> 1"
|
45
|
+
end
|