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 +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +2 -2
- data/lib/luna_park/extensions/exceptions/substitutive.rb +0 -1
- data/lib/luna_park/extensions/injector/dependencies.rb +1 -1
- data/lib/luna_park/extensions/injector.rb +1 -1
- data/lib/luna_park/mappers/codirectional/copyists/nested.rb +92 -0
- data/lib/luna_park/mappers/codirectional/copyists/slice.rb +28 -0
- data/lib/luna_park/mappers/codirectional.rb +130 -0
- data/lib/luna_park/mappers/errors.rb +13 -0
- data/lib/luna_park/mappers/simple.rb +7 -3
- data/lib/luna_park/use_cases/scenario.rb +2 -1
- data/lib/luna_park/version.rb +1 -1
- data/lib/luna_park.rb +1 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdf7e8b655b452fed676d668734e7ff9aa9ce6acab8fba29db0e07bd22b9b24d
|
4
|
+
data.tar.gz: 55adce683441034c0b47f1b1f93e45c7d562e7d965ce800eb73e72e71304d73c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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)
|
@@ -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] =
|
51
|
+
cache.key?(key) ? cache[key] : cache[key] = fetch(key).call
|
52
52
|
end
|
53
53
|
|
54
54
|
def []=(key, _val)
|
@@ -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
|
322
|
+
raise error
|
322
323
|
end
|
323
324
|
end
|
324
325
|
end
|
data/lib/luna_park/version.rb
CHANGED
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.
|
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-
|
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
|