Class: RailsLens::Schema::DatabaseAnnotator

Inherits:
Object
  • Object
show all
Includes:
AnnotationRemoval
Defined in:
lib/rails_lens/schema/database_annotator.rb

Overview

Annotates abstract base classes (ApplicationRecord, etc.) with database-level objects like functions, sequences, types, etc.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from AnnotationRemoval

#remove_annotations

Constructor Details

#initialize(base_class) ⇒ DatabaseAnnotator

Returns a new instance of DatabaseAnnotator.



12
13
14
# File 'lib/rails_lens/schema/database_annotator.rb', line 12

def initialize(base_class)
  @base_class = base_class
end

Instance Attribute Details

#base_classObject (readonly)

Returns the value of attribute base_class.



10
11
12
# File 'lib/rails_lens/schema/database_annotator.rb', line 10

def base_class
  @base_class
end

Class Method Details

.annotate_all(options = {}) ⇒ Object

Class methods for batch operations



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rails_lens/schema/database_annotator.rb', line 58

def self.annotate_all(options = {})
  results = { annotated: [], skipped: [], failed: [] }

  abstract_classes = detect_abstract_base_classes

  abstract_classes.each do |klass|
    annotator = new(klass)

    begin
      if annotator.annotate_file
        results[:annotated] << klass.name
      else
        results[:skipped] << klass.name
      end
    rescue StandardError => e
      results[:failed] << { model: klass.name, error: e.message }
    end
  end

  results
end

.remove_all(options = {}) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/rails_lens/schema/database_annotator.rb', line 80

def self.remove_all(options = {})
  results = { removed: [], skipped: [], failed: [] }

  begin
    abstract_classes = detect_abstract_base_classes
  rescue StandardError => e
    RailsLens.logger.error { "Failed to detect abstract base classes: #{e.message}" }
    return results
  end

  abstract_classes.each do |klass|
    annotator = new(klass)
    if annotator.remove_annotations
      results[:removed] << klass.name
    else
      results[:skipped] << klass.name
    end
  rescue StandardError => e
    results[:failed] << { model: klass.name, error: e.message }
  end

  results
end

Instance Method Details

#annotate_file(file_path = nil) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/rails_lens/schema/database_annotator.rb', line 16

def annotate_file(file_path = nil)
  file_path ||= model_file_path
  return unless file_path && File.exist?(file_path)

  annotation_text = generate_annotation
  return if annotation_text.empty?

  # Remove existing annotations
  content = File.read(file_path)
  Annotation.remove(content) if Annotation.extract(content)

  # Use Prism-based insertion
  class_name = base_class.name.split('::').last
  if FileInsertionHelper.insert_at_class_definition(file_path, class_name, annotation_text)
    true
  else
    false
  end
end

#generate_annotationObject



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/rails_lens/schema/database_annotator.rb', line 36

def generate_annotation
  annotation = Annotation.new

  # Detect adapter
  adapter_name = base_class.connection.adapter_name

  # Always add database dialect for abstract classes
  annotation.add_line("database_dialect = \"#{adapter_name}\"")

  case adapter_name
  when /PostgreSQL/i
    add_postgresql_functions(annotation)
  when /MySQL/i
    add_mysql_functions(annotation)
  when /SQLite/i
    # SQLite doesn't have stored functions
  end

  annotation.to_s
end