seedie 0.3.0 → 0.4.1

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,18 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Seedie
2
4
  module Model
3
5
  class Creator
4
6
  include Reporters::Reportable
5
-
7
+
6
8
  def initialize(model, reporters = [])
7
9
  @model = model
8
10
  @reporters = reporters
9
11
 
10
12
  add_observers(@reporters)
11
13
  end
12
-
14
+
13
15
  def create!(field_values_set)
14
16
  record = @model.create!(field_values_set)
15
- report(:record_created, name: "#{record.class}", id: "#{record.id}")
17
+ report(:record_created, name: record.class.to_s, id: record.id.to_s)
16
18
 
17
19
  record
18
20
  end
@@ -22,9 +24,9 @@ module Seedie
22
24
  create!(field_values_set)
23
25
  rescue ActiveRecord::RecordInvalid => e
24
26
  report(:record_invalid, record: e.record)
25
- return nil
27
+ nil
26
28
  end
27
29
  end
28
30
  end
29
31
  end
30
- end
32
+ end
@@ -1,30 +1,32 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Seedie
2
4
  module Model
3
5
  class IdGenerator
4
6
  def initialize(model)
5
7
  @model = model
6
8
  end
7
-
9
+
8
10
  def random_id
9
11
  id = @model.pluck(:id).sample
10
12
  raise InvalidAssociationConfigError, "#{@model} has no records" unless id
11
13
 
12
- return id
14
+ id
13
15
  end
14
-
16
+
15
17
  def unique_id_for(association_klass, model_id_column)
16
18
  unless association_klass.column_names.include?(model_id_column)
17
- raise InvalidAssociationConfigError, "#{model_id_column} does not exist in #{association_klass}"
19
+ raise InvalidAssociationConfigError, "#{model_id_column} does not exist in #{association_klass}"
18
20
  end
19
-
21
+
20
22
  unique_ids = @model.ids - association_klass.pluck(model_id_column)
21
-
23
+
22
24
  if unique_ids.empty?
23
25
  raise InvalidAssociationConfigError, "No unique ids for #{@model}"
24
26
  end
25
-
27
+
26
28
  unique_ids.first
27
29
  end
28
30
  end
29
31
  end
30
- end
32
+ end
@@ -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.1"
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