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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6557e20a7d3813b7250a1a6b4e346d07e3b8f89b9ad984d66c6632e8e172bf9e
4
- data.tar.gz: 8ddacccc9e46e5102dc4056fd4a139e6dde8302e15bd108f66ab7b15214880e7
3
+ metadata.gz: 00fb5f260f1d2ff40dc4adcb5d2dc868c45fc909753f229b60fcf878164fb933
4
+ data.tar.gz: a597101125686d651b810ba3da7a84ba1cb743eeba42e3019c6bde573999adc7
5
5
  SHA512:
6
- metadata.gz: cf9a0fdfba234f852ffd8fc97fe18b709eaff996037da995bccb672696f03d749ac52e4dc2a82306c87f8bb12efd4f7d9f942a43718bb86d309d6b169fd868dd
7
- data.tar.gz: 39662c4f73d0d4f1468a1e02d95ddb6624a907079a9ae4984b449356e51bc5ebf631c162508946f330035747591131f469249e8c72b5484ef0fc6c569aca3e5f
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 { |p| p.to_s }
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 :_acts_as_nosql_init
7
+ after_initialize :_acts_as_nosql_init_defaults
8
8
  end
9
9
 
10
- def _acts_as_nosql_init
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 instance_methods.include?(name.to_sym) || name.to_sym == attribute.to_sym
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.table_name) +
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActsAsNosql
2
- VERSION = '0.1.0'.freeze
4
+ VERSION = '0.1.3'
3
5
  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
- # cattr_accessor :_acts_as_nosql_options
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 'fileds are saved as string' do
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
- # expect(query.to_sql).to eq(
20
- # "SELECT \"articles\".* FROM \"articles\" WHERE (\"articles\".\"data\"->>\"body\" = 'body')"
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
- # expect(query.to_sql).to eq(
40
- # "SELECT \"settings\".* FROM \"settings\" WHERE (\"settings\".\"config\"->>\"user\"->>\"auth\"->>\"token\" = '123123')"
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
@@ -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.0
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: activesupport
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: activerecord
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.2.33
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