Class: Pinspec::Setup::DependencyResolver
- Inherits:
-
Object
- Object
- Pinspec::Setup::DependencyResolver
- Defined in:
- lib/pinspec/setup/dependency_resolver.rb
Constant Summary collapse
- PLACEHOLDERS =
{ string: "pinspec", text: "pinspec", citext: "pinspec", integer: 1, bigint: 1, smallint: 1, tinyint: 1, float: 1.0, decimal: "1.0", numeric: "1.0", money: "1.0", boolean: false, json: {}, jsonb: {}, hstore: {}, xml: "<pinspec/>", uuid: "00000000-0000-4000-8000-000000000001", inet: "127.0.0.1", cidr: "127.0.0.0/8", macaddr: "00:00:00:00:00:01", binary: "pinspec", blob: "pinspec", interval: "P1D", ltree: "pinspec", oid: 1, bit: "0", bit_varying: "0" }.freeze
- TEMPORAL_TYPES =
%i[datetime timestamp timestamptz date time].freeze
Instance Method Summary collapse
- #creation_order(root_tables, prune: ->(_table) { false }) ⇒ Object
- #declined_factory_for(table_name) ⇒ Object
- #factory_for(table_name) ⇒ Object
-
#initialize(schema, factories) ⇒ DependencyResolver
constructor
A new instance of DependencyResolver.
- #model_for(table_name) ⇒ Object
- #placeholder_for(column, frozen_time:, uniquifier: nil) ⇒ Object
- #required_associations(table) ⇒ Object
- #required_scalars(table) ⇒ Object
- #self_referential_required?(table) ⇒ Boolean
- #table_candidates_for(model_name) ⇒ Object
- #table_for(model_name) ⇒ Object
- #table_for_type_hint(hint) ⇒ Object
- #table_from_factory_class(hint) ⇒ Object
- #table_from_unique_prefix(hint) ⇒ Object
- #unique_columns(table) ⇒ Object
Constructor Details
#initialize(schema, factories) ⇒ DependencyResolver
Returns a new instance of DependencyResolver.
38 39 40 41 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 38 def initialize(schema, factories) @schema = schema @factories = factories end |
Instance Method Details
#creation_order(root_tables, prune: ->(_table) { false }) ⇒ Object
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 142 def creation_order(root_tables, prune: ->(_table) { false }) ordered = [] state = {} walk = lambda do |table_name, path| case state[table_name] when :done then return when :visiting raise UnresolvableSetup.new( :association_cycle, "#{path.join(' -> ')} -> #{table_name}: these tables require each " \ "other through NOT NULL foreign keys, so no row can be created " \ "first. Making one side optional would break the cycle." ) end state[table_name] = :visiting unless prune.call(table_name) table = @schema.table(table_name) required_associations(table).each do |_column, parent| next if parent == table_name walk.call(parent, path + [table_name]) end end state[table_name] = :done ordered << table_name end Array(root_tables).compact.uniq.each { |name| walk.call(name, []) } ordered end |
#declined_factory_for(table_name) ⇒ Object
117 118 119 120 121 122 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 117 def declined_factory_for(table_name) @factories.factories .select { |f| table_for(f.model)&.name == table_name.to_s } .reject(&:persists?) .first end |
#factory_for(table_name) ⇒ Object
111 112 113 114 115 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 111 def factory_for(table_name) candidates = @factories.factories.select { |f| table_for(f.model)&.name == table_name.to_s } candidates.find(&:persists?) end |
#model_for(table_name) ⇒ Object
104 105 106 107 108 109 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 104 def model_for(table_name) declared = @factories.factories.find { |f| table_for(f.model)&.name == table_name.to_s } return declared.model if declared camelize(Analyzer::Inflector.singular_candidates(table_name).first) end |
#placeholder_for(column, frozen_time:, uniquifier: nil) ⇒ Object
181 182 183 184 185 186 187 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 181 def placeholder_for(column, frozen_time:, uniquifier: nil) return frozen_value(column, frozen_time) if TEMPORAL_TYPES.include?(column.type) base = PLACEHOLDERS[column.type] base = apply_uniquifier(base, column, uniquifier) if uniquifier clamp_to_limit(base, column) end |
#required_associations(table) ⇒ Object
124 125 126 127 128 129 130 131 132 133 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 124 def required_associations(table) return [] if table.nil? table.required_columns.filter_map do |column| fk = @schema.fk_for(table.name, column.name) next unless fk [column.name, fk.to_table] end end |
#required_scalars(table) ⇒ Object
135 136 137 138 139 140 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 135 def required_scalars(table) return [] if table.nil? association_columns = required_associations(table).map(&:first) table.required_columns.reject { |column| association_columns.include?(column.name) } end |
#self_referential_required?(table) ⇒ Boolean
177 178 179 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 177 def self_referential_required?(table) required_associations(table).any? { |_column, parent| parent == table&.name } end |
#table_candidates_for(model_name) ⇒ Object
95 96 97 98 99 100 101 102 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 95 def table_candidates_for(model_name) parts = model_name.to_s.split("::") demodulized = underscore(parts.last) namespaced = parts.map { |part| underscore(part) }.join("_") (Analyzer::Inflector.table_candidates(demodulized) + Analyzer::Inflector.table_candidates(namespaced)).uniq end |
#table_for(model_name) ⇒ Object
43 44 45 46 47 48 49 50 51 52 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 43 def table_for(model_name) return nil if model_name.nil? table_candidates_for(model_name).each do |candidate| table = @schema.table(candidate) return table if table end nil end |
#table_for_type_hint(hint) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 54 def table_for_type_hint(hint) return nil if hint.nil? words = hint.to_s.scan(/[A-Z][a-z0-9]*/) if words.size < 2 direct = table_for(hint) return direct if direct else words.each_index do |index| table = table_for(words[index..].join) return table if table end end table_from_factory_class(hint) || table_from_unique_prefix(hint) end |
#table_from_factory_class(hint) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 72 def table_from_factory_class(hint) wanted = underscore(hint.to_s.split("::").last) @factories.factories.each do |factory| next unless factory.name.to_s == wanted next if factory.model.nil? table = table_for(factory.model) return table if table end nil end |
#table_from_unique_prefix(hint) ⇒ Object
86 87 88 89 90 91 92 93 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 86 def table_from_unique_prefix(hint) candidates = Analyzer::Inflector.table_candidates(underscore(hint.to_s.split("::").last)) matches = @schema.tables.select do |table| candidates.any? { |candidate| table.name.end_with?("_#{candidate}") } end matches.size == 1 ? matches.first : nil end |
#unique_columns(table) ⇒ Object
189 190 191 192 193 |
# File 'lib/pinspec/setup/dependency_resolver.rb', line 189 def unique_columns(table) return [] if table.nil? table.unique_indexes.flat_map(&:columns).uniq end |