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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 561377deea81325062cee19ab2cd29e48d6d434e2872b97474712c1ab07a4d87
4
- data.tar.gz: 06a8f58b9488ec48da96b6678696bbfc672fd71f881395a795a8a97eff4d1478
3
+ metadata.gz: dba945f1f8d911d59194de8191ef857885bc79fb3986fe4d159bbf21842758d9
4
+ data.tar.gz: 330174e781fa44b766d1fdcc4fbca9b4cc4f549db447913a60e2c1a41a4f0f51
5
5
  SHA512:
6
- metadata.gz: eda91d6bd4be5e638ef13e963d517f25055e9a96bbccfd222d565caeed5eddaf929fff9742a45bc260c27cafb5c2f0d37e4d91948c1d7786e17cc10202c05289
7
- data.tar.gz: 18f0f86fadc97d6e9be4a736d0795cdf09a6a8df044fd5f6d1a7ae4d1e3f0c75a3be706111b56c5c44bacfaf3f7d072fc5479091f412be6f319591b83616e8c8
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
+ [![Gem Version](https://badge.fury.io/rb/seedie.svg)](https://badge.fury.io/rb/seedie)
9
+ ![Build Status](https://github.com/keshavbiswa/seedie/workflows/CI/badge.svg?branch=main)
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: &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 "active_record"
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", "_type", "_digest")
55
- next if column.default_function.present?
56
- next if column.default.present?
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
- config[association.name.to_s] = "random"
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) && value.key?("custom_attr_value") -%>
7
+ <% if value.is_a?(Hash) -%>
8
8
  <%= name %>:
9
- custom_attr_value:
10
- values: <%= value["custom_attr_value"]["values"] %>
11
- pick_strategy: <%= value["custom_attr_value"]["pick_strategy"] %>
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
- case get_type(association_config)
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, association_config)
66
+ handle_other_config_type(klass, reflection, strategy)
42
67
  end
43
68
  end
44
69
 
45
- def handle_random_config_type(reflection)
46
- klass = reflection.klass
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", "pick_strategy"]
5
- CUSTOM_VALUE = "custom_attr_value"
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
- @custom_attr_value = false
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 validate_template
32
- @value_template = @value_template[CUSTOM_VALUE]
33
- @custom_attr_value = true
30
+ def validate_value_template
31
+ return unless @value_template.is_a?(Hash)
34
32
 
35
- validate_hash_keys
36
- validate_values_key
37
- validate_pick_strategy_key
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 validate_hash_keys
41
- invalid_keys = @value_template.keys - VALID_KEYS
42
- return if invalid_keys.empty?
43
-
44
- raise InvalidCustomFieldKeysError,
45
- "Invalid keys for #{@name}: #{invalid_keys.join(", ")}. Only 'values' and 'pick_strategy' are allowed."
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 validate_values_key
49
- return if @value_template["values"].is_a?(Array)
49
+ def validate_options
50
+ options = @value_template["options"]
51
+ pick_strategy = options["pick_strategy"]
50
52
 
51
- raise InvalidCustomFieldValuesError, "The values key for #{@name} must be an array."
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
- def validate_values_length
55
- return if @value_template["values"].length >= @index
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
- raise CustomFieldNotEnoughValuesError, "There are not enough values for name. Please add more values."
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 validate_pick_strategy_key
61
- @pick_strategy = @value_template["pick_strategy"] || "random"
62
- return if %w[random sequential].include?(@pick_strategy)
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
- raise CustomFieldInvalidPickValueError, "The pick_strategy for #{@name} must be either 'sequential' or 'random'."
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 @custom_attr_value
83
- values = @value_template["values"]
84
- if @pick_strategy == "sequential"
85
- validate_values_length
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
- else
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
- @class_prefix = "Json."
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
- @class_prefix = "Json."
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
- @faker_expression = { "custom_attr_value" => { "values" => options[:in], "pick_strategy" => "random" } }
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Seedie
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
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.1.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-07-30 00:00:00.000000000 Z
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: '0'
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: '0'
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: '0'
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: '0'
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