This library officially supports the following Ruby versions:
- MRI >=
2.5
- jruby >=
9.2
See LICENSE
file.
Data generator with support for persistence backends
License: MIT License
This library officially supports the following Ruby versions:
2.5
9.2
See LICENSE
file.
Thanks for the great gem.
The CHANGELOG has been made to look like the latest version should be 0.7.0, but it doesn't look like a gem has been pushed nor is there a corresponding tag. Should the CHANGELOG be changed so that the 0.7.0 changes are marked as upcoming, or was 0.7.0 intended to have been released?
http://www.rubydoc.info/gems/factory_girl/file/GETTING_STARTED.md#Traits
factory :user, aliases: [:author]
factory :story do
title "My awesome story"
author
trait :published do
published true
end
trait :unpublished do
published false
end
trait :week_long_publishing do
start_at { 1.week.ago }
end_at { Time.now }
end
trait :month_long_publishing do
start_at { 1.month.ago }
end_at { Time.now }
end
factory :week_long_published_story, traits: [:published, :week_long_publishing]
factory :month_long_published_story, traits: [:published, :month_long_publishing]
factory :week_long_unpublished_story, traits: [:unpublished, :week_long_publishing]
factory :month_long_unpublished_story, traits: [:unpublished, :month_long_publishing]
end
At the moment it's not possible to use unique-feature of faker.
Factory.define(:company) do |f|
f.id { fake(:alphanumeric, :unique, :alpha, number: 3).upcase } # will fail
f.name { fake(:name, :name) }
end
id should be unique
What do you think about following solution:
We could allow a unique
-option at our DSL and if unique
is set to true, the method unique
is called in front of the specified method (alpha
in this case)
Factory.define(:company) do |f|
f.id { fake(:alphanumeric, :alpha, number: 3, unique: true).upcase }
# resulting call will be Faker::Alphanumeric.unique.alpha(number: 3)
end
WDYT?
Thanks and best regards
Hi all!
It seems that when we have a cascade has_many or has_one with 3 or more factories some records are not created properly.
In the example below, when I call MyFactory[:company] the actual result is:
#<ROM::Struct::Company id=1 name="Reilly-Labadie" users=[#<ROM::Struct::User id=1 name="Bernie Mueller" company_id=1>, #<ROM::Struct::User id=2 name="Jeff Dickens" company_id=1>]>
But should be:
#<ROM::Struct::Company id=1 name="Reilly-Labadie" users=[#<ROM::Struct::User id=1 name="Bernie Mueller" company_id=1 tasks=#<ROM::Struct::Task id=18 name="Jessie Roob" user_id=1>>, #<ROM::Struct::User id=2 name="Jeff Dickens" company_id=1 tasks=#<ROM::Struct::Task id=19 name="Jessie Roob" user_id=2>>]>
require 'rom'
require 'rom-factory'
rom = ROM.container(:sql, 'sqlite::memory') do |conf|
conf.default.create_table(:companies) do
primary_key :id
column :name, String, null: false
end
conf.default.create_table(:users) do
primary_key :id
column :name, String, null: false
column :company_id, Integer, null: false
end
conf.default.create_table(:tasks) do
primary_key :id
column :name, String, null: false
column :user_id, Integer, null: false
end
conf.relation(:companies) do
schema(:companies, infer: true) do
associations do
has_many :users
end
end
end
conf.relation(:users) do
schema(:users, infer: true) do
associations do
belongs_to :companies, as: :company
has_one :tasks
end
end
end
conf.relation(:tasks) do
schema(:tasks, infer: true) do
associations do
belongs_to :users, as: :user
end
end
end
end
MyFactory = ROM::Factory.configure do |c|
c.rom = rom
end
MyFactory.define(:company) do |f|
f.name { fake(:company, :name) }
f.association(:users, count: 2)
end
MyFactory.define(:user) do |f|
f.name { fake(:name) }
f.association(:company)
f.association(:tasks)
end
MyFactory.define(:task) do |f|
f.name { fake(:name) }
f.association(:user)
end
I have a custom struct for Article that holds the number of favorites attached to it (as favorites_count
). This is computed via a join with the favorites relation.
When trying to create a Factory for Article that has a favorites_count
specified, I get an error on ROM::Factory::DSL
saying the favorites_count is not defined.
require "rom"
require "rom-factory"
Types = Dry.Types()
module Structs
class Article < ROM::Struct
# Including `title` and `body` is optional, we are able to declare struct-only attributes
# If you comment these two lines out, we get the same result and same error
attribute :title, Types::String
attribute :body, Types::String
attribute :favorites_count, Types::Integer
end
end
rom = ROM.container(:sql, "sqlite::memory") do |conf|
conf.default.create_table(:users) do
primary_key :id
column :email, String, null: false
end
conf.default.create_table(:articles) do
primary_key :id
column :title, String, null: false
column :body, String, null: false
end
conf.default.create_table(:favorites) do
primary_key %i[user_id article_id]
foreign_key :user_id, :users
foreign_key :article_id, :articles
end
conf.relation(:users) do
schema(infer: true)
end
conf.relation(:articles) do
schema(infer: true) do
associations do
has_many :favorites
end
end
def with_favorites_count
left_join(favorites, {id: :article_id})
.group(:id)
.select_append { integer.count(:user_id).as(:favorites_count) }
end
end
conf.relation(:favorites) do
schema(infer: true) do
associations do
belongs_to :user
belongs_to :article
end
end
end
end
class ArticleRepo < ROM::Repository[:articles]
struct_namespace Structs
auto_struct true
def with_favorites_count
articles.with_favorites_count
end
end
user1_id = rom.relations[:users].insert(email: "[email protected]")
user2_id = rom.relations[:users].insert(email: "[email protected]")
article_id = rom.relations[:articles].insert(title: "Title", body: "Body")
rom.relations[:favorites].insert(user_id: user1_id, article_id: article_id)
rom.relations[:favorites].insert(user_id: user2_id, article_id: article_id)
p ArticleRepo.new(rom).with_favorites_count.to_a
#=> [#<Article title="Title" body="Body" favorites_count=2>]
MyFactory = ROM::Factory.configure do |config|
config.rom = rom
end
MyFactory.define(:article, struct_namespace: Structs) do |f|
f.title "Title"
f.favorites_count(123)
end
# Raises following error:
# ~/.asdf/installs/ruby/3.3.1/lib/ruby/gems/3.3.0/gems/rom-factory-0.12.0/lib/rom/factory/dsl.rb:172:in `method_missing': undefined method `favorites_count' for an instance of ROM::Factory::DSL (NoMethodError)
# from example.rb:85:in `block in <main>'
# from /Users/sean/.asdf/installs/ruby/3.3.1/lib/ruby/gems/3.3.0/gems/rom-factory-0.12.0/lib/rom/factory/dsl.rb:48:in `initialize'
# from /Users/sean/.asdf/installs/ruby/3.3.1/lib/ruby/gems/3.3.0/gems/rom-factory-0.12.0/lib/rom/factory/factories.rb:143:in `new'
# from /Users/sean/.asdf/installs/ruby/3.3.1/lib/ruby/gems/3.3.0/gems/rom-factory-0.12.0/lib/rom/factory/factories.rb:143:in `define'
# from example.rb:83:in `<main>'
I would expect that I could define the factory as above. Then be able to use it with MyFactory[:article]
and MyFactory.structs[:article]
where the Struct::Article
would have a favorites_count of 123.
I think I would expect rom-factory to infer the attributes from the relation, but then also look at the associated struct (in the struct_namespace) to see if there are any other attributes there and allow those to be declared in the factory as well.
This may not be the proper way of doing this, so I'm open to feedback on the approach, and workarounds.
If you make a belongs_to association inside trait, it will be created 2 times. This causes an error if there is a uniqueness check.
I have written a test for an example.
On version 0.10.2 it works correct.
# frozen_string_literal: true
RSpec.describe ROM::Factory do
include_context "database"
subject(:factories) do
ROM::Factory.configure do |config|
config.rom = rom
end
end
before do
conn.create_table?(:book_types) do
primary_key :id
column :type, String, null: false
index :type, unique: true
end
conn.create_table?(:books) do
primary_key :id
foreign_key :book_type_id, :book_types, index: true
end
conf.relation(:book_types) do
schema(infer: true) do
associations do
has_many :books
end
end
end
conf.relation(:books) do
schema(infer: true) do
associations do
belongs_to :book_type
end
end
end
rom.gateways[:default].use_logger(Logger.new($stdout))
end
context "trait with associations" do
it "creates book type only once" do
factories.define(:book) do |f|
f.trait :with_type do |t|
t.association(:book_type)
end
end
factories.define(:book_type) do |f|
f.type { "NOT_UNIQUE" }
end
factories[:book, :with_type]
expect(rom.relations[:book_types].count).to eq(1)
end
end
after do
conn.drop_table?(:books)
conn.drop_table?(:book_types)
end
end
And the error
I, [2024-07-22T16:45:11.954139 #19499] INFO -- : (0.002133s) INSERT INTO "book_types" ("type") VALUES ('NOT_UNIQUE') RETURNING "book_types"."id", "book_types"."type"
E, [2024-07-22T16:45:11.955342 #19499] ERROR -- : PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "book_types_type_index"
DETAILS: Key (type)=(NOT_UNIQUE) already exists.: INSERT INTO "book_types" ("type") VALUES ('NOT_UNIQUE') RETURNING "book_types"."id", "book_types"."type"
I, [2024-07-22T16:45:11.964446 #19499] INFO -- : (0.008830s) DROP TABLE IF EXISTS "books"
I, [2024-07-22T16:45:11.970889 #19499] INFO -- : (0.006384s) DROP TABLE IF EXISTS "book_types"
F
Failures:
1) ROM::Factory trait with associations creates book type only once
Failure/Error:
result = relation
.with(auto_struct: !tuple_evaluator.has_associations?)
.command(:create)
.call(attrs)
ROM::SQL::UniqueConstraintError:
PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "book_types_type_index"
DETAILS: Key (type)=(NOT_UNIQUE) already exists.
# ./lib/rom/factory/builder/persistable.rb:48:in `persist'
# ./lib/rom/factory/builder/persistable.rb:28:in `create'
# ./lib/rom/factory/attributes/association.rb:82:in `call'
# ./lib/rom/factory/tuple_evaluator.rb:186:in `block in evaluate_associations'
# ./lib/rom/factory/attribute_registry.rb:22:in `each'
# ./lib/rom/factory/attribute_registry.rb:22:in `each'
# ./lib/rom/factory/tuple_evaluator.rb:178:in `each_with_object'
# ./lib/rom/factory/tuple_evaluator.rb:178:in `evaluate_associations'
# ./lib/rom/factory/tuple_evaluator.rb:149:in `evaluate'
# ./lib/rom/factory/tuple_evaluator.rb:59:in `defaults'
# ./lib/rom/factory/tuple_evaluator.rb:173:in `evaluate_traits'
# ./lib/rom/factory/tuple_evaluator.rb:150:in `evaluate'
# ./lib/rom/factory/tuple_evaluator.rb:59:in `defaults'
# ./lib/rom/factory/builder.rb:37:in `tuple'
# ./lib/rom/factory/builder/persistable.rb:27:in `create'
# ./lib/rom/factory/factories.rb:171:in `[]'
# ./spec/integration/rom/association_trait_spec.rb:56:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# PG::UniqueViolation:
# ERROR: duplicate key value violates unique constraint "book_types_type_index"
# DETAILS: Key (type)=(NOT_UNIQUE) already exists.
# ./lib/rom/factory/builder/persistable.rb:48:in `persist'
```
## Expected behavior
Associations in traits should be created only 1 time.
## My environment
- Affects my production application: YES
- Ruby version: 3.2.2
- OS: MacOS 14.5 (Sonoma)
Here is what I am trying to build:
Factory[:shift,
shift_positions: [
Factory[:shift_position],
Factory[:shift_position]
]
]
My factory definitions are:
Factory.define :shift do |f|
f.association(:shift_positions, count: 2)
end
Factory.define :shift_position do |f|
f.association(:shift)
end
The problem is the top code will return the shift_positions
code empty.
This factory won't work.
Factory.define(:announcement) do |f|
f.when { 10.hours.since..12.hours.since } # time range
f.start_time { |when| when.begin.strftime('%H:%M') }
f.end_time { |when| when.end.strftime('%H:%M') }
end
syntax error, unexpected keyword_when, expecting '|'
Noticed that when using a relation as dependency in creating an attribute the relation always comes in nil, any way I can achieve this?
I have tables that have some of the data denormalized and some attributes need to have the same value on the entity and on the relation.
In-memory struct creation that worked under 0.6.0 no longer works with 0.7.0
Factories defined as:
factories.define(:account) do |f|
f.email { fake(:internet, :email) }
# ...
end
factories.define(:member) do |f|
f.association(:account)
f.name { fake(:name) }
# ...
end
When I call factories.structs[:member]
, I get the following error:
[ROM::Struct::Member.new] :account is missing in Hash input (Dry::Struct::Error)
I believe the problem is related to this line:
Before that method call, attributes
does contain a value for the :account
key, afterwards it does not.
Whenever I have an attribute which depends on another one, overriding the dependency (i.e. with a trait) doesn't affect the calculated attribute.
Seems similar to #63, but a bit different
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'rom'
gem 'rom-sql'
gem 'sqlite3'
gem 'rom-factory', '~> 0.10.2'
end
require 'rom'
require 'rom-factory'
ROM_CONTAINER = ROM.container(:sql, 'sqlite::memory') do |conf|
conf.default.create_table(:users) do
primary_key :id
column :name, String, null: false
column :email, String, null: false
end
class Users < ROM::Relation[:sql]
schema(infer: true)
end
conf.register_relation(Users)
end
Factory = ROM::Factory.configure do |config|
config.rom = ROM_CONTAINER
end
Factory.define(:user) do |f|
f.name 'John'
f.email { |name| name.downcase + '@example.com' }
f.trait :jane do |t|
t.name 'Jane'
end
end
pp Factory[:user, :jane] # #<ROM::Struct::User id=1 name="Jane" email="[email protected]">
I expect calculated field to change its value depending on name
, even if I override name
in a trait.
When using the dependent attribute feature of factories there is an unforeseen result. If the method that is being defined is created as a part of the trait and another method uses the dependent attribute feature to access that value the result of said method corresponds with the parent factory object and not the trait. This can be fixed by defining the method value directly in the creation of the factory object. But should also work in the previous statement.
Factory.define(:store) do |f|
f.name { fake(:company, :name) }
f.location_name { |name| "#{name} west" }
end
f.trait :new_store do |t|
t.name { 'New Store' }
end
create :store
result = { name: 'Random Store Name, location_name: 'Random Store Name West'} #Correct
create :store, :new_store
result = { name: 'New Store', location_name: 'Random Store Name West'} # Incorrect
HOWEVER
create :store, :new_store, name: 'Explicit Store Name'
result = { name: 'Explicit Store Name', location_name: 'Explicit Store Name West'} #Correct
Factory.define(:store) do |f|
f.name { fake(:company, :name) }
f.location_name { |name| "#{name} west" }
end
f.trait :new_store do |t|
t.name { 'New Store' }
end
create :store
result = { name: 'Random Store Name, location_name: 'Random Store Name West'}
create :store, :new_store
result = { name: 'New Store', location_name: 'New Store West'}
Currently when you try to use a factory that was not defined you'll get an exception that doesn't tell you anything meaningful.
IDs are not created for associations in v0.12 as they were in v0.11
with Factories:
Factory.define(:operator) do |f|
f.id { SecureRandom.uuid }
f.name 'Some Operator'
f.created_at { Date.today.prev_month }
...
end
Factory.define(:membership) do |f|
f.id { SecureRandom.uuid }
f.customer_id { SecureRandom.uuid }
f.created_at { Date.today.prev_month }
f.status 'active'
f.association(:operator)
...
end
def build(name, **args)
Factory.structs[name, **args]
end
and called in rspec tests with
let(:membership) { build(:membership) }
in v0.11 it returned:
membership: #<ROM::Struct::Membership
id="8e2225df-a2bb-4305-b949-67587bd4c949"
customer_id="f2e10f3c-52cc-43fe-9958-6a17255208fb"
created_at=#<Date: 2024-03-05 ((2460375j,0s,0n),+0s,2299161j)>
status="active"
operator_id="93f53cca-603f-41b3-bb67-e2f3fa8b6fc3"
operator=#<ROM::Struct::Operator
id="93f53cca-603f-41b3-bb67-e2f3fa8b6fc3"
name="Some Operator"
created_at=#<Date: 2024-03-05 ((2460375j,0s,0n),+0s,2299161j)>
...
>
...
>
in v0.12 it returns:
membership: #<ROM::Struct::Membership
id="8e2225df-a2bb-4305-b949-67587bd4c949"
customer_id="f2e10f3c-52cc-43fe-9958-6a17255208fb"
created_at=#<Date: 2024-03-05 ((2460375j,0s,0n),+0s,2299161j)>
status="active"
operator_id=nil
operator=#<ROM::Struct::Operator
id=nil
name="Some Operator"
created_at=#<Date: 2024-03-05 ((2460375j,0s,0n),+0s,2299161j)>
...
>
...
I would have expected the same result as in v0.11
Currently this is tied to rom-sql as it uses Relation#insert
, when we switch to commands it'll be possible to use it with any rom adapter.
Overriding attributes is causing factory field resolver to receive nil
instead of overwritten value.
create file app_spec.rb
with:
require 'rom'
require 'rom-factory'
ROM_CONTAINER = ROM.container(:sql, 'sqlite::memory') do |conf|
conf.default.create_table(:users) do
primary_key :id
column :name, String, null: false
column :email, String, null: false
end
class Users < ROM::Relation[:sql]
schema(infer: true)
end
conf.register_relation(Users)
end
Factory = ROM::Factory.configure do |config|
config.rom = ROM_CONTAINER
end
Factory.define(:user) do |f|
f.name 'John'
f.email { |name| name.downcase + '@example.com' }
end
RSpec.describe 'app' do
let(:data) do
{ name: 'Alice' }
end
let(:user) { Factory[:user, data] }
specify do
pp user
end
end
now rspec app_spec.rb
is producing following error:
NoMethodError:
undefined method `downcase' for nil:NilClass
# ./app_spec.rb:24:in `block (2 levels) in <top (required)>'
# ./app_spec.rb:32:in `block (2 levels) in <top (required)>'
# ./app_spec.rb:35:in `block (2 levels) in <top (required)>'
I was expecting email
callback to receive Alice
value.
I found that has_one
and has_many
associations didn't work properly.
In this reproduction code, has_many
is used, but has_one
results in the same.
I traced into rom-factory and dry, but there was no idea about the root cause.
Steps for Reproduction
require 'rom'
require 'rom-factory'
rom = ROM.container(:sql, 'sqlite::memory') do |conf|
conf.default.create_table(:companies) do
primary_key :id
column :name, String, null: false
end
conf.default.create_table(:users) do
primary_key :id
column :name, String, null: false
column :company_id, Integer, null: false
end
conf.relation(:companies) do
schema(:companies, infer: true) do
associations do
has_many :users
end
end
end
conf.relation(:users) do
schema(:users, infer: true) do
associations do
belongs_to :companies, as: :company
end
end
end
end
MyFactory = ROM::Factory.configure do |c|
c.rom = rom
end
MyFactory.define(:company) do |f|
f.name { fake(:company, :name) }
f.association(:users, count: 2)
end
MyFactory.define(:user) do |f|
f.name { fake(:name) }
f.association(:company)
end
p MyFactory.structs[:user]
p MyFactory.structs[:company]
Expected behavior:
#<ROM::Struct::User id=1 name="Emmet Koss" company_id=1 company=#<ROM::Struct::Company id=1 name="Heaney, Wilkinson and Senger">>
#<ROM::Struct::Company id=1 name="Acme Inc" users=[#<ROM::Struct::User id=1 name="Emmet Koss" company_id="1">, #<ROM::Struct::User id=2 name="Bryce Lehner" company_id="1">]>
Actual behavior:
#<ROM::Struct::User id=1 name="Emmet Koss" company_id=1 company=#<ROM::Struct::Company id=1 name="Heaney, Wilkinson and Senger">>
Traceback (most recent call last):
12: from assoc_test.rb:48:in `<main>'
11: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/rom-factory-0.6.0/lib/rom/factory/factories.rb:43:in `[]'
10: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/rom-factory-0.6.0/lib/rom/factory/builder.rb:30:in `struct'
9: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/rom-factory-0.6.0/lib/rom/factory/tuple_evaluator.rb:34:in `struct'
8: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/dry-struct-0.4.0/lib/dry/struct/class_interface.rb:95:in `new'
7: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/dry-types-0.12.2/lib/dry/types/constructor.rb:47:in `call'
6: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/dry-types-0.12.2/lib/dry/types/hash/schema.rb:27:in `call'
5: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/dry-types-0.12.2/lib/dry/types/hash/schema.rb:97:in `coerce'
4: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/dry-types-0.12.2/lib/dry/types/hash/schema.rb:110:in `resolve'
3: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/dry-types-0.12.2/lib/dry/types/hash/schema.rb:110:in `each'
2: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/dry-types-0.12.2/lib/dry/types/hash/schema.rb:112:in `block in resolve'
1: from /Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/dry-types-0.12.2/lib/dry/types/hash/schema.rb:99:in `block in coerce'
/Users/tokitake/workspace/rom/vendor/bundle/ruby/2.5.0/gems/dry-types-0.12.2/lib/dry/types/array/member.rb:20:in `call': undefined method `map' for #<Proc:0x00007fb77731e698> (NoMethodError)
Did you mean? tap
Platforms:
macOS 10.13.3
ruby 2.5.0
Version:
rom 4.1.3
rom-factory 0.6.0
This test will fail. Overriding has_many
association does not work.
context 'has_many' do
before do
factories.define(:user) do |f|
# ...
f.association(:tasks, count: 2)
end
factories.define(:task) do |f|
f.sequence(:title) { |n| "Task #{n}" }
end
end
# ...
it 'allows overrides' do
task = factories[:task]
user = factories[:user, tasks: [task]]
expect(rom.relations[:tasks].count).to eq 1
task = rom.relations[:tasks].one
expect(task[:user_id]).to_not be(nil) # fail
expect(user.tasks.count).to eq 1 # fail
end
end
We can define custom structs nested in a module
, and then pointing to it via structs_namespace
option. It works fine, but it does not work with top-level custom struct classes.
Reasoning:
It makes it problematic to update Hanami 1 applications to Hanami 2, because Hanami-Model (Hanami 1) assumed top-level entities to be defined.
Other than that, this behaviour is inconsistent.
I've written rspec examples for this usecase: swilgosz@b0afeb7
class User < ROM::Struct
end
factories.define(:user) do |f|
f.first_name "Jane"
end
factories.define(admin: :user) do |f|
f.first_name "John"
end
Factory[:user].class
=> ROM::Struct::User
Factory[:admin]
=> ROM::Struct::Admin.class
module Entities
class User < ROM::Struct
end
end
factories.define(:user, struct_namespace: Entities) do |f|
f.first_name "Jane"
end
factories.define(admin: :user, struct_namespace: Entities) do |f|
f.first_name "John"
end
Factory[:user].class
=> Entities::User
Factory[:admin].class
=> ROM::Struct::Admin
I expect that either, by passing struct_namespace: nil
or by default, ROM-Factory will try to call the top-level structs if they are defined. It should fallback to ROM::Struct::[[FactoryClass]]
in the constant is not found, or is not a kind of ROM::Struct
I have primary keys which are bytea
strings. If I have a relation like this
class Thing < ROM::Relation[:sql]
schema(:things) do
attribute :custom_id, ROM::SQL::Types::Blob
attribute :name, String
primary_key :custom_id
end
end
and then my factory definition looks like this
Factory = ROM::Factory.configure { |c| c.rom = rom }
Factory.define(:thing) do |f|
f.sequence(:custom_id) { |_| File.binread('/dev/urandom', 10) }
f.name 'some thing'
end
then the factory builder will clobber it.
It would be nice if it didn't. If I have a non-numeric primary key then I'd also love if it raised an error if I didn't define a sequence for it.
I am using rom-rb with rom-sql and rom-factory.
In short, a struct creation via factory (Factory.structs[:foo]
) is not using default type value unless schema also has unrelated jsonb
type field.
Took me forever to isolate the source of issue to that jsonb
type column ๐
Example repo:
https://github.com/trafium/rom_factory_bug
To run:
bundle exec rake db:create
bundle exec rake db:migrate
ruby test.rb
The output is:
#<Entities::Foo column_with_default=nil id=1 random_column=nil>
#<Entities::Bar column_with_default="default" id=1 random_column=nil>
#<Entities::Foo column_with_default="default" id=1 random_column=nil>
#<Entities::Bar column_with_default="default" id=1 random_column=nil>
I am not sure what is the expected behaviour for rom-factory
, but I would expect it should always use default values for factory structs creation.
# Create in-memory object
Factory.structs(:user)
I suppose it should be:
Factory.structs[:user]
Thanks!
Describe the bug
rom-factory
causes deprecation warnings when used with Ruby 2.7.
To Reproduce
rom-factory
with Ruby 2.7Example
ruby/2.7.0/lib/ruby/gems/2.7.0/gems/rom-factory-0.10.1/lib/rom/factory/dsl.rb:18: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
Expected behavior
It should not cause deprecation warnings.
Your environment
I recently managed to create a join table for image attachments on news items in which I failed to define a primary key like the below:
primary_key [:news_item_id, :asset_id]
The first sign of my mistake was rom-factory raising the following error when calling the relation's factory:
ArgumentError:
ROM::Relation::Combined#by_pk arity is 1 (0 args given)
I was able to find my mistake with help from @timriley, but I wonder if we could add mention to that error to check one's primary key as a pointer to others?
The top of the stacktrace was:
/Users/andrewcroome/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/rom-core-4.2.0/lib/rom/relation/curried.rb:73:in `to_a'
/Users/andrewcroome/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/rom-core-4.2.0/lib/rom/relation/materializable.rb:55:in `first'
/Users/andrewcroome/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/rom-factory-0.6.0/lib/rom/factory/builder/persistable.rb:31:in `create'
The association now crashes when run against the latest version of rom:
It appears that for associations the key that is being passed in to the 'def fetch(key)' method is the actual factory that has been initialized, instead of the key.
The error:
NoMethodError:
undefined method `to_sym' for #<IdentityProviders:0x007fe1c0554e58>
Did you mean? to_s
# /Users/cmavromoustakos/.rvm/gems/ruby-2.4.1/gems/rom-core-4.0.0/lib/rom/registry.rb:63:in `fetch'
# /Users/cmavromoustakos/.rvm/gems/ruby-2.4.1/gems/rom-factory-0.4.0/lib/rom/factory/dsl.rb:59:in `association'
# ./spec/support/factories.rb:12:in `block in <main>'
# /Users/cmavromoustakos/.rvm/gems/ruby-2.4.1/gems/rom-factory-0.4.0/lib/rom/factory/dsl.rb:31:in `initialize'
Debugger
From: /Users/cmavromoustakos/.rvm/gems/ruby-2.4.1/gems/rom-core-4.0.0/lib/rom/registry.rb @ line 66 ROM::Registry#fetch:
60: def fetch(key)
61: raise ArgumentError.new('key cannot be nil') if key.nil?
62:
63: require 'pry'
64: binding.pry
65:
=> 66: elements.fetch(key.to_sym) do
67: return yield if block_given?
68:
69: raise self.class.element_not_found_error.new(key, self)
70: end
71: end
[1] pry(#<ROM::RelationRegistry>)> key
=> #<IdentityProviders name=ROM::Relation::Name(identity_providers) dataset=#<Sequel::Postgres::Dataset: "SELECT \"identity_providers\".\"id\", \"identity_providers\".\"name\", \"identity_providers\".\"saml_metadata_url\", \"identity_providers\".\"created_at\", \"identity_providers\".\"updated_at\" FROM \"identity_providers\" ORDER BY \"identity_providers\".\"id\"">>
Factory.define(:user) do |f|
...
f.association(:identity_provider)
f.timestamps
end
Gemfile.lock
โ rom (4.0.0)
โ โ rom-changeset (~> 1.0)
โ โ rom-core (~> 4.0)
โ โ rom-mapper (~> 1.0)
โ โ rom-repository (~> 2.0)
โ rom-changeset (1.0.0)
โ โ dry-core (~> 0.3, >= 0.3.1)
โ โ rom-core (~> 4.0.0.rc)
โ โ transproc (~> 1.0)
โ rom-core (4.0.0)
โ โ concurrent-ruby (~> 1.0)
โ โ dry-container (~> 0.6)
โ โ dry-core (~> 0.3)
โ โ dry-equalizer (~> 0.2)
โ โ dry-initializer (~> 2.0)
โ โ dry-types (~> 0.12, >= 0.12.1)
โ โ rom-mapper (~> 1.0)
โ rom-factory (0.4.0)
โ โ dry-configurable (~> 0.1)
โ โ dry-core (~> 0.2)
โ โ dry-struct (~> 0.2)
โ โ faker (~> 1.7)
โ rom-mapper (1.0.0)
โ โ dry-core (~> 0.3, >= 0.3.1)
โ โ dry-equalizer (~> 0.2)
โ โ transproc (~> 1.0)
โ rom-repository (2.0.0)
โ โ dry-struct (~> 0.3)
โ โ rom-mapper (~> 1.0)
โ rom-sql (2.0.0)
โ โ dry-core (~> 0.3)
โ โ dry-equalizer (~> 0.2)
โ โ dry-types (~> 0.12, >= 0.12.1)
rom-core (~> 4.0)
โ โ sequel (>= 4.49)
I have a unique problem where my Repo/Entity is called indie as in an Indie artist. The infer_factory_name(name)
method https://github.com/rom-rb/rom-factory/blob/v0.6.0/lib/rom/factory/factories.rb#L203 tries looking for the Indy factory which does not exist.
Testing features such as pagination requires presence of a number of objects in the repository. Creation of these entities takes more time, since each faked object is created separately. Yet ROM allows for calling commands with multiple instances, which is much more efficient. It would be a nice feature if instead of
10.times { Factory[:user] }
we had
Factory[:user, instances: 10]
which would be executed as a single DB call.
Currently only belongs_to
is supported
has_many
has_one
has_many-through
It is not possible to overwrite an association with nil.
class Units < ROM::Relation[:sql]
schema(:units, infer: true) do
associations do
has_many :users
end
end
end
class Users < ROM::Relation[:sql]
schema(:users, infer: true) do
associations do
belongs_to :unit
end
end
end
Factory.define(:user) do |f|
f.id { fake(:number, :number, digits: 3) }
f.name { fake(:name, :name) }
f.association(:unit)
end
Following overwrite of the association unit
fails:
Factory[:user, id: 1, unit: nil]
NoMethodError:
undefined method `fetch' for nil:NilClass
child.merge(fk => parent.fetch(pk))
# /usr/local/bundle/gems/rom-core-5.2.5/lib/rom/associations/many_to_one.rb:45:in `associate'
# /usr/local/bundle/bundler/gems/rom-factory-94c8d02faf68/lib/rom/factory/attributes/association.rb:57:in `call'
the expected behavior should be a resulting user-db-entry holding a unit_id
of NULL
and the returned ruby-object should be look like this:
{ id: 1, name: "Michael Knight", unit: nil }
Factory[:user, id: 1, unit: { id: nil }]
WDYT? How should we fix this?
Thanks and best regards
Description
Dependent attributes are not taking into account when the source attribute is passed to factory call.
Factory.define(:user) do |f|
f.user_name { fake(:name) }
f.email { |user_name| "#{user_name}@example.com" }
end
Factory[:user] #=> <#User user_name="rand" email="[email protected]">
Factory[:user, user_name: "rrom"] #=> <#User user_name="rrom" email="@example.com">
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.