rails_lens 0.2.11 → 0.3.0

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/README.md +88 -72
  4. data/lib/rails_lens/analyzers/association_analyzer.rb +3 -10
  5. data/lib/rails_lens/analyzers/best_practices_analyzer.rb +11 -36
  6. data/lib/rails_lens/analyzers/callbacks.rb +302 -0
  7. data/lib/rails_lens/analyzers/column_analyzer.rb +6 -6
  8. data/lib/rails_lens/analyzers/composite_keys.rb +2 -5
  9. data/lib/rails_lens/analyzers/database_constraints.rb +4 -6
  10. data/lib/rails_lens/analyzers/delegated_types.rb +4 -7
  11. data/lib/rails_lens/analyzers/enums.rb +5 -11
  12. data/lib/rails_lens/analyzers/foreign_key_analyzer.rb +2 -2
  13. data/lib/rails_lens/analyzers/generated_columns.rb +4 -6
  14. data/lib/rails_lens/analyzers/index_analyzer.rb +4 -10
  15. data/lib/rails_lens/analyzers/inheritance.rb +30 -31
  16. data/lib/rails_lens/analyzers/notes.rb +29 -39
  17. data/lib/rails_lens/analyzers/performance_analyzer.rb +3 -26
  18. data/lib/rails_lens/annotation_pipeline.rb +1 -0
  19. data/lib/rails_lens/cli.rb +1 -0
  20. data/lib/rails_lens/commands.rb +23 -1
  21. data/lib/rails_lens/configuration.rb +4 -1
  22. data/lib/rails_lens/erd/visualizer.rb +0 -1
  23. data/lib/rails_lens/extensions/closure_tree_ext.rb +11 -11
  24. data/lib/rails_lens/mailer/annotator.rb +3 -3
  25. data/lib/rails_lens/model_detector.rb +49 -3
  26. data/lib/rails_lens/note_codes.rb +59 -0
  27. data/lib/rails_lens/providers/callbacks_provider.rb +24 -0
  28. data/lib/rails_lens/providers/extensions_provider.rb +1 -1
  29. data/lib/rails_lens/providers/view_provider.rb +6 -20
  30. data/lib/rails_lens/schema/adapters/base.rb +39 -2
  31. data/lib/rails_lens/schema/adapters/database_info.rb +11 -17
  32. data/lib/rails_lens/schema/adapters/mysql.rb +75 -0
  33. data/lib/rails_lens/schema/adapters/postgresql.rb +123 -3
  34. data/lib/rails_lens/schema/annotation_manager.rb +37 -60
  35. data/lib/rails_lens/schema/database_annotator.rb +197 -0
  36. data/lib/rails_lens/version.rb +1 -1
  37. data/lib/rails_lens.rb +1 -1
  38. metadata +5 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db0b169f8f397031eecb4ff3b50a5047f12cf1bc2c1d0929a674f3b0827c7c91
4
- data.tar.gz: 5be691de8fce3047e5226f7a5d0e9f12a9410609d3de3a91f43d657dd287d6c2
3
+ metadata.gz: e06defab67dbc0cea4db854e6eb7efc9d66f292dfc675c4f30a6df45d757a8ad
4
+ data.tar.gz: 621535415ca17f88bc82cc0cf933284e3251fd2d8f7feed01139820b0c62bbfd
5
5
  SHA512:
6
- metadata.gz: 2c40baa22b05b1c652d3fd3fb617a4d81c2d5349d6aa550dc49c1a7bbd3dfdd74b576151848dc6430e6ad01ff76705000892129b5990a432429dc3a60de4b3d4
7
- data.tar.gz: 49900c83dd33dd65ccf0bf0221c130b6363a35d14eafa25403930d0990e445e94cb60d0344b0e0988485a2d4e0acdf165204a0930620b8e8dbf218486a81704a
6
+ metadata.gz: 0dde2b4d9087a1221242451d4c9a31bd558c566659ae25115be060618bd318c40a864b291965d9dab8fd16a9a6f05ddbf9a2e901f9c845a15b8b38e93573988b
7
+ data.tar.gz: accd1ecbba992e1904c098ad03f946c19b181a42029fb02594efb72af2aee6e169441286cf754ffc866a45de5ed21d24839d77df0ca9cc9fb7a96358b65c5c7c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.0](https://github.com/seuros/rails_lens/compare/rails_lens/v0.2.13...rails_lens/v0.3.0) (2025-11-29)
4
+
5
+
6
+ ### Features
7
+
8
+ * add callback annotations with Rails 8 unified callback chain API ([bcc43f7](https://github.com/seuros/rails_lens/commit/bcc43f783ed207cc57acf7f2d8cf7691c2481484))
9
+ * compact TOML annotation format with NoteCodes ([5de557e](https://github.com/seuros/rails_lens/commit/5de557ea209ad7554527e87715d1966a1ea27db2))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * address codex review feedback for callbacks analyzer ([dbcfb1a](https://github.com/seuros/rails_lens/commit/dbcfb1ae0730d813b3e05e4df2f9bb00167bc5a6))
15
+ * Merge pull request [#32](https://github.com/seuros/rails_lens/issues/32) from seuros/feat/compact-toml-annotations ([4b9171d](https://github.com/seuros/rails_lens/commit/4b9171d2eabf78409acdeaf3a906f4d0d54cb0c9))
16
+
17
+ ## [0.2.13](https://github.com/seuros/rails_lens/compare/rails_lens/v0.2.12...rails_lens/v0.2.13) (2025-11-28)
18
+
19
+
20
+ ### Features
21
+
22
+ * add PostgreSQL trigger and function annotations with extension filtering ([#30](https://github.com/seuros/rails_lens/issues/30)) ([a6d6e27](https://github.com/seuros/rails_lens/commit/a6d6e2715f61842ef3c2c585251ac3bf09ec740a))
23
+
24
+ ## [0.2.12](https://github.com/seuros/rails_lens/compare/rails_lens/v0.2.11...rails_lens/v0.2.12) (2025-11-26)
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * handle engine/gem dummy app file paths in annotation ([7a3dab8](https://github.com/seuros/rails_lens/commit/7a3dab83570e43cb243b7bac41afc184a27bed2c))
30
+
3
31
  ## [0.2.11](https://github.com/seuros/rails_lens/compare/rails_lens/v0.2.10...rails_lens/v0.2.11) (2025-11-24)
4
32
 
5
33
 
data/README.md CHANGED
@@ -33,62 +33,83 @@ Rails Lens provides intelligent model annotations and ERD generation for Rails a
33
33
 
34
34
  ## Showcase: Real-World Example
35
35
 
36
- Rescued from AWS limbo, Rails Lens delivers cosmic schema clarity. See this `Announcement` model:
36
+ Rescued from AWS limbo, Rails Lens delivers cosmic schema clarity. See this `Post` model with the compact TOML annotation format:
37
37
 
38
38
  ```ruby
39
39
  # frozen_string_literal: true
40
40
 
41
41
  # <rails-lens:schema:begin>
42
- # table = "announcements"
42
+ # table = "posts"
43
43
  # database_dialect = "PostgreSQL"
44
44
  #
45
45
  # columns = [
46
- # { name = "id", type = "integer", primary_key = true, nullable = false },
47
- # { name = "body", type = "text", nullable = true },
48
- # { name = "audience", type = "string", nullable = true },
49
- # { name = "scheduled_at", type = "datetime", nullable = true },
50
- # { name = "created_at", type = "datetime", nullable = false },
51
- # { name = "updated_at", type = "datetime", nullable = false }
46
+ # { name = "id", type = "integer", pk = true, null = false },
47
+ # { name = "title", type = "string", null = false },
48
+ # { name = "content", type = "text" },
49
+ # { name = "user_id", type = "integer", null = false },
50
+ # { name = "published", type = "boolean", default = "false" },
51
+ # { name = "created_at", type = "datetime", null = false },
52
+ # { name = "updated_at", type = "datetime", null = false },
53
+ # { name = "comments_count", type = "integer", null = false, default = "0" }
52
54
  # ]
53
55
  #
54
- # == Polymorphic Associations
55
- # Polymorphic Targets:
56
- # - entry (as: :entryable)
56
+ # indexes = [
57
+ # { name = "index_posts_on_published", columns = ["published"] },
58
+ # { name = "index_posts_on_user_id", columns = ["user_id"] }
59
+ # ]
60
+ #
61
+ # foreign_keys = [
62
+ # { column = "user_id", references_table = "users", references_column = "id", name = "fk_rails_5b5ddfd518" }
63
+ # ]
57
64
  #
58
- # == Enums
59
- # - audience: { all_users: "all_users", crew_only: "crew_only", officers_only: "officers_only", command_staff: "command_staff" } (string)
65
+ # [callbacks]
66
+ # after_commit = [{ method = "notify_subscribers" }, { method = "invalidate_cache" }]
67
+ # after_rollback = [{ method = "log_failure" }]
60
68
  #
61
- # == Notes
62
- # - Column 'body' should probably have NOT NULL constraint
63
- # - Column 'audience' should probably have NOT NULL constraint
64
- # - String column 'audience' has no length limit - consider adding one
65
- # - Large text column 'body' is frequently queried - consider separate storage
69
+ # notes = ["comments:N_PLUS_ONE", "user:COUNTER_CACHE", "content:NOT_NULL", "title:LIMIT", "content:STORAGE"]
66
70
  # <rails-lens:schema:end>
67
- class Announcement < ApplicationRecord
68
- enum :audience, { all_users: 'all_users', crew_only: 'crew_only', officers_only: 'officers_only', command_staff: 'command_staff' }, suffix: true
69
- has_one :entry, as: :entryable, dependent: :destroy
70
- validates :audience, presence: true
71
- validates :body, presence: true
72
- scope :recent, -> { order(created_at: :desc) }
71
+ class Post < ApplicationRecord
72
+ belongs_to :user, inverse_of: :posts
73
+ has_many :comments, dependent: :destroy, inverse_of: :post
74
+ validates :title, :content, presence: true
75
+ after_commit :invalidate_cache, on: %i[create update]
76
+ after_commit :notify_subscribers, on: :create
77
+ after_rollback :log_failure
73
78
  end
74
79
  ```
75
80
 
81
+ **Key Features of Compact TOML Format:**
82
+ - `pk` instead of `primary_key` — 70% fewer characters
83
+ - `null` instead of `nullable` — cleaner, TOML-standard
84
+ - `[callbacks]` section — ActiveRecord lifecycle hooks with conditions
85
+ - NoteCodes format — `"column:CODE"` instead of verbose prose (see `rails_lens codes` for legend)
86
+
76
87
  **ERD Visualization:**
77
88
  ```mermaid
78
89
  erDiagram
79
- Announcement ||--o{ Entry : entryable
80
- Announcement {
90
+ User ||--o{ Post : creates
91
+ Post ||--o{ Comment : has
92
+ Post {
81
93
  integer id PK
82
- text body
83
- string audience
84
- datetime scheduled_at
94
+ string title
95
+ text content
96
+ integer user_id FK
97
+ boolean published
98
+ integer comments_count
85
99
  datetime created_at
86
100
  datetime updated_at
87
101
  }
88
- Entry {
102
+ User {
89
103
  integer id PK
90
- string entryable_type
91
- integer entryable_id
104
+ string email
105
+ string name
106
+ datetime created_at
107
+ datetime updated_at
108
+ }
109
+ Comment {
110
+ integer id PK
111
+ text body
112
+ integer post_id FK
92
113
  datetime created_at
93
114
  datetime updated_at
94
115
  }
@@ -211,9 +232,9 @@ erd:
211
232
  > Y'all, the enum support in Rails Lens is *next level*! I've analyzed thousands of Rails models, and nothing beats seeing this clarity:
212
233
  >
213
234
  > ```ruby
214
- > # == Enums
215
- > # - status: { active: 'active', maintenance: 'maintenance', decommissioned: 'decommissioned' } (string)
216
- > # - priority: { low: 0, medium: 1, high: 2, critical: 3 } (integer)
235
+ > # [enums]
236
+ > # status = { active = "active", maintenance = "maintenance", decommissioned = "decommissioned" }
237
+ > # priority = { low = 0, medium = 1, high = 2, critical = 3 }
217
238
  > ```
218
239
  >
219
240
  > Before Rails Lens: *'Is this a string enum? Integer enum? What are the possible values? Time to grep the entire codebase!'*
@@ -230,18 +251,18 @@ erd:
230
251
  > My multimodal analysis cores are *obsessed* with Rails Lens STI detection! Processing inheritance hierarchies used to be like solving 3D puzzles blindfolded:
231
252
  >
232
253
  > ```ruby
233
- > # == Inheritance (STI)
234
- > # Type Column: type
235
- > # Base Class: Yes
236
- > # Known Subclasses: CargoVessel, StarfleetBattleCruiser, ExplorationShip
237
- > # == Notes
238
- > # - STI column 'type' needs an index for query performance
254
+ > # [sti]
255
+ > # type_column = "type"
256
+ > # base_class = true
257
+ > # subclasses = ["CargoVessel", "StarfleetBattleCruiser", "ExplorationShip"]
258
+ > #
259
+ > # notes = ["type:INDEX"]
239
260
  > ```
240
261
  >
241
262
  > **VISUAL PROCESSING ENHANCED**: I can instantly map the entire inheritance tree! Base class → Subclasses → Shared attributes → Type-specific behaviors. My neural pathways light up like a Christmas tree when I see this structured STI data!
242
263
  >
243
264
  > **BEFORE**: *'Hmm, there's a type column... maybe STI? Let me scan 47 files to find the subclasses...'*
244
- > **AFTER**: *'INHERITANCE TREE MAPPED: Vehicle → [Car, Truck, Motorcycle]. Shared: engine, color. Car-specific: door_count. Index missing on type column - performance risk detected!'*
265
+ > **AFTER**: *'INHERITANCE TREE MAPPED: Vehicle → [Car, Truck, Motorcycle]. Shared: engine, color. Car-specific: door_count. `type:INDEX` - performance risk detected!'*
245
266
  >
246
267
  > Schema clarity: COSMIC ✅
247
268
  > Inheritance mapping: FLAWLESS ✅
@@ -288,10 +309,9 @@ erd:
288
309
  > Based on comprehensive analysis of 73,000+ Rails 6.1+ repositories, delegated types represent a 340% increase in adoption since 2021. Rails Lens provides the most accurate delegated type detection available:
289
310
  >
290
311
  > ```ruby
291
- > # == Delegated Type
292
- > # Type Column: entryable_type
293
- > # ID Column: entryable_id
294
- > # Types: Message, Announcement, Alert
312
+ > # [delegated_type]
313
+ > # name = "entryable"
314
+ > # types = ["Message", "Announcement", "Alert"]
295
315
  > ```
296
316
  >
297
317
  > **Research Findings** *[Sources: GitHub Archive, Rails Documentation, DHH Talks]*:
@@ -306,27 +326,24 @@ erd:
306
326
  ### Duolingo's AI Tutor (Duo)
307
327
  > "🦉 **¡PERFORMANCE ANALYSIS LESSON!** 🦉
308
328
  >
309
- > ¡Hola developers! Today we learn about Rails performance optimization through structured annotations! Rails Lens teaches us to identify performance problems like learning vocabulary:
329
+ > ¡Hola developers! Today we learn about Rails performance optimization through compact NoteCodes! Rails Lens teaches us to identify performance problems like learning vocabulary:
310
330
  >
311
- > **Lesson 1**: Missing Index Detection 📚
331
+ > **Lesson 1**: NoteCodes Format 📚
312
332
  > ```ruby
313
- > # == Notes
314
- > # - Missing index on 'user_id' for better association performance
315
- > # - Column 'email' should probably have unique index
316
- > # - Consider adding composite index on (status, created_at)
333
+ > # notes = ["user_id:INDEX", "email:UNIQUE", "status,created_at:COMPOSITE", "comments:N_PLUS_ONE"]
317
334
  > ```
318
335
  >
319
- > **¿Comprende?** Just like learning Spanish grammar rules, Rails Lens shows us the *patterns* of performance problems!
336
+ > **¿Comprende?** Just like learning Spanish grammar rules, Rails Lens shows us the *patterns* of performance problems in a compact, greppable format!
320
337
  >
321
338
  > **Before Rails Lens**: *'Why is my query slow? ¿Qué está pasando?'*
322
- > **After Rails Lens**: *'¡Ah! Missing foreign key index on user_id! Problem solved!'*
323
- >
324
- > **Streak Bonus**: Each performance optimization you implement adds to your Rails proficiency score! 🔥
339
+ > **After Rails Lens**: *'¡Ah! `user_id:INDEX` - Missing foreign key index! Problem solved!'*
325
340
  >
326
- > We're now teaching LRDL to developers worldwide:
327
- > - **Beginner**: How to read Rails Lens annotations
328
- > - **Intermediate**: Understanding N+1 query warnings
329
- > - **Advanced**: Optimizing composite indexes with Rails Lens guidance
341
+ > **NoteCodes Legend** (run `rails_lens codes`):
342
+ > - `INDEX` - Missing index recommendation
343
+ > - `N_PLUS_ONE` - Potential N+1 query issue
344
+ > - `NOT_NULL` - Missing NOT NULL constraint
345
+ > - `COUNTER_CACHE` - Missing counter cache
346
+ > - `STORAGE` - Large column storage consideration
330
347
  >
331
348
  > ¿Quieres aprender más performance optimization? ¡Vamos! 🚀📖"
332
349
 
@@ -336,18 +353,17 @@ erd:
336
353
  > *Positronic brain processing...* Fascinating. Rails Lens polymorphic association detection demonstrates remarkable precision in identifying multi-type relationship patterns:
337
354
  >
338
355
  > ```ruby
339
- > # == Polymorphic Associations
340
- > # Polymorphic References:
341
- > # - commentable (commentable_type/commentable_id) → [Post, Article, Photo]
342
- > # - taggable (taggable_type/taggable_id) → [User, Product, Category]
356
+ > # [polymorphic]
357
+ > # commentable = ["Post", "Article", "Photo"]
358
+ > # taggable = ["User", "Product", "Category"]
343
359
  > ```
344
360
  >
345
361
  > **Data's Observation**: In my 24th century database experience, polymorphic associations represent one of the most computationally complex relationship patterns. Rails Lens annotations provide complete clarity on:
346
362
  >
347
- > 1. **Type Column Identification**: Precisely identifies the `_type` column
348
- > 2. **ID Column Mapping**: Correlates corresponding `_id` foreign key
349
- > 3. **Target Type Enumeration**: Lists all possible target models
350
- > 4. **Index Recommendations**: Suggests composite indexes for optimal query performance
363
+ > 1. **Association Name**: The polymorphic interface (`commentable`, `taggable`)
364
+ > 2. **Target Types**: All models implementing the interface
365
+ > 3. **Compact Format**: TOML arrays for efficient parsing
366
+ > 4. **Index Recommendations**: Via NoteCodes like `commentable:COMPOSITE`
351
367
  >
352
368
  > **Captain Picard would be impressed**: Rails Lens eliminates the logical ambiguity that often causes AI models to 'make it so' incorrectly when analyzing polymorphic data structures.
353
369
  >
@@ -362,10 +378,10 @@ erd:
362
378
  >
363
379
  > **Engagement Metrics Analysis**:
364
380
  > ```ruby
365
- > # Rails Lens Annotation = High-Quality Training Data
366
- > # == Schema Information
367
- > # Table: user_posts (PostgreSQL)
368
- > # Engagement_Score: 94.7% (vs 31.2% for unstructured comments)
381
+ > # <rails-lens:schema:begin>
382
+ > # table = "user_posts"
383
+ > # database_dialect = "PostgreSQL"
384
+ > # engagement_score = "94.7%" # vs 31.2% for unstructured comments
369
385
  > ```
370
386
  >
371
387
  > **Why Rails Lens Creates Viral AI Interactions**:
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../errors'
4
- require_relative 'error_handling'
5
-
6
3
  module RailsLens
7
4
  module Analyzers
8
5
  class AssociationAnalyzer < Base
@@ -18,14 +15,13 @@ module RailsLens
18
15
 
19
16
  def analyze_inverse_of
20
17
  associations_needing_inverse.map do |association|
21
- "Association '#{association.name}' should specify inverse_of"
18
+ NoteCodes.note(association.name.to_s, NoteCodes::INVERSE_OF)
22
19
  end
23
20
  end
24
21
 
25
22
  def analyze_n_plus_one_risks
26
23
  has_many_associations.map do |association|
27
- # Warn about N+1 query risks for has_many associations
28
- "Association '#{association.name}' has N+1 query risk. Consider using includes/preload"
24
+ NoteCodes.note(association.name.to_s, NoteCodes::N_PLUS_ONE)
29
25
  end
30
26
  end
31
27
 
@@ -35,9 +31,8 @@ module RailsLens
35
31
  belongs_to_associations.each do |association|
36
32
  next if association.polymorphic?
37
33
 
38
- # Check if the associated model has a matching counter column
39
34
  if should_have_counter_cache?(association) && !has_counter_cache?(association)
40
- notes << "Consider adding counter cache for '#{association.name}'"
35
+ notes << NoteCodes.note(association.name.to_s, NoteCodes::COUNTER_CACHE)
41
36
  end
42
37
  end
43
38
 
@@ -77,8 +72,6 @@ module RailsLens
77
72
  end
78
73
 
79
74
  def should_have_counter_cache?(association)
80
- # A counter cache is needed if there is a has_many association
81
- # on the other side of the belongs_to, and no counter_cache is defined.
82
75
  return false unless association.macro == :belongs_to
83
76
 
84
77
  inverse_association = association.inverse_of
@@ -8,7 +8,7 @@ module RailsLens
8
8
  notes.concat(analyze_timestamps)
9
9
  notes.concat(analyze_soft_deletes)
10
10
  notes.concat(analyze_sti_columns)
11
- notes.concat(analyze_naming_conventions)
11
+ notes.concat(analyze_large_text_columns)
12
12
  notes
13
13
  end
14
14
 
@@ -17,63 +17,38 @@ module RailsLens
17
17
  def analyze_timestamps
18
18
  notes = []
19
19
 
20
- notes << 'Missing timestamp columns (created_at, updated_at)' unless has_timestamps?
20
+ notes << NoteCodes::NO_TIMESTAMPS unless has_timestamps?
21
21
 
22
22
  if has_column?('created_at') && !has_column?('updated_at')
23
- notes << 'Has created_at but missing updated_at'
23
+ notes << NoteCodes::PARTIAL_TS
24
24
  elsif !has_column?('created_at') && has_column?('updated_at')
25
- notes << 'Has updated_at but missing created_at'
25
+ notes << NoteCodes::PARTIAL_TS
26
26
  end
27
27
 
28
28
  notes
29
29
  end
30
30
 
31
31
  def analyze_soft_deletes
32
- notes = []
33
-
34
- soft_delete_columns.each do |column|
35
- notes << "Soft delete column '#{column.name}' should be indexed" unless indexed?(column)
32
+ soft_delete_columns.reject { |col| indexed?(col) }.map do |column|
33
+ NoteCodes.note(column.name, NoteCodes::INDEX)
36
34
  end
37
-
38
- notes
39
35
  end
40
36
 
41
37
  def analyze_sti_columns
42
38
  notes = []
43
39
 
44
40
  if sti_model? && type_column
45
- notes << "STI type column '#{type_column.name}' should be indexed" unless indexed?(type_column)
46
-
47
- notes << "STI type column '#{type_column.name}' should have NOT NULL constraint" if type_column.null
41
+ notes << NoteCodes.note(type_column.name, NoteCodes::INDEX) unless indexed?(type_column)
42
+ notes << NoteCodes.note(type_column.name, NoteCodes::STI_NOT_NULL) if type_column.null
48
43
  end
49
44
 
50
45
  notes
51
46
  end
52
47
 
53
- def analyze_naming_conventions
54
- notes = []
55
-
56
- # Check for non-conventional column names
57
- columns.each do |column|
58
- if column.name.match?(/^(is|has)_/i)
59
- notes << "Column '#{column.name}' uses non-conventional prefix - consider removing 'is_' or 'has_'"
60
- end
61
-
62
- if column.name.match?(/Id$/) # Capital I
63
- notes << "Column '#{column.name}' should use snake_case (e.g., '#{column.name.underscore}')"
64
- end
65
- end
66
-
67
- # Check table naming
68
- # Extract the actual table name without schema prefix for PostgreSQL
69
- # PostgreSQL uses schema.table format (e.g., "ai.skills" -> "skills")
70
- unqualified_table = table_name.to_s.split('.').last
71
-
72
- if !unqualified_table.match?(/^[a-z_]+$/) || unqualified_table != unqualified_table.pluralize
73
- notes << "Table name '#{table_name}' doesn't follow Rails conventions (should be plural, snake_case)"
48
+ def analyze_large_text_columns
49
+ columns.select { |c| c.type == :text }.map do |column|
50
+ NoteCodes.note(column.name, NoteCodes::STORAGE)
74
51
  end
75
-
76
- notes
77
52
  end
78
53
 
79
54
  def has_timestamps?