rom-factory 0.10.1 → 0.11.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/.action_hero.yml +21 -0
- data/.devtools/templates/changelog.erb +43 -0
- data/.devtools/templates/release.erb +36 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/ISSUE_TEMPLATE/bug-report.md +26 -0
- data/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/.github/SUPPORT.md +3 -0
- data/.github/workflows/ci.yml +87 -0
- data/.github/workflows/docsite.yml +38 -9
- data/.github/workflows/rubocop.yml +46 -0
- data/.github/workflows/sync_configs.yml +41 -18
- data/.rspec +1 -1
- data/.rubocop.yml +198 -40
- data/CHANGELOG.md +88 -33
- data/CODEOWNERS +1 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/CONTRIBUTING.md +4 -4
- data/Gemfile +22 -22
- data/Gemfile.devtools +20 -0
- data/LICENSE +1 -1
- data/README.md +13 -48
- data/Rakefile +1 -1
- data/benchmarks/basic.rb +10 -10
- data/changelog.yml +99 -0
- data/docsite/source/index.html.md +162 -1
- data/lib/rom/factory/attribute_registry.rb +2 -2
- data/lib/rom/factory/attributes/association.rb +52 -12
- data/lib/rom/factory/attributes/callable.rb +1 -1
- data/lib/rom/factory/attributes/value.rb +1 -1
- data/lib/rom/factory/attributes.rb +4 -6
- data/lib/rom/factory/builder/persistable.rb +3 -5
- data/lib/rom/factory/builder.rb +8 -18
- data/lib/rom/factory/constants.rb +1 -1
- data/lib/rom/factory/dsl.rb +36 -23
- data/lib/rom/factory/factories.rb +13 -15
- data/lib/rom/factory/registry.rb +2 -2
- data/lib/rom/factory/sequences.rb +1 -1
- data/lib/rom/factory/tuple_evaluator.rb +18 -22
- data/lib/rom/factory/version.rb +1 -1
- data/lib/rom/factory.rb +8 -5
- data/lib/rom-factory.rb +1 -1
- data/project.yml +3 -0
- data/rom-factory.gemspec +8 -11
- metadata +43 -43
- data/.codeclimate.yml +0 -12
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
- data/.github/ISSUE_TEMPLATE/----please-don-t-report-feature-requests-via-issues.md +0 -10
- data/.github/ISSUE_TEMPLATE/---a-detailed-bug-report.md +0 -30
- data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -30
- data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
- data/.github/workflows/custom_ci.yml +0 -118
- data/Appraisals +0 -9
- data/LICENSE.txt +0 -21
- data/gemfiles/faker_1.gemfile +0 -34
- data/gemfiles/faker_1.gemfile.lock +0 -178
- data/gemfiles/faker_2.gemfile +0 -34
- data/gemfiles/faker_2.gemfile.lock +0 -178
data/README.md
CHANGED
@@ -1,64 +1,29 @@
|
|
1
1
|
[gem]: https://rubygems.org/gems/rom-factory
|
2
2
|
[actions]: https://github.com/rom-rb/rom-factory/actions
|
3
|
-
[
|
3
|
+
[codacy]: https://www.codacy.com/gh/rom-rb/rom-factory
|
4
|
+
[chat]: https://rom-rb.zulipchat.com
|
4
5
|
[inchpages]: http://inch-ci.org/github/rom-rb/rom-factory
|
5
6
|
|
6
|
-
# rom-factory
|
7
|
+
# rom-factory [][chat]
|
7
8
|
|
8
9
|
[][gem]
|
9
10
|
[][actions]
|
10
|
-
[][codacy]
|
12
|
+
[][codacy]
|
12
13
|
[][inchpages]
|
13
14
|
|
14
|
-
|
15
|
+
## Links
|
15
16
|
|
16
|
-
|
17
|
+
* [User documentation](https://rom-rb.org/learn/factory)
|
18
|
+
* [API documentation](https://rubydoc.info/gems/rom-factory)
|
17
19
|
|
18
|
-
|
20
|
+
## Supported Ruby versions
|
19
21
|
|
20
|
-
|
22
|
+
This library officially supports the following Ruby versions:
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
```ruby
|
25
|
-
gem 'rom-factory'
|
26
|
-
```
|
27
|
-
|
28
|
-
And then execute:
|
29
|
-
|
30
|
-
$ bundle
|
31
|
-
|
32
|
-
Or install it yourself as:
|
33
|
-
|
34
|
-
$ gem install rom-factory
|
35
|
-
|
36
|
-
### Performance
|
37
|
-
|
38
|
-
Seems like this thing is a bit faster than other popular factory gems:
|
39
|
-
|
40
|
-
```
|
41
|
-
Warming up --------------------------------------
|
42
|
-
rom-factory 1.000 i/100ms
|
43
|
-
factory_girl 1.000 i/100ms
|
44
|
-
fabrication 1.000 i/100ms
|
45
|
-
Calculating -------------------------------------
|
46
|
-
rom-factory 1.550 (± 0.0%) i/s - 8.000 in 5.166227s
|
47
|
-
factory_girl 0.982 (± 0.0%) i/s - 5.000 in 5.098193s
|
48
|
-
fabrication 1.011 (± 0.0%) i/s - 6.000 in 5.942209s
|
49
|
-
|
50
|
-
Comparison:
|
51
|
-
rom-factory: 1.5 i/s
|
52
|
-
fabrication: 1.0 i/s - 1.53x slower
|
53
|
-
factory_girl: 1.0 i/s - 1.58x slower
|
54
|
-
```
|
55
|
-
|
56
|
-
> See [benchmarks/basic.rb](https://github.com/rom-rb/rom-factory/blob/master/benchmarks/basic.rb)
|
57
|
-
|
58
|
-
## Credits
|
59
|
-
|
60
|
-
This project was originally created by [Jānis Miezītis](https://github.com/janjiss) and eventually moved to `rom-rb` organization.
|
24
|
+
* MRI >= `2.5`
|
25
|
+
* jruby >= `9.2`
|
61
26
|
|
62
27
|
## License
|
63
28
|
|
64
|
-
See `LICENSE
|
29
|
+
See `LICENSE` file.
|
data/Rakefile
CHANGED
data/benchmarks/basic.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
3
|
+
require "rom-factory"
|
4
|
+
require "rom-core"
|
5
|
+
require "active_record"
|
6
|
+
require "factory_bot"
|
7
|
+
require "fabrication"
|
8
|
+
require "benchmark/ips"
|
9
9
|
|
10
|
-
DATABASE_URL =
|
10
|
+
DATABASE_URL = "postgres://localhost/rom_factory_bench"
|
11
11
|
|
12
12
|
rom = ROM.container(:sql, DATABASE_URL) do |conf|
|
13
13
|
conf.default.connection.create_table?(:users) do
|
@@ -50,15 +50,15 @@ Fabricator(:user) do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
Benchmark.ips do |x|
|
53
|
-
x.report(
|
53
|
+
x.report("rom-factory persisted struct") do
|
54
54
|
factory[:user]
|
55
55
|
end
|
56
56
|
|
57
|
-
x.report(
|
57
|
+
x.report("factory_bot") do
|
58
58
|
FactoryBot.create(:user)
|
59
59
|
end
|
60
60
|
|
61
|
-
x.report(
|
61
|
+
x.report("fabrication") do
|
62
62
|
Fabricate(:user)
|
63
63
|
end
|
64
64
|
|
data/changelog.yml
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
---
|
2
|
+
- version: 0.11.0
|
3
|
+
date: 2022-11-11
|
4
|
+
added:
|
5
|
+
- Support for one-to-one associations (@ianks)
|
6
|
+
- "[internal] cache for Faker constants (@flash-gordon)"
|
7
|
+
changed:
|
8
|
+
- |
|
9
|
+
[BREAKING] attributes are always passed as keywords (@alassek)
|
10
|
+
This may affect your code in places where attributes are passed as hashes.
|
11
|
+
Places like
|
12
|
+
```ruby
|
13
|
+
user_attributes = { name: 'Jane' }
|
14
|
+
Factory[:user, user_attributes]
|
15
|
+
```
|
16
|
+
must be updated to
|
17
|
+
```ruby
|
18
|
+
user_attributes = { name: 'Jane' }
|
19
|
+
Factory[:user, **user_attributes]
|
20
|
+
```
|
21
|
+
- "Upgraded to the latest versions of dry-rb dependencies, compatible with rom 5.3 (@flash-gordon)"
|
22
|
+
- Support for Faker 1.x was dropped (@alassek)
|
23
|
+
fixed:
|
24
|
+
- Support for plural Faker generators (@wuarmin)
|
25
|
+
- version: 0.10.2
|
26
|
+
date: "2020-04-05"
|
27
|
+
fixed:
|
28
|
+
- Fix more keyword warnings (@flash-gordon)
|
29
|
+
- version: 0.10.1
|
30
|
+
date: '2019-12-28'
|
31
|
+
added:
|
32
|
+
- 'Support for faker 2 (@ianks)'
|
33
|
+
fixed:
|
34
|
+
- Keyword warnings reported by Ruby 2.7 (@flash-gordon)
|
35
|
+
- version: 0.10.0
|
36
|
+
date: '2019-12-11'
|
37
|
+
added:
|
38
|
+
- |-
|
39
|
+
`struct_namespace` option is supported by factory builders (@graceful-potato)
|
40
|
+
|
41
|
+
``` ruby
|
42
|
+
factories.define(:user, struct_namespace: MyApp::Entities) do |f|
|
43
|
+
# ...
|
44
|
+
end
|
45
|
+
```
|
46
|
+
fixed:
|
47
|
+
- Support building structs when child assoc does not define parent (@psparrow)
|
48
|
+
- 'Fixed `TupleEvaluator#struct_attrs` for non-standard output schema (@AMHOL)'
|
49
|
+
- version: 0.9.1
|
50
|
+
date: '2019-10-23'
|
51
|
+
fixed:
|
52
|
+
- Attributes of a struct are no longer accidentally passed to their associations (@psparrow)
|
53
|
+
- version: 0.9.0
|
54
|
+
date: '2019-08-12'
|
55
|
+
added:
|
56
|
+
- 'When attributes hash includes unknown attributes, a `ROM::Factory::UnknownAttributeError` will be raised (@rawburt)'
|
57
|
+
- version: 0.8.0
|
58
|
+
date: '2019-04-24'
|
59
|
+
fixed:
|
60
|
+
- 'Loaded association structs are no longer rejected by output schemas (issue #34) (flash-gordon + solnic)'
|
61
|
+
- version: 0.7.0
|
62
|
+
date: '2018-11-17'
|
63
|
+
added:
|
64
|
+
- Support for traits (v-kolesnikov)
|
65
|
+
- Support building structs with associations (@ianks)
|
66
|
+
fixed:
|
67
|
+
- Overwritten attributes with dependencies (JanaVPetrova)
|
68
|
+
- version: 0.6.0
|
69
|
+
date: '2018-01-31'
|
70
|
+
added:
|
71
|
+
- Support for factories with custom struct namespaces (solnic)
|
72
|
+
changed:
|
73
|
+
- 'Accessing a factory which is not defined will result in `FactoryNotDefinedError` exception (GustavoCaso + solnic)'
|
74
|
+
fixed:
|
75
|
+
- 'Using dependent attributes with sequences works correctly, ie `f.sequence(:login) { |i, name| "name-#{i}"}` (solnic)'
|
76
|
+
- version: 0.5.0
|
77
|
+
date: '2017-10-24'
|
78
|
+
added:
|
79
|
+
- Updated to rom 4.0 (solnic)
|
80
|
+
- 'Support for `has_many` and `has_one` associations (solnic)'
|
81
|
+
- Support for attributes depending on values from other attributes (solnic)
|
82
|
+
- 'Support for `rand` inside the generator block (flash-gordon)'
|
83
|
+
changed:
|
84
|
+
- 'Depends on `rom-core` now (solnic)'
|
85
|
+
- version: 0.4.0
|
86
|
+
date: '2017-03-03'
|
87
|
+
summary: improves internals.
|
88
|
+
added:
|
89
|
+
- 'Support for defining multiple factories via `MyFactory = ROM::Factory.configure { |c| ... }` (solnic)'
|
90
|
+
- 'Support for builder inheritence via `define(admin: :user) { |f| ... }` (solnic)'
|
91
|
+
- 'Support for generating in-memory structs via `MyFactory.structs[:user]` that are not persisted (solnic)'
|
92
|
+
- 'Support for `belongs_to` associations via `f.association(:user)` (solnic)'
|
93
|
+
- 'New DSL for defining builders `MyFactory.define(:user) { |f| ... }` which infers default relation name (solnic)'
|
94
|
+
- 'New factory method `MyFactory#[]` ie `MyFactory[:user, name: "Jane"]` (solnic)'
|
95
|
+
- 'New `fake` helper which uses faker gem under the hood ie `f.email { fake(:internet, :email) }` (solnic)'
|
96
|
+
changed:
|
97
|
+
- "`Rom::Factory::Config.configure` was replaced with `ROM::Factory.configure` (solnic)"
|
98
|
+
- Global factory config and builders are gone (solnic)
|
99
|
+
- Structs are now based on dry-struct (solnic)
|
@@ -5,4 +5,165 @@ chapter: Factory
|
|
5
5
|
|
6
6
|
# rom-factory
|
7
7
|
|
8
|
-
|
8
|
+
`rom-factory` provides a simple API for creating and persisting `ROM::Struct`'s. If you already know FactoryBot you'll definitely understand the concept.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
First of all you need to define a ROM Container for Factory. For example if you are using `rspec`, you can add these lines to `spec_helper.rb`. Also you need to require here all files with Factories.
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
Factory = ROM::Factory.configure do |config|
|
16
|
+
config.rom = my_rom_container
|
17
|
+
end
|
18
|
+
|
19
|
+
Dir[File.dirname(__FILE__) + '/support/factories/*.rb'].each { |file| require file }
|
20
|
+
```
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
### Define factory
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
# 'spec/support/factories/users.rb'
|
28
|
+
|
29
|
+
Factory.define(:user) do |f|
|
30
|
+
f.name 'John'
|
31
|
+
f.age 42
|
32
|
+
end
|
33
|
+
```
|
34
|
+
#### Specify relations
|
35
|
+
|
36
|
+
You can specify ROM relation if you want. It'll be pluralized factory name by default.
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
Factory.define(:user, relation: :people) do |f|
|
40
|
+
f.name 'John'
|
41
|
+
f.age 42
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
#### Specify namespace for your structs
|
46
|
+
|
47
|
+
Struct `User` will be find in MyApp::Entities namespace
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
Factory.define(:user, struct_namespace: MyApp::Entities) do |f|
|
51
|
+
# ...
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
#### Sequences
|
56
|
+
|
57
|
+
You can use sequences for uniq fields
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
Factory.define(:user) do |f|
|
61
|
+
f.name 'John'
|
62
|
+
f.sequence(:email) { |n| "john#{n}@example.com" }
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
#### Timestamps
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
Factory.define(:user) do |f|
|
70
|
+
f.name 'John'
|
71
|
+
f.timestamps
|
72
|
+
# same as
|
73
|
+
# f.created_at { Time.now }
|
74
|
+
# f.updated_at { Time.now }
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
#### Associations
|
79
|
+
|
80
|
+
* belongs_to
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
Factory.define(:group) do |f|
|
84
|
+
f.name 'Admins'
|
85
|
+
end
|
86
|
+
|
87
|
+
Factory.define(:user) do |f|
|
88
|
+
f.name 'John'
|
89
|
+
f.association(:user)
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
* has_many
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
Factory.define(:group) do |f|
|
97
|
+
f.name 'Admins'
|
98
|
+
f.association(:user, count: 2)
|
99
|
+
end
|
100
|
+
|
101
|
+
Factory.define(:user) do |f|
|
102
|
+
f.name 'John'
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
#### Extend already existing factory
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
Factory.define(:user) do |f|
|
110
|
+
f.name 'John'
|
111
|
+
f.admin false
|
112
|
+
end
|
113
|
+
|
114
|
+
Factory.define(admin: :user) do |f|
|
115
|
+
f.admin true
|
116
|
+
end
|
117
|
+
|
118
|
+
# Factory.structs(:admin)
|
119
|
+
```
|
120
|
+
|
121
|
+
#### Traits
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
Factory.define(:user) do |f|
|
125
|
+
f.name 'John'
|
126
|
+
f.admin false
|
127
|
+
|
128
|
+
f.trait :with_age do |t|
|
129
|
+
t.age 42
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Factory.structs(:user, :with_age)
|
134
|
+
```
|
135
|
+
|
136
|
+
#### Build-in [Faker](https://github.com/faker-ruby/faker) objects
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
Factory.define(:user) do |f|
|
140
|
+
f.email { fake(:internet, :email) }
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
#### Dependent attributes
|
145
|
+
|
146
|
+
Attributes can be based on the values of other attributes:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
Factory.define(:user) do |f|
|
150
|
+
f.full_name { fake(:name) }
|
151
|
+
# Dependent attributes are inferred from the block parameter names:
|
152
|
+
f.login { |full_name| full_name.downcase.gsub(/\s+/, '_') }
|
153
|
+
# Works with sequences too:
|
154
|
+
f.sequence(:email) { |n, login| "#{login}-#{n}@example.com" }
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
### Build and persist objects
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
# Create in-memory object
|
162
|
+
Factory.structs[:user]
|
163
|
+
|
164
|
+
# Persist struct in database
|
165
|
+
Factory[:user]
|
166
|
+
|
167
|
+
# Override attributes
|
168
|
+
Factory[:user, age: 24]
|
169
|
+
```
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "tsort"
|
4
4
|
|
5
5
|
module ROM
|
6
6
|
module Factory
|
@@ -47,7 +47,7 @@ module ROM
|
|
47
47
|
|
48
48
|
# @api private
|
49
49
|
def associations
|
50
|
-
self.class.new(elements.select { |e| e.
|
50
|
+
self.class.new(elements.select { |e| e.is_a?(Attributes::Association::Core) })
|
51
51
|
end
|
52
52
|
|
53
53
|
private
|
@@ -5,10 +5,9 @@ module ROM::Factory
|
|
5
5
|
# @api private
|
6
6
|
module Association
|
7
7
|
class << self
|
8
|
-
def new(assoc, builder, *
|
9
|
-
const_get(assoc.definition.type).new(assoc, builder, *
|
8
|
+
def new(assoc, builder, *traits, **options)
|
9
|
+
const_get(assoc.definition.type).new(assoc, builder, *traits, **options)
|
10
10
|
end
|
11
|
-
ruby2_keywords(:new) if respond_to?(:ruby2_keywords, true)
|
12
11
|
end
|
13
12
|
|
14
13
|
# @api private
|
@@ -23,6 +22,11 @@ module ROM::Factory
|
|
23
22
|
@options = options
|
24
23
|
end
|
25
24
|
|
25
|
+
# @api private
|
26
|
+
def through?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
26
30
|
# @api private
|
27
31
|
def builder
|
28
32
|
@__builder__ ||= @builder_proc.call
|
@@ -56,7 +60,7 @@ module ROM::Factory
|
|
56
60
|
else
|
57
61
|
builder.struct(*traits)
|
58
62
|
end
|
59
|
-
tuple = {
|
63
|
+
tuple = {name => struct}
|
60
64
|
assoc.associate(tuple, struct)
|
61
65
|
end
|
62
66
|
end
|
@@ -78,13 +82,13 @@ module ROM::Factory
|
|
78
82
|
association_hash = assoc.associate(attrs, parent)
|
79
83
|
|
80
84
|
if persist
|
81
|
-
builder.persistable.create(*traits, association_hash)
|
85
|
+
builder.persistable.create(*traits, **association_hash)
|
82
86
|
else
|
83
|
-
builder.struct(*traits, attrs
|
87
|
+
builder.struct(*traits, **attrs, **association_hash)
|
84
88
|
end
|
85
89
|
end
|
86
90
|
|
87
|
-
{
|
91
|
+
{name => structs}
|
88
92
|
end
|
89
93
|
|
90
94
|
# @api private
|
@@ -103,22 +107,22 @@ module ROM::Factory
|
|
103
107
|
# @api private
|
104
108
|
def call(attrs = EMPTY_HASH, parent, persist: true)
|
105
109
|
# do not associate if count is 0
|
106
|
-
return {
|
110
|
+
return {name => nil} if count.zero?
|
107
111
|
|
108
112
|
return if attrs.key?(name)
|
109
113
|
|
110
114
|
association_hash = assoc.associate(attrs, parent)
|
111
115
|
|
112
116
|
struct = if persist
|
113
|
-
builder.persistable.create(*traits, association_hash)
|
117
|
+
builder.persistable.create(*traits, **association_hash)
|
114
118
|
else
|
115
119
|
belongs_to_name = Dry::Core::Inflector.singularize(assoc.source_alias)
|
116
|
-
belongs_to_associations = {
|
120
|
+
belongs_to_associations = {belongs_to_name.to_sym => parent}
|
117
121
|
final_attrs = attrs.merge(association_hash).merge(belongs_to_associations)
|
118
|
-
builder.struct(*traits, final_attrs)
|
122
|
+
builder.struct(*traits, **final_attrs)
|
119
123
|
end
|
120
124
|
|
121
|
-
{
|
125
|
+
{name => struct}
|
122
126
|
end
|
123
127
|
|
124
128
|
# @api private
|
@@ -126,6 +130,42 @@ module ROM::Factory
|
|
126
130
|
options.fetch(:count, 1)
|
127
131
|
end
|
128
132
|
end
|
133
|
+
|
134
|
+
class OneToOneThrough < Core
|
135
|
+
def call(attrs = EMPTY_HASH, parent, persist: true)
|
136
|
+
return if attrs.key?(name)
|
137
|
+
|
138
|
+
struct = if persist && attrs[tpk]
|
139
|
+
attrs
|
140
|
+
elsif persist
|
141
|
+
builder.persistable.create(*traits, **attrs)
|
142
|
+
else
|
143
|
+
builder.struct(*traits, **attrs)
|
144
|
+
end
|
145
|
+
|
146
|
+
assoc.persist([parent], struct) if persist
|
147
|
+
|
148
|
+
{name => struct}
|
149
|
+
end
|
150
|
+
|
151
|
+
def dependency?(rel)
|
152
|
+
assoc.source == rel
|
153
|
+
end
|
154
|
+
|
155
|
+
def through?
|
156
|
+
true
|
157
|
+
end
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
def count
|
162
|
+
options.fetch(:count, 1)
|
163
|
+
end
|
164
|
+
|
165
|
+
def tpk
|
166
|
+
assoc.target.primary_key
|
167
|
+
end
|
168
|
+
end
|
129
169
|
end
|
130
170
|
end
|
131
171
|
end
|
@@ -1,14 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'dry/core/constants'
|
4
|
-
|
5
3
|
module ROM
|
6
4
|
module Factory
|
7
5
|
include Dry::Core::Constants
|
8
6
|
end
|
9
7
|
end
|
10
8
|
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
9
|
+
require "rom/factory/attributes/value"
|
10
|
+
require "rom/factory/attributes/callable"
|
11
|
+
require "rom/factory/attributes/sequence"
|
12
|
+
require "rom/factory/attributes/association"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "delegate"
|
4
4
|
|
5
5
|
module ROM
|
6
6
|
module Factory
|
@@ -21,10 +21,8 @@ module ROM
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# @api private
|
24
|
-
def create(*
|
25
|
-
traits, attrs
|
26
|
-
|
27
|
-
tuple = tuple(*traits, attrs)
|
24
|
+
def create(*traits, **attrs)
|
25
|
+
tuple = tuple(*traits, **attrs)
|
28
26
|
validate_keys(traits, attrs)
|
29
27
|
persisted = persist(tuple)
|
30
28
|
|
data/lib/rom/factory/builder.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require 'rom/factory/tuple_evaluator'
|
8
|
-
require 'rom/factory/builder/persistable'
|
3
|
+
require "rom/struct"
|
4
|
+
require "rom/initializer"
|
5
|
+
require "rom/factory/tuple_evaluator"
|
6
|
+
require "rom/factory/builder/persistable"
|
9
7
|
|
10
8
|
module ROM::Factory
|
11
9
|
# @api private
|
@@ -31,18 +29,15 @@ module ROM::Factory
|
|
31
29
|
option :struct_namespace, reader: false
|
32
30
|
|
33
31
|
# @api private
|
34
|
-
def tuple(*
|
35
|
-
traits, attrs = extract_tuple(args)
|
36
|
-
|
32
|
+
def tuple(*traits, **attrs)
|
37
33
|
tuple_evaluator.defaults(traits, attrs)
|
38
34
|
end
|
39
35
|
|
40
36
|
# @api private
|
41
|
-
def struct(*
|
42
|
-
traits, attrs = extract_tuple(args)
|
37
|
+
def struct(*traits, **attrs)
|
43
38
|
validate_keys(traits, attrs, allow_associations: true)
|
44
39
|
|
45
|
-
tuple_evaluator.struct(*
|
40
|
+
tuple_evaluator.struct(*traits, **attrs)
|
46
41
|
end
|
47
42
|
alias_method :create, :struct
|
48
43
|
|
@@ -75,18 +70,13 @@ module ROM::Factory
|
|
75
70
|
tuple_evaluator.relation
|
76
71
|
end
|
77
72
|
|
78
|
-
# @api private
|
79
|
-
def extract_tuple(args)
|
80
|
-
tuple_evaluator.extract_tuple(args)
|
81
|
-
end
|
82
|
-
|
83
73
|
# @api private
|
84
74
|
def validate_keys(traits, tuple, allow_associations: false)
|
85
75
|
schema_keys = relation.schema.attributes.map(&:name)
|
86
76
|
assoc_keys = tuple_evaluator.assoc_names(traits)
|
87
77
|
unknown_keys = tuple.keys - schema_keys - assoc_keys
|
88
78
|
|
89
|
-
unknown_keys
|
79
|
+
unknown_keys -= relation.schema.associations.to_h.keys if allow_associations
|
90
80
|
|
91
81
|
raise UnknownFactoryAttributes, unknown_keys unless unknown_keys.empty?
|
92
82
|
end
|