seedie 0.1.0 → 0.2.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/CHANGELOG.md +75 -0
- data/README.md +10 -2
- data/lib/generators/seedie/install_generator.rb +38 -8
- data/lib/generators/seedie/templates/seedie.yml +26 -4
- data/lib/seedie/associations/belongs_to.rb +41 -15
- data/lib/seedie/field_values/custom_value.rb +80 -35
- data/lib/seedie/field_values/fake_value.rb +2 -2
- data/lib/seedie/field_values/faker_builder.rb +7 -6
- data/lib/seedie/model/id_generator.rb +1 -3
- data/lib/seedie/model/model_sorter.rb +10 -2
- data/lib/seedie/polymorphic_association_helper.rb +20 -0
- data/lib/seedie/version.rb +1 -1
- data/lib/seedie.rb +3 -1
- metadata +10 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dba945f1f8d911d59194de8191ef857885bc79fb3986fe4d159bbf21842758d9
|
4
|
+
data.tar.gz: 330174e781fa44b766d1fdcc4fbca9b4cc4f549db447913a60e2c1a41a4f0f51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4717460bd7dc315de646b3e839f5d8be92881245638711c790b5f8a8b3dac216d8ab0eccf8c6d3bc974f7c9ecf1f00b8520bbf44f6b112af18e2620a44faee71
|
7
|
+
data.tar.gz: cc648a856d662822565da6d648f16d5f17da1f9b5f1eca45f0e2748fc8633e98d7018efda18d699af4771315b424fa83d13b397a632716a06d79910ee4ec4ae9
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
## Version 0.3.0
|
2
|
+
|
3
|
+
### New Features
|
4
|
+
|
5
|
+
#### Polymorphic Association
|
6
|
+
* [GitHub PR](https://github.com/keshavbiswa/seedie/pull/12)
|
7
|
+
|
8
|
+
You can now add a polymorphic association to your seedie.yml file:
|
9
|
+
|
10
|
+
```yaml
|
11
|
+
belongs_to:
|
12
|
+
commentable:
|
13
|
+
polymorphic: post # or [post, article] for multiple options
|
14
|
+
strategy: random
|
15
|
+
```
|
16
|
+
|
17
|
+
#### Automatic Polymorphic Association Generator
|
18
|
+
* [GitHub PR](https://github.com/keshavbiswa/seedie/pull/13)
|
19
|
+
|
20
|
+
When you run `rails g seedie:install`, it'll also generate the necessary polymorphic associations.
|
21
|
+
|
22
|
+
#### Custom Value Attributes with Validations
|
23
|
+
* [GitHub PR](https://github.com/keshavbiswa/seedie/pull/14)
|
24
|
+
|
25
|
+
Replaced custom_attr_value with a simplified value key:
|
26
|
+
|
27
|
+
Before:
|
28
|
+
```yaml
|
29
|
+
some_attribute:
|
30
|
+
custom_attr_value:
|
31
|
+
values: [1,2,3]
|
32
|
+
pick_strategy: random
|
33
|
+
```
|
34
|
+
|
35
|
+
After:
|
36
|
+
```yaml
|
37
|
+
some_attribute:
|
38
|
+
values: [1,2,3] # or value (in which case pick_strategy is not required)
|
39
|
+
options:
|
40
|
+
pick_strategy: random
|
41
|
+
```
|
42
|
+
|
43
|
+
#### Custom Value Generator
|
44
|
+
|
45
|
+
* [GitHub PR](https://github.com/keshavbiswa/seedie/pull/17)
|
46
|
+
|
47
|
+
Upon invoking `rails g seedie:install`, the generator will also add custom values.
|
48
|
+
|
49
|
+
#### Inclusion of Non-polymorphic _type Columns
|
50
|
+
* [Github PR](https://github.com/keshavbiswa/seedie/pull/18)
|
51
|
+
|
52
|
+
Earlier, columns with `_type` were skipped during seedie.yml generation, causing some attributes to be overlooked.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
class User < ApplicationRecord
|
56
|
+
enum role_type: { admin: 0, user: 1 }
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
We've resolved this, now only columns related to polymorphic foreign_types are excluded.
|
61
|
+
|
62
|
+
#### Range Inclusions
|
63
|
+
* [Github PR](https://github.com/keshavbiswa/seedie/pull/19)
|
64
|
+
|
65
|
+
Define ranges using the start and end keys:
|
66
|
+
|
67
|
+
```yaml
|
68
|
+
score:
|
69
|
+
values:
|
70
|
+
start: 0
|
71
|
+
end: 100
|
72
|
+
options: { pick_strategy: sequential }
|
73
|
+
```
|
74
|
+
|
75
|
+
This configuration will generate sequential numbers between 0 and 100.
|
data/README.md
CHANGED
@@ -5,6 +5,9 @@ Utilizing the Faker library, Seedie generates realistic data for ActiveRecord mo
|
|
5
5
|
Currently supports only PostrgreSQL and SQLite3 databases.
|
6
6
|
The gem includes a Rake task for seeding models and a Rails generator for easy setup.
|
7
7
|
|
8
|
+
[](https://badge.fury.io/rb/seedie)
|
9
|
+

|
10
|
+
|
8
11
|
## Installation
|
9
12
|
|
10
13
|
Add the following line to your application's Gemfile:
|
@@ -55,15 +58,19 @@ models:
|
|
55
58
|
email: "{{Faker::Internet.email}}"
|
56
59
|
address: "{{Faker::Address.street_address}}"
|
57
60
|
disabled_fields: [nickname password password_digest]
|
58
|
-
post:
|
61
|
+
post:
|
59
62
|
count: 2
|
60
63
|
attributes:
|
61
64
|
title: "title {{index}}"
|
65
|
+
category:
|
66
|
+
values: [tech, sports, politics, entertainment]
|
67
|
+
options:
|
68
|
+
pick_strategy: random # or sequential
|
62
69
|
associations:
|
63
70
|
has_many:
|
64
71
|
comments: 4
|
65
72
|
belongs_to:
|
66
|
-
user: random
|
73
|
+
user: random # or new
|
67
74
|
has_one:
|
68
75
|
post_metadatum:
|
69
76
|
attributes:
|
@@ -87,6 +94,7 @@ In this file:
|
|
87
94
|
- `attributes` is a hash that maps field names to the values that should be used. If attributes are not defined, Seedie will use Faker to generate a value for the field.
|
88
95
|
- The special `{{index}}` placeholder will be replaced by the index of the current record being created, starting from 1. This allows you to have unique values for each record.
|
89
96
|
- Additionally, we can use placeholders like `{{Faker::Internet.email}}` to generate dynamic and unique data for each record using Faker.
|
97
|
+
- We can also specify an array of values that can be picked from randomly or sequentially using the `values` and `pick_strategy` options.
|
90
98
|
- `disabled_fields` is an array of fields that should not be automatically filled by Seedie.
|
91
99
|
- `associations` specify how associated models should be generated. Here, `has_many`, `belongs_to`, and `has_one` are supported.
|
92
100
|
- The specified number for `has_many` represents the number of associated records to create.
|
@@ -1,9 +1,11 @@
|
|
1
1
|
require "rails/generators/base"
|
2
|
-
require "
|
2
|
+
require "seedie"
|
3
3
|
|
4
4
|
module Seedie
|
5
5
|
module Generators
|
6
6
|
class InstallGenerator < Rails::Generators::Base
|
7
|
+
include PolymorphicAssociationHelper
|
8
|
+
|
7
9
|
EXCLUDED_MODELS = %w[
|
8
10
|
ActiveRecord::SchemaMigration
|
9
11
|
ActiveRecord::InternalMetadata
|
@@ -24,6 +26,7 @@ module Seedie
|
|
24
26
|
@models = get_models
|
25
27
|
@models_config = build_models_config
|
26
28
|
template "seedie.yml", "config/seedie.yml"
|
29
|
+
|
27
30
|
output_seedie_warning(output)
|
28
31
|
end
|
29
32
|
|
@@ -45,18 +48,32 @@ module Seedie
|
|
45
48
|
def attributes_configuration(model)
|
46
49
|
active_columns = []
|
47
50
|
disabled_columns = []
|
51
|
+
default_columns = []
|
52
|
+
foreign_keys = []
|
53
|
+
polymorphic_types = []
|
54
|
+
|
55
|
+
# Collect all foreign keys and polymorphic types
|
56
|
+
model.reflect_on_all_associations.each do |assoc|
|
57
|
+
foreign_keys << assoc.foreign_key
|
58
|
+
polymorphic_types << assoc.foreign_type if assoc.options[:polymorphic]
|
59
|
+
end
|
48
60
|
|
49
61
|
model.columns.each do |column|
|
50
62
|
# Excluding DEFAULT_DISABLED_FIELDS
|
51
63
|
# Excluding foreign_keys, polymorphic associations,
|
52
64
|
# password digest, columns with default functions or values
|
53
65
|
next if ModelFields::DEFAULT_DISABLED_FIELDS.include?(column.name)
|
54
|
-
next if column.name.end_with?("_id", "
|
55
|
-
|
56
|
-
|
57
|
-
|
66
|
+
next if column.name.end_with?("_id", "_digest")
|
67
|
+
|
68
|
+
if polymorphic_types.include?(column.name) || foreign_keys.include?(column.name)
|
69
|
+
next
|
70
|
+
end
|
71
|
+
|
72
|
+
# Adding default columns to default_columns
|
73
|
+
if column.default.present? || column.default_function.present?
|
74
|
+
default_columns << column
|
75
|
+
elsif column.null == false || has_presence_validator?(model, column.name)
|
58
76
|
# Only add to active if its required or has presence validator
|
59
|
-
if column.null == false || has_presence_validator?(model, column.name)
|
60
77
|
active_columns << column
|
61
78
|
else
|
62
79
|
disabled_columns << column
|
@@ -65,6 +82,9 @@ module Seedie
|
|
65
82
|
|
66
83
|
# Add atleast one column to active columns
|
67
84
|
active_columns << disabled_columns.pop if active_columns.empty? && disabled_columns.present?
|
85
|
+
|
86
|
+
# Disable all default columns
|
87
|
+
disabled_columns += default_columns
|
68
88
|
|
69
89
|
{
|
70
90
|
"attributes" => active_columns_configuration(model, active_columns),
|
@@ -100,14 +120,24 @@ module Seedie
|
|
100
120
|
|
101
121
|
def belongs_to_associations_configuration(model)
|
102
122
|
belongs_to_associations = model.reflect_on_all_associations(:belongs_to).reject do |association|
|
103
|
-
association.options[:polymorphic] == true || # Excluded Polymorphic Associations
|
104
123
|
association.options[:optional] == true # Excluded Optional Associations
|
105
124
|
end
|
106
125
|
|
107
126
|
belongs_to_associations.reduce({}) do |config, association|
|
108
|
-
|
127
|
+
if association.polymorphic?
|
128
|
+
config[association.name.to_s] = set_polymorphic_association_config(model, association)
|
129
|
+
else
|
130
|
+
config[association.name.to_s] = "random"
|
131
|
+
end
|
109
132
|
config
|
110
133
|
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def set_polymorphic_association_config(model, association)
|
137
|
+
{
|
138
|
+
"polymorphic" => find_polymorphic_types(model, association.name),
|
139
|
+
"strategy" => "random"
|
140
|
+
}
|
111
141
|
end
|
112
142
|
|
113
143
|
def has_presence_validator?(model, column_name)
|
@@ -4,11 +4,26 @@ models:
|
|
4
4
|
<%= model %>:
|
5
5
|
attributes:
|
6
6
|
<% config['attributes'].each do |name, value| -%>
|
7
|
-
<% if value.is_a?(Hash)
|
7
|
+
<% if value.is_a?(Hash) -%>
|
8
8
|
<%= name %>:
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
<% if value['values'] -%>
|
10
|
+
<% if value['values'].is_a?(Array) -%>
|
11
|
+
values: <%= value['values'] %>
|
12
|
+
<% elsif value['values'].is_a?(Hash) -%>
|
13
|
+
values:
|
14
|
+
<% value['values'].each do |key, value| -%>
|
15
|
+
<%= key %>: <%= value %>
|
16
|
+
<% end -%>
|
17
|
+
<% end -%>
|
18
|
+
<% elsif value['value'] -%>
|
19
|
+
value: '<%= value['value'] %>'
|
20
|
+
<% end -%>
|
21
|
+
<% if value['options'] -%>
|
22
|
+
options:
|
23
|
+
<% value['options'].each do |key, value| -%>
|
24
|
+
<%= key %>: '<%= value %>'
|
25
|
+
<% end -%>
|
26
|
+
<% end -%>
|
12
27
|
<% else -%>
|
13
28
|
<%= name %>: '<%= value %>'
|
14
29
|
<% end -%>
|
@@ -19,8 +34,15 @@ models:
|
|
19
34
|
<% config['associations'].each do |type, associations| -%>
|
20
35
|
<%= type %>:
|
21
36
|
<% associations.each do |association, value| -%>
|
37
|
+
<% if value.is_a?(Hash) && value.key?("polymorphic") -%>
|
38
|
+
<% next if value["polymorphic"].blank? -%>
|
39
|
+
<%= association %>:
|
40
|
+
polymorphic: <%= value["polymorphic"] %>
|
41
|
+
strategy: <%= value["strategy"] %>
|
42
|
+
<% else -%>
|
22
43
|
<%= association %>: <%= value %>
|
23
44
|
<% end -%>
|
24
45
|
<% end -%>
|
25
46
|
<% end -%>
|
26
47
|
<% end -%>
|
48
|
+
<% end -%>
|
@@ -30,45 +30,71 @@ module Seedie
|
|
30
30
|
private
|
31
31
|
|
32
32
|
def handle_association_config_type(reflection, association_name, association_config)
|
33
|
-
|
33
|
+
if reflection.polymorphic?
|
34
|
+
handle_polymorphic_config_type(reflection, association_config)
|
35
|
+
else
|
36
|
+
klass = reflection.klass
|
37
|
+
strategy = get_type(association_config)
|
38
|
+
handle_strategy(klass, reflection, strategy)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def handle_polymorphic_config_type(reflection, association_config)
|
44
|
+
type_name = get_polymorphic_class_name(association_config["polymorphic"])
|
45
|
+
klass = type_name.classify.constantize
|
46
|
+
strategy = get_type(association_config["strategy"])
|
47
|
+
associated_field_set.merge!(generate_associated_field(klass.to_s, reflection.foreign_type))
|
48
|
+
|
49
|
+
handle_strategy(klass, reflection, strategy)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Handles the strategy for belongs_to associations
|
53
|
+
# For polymorphic reflection, we might not add a strategy
|
54
|
+
# so we need to default it to random
|
55
|
+
def handle_strategy(klass, reflection, strategy)
|
56
|
+
strategy ||= reflection.polymorphic? ? "random" : nil
|
57
|
+
|
58
|
+
case get_type(strategy)
|
34
59
|
when "random"
|
35
|
-
handle_random_config_type(reflection)
|
60
|
+
handle_random_config_type(klass, reflection)
|
36
61
|
when "unique"
|
37
|
-
handle_unique_config_type(reflection)
|
62
|
+
handle_unique_config_type(klass, reflection)
|
38
63
|
when "new"
|
39
|
-
handle_new_config_type(reflection)
|
64
|
+
handle_new_config_type(klass, reflection)
|
40
65
|
else
|
41
|
-
handle_other_config_type(reflection,
|
66
|
+
handle_other_config_type(klass, reflection, strategy)
|
42
67
|
end
|
43
68
|
end
|
44
69
|
|
45
|
-
|
46
|
-
|
70
|
+
# polymorphic option can either be single value "post" or an array ["post", "game_room"]
|
71
|
+
# type pick strategy will be either the single value or a random value from the array
|
72
|
+
def get_polymorphic_class_name(polymorphic_types)
|
73
|
+
polymorphic_types.is_a?(String) ? polymorphic_types : polymorphic_types.sample
|
74
|
+
end
|
75
|
+
|
76
|
+
def handle_random_config_type(klass, reflection)
|
47
77
|
id = Model::IdGenerator.new(klass).random_id
|
48
78
|
|
49
79
|
report(:random_association, name: klass.to_s, parent_name: model.to_s, id: id)
|
50
80
|
associated_field_set.merge!(generate_associated_field(id, reflection.foreign_key))
|
51
81
|
end
|
52
82
|
|
53
|
-
def handle_unique_config_type(reflection)
|
54
|
-
klass = reflection.klass
|
83
|
+
def handle_unique_config_type(klass, reflection)
|
55
84
|
report(:unique_association, name: klass.to_s, parent_name: @model.to_s)
|
56
85
|
|
57
|
-
id = Model::IdGenerator.new(klass).unique_id_for(@model)
|
86
|
+
id = Model::IdGenerator.new(klass).unique_id_for(@model, reflection.foreign_key)
|
58
87
|
associated_field_set.merge!(generate_associated_field(id, reflection.foreign_key))
|
59
88
|
end
|
60
89
|
|
61
|
-
def handle_new_config_type(reflection)
|
62
|
-
klass = reflection.klass
|
90
|
+
def handle_new_config_type(klass, reflection)
|
63
91
|
report(:belongs_to_associations, name: klass.to_s, parent_name: model.to_s)
|
64
92
|
|
65
93
|
new_associated_record = generate_association(klass, {}, INDEX)
|
66
94
|
associated_field_set.merge!(generate_associated_field(new_associated_record.id, reflection.foreign_key))
|
67
95
|
end
|
68
96
|
|
69
|
-
def handle_other_config_type(reflection, association_config)
|
70
|
-
klass = reflection.klass
|
71
|
-
|
97
|
+
def handle_other_config_type(klass, reflection, association_config)
|
72
98
|
report(:belongs_to_associations, name: klass.to_s, parent_name: model.to_s)
|
73
99
|
|
74
100
|
new_associated_record = generate_association(klass, association_config, INDEX)
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Seedie
|
2
2
|
module FieldValues
|
3
3
|
class CustomValue
|
4
|
-
VALID_KEYS = ["values", "
|
5
|
-
|
6
|
-
|
4
|
+
VALID_KEYS = ["values", "value", "options"].freeze
|
5
|
+
PICK_STRATEGIES = ["random", "sequential"].freeze
|
6
|
+
|
7
7
|
attr_reader :name, :parsed_value
|
8
8
|
|
9
9
|
def initialize(name, value_template, index)
|
@@ -11,9 +11,8 @@ module Seedie
|
|
11
11
|
@value_template = value_template
|
12
12
|
@index = index
|
13
13
|
@parsed_value = ""
|
14
|
-
|
15
|
-
|
16
|
-
validate_template if @value_template.is_a?(Hash) && @value_template.has_key?(CUSTOM_VALUE)
|
14
|
+
|
15
|
+
validate_value_template
|
17
16
|
end
|
18
17
|
|
19
18
|
def generate_custom_field_value
|
@@ -28,40 +27,77 @@ module Seedie
|
|
28
27
|
|
29
28
|
private
|
30
29
|
|
31
|
-
def
|
32
|
-
|
33
|
-
@custom_attr_value = true
|
30
|
+
def validate_value_template
|
31
|
+
return unless @value_template.is_a?(Hash)
|
34
32
|
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
validate_keys
|
34
|
+
validate_values if @value_template.key?("values")
|
35
|
+
validate_options if @value_template.key?("options")
|
38
36
|
end
|
39
37
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
def validate_values
|
39
|
+
values = @value_template["values"]
|
40
|
+
options = @value_template["options"]
|
41
|
+
|
42
|
+
if values.is_a?(Array) || values.is_a?(Hash)
|
43
|
+
validate_sequential_values_length
|
44
|
+
else
|
45
|
+
raise InvalidCustomFieldValuesError, "The values key for #{@name} must be an array or a hash with start and end keys."
|
46
|
+
end
|
46
47
|
end
|
47
48
|
|
48
|
-
def
|
49
|
-
|
49
|
+
def validate_options
|
50
|
+
options = @value_template["options"]
|
51
|
+
pick_strategy = options["pick_strategy"]
|
50
52
|
|
51
|
-
|
53
|
+
if pick_strategy.present? && !PICK_STRATEGIES.include?(pick_strategy)
|
54
|
+
raise InvalidCustomFieldOptionsError,
|
55
|
+
"The pick_strategy for #{@name} must be either 'sequential' or 'random'."
|
56
|
+
end
|
52
57
|
end
|
53
58
|
|
54
|
-
|
55
|
-
|
59
|
+
## If pick strategy is sequential, we need to ensure there is a value for each index
|
60
|
+
# If there isn't sufficient values, we raise an error
|
61
|
+
def validate_sequential_values_length
|
62
|
+
return unless @value_template.key?("options")
|
63
|
+
return unless @value_template["options"]["pick_strategy"] == "sequential"
|
64
|
+
|
65
|
+
values = @value_template["values"]
|
66
|
+
|
67
|
+
if values.is_a?(Hash) && values.keys.sort == ["end", "start"]
|
68
|
+
# Assuming the values are an inclusive range
|
69
|
+
values_length = values["end"] - values["start"] + 1
|
70
|
+
else
|
71
|
+
values_length = values.length
|
72
|
+
end
|
56
73
|
|
57
|
-
|
74
|
+
if values_length < @index + 1
|
75
|
+
raise CustomFieldNotEnoughValuesError,
|
76
|
+
"There are not enough values for #{@name}. Please add more values."
|
77
|
+
end
|
58
78
|
end
|
59
79
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
80
|
+
def validate_keys
|
81
|
+
invalid_keys = @value_template.keys - VALID_KEYS
|
82
|
+
|
83
|
+
if invalid_keys.present?
|
84
|
+
raise InvalidCustomFieldKeysError,
|
85
|
+
"Invalid keys for #{@name}: #{invalid_keys.join(", ")}. Only #{VALID_KEYS} are allowed."
|
86
|
+
end
|
87
|
+
|
88
|
+
if @value_template.key?("values")
|
89
|
+
if @value_template.key?("value")
|
90
|
+
raise InvalidCustomFieldKeysError,
|
91
|
+
"Invalid keys for #{@name}: values and value cannot be used together."
|
92
|
+
end
|
63
93
|
|
64
|
-
|
94
|
+
if @value_template["values"].is_a?(Hash)
|
95
|
+
if !@value_template["values"].key?("start") || !@value_template["values"].key?("end")
|
96
|
+
raise InvalidCustomFieldValuesError,
|
97
|
+
"The values key for #{@name} must be an array or a hash with start and end keys."
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
65
101
|
end
|
66
102
|
|
67
103
|
def generate_custom_value_from_string
|
@@ -79,19 +115,28 @@ module Seedie
|
|
79
115
|
end
|
80
116
|
|
81
117
|
def generate_custom_value_from_hash
|
82
|
-
if @
|
83
|
-
values = @value_template["values"]
|
84
|
-
|
85
|
-
|
86
|
-
|
118
|
+
if @value_template.key?("values")
|
119
|
+
values = if @value_template["values"].is_a?(Array)
|
120
|
+
@value_template["values"]
|
121
|
+
else
|
122
|
+
# generate_custom_value_from_range
|
123
|
+
generate_custom_values_from_range(@value_template["values"]["start"], @value_template["values"]["end"])
|
124
|
+
end
|
125
|
+
options = @value_template["options"]
|
126
|
+
|
127
|
+
if options.present? && options["pick_strategy"] == "sequential"
|
87
128
|
@parsed_value = values[@index]
|
88
129
|
else
|
89
130
|
@parsed_value = values.sample
|
90
131
|
end
|
91
|
-
|
92
|
-
@parsed_value = @value_template
|
132
|
+
elsif @value_template.key?("value")
|
133
|
+
@parsed_value = @value_template["value"]
|
93
134
|
end
|
94
135
|
end
|
136
|
+
|
137
|
+
def generate_custom_values_from_range(start, ending)
|
138
|
+
(start..ending).to_a
|
139
|
+
end
|
95
140
|
end
|
96
141
|
end
|
97
142
|
end
|
@@ -25,7 +25,7 @@ module Seedie
|
|
25
25
|
when :boolean
|
26
26
|
Faker::Boolean.boolean
|
27
27
|
when :json, :jsonb
|
28
|
-
{ "key1" => Faker::Lorem.word, "key2" => Faker::Number.number(digits: 2) }
|
28
|
+
{ "value" => { "key1" => Faker::Lorem.word, "key2" => Faker::Number.number(digits: 2) } }
|
29
29
|
when :inet
|
30
30
|
Faker::Internet.ip_v4_address
|
31
31
|
when :cidr, :macaddr
|
@@ -37,7 +37,7 @@ module Seedie
|
|
37
37
|
when :money
|
38
38
|
Faker::Commerce.price.to_s
|
39
39
|
when :hstore
|
40
|
-
{ "key1" => Faker::Lorem.word, "key2" => Faker::Number.number(digits: 2) }
|
40
|
+
{ "value" => { "key1" => Faker::Lorem.word, "key2" => Faker::Number.number(digits: 2) } }
|
41
41
|
when :year
|
42
42
|
rand(1901..2155)
|
43
43
|
else
|
@@ -62,8 +62,7 @@ module Seedie
|
|
62
62
|
@class_prefix = "Boolean."
|
63
63
|
@method_prefix = "boolean"
|
64
64
|
when :json, :jsonb
|
65
|
-
@
|
66
|
-
@method_prefix = "shallow_json(width: 3, options: { key: \"Name.first_name\", value: \"Number.number(digits: 2)\" })"
|
65
|
+
@faker_expression = { "value" => "Json.shallow_json(width: 3, options: { key: 'Name.first_name', value: 'Number.number(digits: 2)' })" }
|
67
66
|
when :inet
|
68
67
|
@class_prefix = "Internet."
|
69
68
|
@method_prefix = "ip_v4_address"
|
@@ -80,9 +79,7 @@ module Seedie
|
|
80
79
|
@class_prefix = "Commerce."
|
81
80
|
@method_prefix = "price.to_s"
|
82
81
|
when :hstore
|
83
|
-
@
|
84
|
-
@method_prefix = "shallow_json"
|
85
|
-
@options = "(width: 3, options: { key: \"Name.first_name\", value: \"Number.number(digits: 2)\" })"
|
82
|
+
@faker_expression = { "value" => "Json.shallow_json(width: 3, options: { key: 'Name.first_name', value: 'Number.number(digits: 2)' })" }
|
86
83
|
when :year
|
87
84
|
@class_prefix = "Number."
|
88
85
|
@method_prefix = "number"
|
@@ -131,7 +128,11 @@ module Seedie
|
|
131
128
|
@class_prefix = ""
|
132
129
|
@method_prefix = ""
|
133
130
|
@options = ""
|
134
|
-
|
131
|
+
if options[:in].is_a?(Range)
|
132
|
+
@faker_expression = { "values" => { "start" => options[:in].first, "end" => options[:in].last }, "options" => { "pick_strategy" => "random" } }
|
133
|
+
else
|
134
|
+
@faker_expression = { "values" => options[:in], "options" => { "pick_strategy" => "random" } }
|
135
|
+
end
|
135
136
|
end
|
136
137
|
end
|
137
138
|
end
|
@@ -12,9 +12,7 @@ module Seedie
|
|
12
12
|
return id
|
13
13
|
end
|
14
14
|
|
15
|
-
def unique_id_for(association_klass)
|
16
|
-
model_id_column = "#{@model.to_s.underscore}_id"
|
17
|
-
|
15
|
+
def unique_id_for(association_klass, model_id_column)
|
18
16
|
unless association_klass.column_names.include?(model_id_column)
|
19
17
|
raise InvalidAssociationConfigError, "#{model_id_column} does not exist in #{association_klass}"
|
20
18
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Seedie
|
2
2
|
module Model
|
3
3
|
class ModelSorter
|
4
|
+
include PolymorphicAssociationHelper
|
5
|
+
|
4
6
|
def initialize(models)
|
5
7
|
@models = models
|
6
8
|
@model_dependencies = models.map {|m| [m, get_model_dependencies(m)]}.to_h
|
@@ -51,7 +53,6 @@ module Seedie
|
|
51
53
|
|
52
54
|
def get_model_dependencies(model)
|
53
55
|
associations = model.reflect_on_all_associations(:belongs_to).reject do |association|
|
54
|
-
association.options[:polymorphic] == true || # Excluded Polymorphic Associations
|
55
56
|
association.options[:optional] == true # Excluded Optional Associations
|
56
57
|
end
|
57
58
|
|
@@ -60,10 +61,17 @@ module Seedie
|
|
60
61
|
associations.map do |association|
|
61
62
|
if association.options[:class_name]
|
62
63
|
constantize_class_name(association.options[:class_name], model.name)
|
64
|
+
elsif association.polymorphic?
|
65
|
+
types = find_polymorphic_types(model, association.name)
|
66
|
+
|
67
|
+
if types.blank?
|
68
|
+
puts "Polymorphic type not found for #{model.name}. Ignoring..."
|
69
|
+
next
|
70
|
+
end
|
63
71
|
else
|
64
72
|
association.klass
|
65
73
|
end
|
66
|
-
end
|
74
|
+
end.compact
|
67
75
|
end
|
68
76
|
|
69
77
|
private
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module PolymorphicAssociationHelper
|
2
|
+
# Returns the type of the polymorphic association
|
3
|
+
# We need only one polymorphic association while generating config
|
4
|
+
# this makes it easier to sort according to dependencies
|
5
|
+
def find_polymorphic_types(model, association_name)
|
6
|
+
type = @models.find { |potential_model| has_association?(potential_model, association_name) }
|
7
|
+
type&.name&.underscore
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_association?(model, association_name)
|
11
|
+
associations = select_associations(model)
|
12
|
+
associations.any? { |association| association.options[:as] == association_name }
|
13
|
+
end
|
14
|
+
|
15
|
+
def select_associations(model)
|
16
|
+
model.reflect_on_all_associations.select do |reflection|
|
17
|
+
%i[has_many has_one].include?(reflection.macro)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/seedie/version.rb
CHANGED
data/lib/seedie.rb
CHANGED
@@ -11,6 +11,8 @@ require_relative "seedie/field_values_set"
|
|
11
11
|
require_relative "seedie/model_fields"
|
12
12
|
require_relative "seedie/model_seeder"
|
13
13
|
|
14
|
+
require_relative "seedie/polymorphic_association_helper"
|
15
|
+
|
14
16
|
require_relative "seedie/model/creator"
|
15
17
|
require_relative "seedie/model/model_sorter"
|
16
18
|
require_relative "seedie/model/id_generator"
|
@@ -37,6 +39,6 @@ module Seedie
|
|
37
39
|
class InvalidAssociationConfigError < StandardError; end
|
38
40
|
class InvalidCustomFieldKeysError < StandardError; end
|
39
41
|
class InvalidCustomFieldValuesError < StandardError; end
|
42
|
+
class InvalidCustomFieldOptionsError < StandardError; end
|
40
43
|
class CustomFieldNotEnoughValuesError < StandardError; end
|
41
|
-
class CustomFieldInvalidPickValueError < StandardError; end
|
42
44
|
end
|
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: seedie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keshav Biswa
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faker
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.9'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activerecord
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 5.2.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 5.2.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -118,6 +118,7 @@ extra_rdoc_files: []
|
|
118
118
|
files:
|
119
119
|
- ".rspec"
|
120
120
|
- ".rubocop.yml"
|
121
|
+
- CHANGELOG.md
|
121
122
|
- Gemfile
|
122
123
|
- LICENSE.txt
|
123
124
|
- README.md
|
@@ -139,6 +140,7 @@ files:
|
|
139
140
|
- lib/seedie/model/model_sorter.rb
|
140
141
|
- lib/seedie/model_fields.rb
|
141
142
|
- lib/seedie/model_seeder.rb
|
143
|
+
- lib/seedie/polymorphic_association_helper.rb
|
142
144
|
- lib/seedie/railtie.rb
|
143
145
|
- lib/seedie/reporters/base_reporter.rb
|
144
146
|
- lib/seedie/reporters/console_reporter.rb
|