seedie 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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