activerecord-postgres-json 0.1.1 → 0.2.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.
- checksums.yaml +5 -5
- data/.rubocop.yml +29 -0
- data/Gemfile +11 -5
- data/README.md +5 -4
- data/VERSION +1 -1
- data/activerecord-postgres-json.gemspec +37 -39
- data/db/ar_postgre_json_test.sql +43 -0
- data/lib/activerecord-postgres-json.rb +2 -0
- data/lib/activerecord-postgres-json/activerecord.rb +64 -33
- data/lib/activerecord-postgres-json/coders.rb +24 -6
- data/spec/activerecord-postgres-json_spec.rb +105 -1
- data/spec/coder_spec.rb +13 -0
- data/spec/database.yml +4 -0
- data/spec/spec_helper.rb +15 -18
- data/spec/support/database_setup.rb +44 -0
- metadata +37 -20
- data/Gemfile.lock +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0e25b4dcf74b8f989c6a5bfe4b54e48ee733e5def17452dfca59d61c756b3db2
|
4
|
+
data.tar.gz: 0a9eae8d07eaf12f97688f50fa19952d3d76082148a3d55f587157176c25247c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6c3a987892882a1f4887ffa39bcf502845efc4863cb461cf047c8d829ca7a4da1b3f00f5c51e6274c31720cbab75b56efde55efa6a7d9be97690c4a70900988
|
7
|
+
data.tar.gz: c6571acbf93ea8647e7acaeb95dd9a81bf3130fb16e9468a4c8d11069f49558c9e2e018bf44304184b971aa95e77bc444ec1b49d09bd5bfe46d7a810db6bf7d8
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
LineLength:
|
2
|
+
Max: 200
|
3
|
+
|
4
|
+
HashSyntax:
|
5
|
+
EnforcedStyle: ruby19
|
6
|
+
|
7
|
+
Layout/SpaceBeforeFirstArg:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
Metrics/AbcSize:
|
11
|
+
Max: 26
|
12
|
+
|
13
|
+
Style/Documentation:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Metrics/ClassLength:
|
17
|
+
Max: 150
|
18
|
+
|
19
|
+
Metrics/MethodLength:
|
20
|
+
Max: 20
|
21
|
+
|
22
|
+
Naming/FileName:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
AllCops:
|
26
|
+
Exclude:
|
27
|
+
- '**/*.gemspec'
|
28
|
+
- 'spec/**/*'
|
29
|
+
- '**/Rakefile'
|
data/Gemfile
CHANGED
@@ -1,12 +1,18 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
gem 'activerecord', '>= 3.2', '< 4.2'
|
4
6
|
gem 'multi_json'
|
5
|
-
gem 'hashie'
|
6
7
|
|
7
|
-
group :development do
|
8
|
+
group :development, :test do
|
9
|
+
gem 'pg', '~> 0.20.0'
|
8
10
|
gem 'rspec'
|
9
|
-
|
11
|
+
end
|
12
|
+
|
13
|
+
group :development do
|
10
14
|
gem 'bundler'
|
11
15
|
gem 'jeweler'
|
16
|
+
gem 'rdoc'
|
17
|
+
gem 'rubocop'
|
12
18
|
end
|
data/README.md
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
# activerecord-postgres-json
|
2
2
|
|
3
|
-
A minimal JSON column type support for ActiveRecord 3.2.x
|
3
|
+
A minimal JSON/JSONB column type support for ActiveRecord 3.2.x
|
4
4
|
This gem adds the following support:
|
5
5
|
|
6
|
-
1. Using json column type in migrations, e.g. `add_column :foo, :bar, :json`
|
6
|
+
1. Using json/jsonb column type in migrations, e.g. `add_column :foo, :bar, :json` or `add_column :foo, :bar, :jsonb`
|
7
7
|
2. json field support in the schema definitions
|
8
8
|
3. JSON coder for using with the `serialize` class method:
|
9
9
|
|
10
10
|
```ruby
|
11
11
|
class User < ActiveRecord::Base
|
12
12
|
serialize :settings, ActiveRecord::Coders::JSON
|
13
|
+
serialize :settings, ActiveRecord::Coders::JSON.new(symbolize_keys: true) # for symbolize keys
|
13
14
|
end
|
14
15
|
|
15
|
-
User.first.settings.class # =>
|
16
|
-
User.first.settings
|
16
|
+
User.first.settings.class # => Hash
|
17
|
+
User.first.settings[:show_popups] # => true
|
17
18
|
...
|
18
19
|
```
|
19
20
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.3
|
@@ -2,18 +2,18 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: activerecord-postgres-json 0.
|
5
|
+
# stub: activerecord-postgres-json 0.2.3 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
|
-
s.name = "activerecord-postgres-json"
|
9
|
-
s.version = "0.
|
8
|
+
s.name = "activerecord-postgres-json".freeze
|
9
|
+
s.version = "0.2.3"
|
10
10
|
|
11
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
-
s.require_paths = ["lib"]
|
13
|
-
s.authors = ["Roman Shterenzon"]
|
14
|
-
s.date = "
|
15
|
-
s.description = "Active Record support for PostgreSQL JSON type"
|
16
|
-
s.email = "romanbsd@yahoo.com"
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib".freeze]
|
13
|
+
s.authors = ["Roman Shterenzon".freeze]
|
14
|
+
s.date = "2020-09-15"
|
15
|
+
s.description = "Active Record support for PostgreSQL JSON type".freeze
|
16
|
+
s.email = "romanbsd@yahoo.com".freeze
|
17
17
|
s.extra_rdoc_files = [
|
18
18
|
"LICENSE.txt",
|
19
19
|
"README.md"
|
@@ -21,52 +21,50 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.files = [
|
22
22
|
".document",
|
23
23
|
".rspec",
|
24
|
+
".rubocop.yml",
|
24
25
|
"Gemfile",
|
25
|
-
"Gemfile.lock",
|
26
26
|
"LICENSE.txt",
|
27
27
|
"README.md",
|
28
28
|
"Rakefile",
|
29
29
|
"VERSION",
|
30
30
|
"activerecord-postgres-json.gemspec",
|
31
|
+
"db/ar_postgre_json_test.sql",
|
31
32
|
"lib/activerecord-postgres-json.rb",
|
32
33
|
"lib/activerecord-postgres-json/activerecord.rb",
|
33
34
|
"lib/activerecord-postgres-json/coders.rb",
|
34
35
|
"spec/activerecord-postgres-json_spec.rb",
|
35
|
-
"spec/
|
36
|
+
"spec/coder_spec.rb",
|
37
|
+
"spec/database.yml",
|
38
|
+
"spec/spec_helper.rb",
|
39
|
+
"spec/support/database_setup.rb"
|
36
40
|
]
|
37
|
-
s.homepage = "http://github.com/romanbsd/activerecord-postgres-json"
|
38
|
-
s.licenses = ["MIT"]
|
39
|
-
s.rubygems_version = "
|
40
|
-
s.summary = "Active Record support for PostgreSQL JSON type"
|
41
|
+
s.homepage = "http://github.com/romanbsd/activerecord-postgres-json".freeze
|
42
|
+
s.licenses = ["MIT".freeze]
|
43
|
+
s.rubygems_version = "3.1.2".freeze
|
44
|
+
s.summary = "Active Record support for PostgreSQL JSON type".freeze
|
41
45
|
|
42
46
|
if s.respond_to? :specification_version then
|
43
47
|
s.specification_version = 4
|
48
|
+
end
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
s.add_dependency(%q<activerecord>, ["< 4", ">= 3.2"])
|
55
|
-
s.add_dependency(%q<multi_json>, [">= 0"])
|
56
|
-
s.add_dependency(%q<hashie>, [">= 0"])
|
57
|
-
s.add_dependency(%q<rspec>, [">= 0"])
|
58
|
-
s.add_dependency(%q<rdoc>, [">= 0"])
|
59
|
-
s.add_dependency(%q<bundler>, [">= 0"])
|
60
|
-
s.add_dependency(%q<jeweler>, [">= 0"])
|
61
|
-
end
|
50
|
+
if s.respond_to? :add_runtime_dependency then
|
51
|
+
s.add_runtime_dependency(%q<activerecord>.freeze, [">= 3.2", "< 4.2"])
|
52
|
+
s.add_runtime_dependency(%q<multi_json>.freeze, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<pg>.freeze, ["~> 0.20.0"])
|
54
|
+
s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
|
56
|
+
s.add_development_dependency(%q<jeweler>.freeze, [">= 0"])
|
57
|
+
s.add_development_dependency(%q<rdoc>.freeze, [">= 0"])
|
58
|
+
s.add_development_dependency(%q<rubocop>.freeze, [">= 0"])
|
62
59
|
else
|
63
|
-
s.add_dependency(%q<activerecord
|
64
|
-
s.add_dependency(%q<multi_json
|
65
|
-
s.add_dependency(%q<
|
66
|
-
s.add_dependency(%q<rspec
|
67
|
-
s.add_dependency(%q<
|
68
|
-
s.add_dependency(%q<
|
69
|
-
s.add_dependency(%q<
|
60
|
+
s.add_dependency(%q<activerecord>.freeze, [">= 3.2", "< 4.2"])
|
61
|
+
s.add_dependency(%q<multi_json>.freeze, [">= 0"])
|
62
|
+
s.add_dependency(%q<pg>.freeze, ["~> 0.20.0"])
|
63
|
+
s.add_dependency(%q<rspec>.freeze, [">= 0"])
|
64
|
+
s.add_dependency(%q<bundler>.freeze, [">= 0"])
|
65
|
+
s.add_dependency(%q<jeweler>.freeze, [">= 0"])
|
66
|
+
s.add_dependency(%q<rdoc>.freeze, [">= 0"])
|
67
|
+
s.add_dependency(%q<rubocop>.freeze, [">= 0"])
|
70
68
|
end
|
71
69
|
end
|
72
70
|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
SET statement_timeout = 0;
|
2
|
+
SET lock_timeout = 0;
|
3
|
+
SET idle_in_transaction_session_timeout = 0;
|
4
|
+
SET client_encoding = 'UTF8';
|
5
|
+
SET standard_conforming_strings = on;
|
6
|
+
SELECT pg_catalog.set_config('search_path', '', false);
|
7
|
+
SET check_function_bodies = false;
|
8
|
+
SET xmloption = content;
|
9
|
+
SET client_min_messages = warning;
|
10
|
+
SET row_security = off;
|
11
|
+
|
12
|
+
SET default_tablespace = '';
|
13
|
+
|
14
|
+
CREATE TABLE public.posts (
|
15
|
+
id integer NOT NULL,
|
16
|
+
old_data json,
|
17
|
+
data jsonb
|
18
|
+
);
|
19
|
+
|
20
|
+
CREATE INDEX index_posts_data_gin ON public.posts USING gin (data);
|
21
|
+
|
22
|
+
CREATE VIEW public.post_questions AS
|
23
|
+
SELECT posts.id,
|
24
|
+
(posts.data ->> 'title'::text) AS title,
|
25
|
+
(posts.data #>> '{author,name}'::text[]) AS author_name,
|
26
|
+
(posts.data #>> '{author,email}'::text[]) AS author_email,
|
27
|
+
((posts.data ->> 'tags'::text))::jsonb AS tags,
|
28
|
+
((posts.data ->> 'draft'::text))::boolean AS draft
|
29
|
+
FROM public.posts;
|
30
|
+
|
31
|
+
CREATE SEQUENCE public.posts_id_seq
|
32
|
+
AS integer
|
33
|
+
START WITH 1
|
34
|
+
INCREMENT BY 1
|
35
|
+
NO MINVALUE
|
36
|
+
NO MAXVALUE
|
37
|
+
CACHE 1;
|
38
|
+
|
39
|
+
ALTER SEQUENCE public.posts_id_seq OWNED BY public.posts.id;
|
40
|
+
|
41
|
+
ALTER TABLE ONLY public.posts ALTER COLUMN id SET DEFAULT nextval('public.posts_id_seq'::regclass);
|
42
|
+
|
43
|
+
ALTER TABLE ONLY public.posts ADD CONSTRAINT posts_pkey PRIMARY KEY (id);
|
@@ -1,15 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_record'
|
2
4
|
require 'active_record/connection_adapters/postgresql_adapter'
|
3
5
|
|
4
6
|
module ActiveRecord
|
5
|
-
|
6
7
|
module ConnectionAdapters
|
7
|
-
|
8
|
+
# jsonb type isn't known by Rails 3.2.x, 4.0.x and 4.1.x, so the gem is defining it
|
9
|
+
PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:jsonb] = { name: 'jsonb' }
|
10
|
+
|
11
|
+
if ActiveRecord.respond_to?(:version)
|
12
|
+
if ::ActiveRecord.version >= Gem::Version.new('4.0.0') && ::ActiveRecord.version < Gem::Version.new('4.2.0')
|
13
|
+
# As suggested here:
|
14
|
+
# http://www.innovationontherun.com/fixing-unknown-oid-geography-errors-with-postgis-and-rails-4-0/
|
15
|
+
# to prevent the Rails 4.0/4.1 error of "unknown OID: {field}"
|
16
|
+
PostgreSQLAdapter::OID.register_type('jsonb', PostgreSQLAdapter::OID::Identity.new)
|
17
|
+
end
|
18
|
+
elsif ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 2
|
19
|
+
# json type isn't known by Rails 3.2.x, so the gem is defining it.
|
20
|
+
# Rails 4.0.x and 4.1.x already have it defined
|
21
|
+
PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:json] = { name: 'json' }
|
22
|
+
end
|
8
23
|
|
9
24
|
class PostgreSQLColumn < Column
|
10
25
|
# Adds the json type for the column.
|
11
26
|
def simplified_type_with_json(field_type)
|
12
|
-
|
27
|
+
case field_type
|
28
|
+
when 'json'
|
29
|
+
:json
|
30
|
+
when 'jsonb'
|
31
|
+
:jsonb
|
32
|
+
else
|
33
|
+
simplified_type_without_json(field_type)
|
34
|
+
end
|
13
35
|
end
|
14
36
|
|
15
37
|
alias_method_chain :simplified_type, :json
|
@@ -17,48 +39,57 @@ module ActiveRecord
|
|
17
39
|
class << self
|
18
40
|
def extract_value_from_default_with_json(default)
|
19
41
|
case default
|
20
|
-
when "'{}'::json"
|
21
|
-
{}
|
22
|
-
when "'[]'::json"
|
23
|
-
[]
|
42
|
+
when "'{}'::json", "'{}'::jsonb"
|
43
|
+
'{}'
|
44
|
+
when "'[]'::json", "'[]'::jsonb"
|
45
|
+
'[]'
|
24
46
|
else
|
25
47
|
extract_value_from_default_without_json(default)
|
26
48
|
end
|
27
49
|
end
|
50
|
+
|
28
51
|
alias_method_chain :extract_value_from_default, :json
|
29
52
|
end
|
30
53
|
end
|
31
|
-
end
|
32
54
|
|
33
|
-
|
55
|
+
class TableDefinition
|
56
|
+
# Adds json type for migrations. So you can add columns to a table like:
|
57
|
+
# create_table :people do |t|
|
58
|
+
# ...
|
59
|
+
# t.json :info
|
60
|
+
# ...
|
61
|
+
# end
|
62
|
+
def json(*args)
|
63
|
+
options = args.extract_options!
|
64
|
+
column_names = args
|
65
|
+
column_names.each { |name| column(name, 'json', options) }
|
66
|
+
end
|
34
67
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# end
|
41
|
-
def json(*args)
|
42
|
-
options = args.extract_options!
|
43
|
-
column_names = args
|
44
|
-
column_names.each { |name| column(name, 'json', options) }
|
68
|
+
def jsonb(*args)
|
69
|
+
options = args.extract_options!
|
70
|
+
column_names = args
|
71
|
+
column_names.each { |name| column(name, 'jsonb', options) }
|
72
|
+
end
|
45
73
|
end
|
46
74
|
|
47
|
-
|
48
|
-
|
49
|
-
|
75
|
+
class Table
|
76
|
+
# Adds json type for migrations. So you can add columns to a table like:
|
77
|
+
# change_table :people do |t|
|
78
|
+
# ...
|
79
|
+
# t.json :info
|
80
|
+
# ...
|
81
|
+
# end
|
82
|
+
def json(*args)
|
83
|
+
options = args.extract_options!
|
84
|
+
column_names = args
|
85
|
+
column_names.each { |name| column(name, 'json', options) }
|
86
|
+
end
|
50
87
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
# end
|
57
|
-
def json(*args)
|
58
|
-
options = args.extract_options!
|
59
|
-
column_names = args
|
60
|
-
column_names.each { |name| column(name, 'json', options) }
|
88
|
+
def jsonb(*args)
|
89
|
+
options = args.extract_options!
|
90
|
+
column_names = args
|
91
|
+
column_names.each { |name| column(name, 'jsonb', options) }
|
92
|
+
end
|
61
93
|
end
|
62
94
|
end
|
63
|
-
|
64
95
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'multi_json'
|
2
|
-
require 'hashie'
|
3
4
|
|
4
5
|
module ActiveRecord
|
5
6
|
module Coders
|
@@ -12,12 +13,20 @@ module ActiveRecord
|
|
12
13
|
new.dump(json)
|
13
14
|
end
|
14
15
|
|
15
|
-
def initialize(
|
16
|
-
@default =
|
16
|
+
def initialize(params = {})
|
17
|
+
@default = {}
|
18
|
+
return unless params.class.name == 'Hash'
|
19
|
+
|
20
|
+
@default = params[:default] if params[:default]
|
21
|
+
@symbolize_keys = params[:symbolize_keys] if params[:symbolize_keys]
|
17
22
|
end
|
18
23
|
|
19
24
|
def dump(obj)
|
20
|
-
obj.nil?
|
25
|
+
if obj.nil?
|
26
|
+
@default.nil? ? nil : to_json(@default)
|
27
|
+
else
|
28
|
+
to_json(obj)
|
29
|
+
end
|
21
30
|
end
|
22
31
|
|
23
32
|
def load(json)
|
@@ -25,13 +34,22 @@ module ActiveRecord
|
|
25
34
|
end
|
26
35
|
|
27
36
|
private
|
37
|
+
|
28
38
|
def to_json(obj)
|
29
39
|
MultiJson.dump(obj)
|
30
40
|
end
|
31
41
|
|
32
|
-
# FIXME: support arrays
|
33
42
|
def from_json(json)
|
34
|
-
|
43
|
+
convert_object MultiJson.load(json, symbolize_keys: @symbolize_keys)
|
44
|
+
end
|
45
|
+
|
46
|
+
def convert_object(obj)
|
47
|
+
case obj
|
48
|
+
when Array
|
49
|
+
obj.map { |member| convert_object(member) }
|
50
|
+
else
|
51
|
+
obj
|
52
|
+
end
|
35
53
|
end
|
36
54
|
end
|
37
55
|
end
|
@@ -1,4 +1,108 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/support/database_setup')
|
2
3
|
|
3
|
-
|
4
|
+
class Post < ActiveRecord::Base
|
5
|
+
serialize :data, ActiveRecord::Coders::JSON.new(symbolize_keys: true)
|
6
|
+
|
7
|
+
# For Rails 3.2.x the json serializer should be explicitly specified, because it is unknown by Rails
|
8
|
+
serialize :old_data, ActiveRecord::Coders::JSON.new(symbolize_keys: true) unless ActiveRecord.respond_to?(:version)
|
9
|
+
end
|
10
|
+
|
11
|
+
class PostQuestions < ActiveRecord::Base
|
12
|
+
serialize :tags, ActiveRecord::Coders::JSON
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'ActiverecordPostgresJson', db: true do
|
16
|
+
after(:all) do
|
17
|
+
db_config = YAML.load_file(File.expand_path('../database.yml', __FILE__))
|
18
|
+
ActiveRecord::Base.connection.execute "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'mydb'"
|
19
|
+
ActiveRecord::Base.establish_connection(db_config['test'].merge('database' => 'postgres', 'schema_search_path' => 'public'))
|
20
|
+
ActiveRecord::Base.connection.execute 'DROP DATABASE IF EXISTS ar_postgres_json_test'
|
21
|
+
end
|
22
|
+
|
23
|
+
before { Post.delete_all }
|
24
|
+
|
25
|
+
let!(:hdd) do
|
26
|
+
Post.create!(data: [
|
27
|
+
{f1: 6, f2: 5, value: true, intencity: 2.0},
|
28
|
+
{f1: 9, f2: 3, value: false, intencity: 1.0}
|
29
|
+
]).reload
|
30
|
+
end
|
31
|
+
|
32
|
+
let!(:tdd) do
|
33
|
+
Post.create!(data: [
|
34
|
+
{f1: 1, f2: 2, value: false, intencity: 2.0},
|
35
|
+
{f1: 1, f2: 4, value: true, intencity: 1.0}
|
36
|
+
]).reload
|
37
|
+
end
|
38
|
+
|
39
|
+
let!(:bdd) do
|
40
|
+
Post.create!(data: {
|
41
|
+
title: 'BDD is woot',
|
42
|
+
author: { name: 'Philippe', email: 'philippe@example.com'},
|
43
|
+
tags: ['bdd', 'testing', 'woot', true],
|
44
|
+
word_count: 42
|
45
|
+
}).reload
|
46
|
+
end
|
47
|
+
|
48
|
+
let!(:foo) do
|
49
|
+
Post.create!(data: {
|
50
|
+
title: 'FOO is bar',
|
51
|
+
author: { name: 'Philippe', email: 'philippe@example.com'},
|
52
|
+
tags: ['foo', 'bar', 42],
|
53
|
+
draft: true
|
54
|
+
}).reload
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'maps fields' do
|
58
|
+
post = PostQuestions.find_by_title! 'FOO is bar'
|
59
|
+
expect(post.author_name).to eq('Philippe')
|
60
|
+
expect(post.author_email).to eq('philippe@example.com')
|
61
|
+
expect(post.tags).to eq ['foo', 'bar', 42]
|
62
|
+
expect(post).to be_draft
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'provides search as if it was a good old table' do
|
66
|
+
expect(PostQuestions.where(author_name: 'Philippe').pluck(:title)).to eq ['BDD is woot', 'FOO is bar']
|
67
|
+
expect(PostQuestions.where(draft: true).count).to eq(1)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'when retrieve objects as array' do
|
71
|
+
expect(Post.where('data @> \'[{"f1":1}]\'').first.data)
|
72
|
+
.to eq [
|
73
|
+
{f1: 1, f2: 2, value: false, intencity: 2.0},
|
74
|
+
{f1: 1, f2: 4, value: true, intencity: 1.0}
|
75
|
+
]
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'when search in objects array' do
|
79
|
+
expect(Post.where('data @> \'[{"f1":6}]\'').count).to eq(1)
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'when the column is of json type' do
|
83
|
+
let!(:plain_json) do
|
84
|
+
Post.create!(data: { title: 'Plain JSON support'},
|
85
|
+
old_data: { title: 'Old JSON is supported too',
|
86
|
+
author: { name: 'Aurel', email: 'aurel@example.com'},
|
87
|
+
draft: true }).reload
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'process plain JSON columns, ' do
|
91
|
+
post = Post.all.to_a[4]
|
92
|
+
|
93
|
+
# Rails 4.0.x and 4.1.x will serialize plain json fields without symbolizing keys with their own serializer
|
94
|
+
if ActiveRecord.respond_to?(:version)
|
95
|
+
if ::ActiveRecord.version >= Gem::Version.new('4.0.0') && ::ActiveRecord.version < Gem::Version.new('4.2.0')
|
96
|
+
expect(post.old_data).to eq({ 'title' => 'Old JSON is supported too',
|
97
|
+
'author' => { 'name' => 'Aurel', 'email' => 'aurel@example.com'},
|
98
|
+
'draft' => true })
|
99
|
+
end
|
100
|
+
# Rails 3.2.x will serialize plain json fields symbolizing keys using this gem
|
101
|
+
elsif ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 2
|
102
|
+
expect(post.old_data).to eq({ title: 'Old JSON is supported too',
|
103
|
+
author: { name: 'Aurel', email: 'aurel@example.com'},
|
104
|
+
draft: true })
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
4
108
|
end
|
data/spec/coder_spec.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRecord::Coders::JSON do
|
4
|
+
it 'converts hashes' do
|
5
|
+
res = described_class.load('{"foo":"bar", "bar":[1,2]}')
|
6
|
+
expect(res).to eq('foo' => 'bar', 'bar' => [1,2])
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'converts arrays' do
|
10
|
+
res = described_class.load('[{"foo":"bar"}, [{"bar":"baz"}], [[1,2],{"baz":"foo"}]]')
|
11
|
+
expect(res).to eq([{'foo' => 'bar'}, [{'bar' => 'baz'}], [[1,2], {'baz' => 'foo'}]])
|
12
|
+
end
|
13
|
+
end
|
data/spec/database.yml
ADDED
data/spec/spec_helper.rb
CHANGED
@@ -1,29 +1,26 @@
|
|
1
|
-
require 'simplecov'
|
2
|
-
|
3
|
-
module SimpleCov::Configuration
|
4
|
-
def clean_filters
|
5
|
-
@filters = []
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
SimpleCov.configure do
|
10
|
-
clean_filters
|
11
|
-
load_adapter 'test_frameworks'
|
12
|
-
end
|
13
|
-
|
14
|
-
ENV["COVERAGE"] && SimpleCov.start do
|
15
|
-
add_filter "/.rvm/"
|
16
|
-
end
|
17
1
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
18
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
19
3
|
|
20
4
|
require 'rspec'
|
5
|
+
require 'active_record'
|
21
6
|
require 'activerecord-postgres-json'
|
22
7
|
|
23
8
|
# Requires supporting files with custom matchers and macros, etc,
|
24
9
|
# in ./support/ and its subdirectories.
|
25
|
-
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
10
|
+
# Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
26
11
|
|
27
12
|
RSpec.configure do |config|
|
28
|
-
|
13
|
+
config.around db: true do |example|
|
14
|
+
if example.metadata[:disable_transactions]
|
15
|
+
example.call
|
16
|
+
else
|
17
|
+
ActiveRecord::Base.transaction do
|
18
|
+
begin
|
19
|
+
example.call
|
20
|
+
ensure
|
21
|
+
raise ActiveRecord::Rollback
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
29
26
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'pg'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
db_config = YAML.load_file(File.expand_path('../../database.yml', __FILE__))
|
6
|
+
structure_sql_filename = 'db/ar_postgre_json_test.sql'
|
7
|
+
|
8
|
+
begin
|
9
|
+
ActiveRecord::Base.establish_connection db_config['test']
|
10
|
+
ActiveRecord::Base.connection.active?
|
11
|
+
rescue Exception => _e
|
12
|
+
encoding = db_config['test']['encoding'] || ENV['CHARSET'] || 'utf8'
|
13
|
+
begin
|
14
|
+
ActiveRecord::Base.establish_connection(db_config['test'].merge('database' => 'postgres', 'schema_search_path' => 'public'))
|
15
|
+
ActiveRecord::Base.connection.recreate_database(db_config['test']['database'], db_config['test'].merge('encoding' => encoding))
|
16
|
+
ActiveRecord::Base.establish_connection(db_config['test'])
|
17
|
+
|
18
|
+
ActiveRecord::Base.configurations = db_config
|
19
|
+
if ActiveRecord.respond_to?(:version)
|
20
|
+
require 'active_record/tasks/database_tasks'
|
21
|
+
|
22
|
+
if ::ActiveRecord.version >= Gem::Version.new('4.1.0') && ::ActiveRecord.version < Gem::Version.new('4.2.0')
|
23
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, structure_sql_filename, 'test')
|
24
|
+
elsif ::ActiveRecord.version >= Gem::Version.new('4.0.0') && ::ActiveRecord.version < Gem::Version.new('4.1.0')
|
25
|
+
ActiveRecord::Tasks::DatabaseTasks.structure_load(db_config['test'], structure_sql_filename)
|
26
|
+
end
|
27
|
+
elsif ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 2
|
28
|
+
require "active_record/base"
|
29
|
+
require "rake"
|
30
|
+
require "rake/dsl_definition"
|
31
|
+
load "active_record/railties/databases.rake"
|
32
|
+
|
33
|
+
set_psql_env(db_config)
|
34
|
+
`psql -f "#{structure_sql_filename}" #{db_config['test']['database']}`
|
35
|
+
end
|
36
|
+
|
37
|
+
rescue Exception => ec
|
38
|
+
$stderr.puts ec, *(ec.backtrace)
|
39
|
+
$stderr.puts "Couldn't create database for #{db_config['test'].inspect}"
|
40
|
+
end
|
41
|
+
ensure
|
42
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
43
|
+
ActiveRecord::Base.logger.formatter = ->(_, _, _, msg) { "#{msg}\n" }
|
44
|
+
end
|
metadata
CHANGED
@@ -1,35 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-postgres-json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roman Shterenzon
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-09-15 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
|
-
- - "<"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '4'
|
20
17
|
- - ">="
|
21
18
|
- !ruby/object:Gem::Version
|
22
19
|
version: '3.2'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '4.2'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - "<"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '4'
|
30
27
|
- - ">="
|
31
28
|
- !ruby/object:Gem::Version
|
32
29
|
version: '3.2'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '4.2'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: multi_json
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,13 +45,27 @@ dependencies:
|
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '0'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
48
|
+
name: pg
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.20.0
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.20.0
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
50
64
|
requirements:
|
51
65
|
- - ">="
|
52
66
|
- !ruby/object:Gem::Version
|
53
67
|
version: '0'
|
54
|
-
type: :
|
68
|
+
type: :development
|
55
69
|
prerelease: false
|
56
70
|
version_requirements: !ruby/object:Gem::Requirement
|
57
71
|
requirements:
|
@@ -59,7 +73,7 @@ dependencies:
|
|
59
73
|
- !ruby/object:Gem::Version
|
60
74
|
version: '0'
|
61
75
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
76
|
+
name: bundler
|
63
77
|
requirement: !ruby/object:Gem::Requirement
|
64
78
|
requirements:
|
65
79
|
- - ">="
|
@@ -73,7 +87,7 @@ dependencies:
|
|
73
87
|
- !ruby/object:Gem::Version
|
74
88
|
version: '0'
|
75
89
|
- !ruby/object:Gem::Dependency
|
76
|
-
name:
|
90
|
+
name: jeweler
|
77
91
|
requirement: !ruby/object:Gem::Requirement
|
78
92
|
requirements:
|
79
93
|
- - ">="
|
@@ -87,7 +101,7 @@ dependencies:
|
|
87
101
|
- !ruby/object:Gem::Version
|
88
102
|
version: '0'
|
89
103
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
104
|
+
name: rdoc
|
91
105
|
requirement: !ruby/object:Gem::Requirement
|
92
106
|
requirements:
|
93
107
|
- - ">="
|
@@ -101,7 +115,7 @@ dependencies:
|
|
101
115
|
- !ruby/object:Gem::Version
|
102
116
|
version: '0'
|
103
117
|
- !ruby/object:Gem::Dependency
|
104
|
-
name:
|
118
|
+
name: rubocop
|
105
119
|
requirement: !ruby/object:Gem::Requirement
|
106
120
|
requirements:
|
107
121
|
- - ">="
|
@@ -124,23 +138,27 @@ extra_rdoc_files:
|
|
124
138
|
files:
|
125
139
|
- ".document"
|
126
140
|
- ".rspec"
|
141
|
+
- ".rubocop.yml"
|
127
142
|
- Gemfile
|
128
|
-
- Gemfile.lock
|
129
143
|
- LICENSE.txt
|
130
144
|
- README.md
|
131
145
|
- Rakefile
|
132
146
|
- VERSION
|
133
147
|
- activerecord-postgres-json.gemspec
|
148
|
+
- db/ar_postgre_json_test.sql
|
134
149
|
- lib/activerecord-postgres-json.rb
|
135
150
|
- lib/activerecord-postgres-json/activerecord.rb
|
136
151
|
- lib/activerecord-postgres-json/coders.rb
|
137
152
|
- spec/activerecord-postgres-json_spec.rb
|
153
|
+
- spec/coder_spec.rb
|
154
|
+
- spec/database.yml
|
138
155
|
- spec/spec_helper.rb
|
156
|
+
- spec/support/database_setup.rb
|
139
157
|
homepage: http://github.com/romanbsd/activerecord-postgres-json
|
140
158
|
licenses:
|
141
159
|
- MIT
|
142
160
|
metadata: {}
|
143
|
-
post_install_message:
|
161
|
+
post_install_message:
|
144
162
|
rdoc_options: []
|
145
163
|
require_paths:
|
146
164
|
- lib
|
@@ -155,9 +173,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
173
|
- !ruby/object:Gem::Version
|
156
174
|
version: '0'
|
157
175
|
requirements: []
|
158
|
-
|
159
|
-
|
160
|
-
signing_key:
|
176
|
+
rubygems_version: 3.1.2
|
177
|
+
signing_key:
|
161
178
|
specification_version: 4
|
162
179
|
summary: Active Record support for PostgreSQL JSON type
|
163
180
|
test_files: []
|
data/Gemfile.lock
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
GEM
|
2
|
-
remote: http://rubygems.org/
|
3
|
-
specs:
|
4
|
-
activemodel (3.2.18)
|
5
|
-
activesupport (= 3.2.18)
|
6
|
-
builder (~> 3.0.0)
|
7
|
-
activerecord (3.2.18)
|
8
|
-
activemodel (= 3.2.18)
|
9
|
-
activesupport (= 3.2.18)
|
10
|
-
arel (~> 3.0.2)
|
11
|
-
tzinfo (~> 0.3.29)
|
12
|
-
activesupport (3.2.18)
|
13
|
-
i18n (~> 0.6, >= 0.6.4)
|
14
|
-
multi_json (~> 1.0)
|
15
|
-
addressable (2.3.6)
|
16
|
-
arel (3.0.3)
|
17
|
-
builder (3.0.4)
|
18
|
-
descendants_tracker (0.0.4)
|
19
|
-
thread_safe (~> 0.3, >= 0.3.1)
|
20
|
-
diff-lcs (1.2.5)
|
21
|
-
faraday (0.9.0)
|
22
|
-
multipart-post (>= 1.2, < 3)
|
23
|
-
git (1.2.6)
|
24
|
-
github_api (0.11.3)
|
25
|
-
addressable (~> 2.3)
|
26
|
-
descendants_tracker (~> 0.0.1)
|
27
|
-
faraday (~> 0.8, < 0.10)
|
28
|
-
hashie (>= 1.2)
|
29
|
-
multi_json (>= 1.7.5, < 2.0)
|
30
|
-
nokogiri (~> 1.6.0)
|
31
|
-
oauth2
|
32
|
-
hashie (2.1.1)
|
33
|
-
highline (1.6.21)
|
34
|
-
i18n (0.6.9)
|
35
|
-
jeweler (2.0.1)
|
36
|
-
builder
|
37
|
-
bundler (>= 1.0)
|
38
|
-
git (>= 1.2.5)
|
39
|
-
github_api
|
40
|
-
highline (>= 1.6.15)
|
41
|
-
nokogiri (>= 1.5.10)
|
42
|
-
rake
|
43
|
-
rdoc
|
44
|
-
jwt (1.0.0)
|
45
|
-
mini_portile (0.6.0)
|
46
|
-
multi_json (1.10.1)
|
47
|
-
multi_xml (0.5.5)
|
48
|
-
multipart-post (2.0.0)
|
49
|
-
nokogiri (1.6.2.1)
|
50
|
-
mini_portile (= 0.6.0)
|
51
|
-
oauth2 (0.9.4)
|
52
|
-
faraday (>= 0.8, < 0.10)
|
53
|
-
jwt (~> 1.0)
|
54
|
-
multi_json (~> 1.3)
|
55
|
-
multi_xml (~> 0.5)
|
56
|
-
rack (~> 1.2)
|
57
|
-
rack (1.5.2)
|
58
|
-
rake (10.3.2)
|
59
|
-
rdoc (4.1.0)
|
60
|
-
rspec (2.14.1)
|
61
|
-
rspec-core (~> 2.14.0)
|
62
|
-
rspec-expectations (~> 2.14.0)
|
63
|
-
rspec-mocks (~> 2.14.0)
|
64
|
-
rspec-core (2.14.8)
|
65
|
-
rspec-expectations (2.14.5)
|
66
|
-
diff-lcs (>= 1.1.3, < 2.0)
|
67
|
-
rspec-mocks (2.14.6)
|
68
|
-
thread_safe (0.3.4)
|
69
|
-
tzinfo (0.3.39)
|
70
|
-
|
71
|
-
PLATFORMS
|
72
|
-
ruby
|
73
|
-
|
74
|
-
DEPENDENCIES
|
75
|
-
activerecord (>= 3.2, < 4)
|
76
|
-
bundler
|
77
|
-
hashie
|
78
|
-
jeweler
|
79
|
-
multi_json
|
80
|
-
rdoc
|
81
|
-
rspec
|