seedie 0.3.0 → 0.4.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.
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Seedie
2
4
  module Model
3
5
  class ModelSorter
4
6
  include PolymorphicAssociationHelper
5
-
7
+
6
8
  def initialize(models)
7
9
  @models = models
8
- @model_dependencies = models.map {|m| [m, get_model_dependencies(m)]}.to_h
10
+ @model_dependencies = models.map { |m| [m, get_model_dependencies(m)] }.to_h
9
11
  @resolved_queue = []
10
12
  @unresolved = []
11
13
  end
12
-
14
+
13
15
  def sort_by_dependency
14
16
  add_independent_models_to_queue
15
17
 
@@ -19,7 +21,7 @@ module Seedie
19
21
 
20
22
  @resolved_queue
21
23
  end
22
-
24
+
23
25
  private
24
26
 
25
27
  # Independent models need to be added first
@@ -30,7 +32,7 @@ module Seedie
30
32
  end
31
33
  end
32
34
  end
33
-
35
+
34
36
  def resolve_dependencies(model)
35
37
  if @unresolved.include?(model)
36
38
  puts "Circular dependency detected for #{model}. Ignoring..."
@@ -38,25 +40,21 @@ module Seedie
38
40
  end
39
41
 
40
42
  @unresolved << model
41
- dependencies = @model_dependencies[model]
42
-
43
- if dependencies
44
- dependencies.each do |dependency|
45
- resolve_dependencies(dependency) unless @resolved_queue.include?(dependency)
46
- end
43
+ @model_dependencies[model]&.each do |dependency|
44
+ resolve_dependencies(dependency) unless @resolved_queue.include?(dependency)
47
45
  end
48
46
 
49
47
  @resolved_queue << model
50
48
  @unresolved.delete(model)
51
49
  end
52
-
50
+
53
51
  def get_model_dependencies(model)
54
52
  associations = model.reflect_on_all_associations(:belongs_to).reject do |association|
55
53
  association.options[:optional] == true # Excluded Optional Associations
56
54
  end
57
-
55
+
58
56
  return [] if associations.blank?
59
-
57
+
60
58
  associations.map do |association|
61
59
  if association.options[:class_name]
62
60
  constantize_class_name(association.options[:class_name], model.name)
@@ -64,7 +62,7 @@ module Seedie
64
62
  types = find_polymorphic_types(model, association.name)
65
63
 
66
64
  if types.blank?
67
- puts "Polymorphic type not found for #{model.name}. Ignoring..."
65
+ puts "Polymorphic type not found for #{model.name}. Ignoring..."
68
66
  next
69
67
  end
70
68
  else
@@ -73,8 +71,6 @@ module Seedie
73
71
  end.compact
74
72
  end
75
73
 
76
- private
77
-
78
74
  def constantize_class_name(class_name, model_name)
79
75
  namespaced_class_name = if model_name.include?("::")
80
76
  "#{model_name.deconstantize}::#{class_name}"
@@ -89,6 +85,6 @@ module Seedie
89
85
  class_name.constantize
90
86
  end
91
87
  end
92
- end
88
+ end
93
89
  end
94
90
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Seedie
2
4
  class ModelFields
3
- DEFAULT_DISABLED_FIELDS = %w[id created_at updated_at]
5
+ DEFAULT_DISABLED_FIELDS = %w[id created_at updated_at].freeze
4
6
 
5
7
  attr_reader :model_name, :model_config, :fields, :disabled_fields, :foreign_fields
6
-
8
+
7
9
  def initialize(model, model_config)
8
10
  @model_name = model.to_s
9
11
  @model_config = model_config
@@ -13,4 +15,4 @@ module Seedie
13
15
  @other_fields = model.column_names - @disabled_fields - @custom_fields - @foreign_fields
14
16
  end
15
17
  end
16
- end
18
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Seedie
2
4
  class ModelSeeder
3
5
  include Reporters::Reportable
@@ -12,22 +14,22 @@ module Seedie
12
14
  @config = config
13
15
  @record_creator = Model::Creator.new(model, reporters)
14
16
  @reporters = reporters
15
-
16
17
  add_observers(@reporters)
17
18
  end
18
19
 
19
20
  def generate_records
20
- report(:model_seed_start, name: "#{model.to_s}")
21
+ report(:model_seed_start, name: model.to_s)
21
22
  model_count(model_config).times do |index|
22
23
  record = generate_record(model_config, index)
23
24
  associations_config = model_config["associations"]
24
25
 
25
- if associations_config.present?
26
- Associations::HasMany.new(record, model, associations_config, reporters).generate_associations
27
- Associations::HasOne.new(record, model, associations_config, reporters).generate_associations
28
- end
26
+ next unless associations_config.present?
27
+
28
+ Associations::HasMany.new(record, model, associations_config, reporters).generate_associations
29
+ Associations::HasAndBelongsToMany.new(record, model, associations_config, reporters).generate_associations
30
+ Associations::HasOne.new(record, model, associations_config, reporters).generate_associations
29
31
  end
30
- report(:model_seed_finish, name: "#{model.to_s}")
32
+ report(:model_seed_finish, name: model.to_s)
31
33
  end
32
34
 
33
35
  private
@@ -40,21 +42,8 @@ module Seedie
40
42
  end
41
43
 
42
44
  def generate_record(model_config, index)
43
- associated_field_set = generate_belongs_to_associations(model, model_config)
44
-
45
- field_values_set = FieldValuesSet.new(model, model_config, index).generate_field_values
46
- field_values_set.merge!(associated_field_set)
45
+ field_values_set = FieldValuesSet.new(model, model_config, index).generate_field_values_with_associations
47
46
  @record_creator.create!(field_values_set)
48
47
  end
49
-
50
- def generate_belongs_to_associations(model, model_config)
51
- associations_config = model_config["associations"]
52
- return {} unless associations_config.present?
53
-
54
- belongs_to_associations = Associations::BelongsTo.new(model, associations_config, reporters)
55
- belongs_to_associations.generate_associations
56
-
57
- return belongs_to_associations.associated_field_set
58
- end
59
48
  end
60
- end
49
+ end
@@ -1,20 +1,24 @@
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
1
+ # frozen_string_literal: true
9
2
 
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)
3
+ module Seedie
4
+ module PolymorphicAssociationHelper
5
+ # Returns the type of the polymorphic association
6
+ # We need only one polymorphic association while generating config
7
+ # this makes it easier to sort according to dependencies
8
+ def find_polymorphic_types(_model, association_name)
9
+ type = @models.find { |potential_model| has_association?(potential_model, association_name) }
10
+ type&.name&.underscore
11
+ end
12
+
13
+ def has_association?(model, association_name)
14
+ associations = select_associations(model)
15
+ associations.any? { |association| association.options[:as] == association_name }
16
+ end
17
+
18
+ def select_associations(model)
19
+ model.reflect_on_all_associations.select do |reflection|
20
+ %i[has_many has_one].include?(reflection.macro)
21
+ end
18
22
  end
19
23
  end
20
24
  end
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "seedie"
2
- require "rails"
3
4
 
4
5
  module Seedie
5
6
  class Railtie < Rails::Railtie
@@ -7,4 +8,4 @@ module Seedie
7
8
  load "tasks/seedie.rake"
8
9
  end
9
10
  end
10
- end
11
+ end
@@ -1,81 +1,88 @@
1
- module Reporters
2
- class BaseReporter
3
- INDENT_SIZE = 2
1
+ # frozen_string_literal: true
4
2
 
5
- attr_reader :output, :reports
3
+ module Seedie
4
+ module Reporters
5
+ class BaseReporter
6
+ INDENT_SIZE = 2
6
7
 
7
- def initialize(output = nil)
8
- @output = output || StringIO.new
9
- @reports = []
10
- @indent_level = 0
11
- end
8
+ attr_reader :output, :reports
12
9
 
13
- def update(event_type, options)
14
- raise NotImplementedError, "Subclasses must define 'update'."
15
- end
10
+ def initialize(output = nil)
11
+ @output = output || StringIO.new
12
+ @reports = []
13
+ @indent_level = 0
14
+ end
16
15
 
17
- def close
18
- return if output.closed?
19
- output.flush
20
- end
16
+ def update(event_type, options)
17
+ raise NotImplementedError, "Subclasses must define 'update'."
18
+ end
21
19
 
22
- private
20
+ def close
21
+ return if output.closed?
23
22
 
24
- def messages(event_type, options)
25
- case event_type
26
- when :seed_start
27
- "############ SEEDIE RUNNING #############"
28
- when :seed_finish
29
- "############ SEEDIE FINISHED ############"
30
- when :model_seed_start
31
- "Seeding #{options[:name]}"
32
- when :model_seed_finish
33
- "Seeding #{options[:name]} finished!"
34
- when :record_created
35
- "Created #{options[:name]} with id: #{options[:id]}"
36
- when :has_many_start
37
- "Creating HasMany associations:"
38
- when :belongs_to_start
39
- "Creating BelongsTo associations:"
40
- when :has_one_start
41
- "Creating HasOne associations:"
42
- when :associated_records
43
- "Creating #{options[:count]} #{options[:name]} for #{options[:parent_name]}"
44
- when :random_association
45
- "Randomly associating #{options[:name]} with id: #{options[:id]} for #{options[:parent_name]}"
46
- when :unique_association
47
- "Uniquely associating #{options[:name]} for #{options[:parent_name]}"
48
- when :belongs_to_associations
49
- "Creating a new #{options[:name].titleize} for #{options[:parent_name]}"
50
- else
51
- "Unknown event type"
23
+ output.flush
52
24
  end
53
- end
54
25
 
55
- def indent_level_for(event_type)
56
- indent_levels = {
57
- seed_start: 0,
58
- seed_finish: 0,
59
- model_seed_start: 1,
60
- model_seed_finish: 1,
61
- record_created: 1,
62
- random_association: 1,
63
- has_many_start: 2,
64
- belongs_to_start: 2,
65
- has_one_start: 2,
66
- associated_records: 3,
67
- belongs_to_associations: 3
68
- }
26
+ private
69
27
 
70
- indent_levels[event_type]
71
- end
28
+ def messages(event_type, options)
29
+ case event_type
30
+ when :seed_start
31
+ "############ SEEDIE RUNNING #############"
32
+ when :seed_finish
33
+ "############ SEEDIE FINISHED ############"
34
+ when :model_seed_start
35
+ "Seeding #{options[:name]}"
36
+ when :model_seed_finish
37
+ "Seeding #{options[:name]} finished!"
38
+ when :record_created
39
+ "Created #{options[:name]} with id: #{options[:id]}"
40
+ when :has_many_start
41
+ "Creating HasMany associations:"
42
+ when :belongs_to_start
43
+ "Creating BelongsTo associations:"
44
+ when :has_one_start
45
+ "Creating HasOne associations:"
46
+ when :has_and_belongs_to_many_start
47
+ "Creating HasAndBelongsToMany associations:"
48
+ when :associated_records
49
+ "Creating #{options[:count]} #{options[:name]} for #{options[:parent_name]}"
50
+ when :random_association
51
+ "Randomly associating #{options[:name]} with id: #{options[:id]} for #{options[:parent_name]}"
52
+ when :unique_association
53
+ "Uniquely associating #{options[:name]} for #{options[:parent_name]}"
54
+ when :belongs_to_associations
55
+ "Creating a new #{options[:name].titleize} for #{options[:parent_name]}"
56
+ else
57
+ "Unknown event type"
58
+ end
59
+ end
60
+
61
+ def indent_level_for(event_type)
62
+ indent_levels = {
63
+ seed_start: 0,
64
+ seed_finish: 0,
65
+ model_seed_start: 1,
66
+ model_seed_finish: 1,
67
+ record_created: 1,
68
+ random_association: 1,
69
+ has_many_start: 2,
70
+ belongs_to_start: 2,
71
+ has_one_start: 2,
72
+ associated_records: 3,
73
+ belongs_to_associations: 3
74
+ }
75
+
76
+ indent_levels[event_type]
77
+ end
72
78
 
73
- def set_indent_level(event_type)
74
- if event_type.in?([:record_created, :random_association, :unique_association])
75
- @indent_level += 1 if !@reports.last[:event_type].in?([:record_created, :random_association, :unique_association])
76
- elsif @reports.blank? || @reports.last[:event_type] != event_type
77
- @indent_level = indent_level_for(event_type)
79
+ def update_indent_level(event_type)
80
+ if event_type.in?(%i[record_created random_association unique_association])
81
+ @indent_level += 1 if !@reports.last[:event_type].in?(%i[record_created random_association unique_association])
82
+ elsif @reports.blank? || @reports.last[:event_type] != event_type
83
+ @indent_level = indent_level_for(event_type)
84
+ end
78
85
  end
79
86
  end
80
87
  end
81
- end
88
+ end
@@ -1,16 +1,20 @@
1
- module Reporters
2
- class ConsoleReporter < BaseReporter
3
- def initialize
4
- super($stdout)
5
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Seedie
4
+ module Reporters
5
+ class ConsoleReporter < BaseReporter
6
+ def initialize
7
+ super($stdout)
8
+ end
6
9
 
7
- def update(event_type, options)
8
- indent_level = set_indent_level(event_type)
9
- message = messages(event_type, options)
10
- @reports << { event_type: event_type, message: message }
10
+ def update(event_type, options)
11
+ update_indent_level(event_type)
12
+ message = messages(event_type, options)
13
+ @reports << { event_type: event_type, message: message }
11
14
 
12
- output.print "#{" " * INDENT_SIZE * @indent_level}"
13
- output.puts message
15
+ output.print "#{' ' * INDENT_SIZE * @indent_level}"
16
+ output.puts message
17
+ end
14
18
  end
15
19
  end
16
- end
20
+ end
@@ -1,16 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "observer"
2
4
 
3
- module Reporters
4
- module Reportable
5
- include Observable
5
+ module Seedie
6
+ module Reporters
7
+ module Reportable
8
+ include Observable
6
9
 
7
- def report(event_type, options = {})
8
- changed
9
- notify_observers(event_type, options)
10
- end
10
+ def report(event_type, options = {})
11
+ changed
12
+ notify_observers(event_type, options)
13
+ end
11
14
 
12
- def add_observers(observers)
13
- observers.each { |observer| add_observer(observer) }
15
+ def add_observers(observers)
16
+ observers.each { |observer| add_observer(observer) }
17
+ end
14
18
  end
15
19
  end
16
- end
20
+ end
data/lib/seedie/seeder.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Seedie
2
4
  class Seeder
3
5
  include Reporters::Reportable
@@ -23,7 +25,7 @@ module Seedie
23
25
  end
24
26
  end
25
27
  report(:seed_finish)
26
-
28
+
27
29
  @reporters.each(&:close)
28
30
  end
29
31
 
@@ -32,8 +34,8 @@ module Seedie
32
34
  def load_config(path)
33
35
  path = Rails.root.join("config", "seedie.yml") if path.nil?
34
36
  raise ConfigFileNotFound, "Config file not found in #{path}" unless File.exist?(path)
35
-
37
+
36
38
  YAML.load_file(path)
37
39
  end
38
40
  end
39
- end
41
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Seedie
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
5
5
  end
data/lib/seedie.rb CHANGED
@@ -1,38 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "seedie/reporters/reportable"
4
- require_relative "seedie/reporters/base_reporter"
5
- require_relative "seedie/reporters/console_reporter"
6
-
7
- require_relative "seedie/field_values/fake_value"
8
- require_relative "seedie/field_values/custom_value"
9
- require_relative "seedie/field_values/faker_builder"
10
- require_relative "seedie/field_values_set"
11
- require_relative "seedie/model_fields"
12
- require_relative "seedie/model_seeder"
13
-
14
- require_relative "seedie/polymorphic_association_helper"
15
-
16
- require_relative "seedie/model/creator"
17
- require_relative "seedie/model/model_sorter"
18
- require_relative "seedie/model/id_generator"
19
-
20
- require_relative "seedie/associations/base_association"
21
- require_relative "seedie/associations/has_many"
22
- require_relative "seedie/associations/has_one"
23
- require_relative "seedie/associations/belongs_to"
24
-
25
- require_relative "seedie/seeder"
26
- require_relative "seedie/version"
27
- require_relative "seedie/configuration"
28
-
29
- require "seedie/railtie" if defined?(Rails)
30
-
31
3
  require "active_record"
32
4
  require "faker"
33
5
  require "yaml"
6
+ require "zeitwerk"
34
7
 
35
8
  module Seedie
9
+ @loader = Zeitwerk::Loader.for_gem
10
+ @loader.ignore("#{__dir__}/generators")
11
+ @loader.setup
12
+
36
13
  class Error < StandardError; end
37
14
  class InvalidFakerMethodError < StandardError; end
38
15
  class UnknownColumnTypeError < StandardError; end
@@ -51,5 +28,11 @@ module Seedie
51
28
  def configuration
52
29
  @configuration ||= Configuration.new
53
30
  end
31
+
32
+ def eager_load!
33
+ @loader.eager_load
34
+ end
54
35
  end
55
36
  end
37
+
38
+ Seedie.eager_load!
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "seedie"
2
4
 
3
5
  namespace :seedie do
4
6
  desc "Load the Seedie seeds"
5
- task :seed => :environment do
7
+ task seed: :environment do
6
8
  Seedie::Seeder.new.seed_models
7
9
  end
8
- end
10
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seedie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.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-10-08 00:00:00.000000000 Z
11
+ date: 2023-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: faker
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -25,21 +39,21 @@ dependencies:
25
39
  - !ruby/object:Gem::Version
26
40
  version: '2.9'
27
41
  - !ruby/object:Gem::Dependency
28
- name: activerecord
42
+ name: zeitwerk
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - ">="
45
+ - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: 5.2.0
47
+ version: '2.4'
34
48
  type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - ">="
52
+ - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: 5.2.0
54
+ version: '2.4'
41
55
  - !ruby/object:Gem::Dependency
42
- name: rspec
56
+ name: generator_spec
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - ">="
@@ -53,7 +67,7 @@ dependencies:
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
- name: rspec-rails
70
+ name: rails
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - ">="
@@ -67,7 +81,7 @@ dependencies:
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: generator_spec
84
+ name: rspec
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - ">="
@@ -81,7 +95,7 @@ dependencies:
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
- name: rails
98
+ name: rspec-rails
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
101
  - - ">="
@@ -131,12 +145,14 @@ files:
131
145
  - lib/seedie.rb
132
146
  - lib/seedie/associations/base_association.rb
133
147
  - lib/seedie/associations/belongs_to.rb
148
+ - lib/seedie/associations/has_and_belongs_to_many.rb
134
149
  - lib/seedie/associations/has_many.rb
135
150
  - lib/seedie/associations/has_one.rb
136
151
  - lib/seedie/configuration.rb
137
152
  - lib/seedie/field_values/custom_value.rb
138
153
  - lib/seedie/field_values/fake_value.rb
139
154
  - lib/seedie/field_values/faker_builder.rb
155
+ - lib/seedie/field_values/value_template_validator.rb
140
156
  - lib/seedie/field_values_set.rb
141
157
  - lib/seedie/model/creator.rb
142
158
  - lib/seedie/model/id_generator.rb