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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/README.md +88 -72
- data/lib/rails_lens/analyzers/association_analyzer.rb +3 -10
- data/lib/rails_lens/analyzers/best_practices_analyzer.rb +11 -36
- data/lib/rails_lens/analyzers/callbacks.rb +302 -0
- data/lib/rails_lens/analyzers/column_analyzer.rb +6 -6
- data/lib/rails_lens/analyzers/composite_keys.rb +2 -5
- data/lib/rails_lens/analyzers/database_constraints.rb +4 -6
- data/lib/rails_lens/analyzers/delegated_types.rb +4 -7
- data/lib/rails_lens/analyzers/enums.rb +5 -11
- data/lib/rails_lens/analyzers/foreign_key_analyzer.rb +2 -2
- data/lib/rails_lens/analyzers/generated_columns.rb +4 -6
- data/lib/rails_lens/analyzers/index_analyzer.rb +4 -10
- data/lib/rails_lens/analyzers/inheritance.rb +30 -31
- data/lib/rails_lens/analyzers/notes.rb +29 -39
- data/lib/rails_lens/analyzers/performance_analyzer.rb +3 -26
- data/lib/rails_lens/annotation_pipeline.rb +1 -0
- data/lib/rails_lens/cli.rb +1 -0
- data/lib/rails_lens/commands.rb +23 -1
- data/lib/rails_lens/configuration.rb +4 -1
- data/lib/rails_lens/erd/visualizer.rb +0 -1
- data/lib/rails_lens/extensions/closure_tree_ext.rb +11 -11
- data/lib/rails_lens/mailer/annotator.rb +3 -3
- data/lib/rails_lens/model_detector.rb +49 -3
- data/lib/rails_lens/note_codes.rb +59 -0
- data/lib/rails_lens/providers/callbacks_provider.rb +24 -0
- data/lib/rails_lens/providers/extensions_provider.rb +1 -1
- data/lib/rails_lens/providers/view_provider.rb +6 -20
- data/lib/rails_lens/schema/adapters/base.rb +39 -2
- data/lib/rails_lens/schema/adapters/database_info.rb +11 -17
- data/lib/rails_lens/schema/adapters/mysql.rb +75 -0
- data/lib/rails_lens/schema/adapters/postgresql.rb +123 -3
- data/lib/rails_lens/schema/annotation_manager.rb +37 -60
- data/lib/rails_lens/schema/database_annotator.rb +197 -0
- data/lib/rails_lens/version.rb +1 -1
- data/lib/rails_lens.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e06defab67dbc0cea4db854e6eb7efc9d66f292dfc675c4f30a6df45d757a8ad
|
|
4
|
+
data.tar.gz: 621535415ca17f88bc82cc0cf933284e3251fd2d8f7feed01139820b0c62bbfd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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 `
|
|
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 = "
|
|
42
|
+
# table = "posts"
|
|
43
43
|
# database_dialect = "PostgreSQL"
|
|
44
44
|
#
|
|
45
45
|
# columns = [
|
|
46
|
-
# { name = "id", type = "integer",
|
|
47
|
-
# { name = "
|
|
48
|
-
# { name = "
|
|
49
|
-
# { name = "
|
|
50
|
-
# { name = "
|
|
51
|
-
# { name = "
|
|
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
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
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
|
-
#
|
|
59
|
-
#
|
|
65
|
+
# [callbacks]
|
|
66
|
+
# after_commit = [{ method = "notify_subscribers" }, { method = "invalidate_cache" }]
|
|
67
|
+
# after_rollback = [{ method = "log_failure" }]
|
|
60
68
|
#
|
|
61
|
-
#
|
|
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
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
validates :
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
80
|
-
|
|
90
|
+
User ||--o{ Post : creates
|
|
91
|
+
Post ||--o{ Comment : has
|
|
92
|
+
Post {
|
|
81
93
|
integer id PK
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
102
|
+
User {
|
|
89
103
|
integer id PK
|
|
90
|
-
string
|
|
91
|
-
|
|
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
|
-
> #
|
|
215
|
-
> #
|
|
216
|
-
> #
|
|
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
|
-
> #
|
|
234
|
-
> #
|
|
235
|
-
> #
|
|
236
|
-
> #
|
|
237
|
-
> #
|
|
238
|
-
> #
|
|
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.
|
|
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
|
-
> #
|
|
292
|
-
> #
|
|
293
|
-
> #
|
|
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
|
|
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**:
|
|
331
|
+
> **Lesson 1**: NoteCodes Format 📚
|
|
312
332
|
> ```ruby
|
|
313
|
-
> #
|
|
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
|
|
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
|
-
>
|
|
327
|
-
> -
|
|
328
|
-
> -
|
|
329
|
-
> -
|
|
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
|
-
> #
|
|
340
|
-
> #
|
|
341
|
-
> #
|
|
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. **
|
|
348
|
-
> 2. **
|
|
349
|
-
> 3. **
|
|
350
|
-
> 4. **Index Recommendations**:
|
|
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
|
-
> #
|
|
366
|
-
> #
|
|
367
|
-
> #
|
|
368
|
-
> #
|
|
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
|
-
|
|
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
|
-
|
|
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 <<
|
|
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(
|
|
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 <<
|
|
20
|
+
notes << NoteCodes::NO_TIMESTAMPS unless has_timestamps?
|
|
21
21
|
|
|
22
22
|
if has_column?('created_at') && !has_column?('updated_at')
|
|
23
|
-
notes <<
|
|
23
|
+
notes << NoteCodes::PARTIAL_TS
|
|
24
24
|
elsif !has_column?('created_at') && has_column?('updated_at')
|
|
25
|
-
notes <<
|
|
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
|
-
|
|
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 <<
|
|
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
|
|
54
|
-
|
|
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?
|