ree_lib 1.0.104 → 1.0.106
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/Gemfile.lock +1 -1
- data/lib/ree_lib/packages/ree_dao/package/ree_dao/dataset_extensions.rb +40 -21
- data/lib/ree_lib/packages/ree_dao/spec/ree_dao/functions/one_to_one_spec.rb +5 -9
- data/lib/ree_lib/packages/ree_dto/Package.schema.json +17 -2
- data/lib/ree_lib/packages/ree_dto/package/ree_dto/dsl.rb +8 -0
- data/lib/ree_lib/packages/ree_dto/package/ree_dto/dto/collection_filter.rb +49 -0
- data/lib/ree_lib/packages/ree_dto/package/ree_dto/dto/collection_meta.rb +13 -0
- data/lib/ree_lib/packages/ree_dto/package/ree_dto/dto/dto_builder.rb +42 -0
- data/lib/ree_lib/packages/ree_dto/package/ree_dto/dto/dto_class_methods.rb +27 -0
- data/lib/ree_lib/packages/ree_dto/package/ree_dto/dto/dto_collection.rb +45 -0
- data/lib/ree_lib/packages/ree_dto/package/ree_dto/dto/dto_instance_methods.rb +111 -0
- data/lib/ree_lib/packages/ree_dto/package/ree_dto/dto/field_meta.rb +21 -0
- data/lib/ree_lib/packages/ree_dto/package/ree_dto/functions/build_dto.rb +62 -0
- data/lib/ree_lib/packages/ree_dto/package/ree_dto/functions/build_dto_collection_class.rb +27 -0
- data/lib/ree_lib/packages/ree_dto/package/ree_dto.rb +16 -3
- data/lib/ree_lib/packages/ree_dto/spec/ree_dto/dsl_spec.rb +117 -0
- data/lib/ree_lib/packages/ree_mapper/Package.schema.json +3 -0
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper.rb +1 -1
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_strategy.rb +2 -0
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/strategy_outputs/ree_dto_output.rb +14 -0
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper.rb +2 -0
- data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/mapper_spec.rb +28 -0
- data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/hash_spec.rb +1 -1
- data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/type_options_spec.rb +1 -1
- data/lib/ree_lib/version.rb +1 -1
- metadata +14 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 558dbd22038f40db477b968aa0595ca664484c05606827276b2d872ad6eb5dab
|
|
4
|
+
data.tar.gz: f190528d1cf21d60f1403252fd16d6e9e62beb291b4cddcca2af03f77bddce85
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b5f0cf27786a919265f1c01982c7f8640e5b27edf837ed9a207243e6c513f3a97ab2487ad4c16ebc01feb7d7641509d38b336ef77024fb325b059aa32a61d96e
|
|
7
|
+
data.tar.gz: 6ddd53ea7f83cded5374da832c06ef845062c2574e832ccfec241602722a63a32390f78f02fc50f2d030f94b7e1cf404e976c00fa3237c11607cd2fa96504ee7
|
data/Gemfile.lock
CHANGED
|
@@ -44,7 +44,8 @@ module ReeDao
|
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def put(entity)
|
|
47
|
-
raw =
|
|
47
|
+
raw = dump_entity(entity)
|
|
48
|
+
|
|
48
49
|
remove_null_primary_key(raw)
|
|
49
50
|
key = insert(raw)
|
|
50
51
|
|
|
@@ -81,7 +82,6 @@ module ReeDao
|
|
|
81
82
|
def import_all(entities, batch_size: IMPORT_BATCH_SIZE)
|
|
82
83
|
return if entities.empty?
|
|
83
84
|
|
|
84
|
-
mapper = opts[:schema_mapper]
|
|
85
85
|
columns = self.columns
|
|
86
86
|
raw = {}
|
|
87
87
|
|
|
@@ -89,7 +89,7 @@ module ReeDao
|
|
|
89
89
|
columns.delete(:row)
|
|
90
90
|
|
|
91
91
|
data = entities.map do |entity|
|
|
92
|
-
hash =
|
|
92
|
+
hash = dump_entity(entity)
|
|
93
93
|
raw[entity] = hash
|
|
94
94
|
|
|
95
95
|
columns.map { hash[_1] }
|
|
@@ -115,16 +115,22 @@ module ReeDao
|
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def update(hash_or_entity)
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
if !opts[:schema_mapper] || hash_or_entity.is_a?(Hash)
|
|
119
|
+
return __original_update(hash_or_entity)
|
|
120
|
+
end
|
|
120
121
|
|
|
121
|
-
|
|
122
|
-
raw = extract_changes(hash_or_entity,
|
|
122
|
+
dump = dump_entity(hash_or_entity)
|
|
123
|
+
raw = extract_changes(hash_or_entity, dump)
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
update_persistence_state(hash_or_entity, raw)
|
|
125
|
+
if !raw.empty?
|
|
126
126
|
key_condition = prepare_key_condition_from_entity(hash_or_entity)
|
|
127
127
|
where(key_condition).__original_update(raw)
|
|
128
|
+
|
|
129
|
+
if is_ree_dto?(hash_or_entity)
|
|
130
|
+
hash_or_entity.reset_changes
|
|
131
|
+
else
|
|
132
|
+
update_persistence_state(hash_or_entity, raw)
|
|
133
|
+
end
|
|
128
134
|
end
|
|
129
135
|
|
|
130
136
|
hash_or_entity
|
|
@@ -159,9 +165,7 @@ module ReeDao
|
|
|
159
165
|
|
|
160
166
|
if m
|
|
161
167
|
entity = m.db_load(hash)
|
|
162
|
-
|
|
163
168
|
self.set_persistence_state(entity, hash)
|
|
164
|
-
|
|
165
169
|
entity
|
|
166
170
|
else
|
|
167
171
|
hash
|
|
@@ -205,6 +209,8 @@ module ReeDao
|
|
|
205
209
|
end
|
|
206
210
|
|
|
207
211
|
def set_persistence_state(entity, raw)
|
|
212
|
+
return if is_ree_dto?(entity)
|
|
213
|
+
|
|
208
214
|
if !entity.is_a?(Integer) && !entity.is_a?(Symbol)
|
|
209
215
|
entity.instance_variable_set(PERSISTENCE_STATE_VARIABLE, raw)
|
|
210
216
|
end
|
|
@@ -219,22 +225,26 @@ module ReeDao
|
|
|
219
225
|
end
|
|
220
226
|
|
|
221
227
|
def extract_changes(entity, hash)
|
|
222
|
-
|
|
223
|
-
|
|
228
|
+
if is_ree_dto?(entity)
|
|
229
|
+
hash.slice(*entity.changed_fields)
|
|
230
|
+
else
|
|
231
|
+
return hash unless entity.instance_variable_defined?(PERSISTENCE_STATE_VARIABLE)
|
|
232
|
+
changes = {}
|
|
224
233
|
|
|
225
|
-
|
|
234
|
+
persistence_state = entity.instance_variable_get(PERSISTENCE_STATE_VARIABLE)
|
|
226
235
|
|
|
227
|
-
|
|
228
|
-
|
|
236
|
+
hash.each do |column, value|
|
|
237
|
+
previous_column_value = persistence_state[column]
|
|
229
238
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
239
|
+
if persistence_state.has_key?(column)
|
|
240
|
+
if previous_column_value != value || value.respond_to?(:each)
|
|
241
|
+
changes[column] = value
|
|
242
|
+
end
|
|
233
243
|
end
|
|
234
244
|
end
|
|
235
|
-
end
|
|
236
245
|
|
|
237
|
-
|
|
246
|
+
changes
|
|
247
|
+
end
|
|
238
248
|
end
|
|
239
249
|
|
|
240
250
|
def set_entity_primary_key(entity, raw, key)
|
|
@@ -246,10 +256,19 @@ module ReeDao
|
|
|
246
256
|
else
|
|
247
257
|
entity.instance_variable_set("@#{primary_key}", key)
|
|
248
258
|
end
|
|
259
|
+
|
|
249
260
|
raw[primary_key] = key
|
|
250
261
|
end
|
|
251
262
|
end
|
|
252
263
|
|
|
264
|
+
def dump_entity(entity_or_hash)
|
|
265
|
+
opts[:schema_mapper].db_dump(entity_or_hash)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def is_ree_dto?(entity)
|
|
269
|
+
entity.class.include?(ReeDto::DSL)
|
|
270
|
+
end
|
|
271
|
+
|
|
253
272
|
def prepare_key_condition_from_entity(entity)
|
|
254
273
|
key_condition = {}
|
|
255
274
|
|
|
@@ -45,6 +45,7 @@ RSpec.describe :one_to_one do
|
|
|
45
45
|
|
|
46
46
|
package do
|
|
47
47
|
depends_on :ree_dao
|
|
48
|
+
depends_on :ree_dto
|
|
48
49
|
end
|
|
49
50
|
|
|
50
51
|
class Db
|
|
@@ -89,16 +90,11 @@ RSpec.describe :one_to_one do
|
|
|
89
90
|
end
|
|
90
91
|
|
|
91
92
|
class ProjectUser
|
|
92
|
-
include ReeDto::
|
|
93
|
-
|
|
94
|
-
properties(
|
|
95
|
-
id: Nilor[Integer],
|
|
96
|
-
project_id: Nilor[Integer]
|
|
97
|
-
)
|
|
93
|
+
include ReeDto::DSL
|
|
98
94
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
build_dto do
|
|
96
|
+
field :id, Nilor[Integer], default: nil
|
|
97
|
+
field :project_id, Nilor[Integer]
|
|
102
98
|
end
|
|
103
99
|
end
|
|
104
100
|
|
|
@@ -7,12 +7,27 @@
|
|
|
7
7
|
"ree_dto"
|
|
8
8
|
],
|
|
9
9
|
"depends_on": [
|
|
10
|
-
|
|
10
|
+
{
|
|
11
|
+
"name": "ree_object"
|
|
12
|
+
}
|
|
11
13
|
],
|
|
12
14
|
"env_vars": [
|
|
13
15
|
|
|
14
16
|
],
|
|
15
17
|
"objects": [
|
|
16
|
-
|
|
18
|
+
{
|
|
19
|
+
"name": "build_dto",
|
|
20
|
+
"schema": "packages/ree_dto/schemas/ree_dto/functions/build_dto.schema.json",
|
|
21
|
+
"tags": [
|
|
22
|
+
"fn"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "build_dto_collection_class",
|
|
27
|
+
"schema": "packages/ree_dto/schemas/ree_dto/functions/build_dto_collection_class.schema.json",
|
|
28
|
+
"tags": [
|
|
29
|
+
"fn"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
17
32
|
]
|
|
18
33
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
class ReeDto::CollectionFilter
|
|
2
|
+
include Ree::Contracts::Core
|
|
3
|
+
include Ree::Contracts::ArgContracts
|
|
4
|
+
include Enumerable
|
|
5
|
+
|
|
6
|
+
InvalidFilterItemErr = Class.new(ArgumentError)
|
|
7
|
+
|
|
8
|
+
contract Any, Symbol, Proc => Any
|
|
9
|
+
def initialize(collection, name, filter_proc)
|
|
10
|
+
@collection = collection
|
|
11
|
+
@name = name
|
|
12
|
+
@filter_proc = filter_proc
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
contract Optblock => Any
|
|
16
|
+
def each(&block)
|
|
17
|
+
@collection.select(&@filter_proc).each(&block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
contract Any => Any
|
|
21
|
+
def add(item)
|
|
22
|
+
check_item(item)
|
|
23
|
+
@collection.add(item)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
contract None => Integer
|
|
27
|
+
def size
|
|
28
|
+
count
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
contract Any => Any
|
|
32
|
+
def remove(item)
|
|
33
|
+
check_item(item)
|
|
34
|
+
@collection.remove(item)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
alias :<< :add
|
|
38
|
+
alias :push :add
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def check_item(item)
|
|
43
|
+
if !@filter_proc.call(item)
|
|
44
|
+
raise InvalidFilterItemErr.new(
|
|
45
|
+
"invalid item for #{@collection.parent_class}##{@name} filter"
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class ReeDto::CollectionMeta
|
|
2
|
+
include Ree::Contracts::Core
|
|
3
|
+
include Ree::Contracts::ArgContracts
|
|
4
|
+
|
|
5
|
+
attr_reader :name, :contract, :filter_proc
|
|
6
|
+
|
|
7
|
+
contract Symbol, Any, Proc => Any
|
|
8
|
+
def initialize(name, contract, filter_proc)
|
|
9
|
+
@name = name
|
|
10
|
+
@contract = contract
|
|
11
|
+
@filter_proc = filter_proc
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
class ReeDto::DtoBuilder
|
|
2
|
+
include Ree::Contracts::Core
|
|
3
|
+
include Ree::Contracts::ArgContracts
|
|
4
|
+
include Ree::LinkDSL
|
|
5
|
+
|
|
6
|
+
link "ree_dto/dto/field_meta", -> { FieldMeta }
|
|
7
|
+
link "ree_dto/dto/collection_meta", -> { CollectionMeta }
|
|
8
|
+
|
|
9
|
+
attr_reader :fields, :collections
|
|
10
|
+
|
|
11
|
+
def initialize(klass)
|
|
12
|
+
@klass = klass
|
|
13
|
+
@fields = []
|
|
14
|
+
@collections = []
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
contract(Symbol, Any, Kwargs[setter: Bool, default: Any] => FieldMeta)
|
|
18
|
+
def field(name, contract, setter: true, default: FieldMeta::NONE)
|
|
19
|
+
existing = @fields.find { _1.name == name }
|
|
20
|
+
|
|
21
|
+
if existing
|
|
22
|
+
raise ArgumentError.new("field :#{name} already defined for #{@klass}")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
field = FieldMeta.new(name, contract, setter, default)
|
|
26
|
+
@fields << field
|
|
27
|
+
field
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
contract Symbol, Any, Optblock => CollectionMeta
|
|
31
|
+
def collection(name, contract, &proc)
|
|
32
|
+
existing = @collections.find { _1.name == name }
|
|
33
|
+
|
|
34
|
+
if existing
|
|
35
|
+
raise ArgumentError.new("collection :#{name} already defined for #{@klass}")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
collection = CollectionMeta.new(name, contract, proc)
|
|
39
|
+
@collections.push(collection)
|
|
40
|
+
collection
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require_relative "./field_meta"
|
|
2
|
+
require_relative "./collection_meta"
|
|
3
|
+
|
|
4
|
+
module ReeDto::DtoClassMethods
|
|
5
|
+
include Ree::Contracts::Core
|
|
6
|
+
include Ree::Contracts::ArgContracts
|
|
7
|
+
|
|
8
|
+
contract None => ArrayOf[ReeDto::FieldMeta]
|
|
9
|
+
def fields
|
|
10
|
+
@fields ||= []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
contract None => ArrayOf[ReeDto::CollectionMeta]
|
|
14
|
+
def collections
|
|
15
|
+
@collections ||= []
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def set_fields(v)
|
|
21
|
+
@fields = v
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def set_collections(v)
|
|
25
|
+
@collections = v
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require_relative "./collection_filter"
|
|
2
|
+
|
|
3
|
+
class ReeDto::DtoCollection
|
|
4
|
+
include Enumerable
|
|
5
|
+
|
|
6
|
+
LoadError = Class.new(ArgumentError)
|
|
7
|
+
|
|
8
|
+
attr_reader :name, :contract, :parent_class
|
|
9
|
+
|
|
10
|
+
contract Symbol, Any, Any => Any
|
|
11
|
+
def initialize(name, contract, parent_class)
|
|
12
|
+
@parent_class = parent_class
|
|
13
|
+
@contract = contract
|
|
14
|
+
@name = name
|
|
15
|
+
@list = nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
contract None => nil
|
|
19
|
+
def reset
|
|
20
|
+
@list = []
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
contract Optblock => Any
|
|
25
|
+
def each(&block)
|
|
26
|
+
if @list.nil?
|
|
27
|
+
raise LoadError.new("collection :#{@name} for #{@parent_class} is not loaded")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
@list.each(&block)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
contract None => Integer
|
|
34
|
+
def size
|
|
35
|
+
@list.size
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class << self
|
|
39
|
+
def filter(name, filter_proc)
|
|
40
|
+
define_method name do
|
|
41
|
+
ReeDto::CollectionFilter.new(self, name, filter_proc)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
require_relative "./field_meta"
|
|
2
|
+
|
|
3
|
+
module ReeDto::DtoInstanceMethods
|
|
4
|
+
include Ree::Contracts::Core
|
|
5
|
+
include Ree::Contracts::ArgContracts
|
|
6
|
+
|
|
7
|
+
FieldNotSetError = Class.new(ArgumentError)
|
|
8
|
+
|
|
9
|
+
if ReeDto.debug_mode?
|
|
10
|
+
contract Hash, Ksplat[RestKeys => Any] => Any
|
|
11
|
+
def initialize(attrs = nil, **kwargs)
|
|
12
|
+
@_attrs = attrs || kwargs
|
|
13
|
+
list = self.class.fields.map(&:name)
|
|
14
|
+
extra = attrs.keys - list
|
|
15
|
+
|
|
16
|
+
if !extra.empty?
|
|
17
|
+
puts("WARNING: #{self.class}.new does not have definition for #{extra.inspect} fields")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
contract Hash, Ksplat[RestKeys => Any] => Any
|
|
22
|
+
def initialize(attrs = nil, **kwargs)
|
|
23
|
+
@_attrs = attrs || kwargs
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
contract None => nil
|
|
28
|
+
def reset_changes
|
|
29
|
+
@changed_fields = nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
contract Symbol => ReeDto::FieldMeta
|
|
33
|
+
def get_meta(name)
|
|
34
|
+
self
|
|
35
|
+
.class
|
|
36
|
+
.fields
|
|
37
|
+
.find { _1.name == name} || (raise ArgumentError.new("field :#{name} not defined for :#{self.class}"))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
contract Symbol => Any
|
|
41
|
+
def get_value(name)
|
|
42
|
+
@_attrs.fetch(name) do
|
|
43
|
+
meta = get_meta(name)
|
|
44
|
+
|
|
45
|
+
if !meta.has_default?
|
|
46
|
+
raise FieldNotSetError.new("field :#{name} not set for:#{self}")
|
|
47
|
+
else
|
|
48
|
+
@_attrs[name] = meta.default
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
contract None => Hash
|
|
54
|
+
def attrs
|
|
55
|
+
@_attrs
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
contract Symbol, Any => Any
|
|
59
|
+
def set_attr(name, val)
|
|
60
|
+
@_attrs[name] = val
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
contract Symbol, Any => Any
|
|
64
|
+
def set_value(name, val)
|
|
65
|
+
if has_value?(name)
|
|
66
|
+
old = get_value(name)
|
|
67
|
+
return if old == val
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
@changed_fields ||= Set.new
|
|
71
|
+
@changed_fields << name
|
|
72
|
+
@_attrs[name] = val
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
contract Symbol => Bool
|
|
76
|
+
def has_value?(name)
|
|
77
|
+
@_attrs.key?(name) || get_meta(name).has_default?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
contract None => ArrayOf[Symbol]
|
|
81
|
+
def changed_fields
|
|
82
|
+
@changed_fields.to_a
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
contract Block => Any
|
|
86
|
+
def each_field(&proc)
|
|
87
|
+
self.class.fields.select { has_value?(_1.name) }.each do |field|
|
|
88
|
+
proc.call(field.name, get_value(field.name))
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
contract None => String
|
|
93
|
+
def to_s
|
|
94
|
+
fields = self.class.fields
|
|
95
|
+
max_length = fields.map(&:name).sort_by(&:size).last.size
|
|
96
|
+
result = "\n#{self.class}\n"
|
|
97
|
+
|
|
98
|
+
data = fields.select { has_value?(_1.name) }.map do |field|
|
|
99
|
+
name = field.name.to_s
|
|
100
|
+
extra_spaces = ' ' * (max_length - name.size)
|
|
101
|
+
%Q( #{name}#{extra_spaces} = #{get_value(field.name).inspect})
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
result << data.join("\n")
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
contract None => String
|
|
108
|
+
def inspect
|
|
109
|
+
to_s
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class ReeDto::FieldMeta
|
|
2
|
+
include Ree::Contracts::Core
|
|
3
|
+
include Ree::Contracts::ArgContracts
|
|
4
|
+
|
|
5
|
+
NONE = Object.new.freeze
|
|
6
|
+
|
|
7
|
+
attr_reader :name, :contract, :setter, :default
|
|
8
|
+
|
|
9
|
+
contract Symbol, Any, Bool, Any => Any
|
|
10
|
+
def initialize(name, contract, setter, default)
|
|
11
|
+
@name = name
|
|
12
|
+
@contract = contract
|
|
13
|
+
@setter = setter
|
|
14
|
+
@default = default
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
contract None => Bool
|
|
18
|
+
def has_default?
|
|
19
|
+
@default != NONE
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ReeDto::BuildDto
|
|
4
|
+
include Ree::FnDSL
|
|
5
|
+
|
|
6
|
+
fn :build_dto do
|
|
7
|
+
target :class
|
|
8
|
+
with_caller
|
|
9
|
+
link :build_dto_collection_class
|
|
10
|
+
link "ree_dto/dto/dto_instance_methods", -> { DtoInstanceMethods }
|
|
11
|
+
link "ree_dto/dto/dto_class_methods", -> { DtoClassMethods }
|
|
12
|
+
link "ree_dto/dto/dto_builder", -> { DtoBuilder }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
contract(Block => nil)
|
|
16
|
+
def call(&proc)
|
|
17
|
+
klass = get_caller
|
|
18
|
+
klass.include DtoInstanceMethods
|
|
19
|
+
klass.extend DtoClassMethods
|
|
20
|
+
|
|
21
|
+
builder = DtoBuilder.new(self)
|
|
22
|
+
builder.instance_exec(&proc)
|
|
23
|
+
|
|
24
|
+
klass.send(:set_fields, builder.fields)
|
|
25
|
+
klass.send(:set_collections, builder.collections)
|
|
26
|
+
|
|
27
|
+
builder.fields.each do |field|
|
|
28
|
+
klass.instance_exec do
|
|
29
|
+
contract None => field.contract
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
klass.define_method field.name do
|
|
33
|
+
get_value(field.name)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if field.setter
|
|
37
|
+
klass.instance_exec do
|
|
38
|
+
contract field.contract => field.contract
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
klass.define_method :"#{field.name}=" do |val|
|
|
42
|
+
set_value(field.name, val)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
builder.collections.each do |collection|
|
|
48
|
+
col_class = build_dto_collection_class(collection.contract)
|
|
49
|
+
col_class.class_exec(&collection.filter_proc)
|
|
50
|
+
|
|
51
|
+
klass.define_method collection.name do
|
|
52
|
+
@collections ||= {}
|
|
53
|
+
|
|
54
|
+
@collections[collection.name] ||= col_class.new(
|
|
55
|
+
collection.name, collection.contract, klass
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class ReeDto::BuildDtoCollectionClass
|
|
2
|
+
include Ree::FnDSL
|
|
3
|
+
|
|
4
|
+
fn :build_dto_collection_class do
|
|
5
|
+
link "ree_dto/dto/dto_collection", -> { DtoCollection }
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
contract Any => Class
|
|
9
|
+
def call(entity_contract)
|
|
10
|
+
Class.new(DtoCollection) do
|
|
11
|
+
contract entity_contract => nil
|
|
12
|
+
def add(item)
|
|
13
|
+
@list ||= []
|
|
14
|
+
@list.push(item)
|
|
15
|
+
nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
contract entity_contract => Nilor[entity_contract]
|
|
19
|
+
def remove(item)
|
|
20
|
+
@list.delete(item)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
alias :<< :add
|
|
24
|
+
alias :push :add
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
module ReeDto
|
|
2
2
|
include Ree::PackageDSL
|
|
3
|
-
|
|
4
|
-
package
|
|
3
|
+
|
|
4
|
+
package do
|
|
5
|
+
depends_on :ree_object
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
def set_debug_mode
|
|
10
|
+
@debug_mode = true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def debug_mode?
|
|
14
|
+
!!@debug_mode
|
|
15
|
+
end
|
|
16
|
+
end
|
|
5
17
|
end
|
|
6
18
|
|
|
7
|
-
require_relative 'ree_dto/entity_dsl'
|
|
19
|
+
require_relative 'ree_dto/entity_dsl'
|
|
20
|
+
require_relative 'ree_dto/dsl'
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
package_require("ree_dto/dsl")
|
|
3
|
+
|
|
4
|
+
RSpec.describe ReeDto::DSL do
|
|
5
|
+
class ReeDto::DtoClass
|
|
6
|
+
include ReeDto::DSL
|
|
7
|
+
|
|
8
|
+
User = Struct.new(:id, :name, :status)
|
|
9
|
+
|
|
10
|
+
build_dto do
|
|
11
|
+
field :with_default, Nilor[Integer], default: 1
|
|
12
|
+
field :string, String
|
|
13
|
+
field :without_setter, Integer, setter: false
|
|
14
|
+
|
|
15
|
+
collection :numbers, Integer do
|
|
16
|
+
filter :odd, -> { _1.odd? }
|
|
17
|
+
|
|
18
|
+
def to_s
|
|
19
|
+
"odd_collection"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
collection :users, User do
|
|
24
|
+
filter :active, -> { _1.status == "active" }
|
|
25
|
+
filter :inactive, -> { _1.status != "active" }
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context "fields" do
|
|
31
|
+
it {
|
|
32
|
+
dto = ReeDto::DtoClass.new
|
|
33
|
+
expect(dto.with_default).to eq(1)
|
|
34
|
+
|
|
35
|
+
dto = ReeDto::DtoClass.new({})
|
|
36
|
+
expect(dto.with_default).to eq(1)
|
|
37
|
+
expect(dto.get_value(:with_default)).to eq(1)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
it {
|
|
41
|
+
dto = ReeDto::DtoClass.new
|
|
42
|
+
expect(dto.has_value?(:with_default)).to eq(true)
|
|
43
|
+
expect(dto.has_value?(:string)).to eq(false)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
it {
|
|
47
|
+
dto = ReeDto::DtoClass.new({with_default: 1, string: "string", without_setter: 22})
|
|
48
|
+
expect(dto.to_s).to include("ReeDto::DtoClass")
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
it {
|
|
52
|
+
dto = ReeDto::DtoClass.new
|
|
53
|
+
|
|
54
|
+
expect {
|
|
55
|
+
dto.string
|
|
56
|
+
}.to raise_error do |e|
|
|
57
|
+
expect(e.message).to eq("field :string not set for:\nReeDto::DtoClass\n with_default = 1")
|
|
58
|
+
end
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
it {
|
|
62
|
+
dto = ReeDto::DtoClass.new(string: "string")
|
|
63
|
+
expect(dto.string).to eq("string")
|
|
64
|
+
|
|
65
|
+
dto.string = "changed"
|
|
66
|
+
expect(dto.string).to eq("changed")
|
|
67
|
+
expect(dto.changed_fields).to eq([:string])
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
it {
|
|
71
|
+
dto = ReeDto::DtoClass.new
|
|
72
|
+
fields = []
|
|
73
|
+
values = []
|
|
74
|
+
|
|
75
|
+
dto.each_field do |name, value|
|
|
76
|
+
fields << name
|
|
77
|
+
values << value
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
expect(fields).to eq([:with_default])
|
|
81
|
+
expect(values).to eq([1])
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "collections" do
|
|
86
|
+
it {
|
|
87
|
+
dto = ReeDto::DtoClass.new
|
|
88
|
+
|
|
89
|
+
dto.numbers << 1
|
|
90
|
+
dto.numbers << 2
|
|
91
|
+
expect(dto.numbers.sum).to eq(3)
|
|
92
|
+
expect(dto.numbers.to_s).to eq("odd_collection")
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
it {
|
|
96
|
+
dto = ReeDto::DtoClass.new
|
|
97
|
+
|
|
98
|
+
dto.users.push(ReeDto::DtoClass::User.new(1, "John", "active"))
|
|
99
|
+
dto.users.push(ReeDto::DtoClass::User.new(1, "Adam", "inactive"))
|
|
100
|
+
|
|
101
|
+
expect(dto.users.active.size).to eq(1)
|
|
102
|
+
|
|
103
|
+
peter = ReeDto::DtoClass::User.new(1, "Peter", "active")
|
|
104
|
+
dto.users.active << peter
|
|
105
|
+
|
|
106
|
+
expect(dto.users.size).to eq(3)
|
|
107
|
+
|
|
108
|
+
expect {
|
|
109
|
+
dto.users.active << ReeDto::DtoClass::User.new(1, "John", "inactive")
|
|
110
|
+
}.to raise_error(ReeDto::CollectionFilter::InvalidFilterItemErr)
|
|
111
|
+
|
|
112
|
+
dto.users.active.remove(peter)
|
|
113
|
+
expect(dto.users.size).to eq(2)
|
|
114
|
+
expect(dto.users.active.size).to eq(1)
|
|
115
|
+
}
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ReeMapper::ReeDtoOutput < ReeMapper::StrategyOutput
|
|
4
|
+
contract(None => Any)
|
|
5
|
+
def build_object
|
|
6
|
+
dto.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
contract(Object, ReeMapper::Field, Any => nil)
|
|
10
|
+
def assign_value(object, field, value)
|
|
11
|
+
object.set_attr(field.name, value)
|
|
12
|
+
nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -6,6 +6,7 @@ module ReeMapper
|
|
|
6
6
|
package do
|
|
7
7
|
depends_on :ree_string
|
|
8
8
|
depends_on :ree_datetime
|
|
9
|
+
depends_on :ree_dto
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
package_require('ree_string/functions/underscore')
|
|
@@ -40,6 +41,7 @@ module ReeMapper
|
|
|
40
41
|
|
|
41
42
|
require_relative 'ree_mapper/strategy_outputs/strategy_output'
|
|
42
43
|
require_relative 'ree_mapper/strategy_outputs/object_output'
|
|
44
|
+
require_relative 'ree_mapper/strategy_outputs/ree_dto_output'
|
|
43
45
|
require_relative 'ree_mapper/strategy_outputs/hash_output'
|
|
44
46
|
require_relative 'ree_mapper/strategy_outputs/struct_output'
|
|
45
47
|
|
|
@@ -57,6 +57,34 @@ RSpec.describe ReeMapper::Mapper do
|
|
|
57
57
|
}
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
describe 'ree_dto dto' do
|
|
61
|
+
class ReeMapper::TestDto
|
|
62
|
+
include ReeDto::DSL
|
|
63
|
+
|
|
64
|
+
build_dto do
|
|
65
|
+
field :my_field, Integer
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
let(:mapper) {
|
|
70
|
+
build_mapper_factory(
|
|
71
|
+
strategies: [
|
|
72
|
+
build_mapper_strategy(method: :cast, dto: ReeMapper::TestDto),
|
|
73
|
+
]
|
|
74
|
+
).call.use(:cast) do
|
|
75
|
+
integer :my_field
|
|
76
|
+
end
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
it {
|
|
80
|
+
expect(mapper.cast({ my_field: 1 }).my_field).to eq(1)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
it {
|
|
84
|
+
expect(mapper.cast({ my_field: 1 })).to be_a(ReeMapper::TestDto)
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
60
88
|
describe 'ostruct dto' do
|
|
61
89
|
let(:mapper) {
|
|
62
90
|
build_mapper_factory(
|
|
@@ -27,7 +27,7 @@ RSpec.describe 'Mapper Hash' do
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
it {
|
|
30
|
-
expect { mapper.cast({ point: 1 }) }.to raise_error(ReeMapper::TypeError, /`point\[x\]` is missing required field/)
|
|
30
|
+
expect { mapper.cast({ point: 1 }) }.to raise_error(ReeMapper::TypeError, /`point\[x\]` is missing \(required field\)/)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
it {
|
|
@@ -174,7 +174,7 @@ RSpec.describe 'ReeMapper::MapperFactory type options' do
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
it {
|
|
177
|
-
expect { mapper.cast({}) }.to raise_error(ReeMapper::TypeError, /`number` is missing required field/)
|
|
177
|
+
expect { mapper.cast({}) }.to raise_error(ReeMapper::TypeError, /`number` is missing \(required field\)/)
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
it {
|
data/lib/ree_lib/version.rb
CHANGED
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.
|
|
4
|
+
version: 1.0.106
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ruslan Gatiyatov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-08-
|
|
11
|
+
date: 2024-08-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ree
|
|
@@ -651,8 +651,19 @@ files:
|
|
|
651
651
|
- lib/ree_lib/packages/ree_dto/Package.schema.json
|
|
652
652
|
- lib/ree_lib/packages/ree_dto/bin/console
|
|
653
653
|
- lib/ree_lib/packages/ree_dto/package/ree_dto.rb
|
|
654
|
+
- lib/ree_lib/packages/ree_dto/package/ree_dto/dsl.rb
|
|
655
|
+
- lib/ree_lib/packages/ree_dto/package/ree_dto/dto/collection_filter.rb
|
|
656
|
+
- lib/ree_lib/packages/ree_dto/package/ree_dto/dto/collection_meta.rb
|
|
657
|
+
- lib/ree_lib/packages/ree_dto/package/ree_dto/dto/dto_builder.rb
|
|
658
|
+
- lib/ree_lib/packages/ree_dto/package/ree_dto/dto/dto_class_methods.rb
|
|
659
|
+
- lib/ree_lib/packages/ree_dto/package/ree_dto/dto/dto_collection.rb
|
|
660
|
+
- lib/ree_lib/packages/ree_dto/package/ree_dto/dto/dto_instance_methods.rb
|
|
661
|
+
- lib/ree_lib/packages/ree_dto/package/ree_dto/dto/field_meta.rb
|
|
654
662
|
- lib/ree_lib/packages/ree_dto/package/ree_dto/entity_dsl.rb
|
|
663
|
+
- lib/ree_lib/packages/ree_dto/package/ree_dto/functions/build_dto.rb
|
|
664
|
+
- lib/ree_lib/packages/ree_dto/package/ree_dto/functions/build_dto_collection_class.rb
|
|
655
665
|
- lib/ree_lib/packages/ree_dto/spec/package_schema_spec.rb
|
|
666
|
+
- lib/ree_lib/packages/ree_dto/spec/ree_dto/dsl_spec.rb
|
|
656
667
|
- lib/ree_lib/packages/ree_dto/spec/ree_dto/entity_dsl_spec.rb
|
|
657
668
|
- lib/ree_lib/packages/ree_dto/spec/spec_helper.rb
|
|
658
669
|
- lib/ree_lib/packages/ree_enum/.gitignore
|
|
@@ -828,6 +839,7 @@ files:
|
|
|
828
839
|
- lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_strategy.rb
|
|
829
840
|
- lib/ree_lib/packages/ree_mapper/package/ree_mapper/strategy_outputs/hash_output.rb
|
|
830
841
|
- lib/ree_lib/packages/ree_mapper/package/ree_mapper/strategy_outputs/object_output.rb
|
|
842
|
+
- lib/ree_lib/packages/ree_mapper/package/ree_mapper/strategy_outputs/ree_dto_output.rb
|
|
831
843
|
- lib/ree_lib/packages/ree_mapper/package/ree_mapper/strategy_outputs/strategy_output.rb
|
|
832
844
|
- lib/ree_lib/packages/ree_mapper/package/ree_mapper/strategy_outputs/struct_output.rb
|
|
833
845
|
- lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/abstract_type.rb
|