rom-factory 0.11.0 → 0.13.0
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/.github/workflows/ci.yml +18 -18
- data/.github/workflows/docsite.yml +2 -3
- data/.github/workflows/sync_configs.yml +9 -15
- data/.postgres.env +4 -0
- data/{.action_hero.yml → .repobot.yml} +8 -5
- data/.rubocop.yml +2 -2
- data/CHANGELOG.md +64 -14
- data/Gemfile +19 -9
- data/Gemfile.devtools +1 -1
- data/README.md +2 -2
- data/changelog.yml +36 -1
- data/compose.yml +7 -0
- data/docsite/source/index.html.md +19 -7
- data/lib/rom/factory/attribute_registry.rb +15 -17
- data/lib/rom/factory/attributes/association.rb +102 -68
- data/lib/rom/factory/attributes/callable.rb +6 -0
- data/lib/rom/factory/builder/persistable.rb +19 -2
- data/lib/rom/factory/builder.rb +9 -1
- data/lib/rom/factory/dsl.rb +66 -34
- data/lib/rom/factory/factories.rb +27 -7
- data/lib/rom/factory/sequences.rb +3 -2
- data/lib/rom/factory/tuple_evaluator.rb +78 -25
- data/lib/rom/factory/version.rb +1 -1
- data/rom-factory.gemspec +12 -12
- metadata +18 -19
- data/CODEOWNERS +0 -1
@@ -6,6 +6,29 @@ module ROM
|
|
6
6
|
module Factory
|
7
7
|
# @api private
|
8
8
|
class TupleEvaluator
|
9
|
+
class TupleEvaluatorError < StandardError
|
10
|
+
attr_reader :original_exception
|
11
|
+
|
12
|
+
def initialize(relation, original_exception, attrs, traits, assoc_attrs)
|
13
|
+
super(<<~STR)
|
14
|
+
Failed to build attributes for #{relation.name}
|
15
|
+
|
16
|
+
Attributes:
|
17
|
+
#{attrs.inspect}
|
18
|
+
|
19
|
+
Associations:
|
20
|
+
#{assoc_attrs}
|
21
|
+
|
22
|
+
Traits:
|
23
|
+
#{traits.inspect}
|
24
|
+
|
25
|
+
Original exception: #{original_exception.message}
|
26
|
+
STR
|
27
|
+
|
28
|
+
set_backtrace(original_exception.backtrace)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
9
32
|
# @api private
|
10
33
|
attr_reader :attributes
|
11
34
|
|
@@ -15,9 +38,6 @@ module ROM
|
|
15
38
|
# @api private
|
16
39
|
attr_reader :traits
|
17
40
|
|
18
|
-
# @api private
|
19
|
-
attr_reader :model
|
20
|
-
|
21
41
|
# @api private
|
22
42
|
attr_reader :sequence
|
23
43
|
|
@@ -26,10 +46,13 @@ module ROM
|
|
26
46
|
@attributes = attributes
|
27
47
|
@relation = relation.with(auto_struct: true)
|
28
48
|
@traits = traits
|
29
|
-
@model = @relation.combine(*assoc_names).mapper.model
|
30
49
|
@sequence = Sequences[relation]
|
31
50
|
end
|
32
51
|
|
52
|
+
def model(traits, combine: assoc_names(traits))
|
53
|
+
@relation.combine(*combine).mapper.model
|
54
|
+
end
|
55
|
+
|
33
56
|
# @api private
|
34
57
|
def defaults(traits, attrs, **opts)
|
35
58
|
mergeable_attrs = select_mergeable_attrs(traits, attrs)
|
@@ -45,21 +68,41 @@ module ROM
|
|
45
68
|
attributes = merged_attrs.reject(&is_callable)
|
46
69
|
|
47
70
|
materialized_callables = {}
|
48
|
-
callables.
|
71
|
+
callables.each_value do |callable|
|
49
72
|
materialized_callables.merge!(callable.call(attributes, persist: false))
|
50
73
|
end
|
51
74
|
|
52
75
|
attributes.merge!(materialized_callables)
|
53
76
|
|
54
|
-
|
55
|
-
|
56
|
-
|
77
|
+
assoc_attrs = attributes.slice(*assoc_names(traits)).merge(
|
78
|
+
assoc_names(traits)
|
79
|
+
.select { |key|
|
80
|
+
build_assoc?(key, attributes)
|
81
|
+
}
|
82
|
+
.map { |key|
|
83
|
+
[key, build_assoc_attrs(key, attributes[relation.primary_key], attributes[key])]
|
84
|
+
}
|
57
85
|
.to_h
|
86
|
+
)
|
87
|
+
|
88
|
+
model_attrs = relation.output_schema[attributes]
|
89
|
+
model_attrs.update(assoc_attrs)
|
90
|
+
|
91
|
+
model(traits).new(**model_attrs)
|
92
|
+
rescue StandardError => e
|
93
|
+
raise TupleEvaluatorError.new(relation, e, attrs, traits, assoc_attrs)
|
94
|
+
end
|
58
95
|
|
59
|
-
|
60
|
-
attributes.
|
96
|
+
def build_assoc?(name, attributes)
|
97
|
+
attributes.key?(name) && attributes[name] != [] && !attributes[name].nil?
|
98
|
+
end
|
61
99
|
|
62
|
-
|
100
|
+
def build_assoc_attrs(key, fk, value)
|
101
|
+
if value.is_a?(Array)
|
102
|
+
value.map { |el| build_assoc_attrs(key, fk, el) }
|
103
|
+
else
|
104
|
+
{attributes[key].foreign_key => fk}.merge(value.to_h)
|
105
|
+
end
|
63
106
|
end
|
64
107
|
|
65
108
|
# @api private
|
@@ -76,10 +119,15 @@ module ROM
|
|
76
119
|
end
|
77
120
|
|
78
121
|
def assocs(traits_names = [])
|
79
|
-
traits
|
122
|
+
found_assocs = traits
|
80
123
|
.values_at(*traits_names)
|
124
|
+
.compact
|
81
125
|
.map(&:associations).flat_map(&:elements)
|
82
126
|
.inject(AttributeRegistry.new(attributes.associations.elements), :<<)
|
127
|
+
|
128
|
+
exclude = traits_names.select { |t| t.is_a?(Hash) }.reduce(:merge) || EMPTY_HASH
|
129
|
+
|
130
|
+
found_assocs.reject { |a| exclude[a.name] == false }
|
83
131
|
end
|
84
132
|
|
85
133
|
# @api private
|
@@ -97,15 +145,15 @@ module ROM
|
|
97
145
|
# @api private
|
98
146
|
def evaluate(traits, attrs, opts)
|
99
147
|
evaluate_values(attrs)
|
100
|
-
.merge(evaluate_associations(attrs, opts))
|
148
|
+
.merge(evaluate_associations(traits, attrs, opts))
|
101
149
|
.merge(evaluate_traits(traits, attrs, opts))
|
102
150
|
end
|
103
151
|
|
104
152
|
# @api private
|
105
153
|
def evaluate_values(attrs)
|
106
|
-
attributes.values.tsort.each_with_object(
|
107
|
-
deps = attr.dependency_names.
|
108
|
-
result = attr.(
|
154
|
+
attributes.values.tsort.each_with_object(attrs.dup) do |attr, h|
|
155
|
+
deps = attr.dependency_names.filter_map { |k| h[k] }
|
156
|
+
result = attr.(h, *deps)
|
109
157
|
|
110
158
|
if result
|
111
159
|
h.update(result)
|
@@ -113,24 +161,29 @@ module ROM
|
|
113
161
|
end
|
114
162
|
end
|
115
163
|
|
116
|
-
def evaluate_traits(
|
117
|
-
return
|
164
|
+
def evaluate_traits(trait_list, attrs, opts)
|
165
|
+
return EMPTY_HASH if trait_list.empty?
|
166
|
+
|
167
|
+
traits = trait_list.map { |v| v.is_a?(Hash) ? v : {v => true} }.reduce(:merge)
|
118
168
|
|
119
|
-
traits_attrs = self.traits.
|
169
|
+
traits_attrs = self.traits.select { |key, _value| traits[key] }.values.flat_map(&:elements)
|
120
170
|
registry = AttributeRegistry.new(traits_attrs)
|
171
|
+
|
121
172
|
self.class.new(registry, relation).defaults([], attrs, **opts)
|
122
173
|
end
|
123
174
|
|
124
175
|
# @api private
|
125
|
-
def evaluate_associations(attrs, opts)
|
126
|
-
|
127
|
-
if
|
128
|
-
|
176
|
+
def evaluate_associations(traits, attrs, opts)
|
177
|
+
assocs(traits).associations.each_with_object({}) do |assoc, memo|
|
178
|
+
if attrs.key?(assoc.name) && attrs[assoc.name].nil?
|
179
|
+
memo
|
180
|
+
elsif assoc.dependency?(relation)
|
181
|
+
memo[assoc.name] = ->(parent, call_opts) do
|
129
182
|
assoc.call(parent, **opts, **call_opts)
|
130
183
|
end
|
131
184
|
else
|
132
185
|
result = assoc.(attrs, **opts)
|
133
|
-
|
186
|
+
memo.update(result) if result
|
134
187
|
end
|
135
188
|
end
|
136
189
|
end
|
@@ -155,7 +208,7 @@ module ROM
|
|
155
208
|
|
156
209
|
def select_mergeable_attrs(traits, attrs)
|
157
210
|
unmergeable = assocs(traits).select(&:through?).map do |a|
|
158
|
-
|
211
|
+
::ROM::Inflector.singularize(a.assoc.target.name.to_sym).to_sym
|
159
212
|
end
|
160
213
|
attrs.dup.delete_if { |key, _| unmergeable.include?(key) }
|
161
214
|
end
|
data/lib/rom/factory/version.rb
CHANGED
data/rom-factory.gemspec
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
lib = File.expand_path(
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
5
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
-
require
|
5
|
+
require "rom/factory/version"
|
7
6
|
|
8
7
|
Gem::Specification.new do |spec|
|
9
8
|
spec.name = "rom-factory"
|
@@ -11,25 +10,26 @@ Gem::Specification.new do |spec|
|
|
11
10
|
spec.authors = ["Janis Miezitis", "Piotr Solnica"]
|
12
11
|
spec.email = ["janjiss@gmail.com", "piotr.solnica@gmail.com"]
|
13
12
|
|
14
|
-
spec.summary =
|
15
|
-
spec.description =
|
13
|
+
spec.summary = "ROM based builder library to make your specs awesome. DSL partially inspired by FactoryBot."
|
14
|
+
spec.description = ""
|
16
15
|
spec.homepage = "https://github.com/rom-rb/rom-factory"
|
17
16
|
spec.license = "MIT"
|
18
17
|
|
19
18
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
20
19
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
21
|
-
spec.metadata[
|
20
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
21
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
22
22
|
|
23
23
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
24
24
|
spec.bindir = "exe"
|
25
25
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
26
|
spec.require_paths = ["lib"]
|
27
27
|
|
28
|
-
spec.required_ruby_version = ">=
|
28
|
+
spec.required_ruby_version = ">= 3.1.0"
|
29
29
|
|
30
|
-
spec.
|
31
|
-
spec.
|
32
|
-
spec.
|
33
|
-
spec.
|
34
|
-
spec.
|
30
|
+
spec.add_dependency "dry-configurable", "~> 1.3"
|
31
|
+
spec.add_dependency "dry-core", "~> 1.1"
|
32
|
+
spec.add_dependency "dry-struct", "~> 1.7"
|
33
|
+
spec.add_dependency "faker", ">= 2.0", "< 4"
|
34
|
+
spec.add_dependency "rom-core", "~> 5.4"
|
35
35
|
end
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rom-factory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janis Miezitis
|
8
8
|
- Piotr Solnica
|
9
|
-
autorequire:
|
10
9
|
bindir: exe
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2025-01-21 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: dry-configurable
|
@@ -17,42 +16,42 @@ dependencies:
|
|
17
16
|
requirements:
|
18
17
|
- - "~>"
|
19
18
|
- !ruby/object:Gem::Version
|
20
|
-
version: '1.
|
19
|
+
version: '1.3'
|
21
20
|
type: :runtime
|
22
21
|
prerelease: false
|
23
22
|
version_requirements: !ruby/object:Gem::Requirement
|
24
23
|
requirements:
|
25
24
|
- - "~>"
|
26
25
|
- !ruby/object:Gem::Version
|
27
|
-
version: '1.
|
26
|
+
version: '1.3'
|
28
27
|
- !ruby/object:Gem::Dependency
|
29
28
|
name: dry-core
|
30
29
|
requirement: !ruby/object:Gem::Requirement
|
31
30
|
requirements:
|
32
31
|
- - "~>"
|
33
32
|
- !ruby/object:Gem::Version
|
34
|
-
version: '1.
|
33
|
+
version: '1.1'
|
35
34
|
type: :runtime
|
36
35
|
prerelease: false
|
37
36
|
version_requirements: !ruby/object:Gem::Requirement
|
38
37
|
requirements:
|
39
38
|
- - "~>"
|
40
39
|
- !ruby/object:Gem::Version
|
41
|
-
version: '1.
|
40
|
+
version: '1.1'
|
42
41
|
- !ruby/object:Gem::Dependency
|
43
42
|
name: dry-struct
|
44
43
|
requirement: !ruby/object:Gem::Requirement
|
45
44
|
requirements:
|
46
45
|
- - "~>"
|
47
46
|
- !ruby/object:Gem::Version
|
48
|
-
version: '1.
|
47
|
+
version: '1.7'
|
49
48
|
type: :runtime
|
50
49
|
prerelease: false
|
51
50
|
version_requirements: !ruby/object:Gem::Requirement
|
52
51
|
requirements:
|
53
52
|
- - "~>"
|
54
53
|
- !ruby/object:Gem::Version
|
55
|
-
version: '1.
|
54
|
+
version: '1.7'
|
56
55
|
- !ruby/object:Gem::Dependency
|
57
56
|
name: faker
|
58
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -62,7 +61,7 @@ dependencies:
|
|
62
61
|
version: '2.0'
|
63
62
|
- - "<"
|
64
63
|
- !ruby/object:Gem::Version
|
65
|
-
version: '
|
64
|
+
version: '4'
|
66
65
|
type: :runtime
|
67
66
|
prerelease: false
|
68
67
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -72,21 +71,21 @@ dependencies:
|
|
72
71
|
version: '2.0'
|
73
72
|
- - "<"
|
74
73
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
74
|
+
version: '4'
|
76
75
|
- !ruby/object:Gem::Dependency
|
77
76
|
name: rom-core
|
78
77
|
requirement: !ruby/object:Gem::Requirement
|
79
78
|
requirements:
|
80
79
|
- - "~>"
|
81
80
|
- !ruby/object:Gem::Version
|
82
|
-
version: '5.
|
81
|
+
version: '5.4'
|
83
82
|
type: :runtime
|
84
83
|
prerelease: false
|
85
84
|
version_requirements: !ruby/object:Gem::Requirement
|
86
85
|
requirements:
|
87
86
|
- - "~>"
|
88
87
|
- !ruby/object:Gem::Version
|
89
|
-
version: '5.
|
88
|
+
version: '5.4'
|
90
89
|
description: ''
|
91
90
|
email:
|
92
91
|
- janjiss@gmail.com
|
@@ -95,7 +94,6 @@ executables: []
|
|
95
94
|
extensions: []
|
96
95
|
extra_rdoc_files: []
|
97
96
|
files:
|
98
|
-
- ".action_hero.yml"
|
99
97
|
- ".devtools/templates/changelog.erb"
|
100
98
|
- ".devtools/templates/release.erb"
|
101
99
|
- ".github/FUNDING.yml"
|
@@ -107,11 +105,12 @@ files:
|
|
107
105
|
- ".github/workflows/rubocop.yml"
|
108
106
|
- ".github/workflows/sync_configs.yml"
|
109
107
|
- ".gitignore"
|
108
|
+
- ".postgres.env"
|
109
|
+
- ".repobot.yml"
|
110
110
|
- ".rspec"
|
111
111
|
- ".rubocop.yml"
|
112
112
|
- ".yardopts"
|
113
113
|
- CHANGELOG.md
|
114
|
-
- CODEOWNERS
|
115
114
|
- CODE_OF_CONDUCT.md
|
116
115
|
- CONTRIBUTING.md
|
117
116
|
- Gemfile
|
@@ -121,6 +120,7 @@ files:
|
|
121
120
|
- Rakefile
|
122
121
|
- benchmarks/basic.rb
|
123
122
|
- changelog.yml
|
123
|
+
- compose.yml
|
124
124
|
- docsite/source/index.html.md
|
125
125
|
- lib/rom-factory.rb
|
126
126
|
- lib/rom/factory.rb
|
@@ -146,7 +146,7 @@ licenses:
|
|
146
146
|
- MIT
|
147
147
|
metadata:
|
148
148
|
allowed_push_host: https://rubygems.org
|
149
|
-
|
149
|
+
rubygems_mfa_required: 'true'
|
150
150
|
rdoc_options: []
|
151
151
|
require_paths:
|
152
152
|
- lib
|
@@ -154,15 +154,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
154
154
|
requirements:
|
155
155
|
- - ">="
|
156
156
|
- !ruby/object:Gem::Version
|
157
|
-
version:
|
157
|
+
version: 3.1.0
|
158
158
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
159
|
requirements:
|
160
160
|
- - ">="
|
161
161
|
- !ruby/object:Gem::Version
|
162
162
|
version: '0'
|
163
163
|
requirements: []
|
164
|
-
rubygems_version: 3.
|
165
|
-
signing_key:
|
164
|
+
rubygems_version: 3.6.2
|
166
165
|
specification_version: 4
|
167
166
|
summary: ROM based builder library to make your specs awesome. DSL partially inspired
|
168
167
|
by FactoryBot.
|
data/CODEOWNERS
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
* @solnic
|