luna_park 0.11.2 → 0.11.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: bc89904bfac7a26a4898141e26a1ec059fdc19a5de2adc7dca5c54e58e04bee8
4
- data.tar.gz: 142b00eeb4fee4f412b9a811e196104b4522a1354a95b5e58dbc766b7e3e8a3c
3
+ metadata.gz: bdf7e8b655b452fed676d668734e7ff9aa9ce6acab8fba29db0e07bd22b9b24d
4
+ data.tar.gz: 55adce683441034c0b47f1b1f93e45c7d562e7d965ce800eb73e72e71304d73c
5
5
  SHA512:
6
- metadata.gz: 8443e5c9f90f0a80647eebe61453e21a0de3130bd16147171dd19ed4df25217b8f8b85d09754b3105b82e3a51485f9fbb6c5726838705f3ba03363fb28fd01fb
7
- data.tar.gz: a6c102273edc954cd156d9f68cc250a22c0ef272d89650a1a84779724e43b507ed8fa40b5704096152efdcc0b6abf2bf29a837de028ac5b9919c3d7905d75eb8
6
+ metadata.gz: 49af03152d02807005c2b308f67d4ce5553762a15608e5a562c5c024ede6ccdc0526c9890e55ab4095302bb80e29b86ae5066b39d43892121ec65b6339c1f744
7
+ data.tar.gz: 03ab2f5cc9c4c4b945ad0f50a39e841a08b5ab1ecb137b7cbba1ee099270765e21fb63b391ec867bba6eaee5d82d207479b39e04bdc15a36fd62c74860f2cb80
data/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.11.3] - 2021-09-02
8
+ Added
9
+ - new mapper `Mappers::Codirectionsl` with DSL
10
+
7
11
  ## [0.11.2] - 2021-09-01
8
12
  Added
9
13
  - Github CI
data/Gemfile.lock CHANGED
@@ -6,7 +6,7 @@ PATH
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- addressable (2.7.0)
9
+ addressable (2.8.0)
10
10
  public_suffix (>= 2.0.2, < 5.0)
11
11
  ast (2.4.1)
12
12
  bugsnag (6.13.1)
@@ -95,7 +95,7 @@ GEM
95
95
  pry-byebug (3.9.0)
96
96
  byebug (~> 11.0)
97
97
  pry (~> 0.13.0)
98
- public_suffix (4.0.5)
98
+ public_suffix (4.0.6)
99
99
  rainbow (3.0.0)
100
100
  rake (13.0.1)
101
101
  regexp_parser (1.7.1)
@@ -4,7 +4,6 @@ module LunaPark
4
4
  module Extensions
5
5
  module Exceptions
6
6
  # class-level mixin
7
-
8
7
  module Substitutive
9
8
  def self.extended(base)
10
9
  base.extend ClassMethods
@@ -48,7 +48,7 @@ module LunaPark
48
48
  # use_case.dependencies[:messenger] # => #<Proc:0x0000564a0d90d438@t.rb:34>
49
49
  # use_case.dependencies.call_with_cache(:messenger) # => 'Foobar'
50
50
  def call_with_cache(key)
51
- cache.key?(key) ? cache[key] : cache[key] = self.fetch(key).call
51
+ cache.key?(key) ? cache[key] : cache[key] = fetch(key).call
52
52
  end
53
53
 
54
54
  def []=(key, _val)
@@ -126,7 +126,7 @@ module LunaPark
126
126
  def dependency(name, &block)
127
127
  raise ArgumentError, 'no block given' unless block_given?
128
128
 
129
- self.dependencies[name] = block
129
+ dependencies[name] = block
130
130
 
131
131
  define_method(name) do
132
132
  dependencies.call_with_cache(name)
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LunaPark
4
+ module Mappers
5
+ class Codirectional < Simple
6
+ module Copyists
7
+ # Copyist for copiyng value between two schemas with DIFFERENT or NESTED paths
8
+ # (Works with only one described attribute)
9
+ class Nested
10
+ def initialize(attrs_path:, row_path:)
11
+ @attrs_path = attrs_path
12
+ @row_path = row_path
13
+
14
+ raise ArgumentError, 'attr path can not be nil' if attrs_path.nil?
15
+ raise ArgumentError, 'store path can not be nil' if row_path.nil?
16
+ end
17
+
18
+ def from_row(row:, attrs:)
19
+ copy_nested(from: row, to: attrs, from_path: @row_path, to_path: @attrs_path)
20
+ end
21
+
22
+ def to_row(row:, attrs:)
23
+ copy_nested(from: attrs, to: row, from_path: @attrs_path, to_path: @row_path)
24
+ end
25
+
26
+ private
27
+
28
+ def copy_nested(from:, to:, from_path:, to_path:)
29
+ value = read(from, from_path)
30
+
31
+ return if value == Undefined # omit undefined keys
32
+
33
+ write(to, to_path, value)
34
+ end
35
+
36
+ def read(from, from_path)
37
+ if from_path.is_a?(Array) # when given `%i[key path]` - not just `:key`
38
+ read_nested(from, path: from_path)
39
+ else # when given just `:key`
40
+ read_plain(from, key: from_path)
41
+ end
42
+ end
43
+
44
+ def write(to, to_path, value)
45
+ if to_path.is_a?(Array) # when given `%i[key path]` - not just `:key`
46
+ write_nested(to, to_path, value)
47
+ else # when given just `:key`
48
+ to[to_path] = value
49
+ end
50
+ end
51
+
52
+ def read_nested(from, path:)
53
+ *path_to_head, head_key = path # split `[:a, :b, :c]` to `[:a, :b]` and `:c`
54
+ head_hash = from.dig(*path_to_head) # from `{a: {b: {c: 'value'}}}` get `{c: 'value'}`
55
+
56
+ return Undefined if head_hash.nil? # when there are no key at the path `[:a, :b]`
57
+ return Undefined unless head_hash.key?(head_key) # when there are no key at the path `[:a, :b, :c]`
58
+
59
+ head_hash[head_key] # get 'value' from from `{c: 'value'}` stored at `{a: {b: {c: 'value'}}}`
60
+ end
61
+
62
+ def read_plain(from, key:)
63
+ from.key?(key) ? from[key] : Undefined
64
+ end
65
+
66
+ def write_nested(hash, full_path, value)
67
+ *tail_path, head_key = full_path
68
+ build_nested_hash(hash, tail_path)[head_key] = value
69
+ end
70
+
71
+ #
72
+ # @example
73
+ # hash = { a: { x: 'x' } }
74
+ # build_nested_hash(hash, [:a, :b, :c]) # => {} # (returns new hash at path [:a, :b, :c])
75
+ # hash # => { a: { b: { c: {} }, x: 'x' } }
76
+ #
77
+ # @example
78
+ # hash = { a: { x: 'x' } }
79
+ # build_nested_hash(hash, [:a, :b, :c])[:d] = 'value'
80
+ # hash # => { a: { b: { c: { d: 'value' } }, x: 'x' } }
81
+ def build_nested_hash(nested_hash, path)
82
+ path.inject(nested_hash) { |output, key| output[key] ||= {} }
83
+ end
84
+
85
+ class Undefined; end
86
+
87
+ private_constant :Undefined
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LunaPark
4
+ module Mappers
5
+ class Codirectional < Simple
6
+ module Copyists
7
+ # Copyist for copiyng value between two schemas with SAME and PLAIN paths
8
+ class Slice
9
+ def initialize
10
+ @keys = []
11
+ end
12
+
13
+ def add_key(key)
14
+ @keys << key
15
+ end
16
+
17
+ def from_row(row:, attrs:)
18
+ attrs.merge! row.slice(*@keys)
19
+ end
20
+
21
+ def to_row(row:, attrs:)
22
+ row.merge! attrs.slice(*@keys)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luna_park/mappers/simple'
4
+ require 'luna_park/mappers/codirectional/copyists/slice'
5
+ require 'luna_park/mappers/codirectional/copyists/nested'
6
+
7
+ module LunaPark
8
+ module Mappers
9
+ ##
10
+ # DSL for describe Nested Schema translation: entity attributes to database row and vice-versa
11
+ #
12
+ # @example
13
+ # class Mappers::Transaction < LunaPark::Mappers::Codirectional
14
+ # map attr: :uid, row: :id
15
+ # map attr: [:charge, :amount], row: :charge_amount
16
+ # map attr: [:charge, :currency], row: :charge_currency # using aliased args
17
+ # map :comment
18
+ # end
19
+ #
20
+ # mapper = Mappers::Transaction
21
+ #
22
+ # attrs = { charge: { amount: 10, currency: 'USD' }, comment: 'Foobar' }
23
+ # transaction = Entities::Transaction.new(attrs)
24
+ #
25
+ # # Mapper transforms attr attributes to database row and vice-verse
26
+ # row = mapper.to_row(transaction) # => { charge_amount: 10, charge_currency: 'USD', comment: 'Foobar' }
27
+ # new_row = sequel_database_table.insert(row) # => { id: 42, charge_amount: 10, charge_currency: 'USD', comment: 'Foobar' }
28
+ # new_attrs = mapper.from_row(new_row) # => { uid: 42, charge: { amount: 10, currency: 'USD' }, comment: 'Foobar' }
29
+ #
30
+ # transaction.set_attributes(new_attrs)
31
+ # transaction.to_h # => { uid: 42, charge: { amount: 10, currency: 'USD' }, comment: 'Foobar' }
32
+ class Codirectional < Simple
33
+ class << self
34
+ ##
35
+ # Describe translation between two schemas: attr and table
36
+ #
37
+ # @example
38
+ # class Mappers::Transaction < LunaPark::Mappers::Codirectional
39
+ # map attr: :id, row: :uid
40
+ # map attr: [:charge, :amount], row: :charge_amount
41
+ # map :comment
42
+ # end
43
+ #
44
+ # Mappers::Transaction.from_row({ id: 1, charge_amount: 2 }) # => { uid: 1, charge: { amount: 2 } }
45
+ # Mappers::Transaction.to_row({ uid: 1, charge: { amount: 2 } }) # => { id: 1, charge_amount: 2 }
46
+ def map(*common_keys, attr: nil, row: nil)
47
+ attrs(*common_keys) if common_keys.any?
48
+
49
+ self.attr attr, row: row if attr
50
+ end
51
+
52
+ # @example
53
+ # class Mappers::Transaction < LunaPark::Mappers::Codirectional
54
+ # attr :uid, row: :id
55
+ # attr %i[charge amount], row: :charge_amount
56
+ # end
57
+ def attr(attr, row: nil)
58
+ return attrs(attr) if row.nil?
59
+
60
+ attr_path = to_path(attr)
61
+ row_path = to_path(row)
62
+
63
+ if attr_path == row_path
64
+ attrs(attr_path)
65
+ else
66
+ nested_copyists << Copyists::Nested.new(attrs_path: attr_path, row_path: row_path)
67
+ end
68
+ end
69
+
70
+ # @example
71
+ # class Mappers::Transaction < LunaPark::Mappers::Codirectional
72
+ # attrs :comment, :uid, %i[addresses home], :created_at
73
+ # end
74
+ def attrs(*common_keys)
75
+ common_keys.each do |common_key|
76
+ path = to_path(common_key)
77
+ if path.is_a?(Array)
78
+ nested_copyists << Copyists::Nested.new(attrs_path: path, row_path: path)
79
+ else
80
+ slice_copyist.add_key(path)
81
+ end
82
+ end
83
+ end
84
+
85
+ def from_row(input)
86
+ row = input.to_h
87
+ {}.tap do |attrs|
88
+ slice_copyist.from_row(row: row, attrs: attrs)
89
+ nested_copyists.each { |copyist| copyist.from_row(row: row, attrs: attrs) }
90
+ end
91
+ end
92
+
93
+ def to_row(input)
94
+ attrs = input.to_h
95
+ {}.tap do |row|
96
+ slice_copyist.to_row(row: row, attrs: attrs)
97
+ nested_copyists.each { |copyist| copyist.to_row(row: row, attrs: attrs) }
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ # @example
104
+ # to_path :email # => :email
105
+ # to_path ['email'] # => :email
106
+ # to_path [:charge, 'amount'] # => [:charge, :amount]
107
+ def to_path(input, full: input)
108
+ case input
109
+ when Symbol then input
110
+ when String then input.to_sym
111
+ when Array
112
+ return to_path(input.first, full: full) if input.size <= 1
113
+
114
+ input.flat_map { |elem| to_path(elem, full: full) }
115
+ else raise ArgumentError, "Unexpected path part `#{input.inspect}` in `#{full.inspect}`. " \
116
+ 'Expected Symbol, String or Array'
117
+ end
118
+ end
119
+
120
+ def slice_copyist
121
+ @slice_copyist ||= Copyists::Slice.new
122
+ end
123
+
124
+ def nested_copyists
125
+ @nested_copyists ||= []
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luna_park/errors'
4
+
5
+ module LunaPark
6
+ module Mappers
7
+ module Errors
8
+ class NotArray < LunaPark::Errors::System
9
+ message { |d| "input MUST be an Array, but given #{d[:input].class} `#{d[:input].inspect}`" }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'luna_park/errors'
3
+ require 'luna_park/mappers/errors'
4
4
 
5
5
  module LunaPark
6
6
  module Mappers
7
+ ##
7
8
  # Abstract mapper for transform data from Entity attributes schema to Database row schema
9
+ #
8
10
  # @example
9
11
  # class TransactionMapper < LunaPark::Mappers::Simple
10
12
  # def self.from_row(row)
@@ -65,6 +67,7 @@ module LunaPark
65
67
  # Transforms array of rows to array of attribute hashes
66
68
  def from_rows(rows)
67
69
  return [] if rows.nil?
70
+ raise Errors::NotArray.new(input: rows) unless rows.is_a?(Array)
68
71
 
69
72
  rows.to_a.map { |hash| from_row(hash) }
70
73
  end
@@ -73,18 +76,19 @@ module LunaPark
73
76
  # Transforms array of attribute hashes to array of rows
74
77
  def to_rows(attr_hashes)
75
78
  return [] if attr_hashes.nil?
79
+ raise Errors::NotArray.new(input: attr_hashes) unless attr_hashes.is_a?(Array)
76
80
 
77
81
  attr_hashes.to_a.map { |entity| to_row(entity) }
78
82
  end
79
83
 
80
84
  # @abstract
81
85
  def from_row(_row)
82
- raise Errors::AbstractMethod
86
+ raise LunaPark::Errors::AbstractMethod
83
87
  end
84
88
 
85
89
  # @abstract
86
90
  def to_row(_attrs)
87
- raise Errors::AbstractMethod
91
+ raise LunaPark::Errors::AbstractMethod
88
92
  end
89
93
  end
90
94
  end
@@ -252,6 +252,7 @@ module LunaPark
252
252
  end
253
253
 
254
254
  alias failure? fail?
255
+ alias failed? fail?
255
256
 
256
257
  # @return [Boolean] true if the scenario runs successfully
257
258
  def success?
@@ -318,7 +319,7 @@ module LunaPark
318
319
  end
319
320
 
320
321
  def on_raise(error)
321
- raise error.cover_up_backtrace
322
+ raise error
322
323
  end
323
324
  end
324
325
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LunaPark
4
- VERSION = '0.11.2'
4
+ VERSION = '0.11.3'
5
5
  end
data/lib/luna_park.rb CHANGED
@@ -67,6 +67,7 @@ require 'luna_park/values/compound'
67
67
  require 'luna_park/values/single'
68
68
  require 'luna_park/values/attributable'
69
69
  require 'luna_park/mappers/simple'
70
+ require 'luna_park/mappers/codirectional'
70
71
  require 'luna_park/repository'
71
72
  require 'luna_park/repositories/sequel'
72
73
  require 'luna_park/repositories/postgres'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: luna_park
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.2
4
+ version: 0.11.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Kudrin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2021-09-01 00:00:00.000000000 Z
12
+ date: 2021-09-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bugsnag
@@ -368,6 +368,10 @@ files:
368
368
  - lib/luna_park/http/request.rb
369
369
  - lib/luna_park/http/response.rb
370
370
  - lib/luna_park/http/send.rb
371
+ - lib/luna_park/mappers/codirectional.rb
372
+ - lib/luna_park/mappers/codirectional/copyists/nested.rb
373
+ - lib/luna_park/mappers/codirectional/copyists/slice.rb
374
+ - lib/luna_park/mappers/errors.rb
371
375
  - lib/luna_park/mappers/simple.rb
372
376
  - lib/luna_park/notifiers/bugsnag.rb
373
377
  - lib/luna_park/notifiers/log.rb