acts_as_nosql 0.1.0 → 0.1.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 +4 -4
- data/lib/acts_as_nosql/attribute.rb +5 -1
- data/lib/acts_as_nosql/attributes.rb +32 -3
- data/lib/acts_as_nosql/querying.rb +2 -1
- data/lib/acts_as_nosql/version.rb +3 -1
- data/lib/acts_as_nosql.rb +9 -1
- data/spec/acts_as_nosql/inheritance_spec.rb +22 -0
- data/spec/acts_as_nosql/model_spec.rb +35 -1
- data/spec/acts_as_nosql/querying_spec.rb +20 -6
- data/spec/support/schema.rb +12 -2
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00fb5f260f1d2ff40dc4adcb5d2dc868c45fc909753f229b60fcf878164fb933
|
4
|
+
data.tar.gz: a597101125686d651b810ba3da7a84ba1cb743eeba42e3019c6bde573999adc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b66ae32d0e756a14bf54c22d755281660cba0c907ab4435447cff643eed28b10bdfec2fb260ec19d896b9425f6c0acac1059c8efa1f85ee9720a577293d1fce5
|
7
|
+
data.tar.gz: 443123f7c7026ff6678d40650be1246cc47623f3c534ca2c679f84d6d6dbbc9bb245cc26677111c18c68a1081570c342f2bad0068d902c6780b37ae79237c36d
|
@@ -3,11 +3,15 @@ module ActsAsNosql
|
|
3
3
|
class Attribute
|
4
4
|
attr_reader :name, :type, :default, :path, :type_caster
|
5
5
|
|
6
|
+
# @param [String, Symbol] name
|
7
|
+
# @param [String, Symbol, nil] type
|
8
|
+
# @param [Object, nil] default
|
9
|
+
# @param [Array<String, Symbol>, nil] path
|
6
10
|
def initialize(name, type: nil, default: nil, path: nil)
|
7
11
|
@name = name.to_s
|
8
12
|
@type = type
|
9
13
|
@default = default
|
10
|
-
@path = path&.map
|
14
|
+
@path = path&.map(&:to_s)
|
11
15
|
@type_caster = type ? "ActiveRecord::Type::#{type}".safe_constantize : nil
|
12
16
|
end
|
13
17
|
|
@@ -4,10 +4,10 @@ module ActsAsNosql
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
after_initialize :
|
7
|
+
after_initialize :_acts_as_nosql_init_defaults
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def _acts_as_nosql_init_defaults
|
11
11
|
self.class.nosql_attributes.each do |name, attribute|
|
12
12
|
public_send("#{name}=", attribute.default.dup) if public_send(name).nil? && !attribute.default.nil?
|
13
13
|
end
|
@@ -22,23 +22,52 @@ module ActsAsNosql
|
|
22
22
|
attribute = self._acts_as_nosql_options[:field_name]
|
23
23
|
|
24
24
|
names.each do |name|
|
25
|
-
raise "Attribute #{name} already defined" if
|
25
|
+
raise "Attribute #{name} already defined" if _acts_as_nosql_attribute_defined?(name)
|
26
26
|
|
27
27
|
nosql_attributes[name] = ActsAsNosql::Attribute.new(name, type: type, default: default, path: path)
|
28
28
|
_acts_as_nosql_define_attribute(nosql_attributes[name])
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
def inherited(subclass)
|
33
|
+
subclass._acts_as_nosql_options = self._acts_as_nosql_options.deep_dup
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
32
37
|
def nosql_attributes
|
33
38
|
self._acts_as_nosql_options[:attributes] ||= {}
|
34
39
|
end
|
35
40
|
|
41
|
+
def connection
|
42
|
+
unless acts_as_nosql_conflicts_checked?
|
43
|
+
@acts_as_nosql_conflicts_checked = true
|
44
|
+
acts_as_nosql_check_conflicts!
|
45
|
+
end
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
49
|
+
def acts_as_nosql_conflicts_checked?
|
50
|
+
@acts_as_nosql_conflicts_checked ||= false
|
51
|
+
end
|
52
|
+
|
53
|
+
def acts_as_nosql_check_conflicts!
|
54
|
+
columns_map = columns.index_by(&:name)
|
55
|
+
nosql_attributes.each do |name, attribute|
|
56
|
+
raise "Attribute #{name} already defined" if columns_map[name.to_s]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
36
60
|
private
|
37
61
|
|
38
62
|
def nosql_data_attribute
|
39
63
|
@nosql_data_attribute ||= self._acts_as_nosql_options[:field_name]
|
40
64
|
end
|
41
65
|
|
66
|
+
def _acts_as_nosql_attribute_defined?(name)
|
67
|
+
instance_methods.include?(name.to_sym) ||
|
68
|
+
name.to_sym == nosql_data_attribute.to_sym
|
69
|
+
end
|
70
|
+
|
42
71
|
def _acts_as_nosql_define_attribute(nosql_attribute)
|
43
72
|
attribute = nosql_data_attribute
|
44
73
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module ActsAsNosql
|
3
4
|
module Querying
|
@@ -78,7 +79,7 @@ module ActsAsNosql
|
|
78
79
|
end
|
79
80
|
|
80
81
|
def quote_full_column(field_name)
|
81
|
-
connection.quote_table_name(arel_table.table_alias || arel_table.
|
82
|
+
connection.quote_table_name(arel_table.table_alias || arel_table.name) +
|
82
83
|
'.' +
|
83
84
|
connection.quote_column_name(field_name)
|
84
85
|
end
|
data/lib/acts_as_nosql.rb
CHANGED
@@ -1,12 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_record'
|
2
4
|
|
5
|
+
# ActsAsNosql
|
6
|
+
#
|
7
|
+
# This gem allows to handle JSON and JSONB fields as if they are proper
|
8
|
+
# database columns, handling default values, type casting and simplifying
|
9
|
+
# validation.
|
10
|
+
# This module is the main entry point for the gem.
|
3
11
|
module ActsAsNosql
|
4
12
|
extend ActiveSupport::Concern
|
5
13
|
extend ActiveSupport::Autoload
|
6
14
|
|
7
15
|
class_methods do
|
8
16
|
attr_accessor :_acts_as_nosql_options
|
9
|
-
|
17
|
+
|
10
18
|
def acts_as_nosql(field_name: nil)
|
11
19
|
@_acts_as_nosql_options = { field_name: field_name }
|
12
20
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Inheritance' do
|
4
|
+
subject { InheritedSetting.new }
|
5
|
+
it 'inherits all methods from Settings' do
|
6
|
+
expect(subject).to respond_to(:user_auth_token)
|
7
|
+
expect(subject).to respond_to(:user_auth_token=)
|
8
|
+
|
9
|
+
subject.user_auth_token = '3'
|
10
|
+
expect(subject.user_auth_token).to eq('3')
|
11
|
+
subject.save!
|
12
|
+
expect do
|
13
|
+
expect(InheritedSetting.where(user_auth_token: '3')).to eq([subject])
|
14
|
+
end.to_not raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can be estended without affecting the parent' do
|
18
|
+
InheritedSetting.nosql_attrs :hello, type: :String
|
19
|
+
expect(subject).to respond_to(:hello)
|
20
|
+
expect(Setting.new).not_to respond_to(:hello)
|
21
|
+
end
|
22
|
+
end
|
@@ -34,11 +34,45 @@ describe 'Fields declaration' do
|
|
34
34
|
expect { Article.nosql_attr :data }.to raise_error("Attribute data already defined")
|
35
35
|
end
|
36
36
|
|
37
|
+
it 'raises error if there\'s a name conflict an actual column' do
|
38
|
+
expect { Article.nosql_attr :title }.to raise_error("Attribute title already defined")
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'raises error if there\'s a name conflict an existing nosql attribute' do
|
42
|
+
expect { Article.nosql_attr :body }.to raise_error("Attribute body already defined")
|
43
|
+
end
|
44
|
+
|
37
45
|
it 'raises error if there\'s a name conflict' do
|
38
46
|
expect { Article.nosql_attr :some_column }.to raise_error("Attribute some_column already defined")
|
39
47
|
end
|
40
48
|
|
41
|
-
it '
|
49
|
+
it 'raises error if there\'s a name conflict when calling #acts_as_nosql_check_conflicts!' do
|
50
|
+
expect do
|
51
|
+
class ConflictingArticle < ActiveRecord::Base
|
52
|
+
self.table_name = 'articles'
|
53
|
+
acts_as_nosql field_name: :data
|
54
|
+
|
55
|
+
nosql_attrs :title, :editor, type: String
|
56
|
+
end
|
57
|
+
end.not_to raise_error("Attribute title already defined")
|
58
|
+
|
59
|
+
expect { ConflictingArticle.acts_as_nosql_check_conflicts! }.to raise_error("Attribute title already defined")
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'raises error if there\'s a name conflict when the model columns are loaded' do
|
63
|
+
expect do
|
64
|
+
class ConflictingArticle2 < ActiveRecord::Base
|
65
|
+
self.table_name = 'articles'
|
66
|
+
acts_as_nosql field_name: :data
|
67
|
+
|
68
|
+
nosql_attrs :title, :editor, type: String
|
69
|
+
end
|
70
|
+
end.not_to raise_error("Attribute title already defined")
|
71
|
+
|
72
|
+
expect { ConflictingArticle2.new }.to raise_error("Attribute title already defined")
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'fields are saved as string' do
|
42
76
|
subject.editor = 'John Doe'
|
43
77
|
subject.save!
|
44
78
|
subject.reload
|
@@ -16,9 +16,16 @@ describe 'Querying' do
|
|
16
16
|
|
17
17
|
it 'can be queried' do
|
18
18
|
query = Article.where(body: 'body')
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
expect(query.to_sql).to include(
|
20
|
+
case ENV['ACTIVE_RECORD_ADAPTER']
|
21
|
+
when 'postgresql'
|
22
|
+
"SELECT \"articles\".* FROM \"articles\" WHERE (\"articles\".\"data\"->>'body' = 'body')"
|
23
|
+
when 'mysql'
|
24
|
+
"SELECT `articles`.* FROM `articles` WHERE (`articles`.`data`->>'$.body' = 'body')"
|
25
|
+
else
|
26
|
+
"SELECT \"articles\".* FROM \"articles\" WHERE (\"articles\".\"data\"->>'$.body' = 'body')"
|
27
|
+
end
|
28
|
+
)
|
22
29
|
expect(query.to_a).to contain_exactly(article)
|
23
30
|
end
|
24
31
|
end
|
@@ -36,9 +43,16 @@ describe 'Querying' do
|
|
36
43
|
|
37
44
|
it 'can query nested attributes' do
|
38
45
|
query = Setting.where(user_auth_token: '123123')
|
39
|
-
|
40
|
-
|
41
|
-
|
46
|
+
expect(query.to_sql).to eq(
|
47
|
+
case ENV['ACTIVE_RECORD_ADAPTER']
|
48
|
+
when 'postgresql'
|
49
|
+
"SELECT \"settings\".* FROM \"settings\" WHERE (\"settings\".\"config\"->'user'->'auth'->>'token' = '123123')"
|
50
|
+
when 'mysql'
|
51
|
+
"SELECT `settings`.* FROM `settings` WHERE (`settings`.`config`->>'$.user.auth.token' = '123123')"
|
52
|
+
else
|
53
|
+
"SELECT \"settings\".* FROM \"settings\" WHERE (\"settings\".\"config\"->>'$.user.auth.token' = '123123')"
|
54
|
+
end
|
55
|
+
)
|
42
56
|
expect(query.to_a).to contain_exactly(setting)
|
43
57
|
end
|
44
58
|
end
|
data/spec/support/schema.rb
CHANGED
@@ -4,6 +4,7 @@ if ENV['ACTIVE_RECORD_ADAPTER'] == 'mysql'
|
|
4
4
|
puts 'Running on MySQL...'
|
5
5
|
ActiveRecord::Base.establish_connection(
|
6
6
|
adapter: 'mysql2',
|
7
|
+
host: ENV['DB_HOST'] || '127.0.0.1',
|
7
8
|
username: ENV['DB_USERNAME'] || 'root',
|
8
9
|
password: ENV['DB_PASSWORD'],
|
9
10
|
database: 'acts_as_nosql'
|
@@ -14,8 +15,8 @@ elsif ENV['ACTIVE_RECORD_ADAPTER'] == 'postgresql'
|
|
14
15
|
adapter: 'postgresql',
|
15
16
|
database: 'acts_as_nosql',
|
16
17
|
host: ENV['DB_HOST'] || '127.0.0.1',
|
17
|
-
username: ENV['DB_USERNAME'] || 'postgres',
|
18
|
-
password: ENV['DB_PASSWORD']
|
18
|
+
username: ENV['DB_USERNAME'] || ENV['POSTGRES_USER'] || 'postgres',
|
19
|
+
password: ENV['DB_PASSWORD'] || ENV['POSTGRES_PASSWORD']
|
19
20
|
)
|
20
21
|
else
|
21
22
|
puts 'Running on SQLite...'
|
@@ -43,6 +44,9 @@ class Setting < ActiveRecord::Base
|
|
43
44
|
nosql_attrs :user_auth_providers, type: Array, default: [], path: [:user, :auth, :providers]
|
44
45
|
end
|
45
46
|
|
47
|
+
class InheritedSetting < Setting
|
48
|
+
end
|
49
|
+
|
46
50
|
module Schema
|
47
51
|
def self.create
|
48
52
|
ActiveRecord::Migration.verbose = false
|
@@ -59,6 +63,12 @@ module Schema
|
|
59
63
|
t.json :config
|
60
64
|
t.timestamps null: false
|
61
65
|
end
|
66
|
+
|
67
|
+
create_table :inherited_settings, force: true do |t|
|
68
|
+
t.string :title
|
69
|
+
t.json :config
|
70
|
+
t.timestamps null: false
|
71
|
+
end
|
62
72
|
end
|
63
73
|
end
|
64
74
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_nosql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mònade
|
@@ -31,7 +31,7 @@ dependencies:
|
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '8'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
34
|
+
name: activerecord
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - ">="
|
@@ -51,7 +51,7 @@ dependencies:
|
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: '8'
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
|
-
name:
|
54
|
+
name: activesupport
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
57
|
- - ">="
|
@@ -110,6 +110,7 @@ files:
|
|
110
110
|
- lib/acts_as_nosql/attributes.rb
|
111
111
|
- lib/acts_as_nosql/querying.rb
|
112
112
|
- lib/acts_as_nosql/version.rb
|
113
|
+
- spec/acts_as_nosql/inheritance_spec.rb
|
113
114
|
- spec/acts_as_nosql/model_spec.rb
|
114
115
|
- spec/acts_as_nosql/nested_spec.rb
|
115
116
|
- spec/acts_as_nosql/querying_spec.rb
|
@@ -134,11 +135,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
135
|
- !ruby/object:Gem::Version
|
135
136
|
version: '0'
|
136
137
|
requirements: []
|
137
|
-
rubygems_version: 3.
|
138
|
+
rubygems_version: 3.4.6
|
138
139
|
signing_key:
|
139
140
|
specification_version: 4
|
140
141
|
summary: Use JSON columns as real activerecord attributes
|
141
142
|
test_files:
|
143
|
+
- spec/acts_as_nosql/inheritance_spec.rb
|
142
144
|
- spec/acts_as_nosql/model_spec.rb
|
143
145
|
- spec/acts_as_nosql/nested_spec.rb
|
144
146
|
- spec/acts_as_nosql/querying_spec.rb
|