ree_lib 1.0.70 → 1.0.72

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: 40e7e6a91b65f1bab58b667f1eebf153ac5fd1c85852e189af8d3a6d2ea8b163
4
- data.tar.gz: 5ac2658d206e2aa8963fd90ed4ca4ef071b701a0d02414d571dcc95df825a88e
3
+ metadata.gz: 0421ad28472f902b4c53091515c749bdcb6aba9ef96ed42009abe27d115edf48
4
+ data.tar.gz: 3909bfecb3e92e05708a9be5effb672fc8042e2f53ed4aadb426539f0eba8574
5
5
  SHA512:
6
- metadata.gz: 221b1612a9ddc52b73f6cd34a1f1228009a3459646d0f129281d5c4ae16557e1044359cb13e44085bf1e727ae07ce3be7cfae9e1728fae8260ed42f888a52010
7
- data.tar.gz: e296d1413246f6813ec865ae1395eec11f71f2066d755d815ccac8a260278f122c20e6ca0c680204245a693aa9668dfaab46c0187e25e51288be6c4d523c5e7a
6
+ metadata.gz: bb696f99d8af84de496f0e6a3bf616256853302d952409832fd89eb24830c0f29cb2cead19b245eee883a2c9dc7d358633bccc308be56369c2d8aeb569a66c7d
7
+ data.tar.gz: 0accc79d4259f341f4fbf6306103e28521b070119b2ee6be3e7bb98e08802b78ad857f476524a128d9c51cd7ca02fb59298ac70886b70a1304de8d39455d13d5
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ree_lib (1.0.70)
4
+ ree_lib (1.0.72)
5
5
  binding_of_caller (~> 1.0.0)
6
6
  i18n (~> 1.12.0)
7
7
  loofah (~> 2.18.0)
@@ -3,14 +3,12 @@ module ReeDao
3
3
  include Ree::LinkDSL
4
4
  include ReeDao::AssociationMethods
5
5
 
6
- link :demodulize, from: :ree_string
7
6
  link :group_by, from: :ree_array
8
7
  link :index_by, from: :ree_array
9
- link :underscore, from: :ree_string
10
8
 
11
9
  attr_reader :parent, :parent_dao, :list, :global_opts
12
10
 
13
- contract(ReeDao::Associations, Sequel::Dataset, Array, Ksplat[RestKeys => Any] => Any)
11
+ contract(ReeDao::Associations, Nilor[Sequel::Dataset], Array, Ksplat[RestKeys => Any] => Any)
14
12
  def initialize(parent, parent_dao, list, **global_opts)
15
13
  @parent = parent
16
14
  @parent_dao = parent_dao
@@ -51,8 +49,7 @@ module ReeDao
51
49
 
52
50
  dao = if scope.is_a?(Array)
53
51
  return [] if scope.empty?
54
- name = underscore(demodulize(scope.first.class.name))
55
- find_dao(name, parent, nil)
52
+ nil
56
53
  else
57
54
  find_dao(assoc_name, parent, scope)
58
55
  end
@@ -125,7 +122,7 @@ module ReeDao
125
122
  **global_opts
126
123
  )
127
124
 
128
- if parent_dao.db.in_transaction? || ReeDao::Associations.sync_mode?
125
+ if parent_dao.nil? || parent_dao.db.in_transaction? || ReeDao::Associations.sync_mode?
129
126
  associations.instance_exec(assoc_list, &block)
130
127
  else
131
128
  threads = associations.instance_exec(assoc_list, &block)
@@ -145,7 +142,7 @@ module ReeDao
145
142
  end
146
143
 
147
144
  contract(
148
- Sequel::Dataset,
145
+ Nilor[Sequel::Dataset],
149
146
  Symbol,
150
147
  Array,
151
148
  Kwargs[
@@ -170,7 +167,11 @@ module ReeDao
170
167
  if reverse
171
168
  # has_one
172
169
  if !foreign_key
173
- foreign_key = "#{parent_dao.first_source_table.to_s.gsub(/s$/,'')}_id".to_sym
170
+ if parent_dao.nil?
171
+ raise ArgumentError.new("foreign_key should be provided for :#{assoc_name} association")
172
+ end
173
+
174
+ foreign_key = foreign_key_from_dao(parent_dao)
174
175
  end
175
176
 
176
177
  root_ids = list.map(&:id).uniq
@@ -206,7 +207,7 @@ module ReeDao
206
207
  end
207
208
 
208
209
  contract(
209
- Sequel::Dataset,
210
+ Nilor[Sequel::Dataset],
210
211
  Symbol,
211
212
  Array,
212
213
  Kwargs[
@@ -228,7 +229,13 @@ module ReeDao
228
229
  assoc_dao = nil
229
230
  assoc_dao = find_dao(assoc_name, parent, scope)
230
231
 
231
- foreign_key ||= "#{parent_dao.first_source_table.to_s.gsub(/s$/, '')}_id".to_sym
232
+ if !foreign_key
233
+ if parent_dao.nil?
234
+ raise ArgumentError.new("foreign_key should be provided for :#{assoc_name} association")
235
+ end
236
+
237
+ foreign_key = foreign_key_from_dao(parent_dao)
238
+ end
232
239
 
233
240
  root_ids = list.map(&:"#{primary_key}")
234
241
 
@@ -343,5 +350,11 @@ module ReeDao
343
350
 
344
351
  parent.agg_caller.send(method, *args, &block)
345
352
  end
353
+
354
+ private
355
+
356
+ def foreign_key_from_dao(dao)
357
+ "#{dao.first_source_table.to_s.gsub(/s$/, '')}_id".to_sym
358
+ end
346
359
  end
347
360
  end
@@ -87,13 +87,13 @@ module ReeDao
87
87
  Optblock => Any
88
88
  )
89
89
  def association(assoc_type, assoc_name, __opts, &block)
90
- if parent_dao.db.in_transaction? || self.class.sync_mode?
90
+ if parent_dao.nil? || parent_dao.db.in_transaction? || self.class.sync_mode?
91
91
  return if association_is_not_included?(assoc_name) || list.empty?
92
92
 
93
93
  association = Association.new(self, parent_dao, list, **global_opts)
94
94
 
95
95
  if assoc_type == :field
96
- association.handle_field(assoc_name, __opts)
96
+ association.handle_field(__opts)
97
97
  else
98
98
  association.load(assoc_type, assoc_name, **get_assoc_opts(__opts), &block)
99
99
  end
@@ -48,7 +48,8 @@ class ReeDao::PgJsonb < ReeMapper::AbstractWrapper
48
48
  Float,
49
49
  String,
50
50
  Bool,
51
- NilClass
51
+ NilClass,
52
+ Rational,
52
53
  ]
53
54
  ).throws(ReeMapper::TypeError)
54
55
  def db_load(value, name:, role: nil, fields_filters: [])
@@ -26,3 +26,11 @@ module ReeDao
26
26
  ENV.has_key?("REE_DAO_SYNC_ASSOCIATIONS") && ENV["REE_DAO_SYNC_ASSOCIATIONS"] == "true"
27
27
  end
28
28
  end
29
+
30
+ # ReeEnum::Value#sql_literal is used to properly serialize enum values
31
+ # for database queries
32
+ class ReeEnum::Value
33
+ def sql_literal(*)
34
+ mapped_value.to_s
35
+ end
36
+ end
@@ -130,8 +130,7 @@ RSpec.describe :agg do
130
130
  end
131
131
 
132
132
  def some_method(list)
133
- # puts list.map(&:id)
134
- # puts list.map { _1.class.name }
133
+ list.each { _1.some_field = :some_value if _1.respond_to?(:some_field=) }
135
134
  end
136
135
 
137
136
  def passport_opts
@@ -978,4 +977,20 @@ RSpec.describe :agg do
978
977
  res = agg(users, users.where(organization_id: organization.id))
979
978
  expect(res.count).to eq(2)
980
979
  }
980
+
981
+ context "when sync mode enabled" do
982
+ it {
983
+ organization = ReeDaoAggTest::Organization.new(name: "Test Org")
984
+ organizations.put(organization)
985
+ user = ReeDaoAggTest::User.new(name: "John", age: 33, organization_id: organization.id)
986
+ users.put(user)
987
+
988
+ allow(user).to receive(:some_field=)
989
+ expect(user).to receive(:some_field=).with(:some_value)
990
+
991
+ ENV['REE_DAO_SYNC_ASSOCIATIONS'] = "true"
992
+ res = agg_users.([user])
993
+ ENV.delete('REE_DAO_SYNC_ASSOCIATIONS')
994
+ }
995
+ end
981
996
  end
@@ -29,6 +29,7 @@ RSpec.describe 'ReeDao::PgJsonb' do
29
29
  pg_jsonb? :number, integer
30
30
  pg_jsonb? :boolean, bool
31
31
  pg_jsonb? :any, any
32
+ pg_jsonb? :rational, rational
32
33
  end
33
34
  }
34
35
 
@@ -39,13 +40,15 @@ RSpec.describe 'ReeDao::PgJsonb' do
39
40
  numbers: [1, 2],
40
41
  figures: [{ coords: 'x=1,y=1' }],
41
42
  number: 1,
42
- boolean: true
43
+ boolean: true,
44
+ rational: Rational("1/3"),
43
45
  })).to eq({
44
46
  payload: { key: 'key' },
45
47
  numbers: [1, 2],
46
48
  figures: [{ coords: 'x=1,y=1' }],
47
49
  number: 1,
48
- boolean: true
50
+ boolean: true,
51
+ rational: "1/3",
49
52
  })
50
53
  }
51
54
 
@@ -69,13 +72,15 @@ RSpec.describe 'ReeDao::PgJsonb' do
69
72
  numbers: Sequel::Postgres::JSONBArray.new([1, 2]),
70
73
  figures: Sequel::Postgres::JSONBArray.new([{ coords: 'x=1,y=1' }]),
71
74
  number: 1,
72
- boolean: true
75
+ boolean: true,
76
+ rational: "1/3"
73
77
  })).to eq({
74
78
  payload: { key: 'key' },
75
79
  numbers: [1, 2],
76
80
  figures: [{ coords: 'x=1,y=1' }],
77
81
  number: 1,
78
- boolean: true
82
+ boolean: true,
83
+ rational: Rational("1/3"),
79
84
  })
80
85
  }
81
86
 
@@ -16,10 +16,6 @@ class ReeEnum::Value
16
16
  value
17
17
  end
18
18
 
19
- def to_sql
20
- mapped_value
21
- end
22
-
23
19
  def as_json(*args)
24
20
  to_s
25
21
  end
@@ -5,8 +5,8 @@ class ReeI18n::SetLocale
5
5
 
6
6
  fn :set_locale
7
7
 
8
- contract(Symbol => Symbol).throws(I18n::InvalidLocale)
8
+ contract(Or[Symbol, String] => Symbol).throws(I18n::InvalidLocale)
9
9
  def call(locale)
10
- I18n.locale = locale
10
+ I18n.locale = locale.to_sym
11
11
  end
12
12
  end
@@ -27,6 +27,7 @@ class ReeMapper::BuildMapperFactory
27
27
  klass.register_type(:integer, ReeMapper::Integer.new)
28
28
  klass.register_type(:string, ReeMapper::String.new)
29
29
  klass.register_type(:any, ReeMapper::Any.new)
30
+ klass.register_type(:rational, ReeMapper::Rational.new)
30
31
 
31
32
  klass.register_wrapper(:array, ReeMapper::Array)
32
33
 
@@ -12,8 +12,8 @@ class ReeMapper::Float < ReeMapper::AbstractType
12
12
 
13
13
  contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Float).throws(ReeMapper::CoercionError, ReeMapper::TypeError)
14
14
  def cast(value, name:, role: nil)
15
- if value.is_a?(Float)
16
- value
15
+ if value.is_a?(Numeric)
16
+ value.to_f
17
17
  elsif value.is_a?(String)
18
18
  begin
19
19
  Float(value)
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ReeMapper::Rational < ReeMapper::AbstractType
4
+ contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Rational).throws(ReeMapper::TypeError)
5
+ def serialize(value, name:, role: nil)
6
+ if value.is_a?(Rational)
7
+ value
8
+ else
9
+ raise ReeMapper::TypeError, "`#{name}` should be a rational"
10
+ end
11
+ end
12
+
13
+ contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Rational).throws(ReeMapper::CoercionError, ReeMapper::TypeError)
14
+ def cast(value, name:, role: nil)
15
+ if value.is_a?(Rational)
16
+ value
17
+ elsif value.is_a?(String)
18
+ begin
19
+ Rational(value)
20
+ rescue ArgumentError, ZeroDivisionError => e
21
+ raise ReeMapper::CoercionError, "`#{name}` is invalid rational"
22
+ end
23
+ elsif value.is_a?(Numeric)
24
+ Rational(value)
25
+ else
26
+ raise ReeMapper::TypeError, "`#{name}` should be a rational"
27
+ end
28
+ end
29
+
30
+ contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => String)
31
+ def db_dump(value, name:, role: nil)
32
+ serialize(value, name: name, role: role).to_s
33
+ end
34
+
35
+ contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Rational)
36
+ def db_load(value, name:, role: nil)
37
+ cast(value, name: name, role: role)
38
+ end
39
+ end
@@ -34,6 +34,7 @@ module ReeMapper
34
34
  require_relative 'ree_mapper/types/float'
35
35
  require_relative 'ree_mapper/types/integer'
36
36
  require_relative 'ree_mapper/types/string'
37
+ require_relative 'ree_mapper/types/rational'
37
38
 
38
39
  require_relative 'ree_mapper/strategy_outputs/strategy_output'
39
40
  require_relative 'ree_mapper/strategy_outputs/object_output'
@@ -32,7 +32,11 @@ RSpec.describe 'ReeMapper::Float' do
32
32
  }
33
33
 
34
34
  it {
35
- expect(mapper.db_load({ float: BigDecimal("1.1") })).to eq({ float: 1.1 })
35
+ expect(mapper.cast({ float: BigDecimal("1.1") })).to eq({ float: 1.1 })
36
+ }
37
+
38
+ it {
39
+ expect(mapper.cast({ float: 1 })).to eq({ float: 1.0 })
36
40
  }
37
41
 
38
42
  it {
@@ -40,7 +44,7 @@ RSpec.describe 'ReeMapper::Float' do
40
44
  }
41
45
 
42
46
  it {
43
- expect { mapper.db_load({ float: '1.1a' }) }.to raise_error(ReeMapper::CoercionError, '`float` is invalid float')
47
+ expect { mapper.cast({ float: '1.1a' }) }.to raise_error(ReeMapper::CoercionError, '`float` is invalid float')
44
48
  }
45
49
 
46
50
  it {
@@ -97,6 +101,10 @@ RSpec.describe 'ReeMapper::Float' do
97
101
  expect(mapper.db_load({ float: BigDecimal("1.1") })).to eq({ float: 1.1 })
98
102
  }
99
103
 
104
+ it {
105
+ expect(mapper.db_load({ float: 1 })).to eq({ float: 1.0 })
106
+ }
107
+
100
108
  it {
101
109
  expect { mapper.db_load({ float: 'a1.1' }) }.to raise_error(ReeMapper::CoercionError, '`float` is invalid float')
102
110
  }
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+ require 'bigdecimal'
3
+
4
+ RSpec.describe 'ReeMapper::Rational' do
5
+ link :build_mapper_factory, from: :ree_mapper
6
+ link :build_mapper_strategy, from: :ree_mapper
7
+
8
+ let(:mapper_factory) {
9
+ build_mapper_factory(
10
+ strategies: [
11
+ build_mapper_strategy(method: :cast, dto: Hash),
12
+ build_mapper_strategy(method: :serialize, dto: Hash),
13
+ build_mapper_strategy(method: :db_dump, dto: Hash),
14
+ build_mapper_strategy(method: :db_load, dto: Hash)
15
+ ]
16
+ )
17
+ }
18
+
19
+ let(:mapper) {
20
+ mapper_factory.call.use(:cast).use(:serialize).use(:db_dump).use(:db_load) {
21
+ rational :rational
22
+ }
23
+ }
24
+
25
+ describe '#cast' do
26
+ it {
27
+ expect(mapper.cast({ rational: Rational("1/3") })).to eq({ rational: Rational("1/3") })
28
+ }
29
+
30
+ it {
31
+ expect(mapper.cast({ rational: 0.33 })).to eq({ rational: Rational(0.33) })
32
+ }
33
+
34
+ it {
35
+ expect(mapper.cast({ rational: '0.33' })).to eq({ rational: Rational('0.33') })
36
+ }
37
+
38
+ it {
39
+ expect(mapper.cast({ rational: BigDecimal("0.33") })).to eq({ rational: Rational(BigDecimal("0.33")) })
40
+ }
41
+
42
+ it {
43
+ expect { mapper.cast({ rational: 'a333' }) }.to raise_error(ReeMapper::CoercionError, '`rational` is invalid rational')
44
+ }
45
+
46
+ it {
47
+ expect { mapper.cast({ rational: '333a' }) }.to raise_error(ReeMapper::CoercionError, '`rational` is invalid rational')
48
+ }
49
+
50
+ it {
51
+ expect { mapper.cast({ rational: Object.new }) }.to raise_error(ReeMapper::TypeError, "`rational` should be a rational")
52
+ }
53
+ end
54
+
55
+ describe '#serialize' do
56
+ it {
57
+ expect(mapper.serialize({ rational: Rational("1/3") })).to eq({ rational: Rational("1/3") })
58
+ }
59
+
60
+ it {
61
+ expect { mapper.serialize({ rational: '1/3' }) }.to raise_error(ReeMapper::TypeError, "`rational` should be a rational")
62
+ }
63
+
64
+ it {
65
+ expect { mapper.serialize({ rational: nil }) }.to raise_error(ReeMapper::TypeError, "`rational` should be a rational")
66
+ }
67
+
68
+ it {
69
+ expect { mapper.serialize({ rational: Object.new }) }.to raise_error(ReeMapper::TypeError, "`rational` should be a rational")
70
+ }
71
+ end
72
+
73
+ describe '#db_dump' do
74
+ it {
75
+ expect(mapper.db_dump({ rational: Rational("1/3") })).to eq({ rational: "1/3" })
76
+ }
77
+
78
+ it {
79
+ expect { mapper.db_dump({ rational: '1/3' }) }.to raise_error(ReeMapper::TypeError, "`rational` should be a rational")
80
+ }
81
+
82
+ it {
83
+ expect { mapper.db_dump({ rational: nil }) }.to raise_error(ReeMapper::TypeError, "`rational` should be a rational")
84
+ }
85
+
86
+ it {
87
+ expect { mapper.db_dump({ rational: Object.new }) }.to raise_error(ReeMapper::TypeError, "`rational` should be a rational")
88
+ }
89
+ end
90
+
91
+ describe '#db_load' do
92
+ it {
93
+ expect(mapper.db_load({ rational: Rational("1/3") })).to eq({ rational: Rational("1/3") })
94
+ }
95
+
96
+ it {
97
+ expect(mapper.db_load({ rational: 0.33 })).to eq({ rational: Rational(0.33) })
98
+ }
99
+
100
+ it {
101
+ expect(mapper.db_load({ rational: '0.33' })).to eq({ rational: Rational('0.33') })
102
+ }
103
+
104
+ it {
105
+ expect(mapper.db_load({ rational: BigDecimal("0.33") })).to eq({ rational: Rational(BigDecimal("0.33")) })
106
+ }
107
+
108
+ it {
109
+ expect { mapper.db_load({ rational: 'a333' }) }.to raise_error(ReeMapper::CoercionError, '`rational` is invalid rational')
110
+ }
111
+
112
+ it {
113
+ expect { mapper.db_load({ rational: '333a' }) }.to raise_error(ReeMapper::CoercionError, '`rational` is invalid rational')
114
+ }
115
+
116
+ it {
117
+ expect { mapper.db_load({ rational: Object.new }) }.to raise_error(ReeMapper::TypeError, "`rational` should be a rational")
118
+ }
119
+ end
120
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReeLib
4
- VERSION = "1.0.70"
4
+ VERSION = "1.0.72"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ree_lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.70
4
+ version: 1.0.72
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-26 00:00:00.000000000 Z
11
+ date: 2023-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ree
@@ -1022,6 +1022,7 @@ files:
1022
1022
  - lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/date_time.rb
1023
1023
  - lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/float.rb
1024
1024
  - lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/integer.rb
1025
+ - lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/rational.rb
1025
1026
  - lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/string.rb
1026
1027
  - lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/time.rb
1027
1028
  - lib/ree_lib/packages/ree_mapper/package/ree_mapper/wrappers/abstract_wrapper.rb
@@ -1042,6 +1043,7 @@ files:
1042
1043
  - lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/float_spec.rb
1043
1044
  - lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/hash_spec.rb
1044
1045
  - lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/integer_spec.rb
1046
+ - lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/rational_spec.rb
1045
1047
  - lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/string_spec.rb
1046
1048
  - lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/time_spec.rb
1047
1049
  - lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/type_options_spec.rb