Module: Glancer::Indexer::SchemaIndexer
- Defined in:
- lib/glancer/indexer/schema_indexer.rb
Class Method Summary collapse
- .eager_load_models! ⇒ Object
- .extract_foreign_keys(schema_text, schema_file) ⇒ Object
- .extract_inflections ⇒ Object
- .extract_table_name(chunk) ⇒ Object
- .find_model_for_table(table_name) ⇒ Object
- .format_association(assoc) ⇒ Object
- .index! ⇒ Object
- .model_associations_block(table_name) ⇒ Object
- .split_into_chunks(schema_text) ⇒ Object
Class Method Details
.eager_load_models! ⇒ Object
60 61 62 63 64 65 |
# File 'lib/glancer/indexer/schema_indexer.rb', line 60 def eager_load_models! Rails.application.eager_load! Glancer::Utils::Logger.debug("Indexer::SchemaIndexer", "Models eager-loaded for association reflection") rescue StandardError => e Glancer::Utils::Logger.warn("Indexer::SchemaIndexer", "Could not eager-load models: #{e.}") end |
.extract_foreign_keys(schema_text, schema_file) ⇒ 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 |
# File 'lib/glancer/indexer/schema_indexer.rb', line 142 def extract_foreign_keys(schema_text, schema_file) lines = schema_text.lines.select { |l| l.strip.start_with?("add_foreign_key") } return nil if lines.empty? relationships = lines.filter_map do |line| # add_foreign_key "orders", "users", column: "user_id" # add_foreign_key "order_items", "orders" m = line.match(/add_foreign_key ["'](\w+)["'],\s*["'](\w+)["'](?:.*column:\s*["'](\w+)["'])?/) next unless m child_table = m[1] parent_table = m[2] column = m[3] || "#{parent_table.singularize}_id" "#{child_table}.#{column} → #{parent_table}.id" end return nil if relationships.empty? content = "# Foreign Key Relationships\n#{relationships.join("\n")}" Glancer::Utils::Logger.debug("Indexer::SchemaIndexer", "Extracted #{relationships.size} foreign key(s)") { content: content, source_type: "schema", source_path: "#{schema_file}#foreign_keys" } end |
.extract_inflections ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/glancer/indexer/schema_indexer.rb', line 112 def extract_inflections inflections_file = Rails.root.join("config/initializers/inflections.rb") return nil unless File.exist?(inflections_file) raw = File.read(inflections_file) return nil unless raw.lines.any? { |l| l.strip.match?(/\binflect\.\w/) } Glancer::Utils::Logger.debug("Indexer::SchemaIndexer", "Found custom inflections, adding as schema chunk") { content: "# Custom Rails Inflections\n# These control plural/singular model name mapping.\n\n#{raw.strip}", source_type: "schema", source_path: inflections_file.to_s } rescue StandardError => e Glancer::Utils::Logger.warn("Indexer::SchemaIndexer", "Could not read inflections: #{e.}") nil end |
.extract_table_name(chunk) ⇒ Object
138 139 140 |
# File 'lib/glancer/indexer/schema_indexer.rb', line 138 def extract_table_name(chunk) chunk[/create_table ["']?([a-zA-Z0-9_]+)["']?/, 1] end |
.find_model_for_table(table_name) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/glancer/indexer/schema_indexer.rb', line 67 def find_model_for_table(table_name) candidates = ActiveRecord::Base.descendants.select do |model| !model.abstract_class? && !model.name&.start_with?("Glancer::") && model.table_name == table_name end return nil if candidates.empty? candidates.find { |m| m.superclass.abstract_class? || m.superclass == ActiveRecord::Base } || candidates.first rescue StandardError nil end |
.format_association(assoc) ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/glancer/indexer/schema_indexer.rb', line 97 def format_association(assoc) parts = [" #{assoc.macro} :#{assoc.name}"] opts = ["class_name: \"#{assoc.class_name}\""] fk = assoc.foreign_key.to_s opts << "foreign_key: \"#{fk}\"" if fk.present? opts << "through: :#{assoc.[:through]}" if assoc.[:through].present? opts << "polymorphic: true" if assoc.[:polymorphic] opts << "as: :#{assoc.[:as]}" if assoc.[:as].present? opts << "source: :#{assoc.[:source]}" if assoc.[:source].present? opts << "dependent: :#{assoc.[:dependent]}" if assoc.[:dependent].present? "#{parts.join} (#{opts.join(", ")})" end |
.index! ⇒ Object
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/glancer/indexer/schema_indexer.rb', line 8 def index! Glancer::Utils::Logger.info("Indexer::SchemaIndexer", "Starting schema indexing...") schema_file = Rails.root.join("db/schema.rb") unless File.exist?(schema_file) Glancer::Utils::Logger.warn("Indexer::SchemaIndexer", "Schema file not found at: #{schema_file}") return [] end Glancer::Utils::Logger.debug("Indexer::SchemaIndexer", "Reading schema file from: #{schema_file}") content = File.read(schema_file) Glancer::Utils::Logger.debug("Indexer::SchemaIndexer", "Read #{content.bytesize} bytes from schema file") eager_load_models! chunks = split_into_chunks(content) Glancer::Utils::Logger.info("Indexer::SchemaIndexer", "Found #{chunks.size} table definition(s) in schema") indexed_chunks = chunks.map do |chunk| table_name = extract_table_name(chunk) if table_name Glancer::Utils::Logger.debug("Indexer::SchemaIndexer", "Indexed table: #{table_name}") enriched = chunk + model_associations_block(table_name) { content: enriched, source_type: "schema", source_path: "#{schema_file}##{table_name}" } else Glancer::Utils::Logger.warn("Indexer::SchemaIndexer", "Could not extract table name from chunk") nil end end.compact fk_chunk = extract_foreign_keys(content, schema_file) indexed_chunks << fk_chunk if fk_chunk inflections_chunk = extract_inflections indexed_chunks << inflections_chunk if inflections_chunk Glancer::Utils::Logger.info("Indexer::SchemaIndexer", "Completed schema indexing. Total indexed chunks: #{indexed_chunks.size}") indexed_chunks rescue StandardError => e Glancer::Utils::Logger.error("Indexer::SchemaIndexer", "Schema indexing failed: #{e.class} - #{e.}") Glancer::Utils::Logger.debug("Indexer::SchemaIndexer", "Backtrace:\n#{e.backtrace.join("\n")}") raise Glancer::Error, "Schema indexing failed: #{e.}" end |
.model_associations_block(table_name) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/glancer/indexer/schema_indexer.rb', line 80 def model_associations_block(table_name) model = find_model_for_table(table_name) return "" unless model assocs = model.reflect_on_all_associations return "" if assocs.empty? lines = assocs.filter_map do |assoc| format_association(assoc) rescue StandardError nil end return "" if lines.empty? "\n\n# ActiveRecord Associations (#{model.name}):\n#{lines.join("\n")}" end |
.split_into_chunks(schema_text) ⇒ Object
130 131 132 133 134 135 136 |
# File 'lib/glancer/indexer/schema_indexer.rb', line 130 def split_into_chunks(schema_text) schema_text.split(/^ create_table /).map do |chunk| next if chunk.strip.empty? "create_table #{chunk.strip}" end.compact end |