annotaterb 4.23.0 → 4.24.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 +59 -3
- data/README.md +116 -0
- data/VERSION +1 -1
- data/lib/annotate_rb/model_annotator/annotation/annotation_builder.rb +8 -1
- data/lib/annotate_rb/model_annotator/exclusion_constraint_annotation/annotation.rb +40 -0
- data/lib/annotate_rb/model_annotator/exclusion_constraint_annotation/annotation_builder.rb +38 -0
- data/lib/annotate_rb/model_annotator/exclusion_constraint_annotation/exclusion_constraint_component.rb +27 -0
- data/lib/annotate_rb/model_annotator/exclusion_constraint_annotation.rb +11 -0
- data/lib/annotate_rb/model_annotator/file_parser/annotation_finder.rb +38 -2
- data/lib/annotate_rb/model_annotator/file_parser/yml_parser.rb +43 -4
- data/lib/annotate_rb/model_annotator/foreign_key_annotation/foreign_key_component_builder.rb +6 -0
- data/lib/annotate_rb/model_annotator/index_annotation/annotation_builder.rb +29 -0
- data/lib/annotate_rb/model_annotator/model_wrapper.rb +33 -1
- data/lib/annotate_rb/model_annotator/single_file_annotation_remover.rb +1 -1
- data/lib/annotate_rb/model_annotator/single_file_annotator.rb +1 -1
- data/lib/annotate_rb/model_annotator/unique_constraint_annotation/annotation.rb +40 -0
- data/lib/annotate_rb/model_annotator/unique_constraint_annotation/annotation_builder.rb +37 -0
- data/lib/annotate_rb/model_annotator/unique_constraint_annotation/unique_constraint_component.rb +27 -0
- data/lib/annotate_rb/model_annotator/unique_constraint_annotation.rb +11 -0
- data/lib/annotate_rb/model_annotator.rb +2 -0
- data/lib/annotate_rb/options.rb +6 -0
- data/lib/annotate_rb/parser.rb +16 -1
- data/lib/annotate_rb/runner.rb +0 -2
- metadata +9 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff11e0177eddc61744806ec5749c7a5d234023e0e7d75d46bd5fc21e4d0998fc
|
|
4
|
+
data.tar.gz: f8c87d260bf6cafbeb120568ecda6131f6bd335ef2c3882630a45cc2e6631a05
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6e2edbfc22db4f8b1bd150313e795993e3f5366ac4594084fec2f7ee9f1d2650d98cef0933bdc92a0ff0a4e52af4bb77b35672cbd0049fed9c8e6c256743e00e
|
|
7
|
+
data.tar.gz: ddf3161a49b9c041083ce42c9264823da16e23703a8f013b98098f24dc4f7d46642a659621f0d0612572865fec1099a91e7622139acc3a1c689e7df1d96e81bf
|
data/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,67 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v4.23.0](https://github.com/drwl/annotaterb/tree/v4.23.0) (2026-06-25)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/drwl/annotaterb/compare/v4.22.0...v4.23.0)
|
|
6
|
+
|
|
7
|
+
**Implemented enhancements:**
|
|
8
|
+
|
|
9
|
+
- \[Request\] Support for multiple serializers for one model [\#329](https://github.com/drwl/annotaterb/issues/329)
|
|
10
|
+
- Support COMMENT on an INDEX [\#258](https://github.com/drwl/annotaterb/issues/258)
|
|
11
|
+
|
|
12
|
+
**Fixed bugs:**
|
|
13
|
+
|
|
14
|
+
- Re-running annotaterb strips indentation from nested \(indented\) schema annotations [\#332](https://github.com/drwl/annotaterb/issues/332)
|
|
15
|
+
- Setting all sort options to `false` sometimes doesn't respect migration/DB order [\#237](https://github.com/drwl/annotaterb/issues/237)
|
|
16
|
+
|
|
17
|
+
**Closed issues:**
|
|
18
|
+
|
|
19
|
+
- mistake post please delete this [\#314](https://github.com/drwl/annotaterb/issues/314)
|
|
20
|
+
- Removal of final empty comment line after foreign keys results in duplicate `fk_rails_...` line [\#297](https://github.com/drwl/annotaterb/issues/297)
|
|
21
|
+
- Default settings does not indent correctly inside a module [\#271](https://github.com/drwl/annotaterb/issues/271)
|
|
22
|
+
- Top does not do what I think it should? And annotator fails to indent. [\#202](https://github.com/drwl/annotaterb/issues/202)
|
|
23
|
+
- annotaterb is moving my class doc [\#201](https://github.com/drwl/annotaterb/issues/201)
|
|
24
|
+
|
|
25
|
+
**Merged pull requests:**
|
|
26
|
+
|
|
27
|
+
- Bump version to v4.23.0 [\#347](https://github.com/drwl/annotaterb/pull/347) ([drwl](https://github.com/drwl))
|
|
28
|
+
- Bump actions/checkout from 6 to 7 [\#346](https://github.com/drwl/annotaterb/pull/346) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
29
|
+
- Fix duplicate annotations when a file ends with a trailing blank line [\#342](https://github.com/drwl/annotaterb/pull/342) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
30
|
+
- Fix update\_config for non-default config locations [\#341](https://github.com/drwl/annotaterb/pull/341) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
31
|
+
- Fix NameError in ZeitwerkClassGetter for collapsed Zeitwerk paths [\#339](https://github.com/drwl/annotaterb/pull/339) ([KaiyuanMa](https://github.com/KaiyuanMa))
|
|
32
|
+
- Fix annotation inserted inside module when doc comment is present [\#338](https://github.com/drwl/annotaterb/pull/338) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
33
|
+
- Add `position_in_class: after_doc` to keep class doc adjacent to class [\#337](https://github.com/drwl/annotaterb/pull/337) ([yamat47](https://github.com/yamat47))
|
|
34
|
+
- Fix annotation placement above inner class declarations under `nested_position` [\#336](https://github.com/drwl/annotaterb/pull/336) ([yamat47](https://github.com/yamat47))
|
|
35
|
+
- Drop Ruby \< 3.3 from CI matrix [\#335](https://github.com/drwl/annotaterb/pull/335) ([drwl](https://github.com/drwl))
|
|
36
|
+
- Fix annotation placement in nested files and around trailing user comments [\#334](https://github.com/drwl/annotaterb/pull/334) ([yamat47](https://github.com/yamat47))
|
|
37
|
+
- Preserve indentation when re-running annotaterb on nested-position annotations. [\#333](https://github.com/drwl/annotaterb/pull/333) ([yamat47](https://github.com/yamat47))
|
|
38
|
+
- Respect `--config-path` during config loading [\#331](https://github.com/drwl/annotaterb/pull/331) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
39
|
+
- Fall back to current task when no top-level task is set [\#328](https://github.com/drwl/annotaterb/pull/328) ([jordan-brough](https://github.com/jordan-brough))
|
|
40
|
+
- Fix --show-migration option not working on Rails 7.2+. [\#327](https://github.com/drwl/annotaterb/pull/327) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
41
|
+
- Exit with non-zero code when database is not accessible [\#326](https://github.com/drwl/annotaterb/pull/326) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
42
|
+
- fix potential ReDoS in route annotator regex [\#325](https://github.com/drwl/annotaterb/pull/325) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
43
|
+
- Support opt-in display of PostgreSQL enum types in annotations [\#324](https://github.com/drwl/annotaterb/pull/324) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
44
|
+
- Fix error when column comments contain `%` [\#322](https://github.com/drwl/annotaterb/pull/322) ([willnet](https://github.com/willnet))
|
|
45
|
+
- Add unit tests for AnnotateRb::Helper [\#321](https://github.com/drwl/annotaterb/pull/321) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
46
|
+
- Migrate issue templates to folder-based format [\#320](https://github.com/drwl/annotaterb/pull/320) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
47
|
+
- Add opt-in show\_indexes\_comments option to display index comments [\#319](https://github.com/drwl/annotaterb/pull/319) ([olleolleolle](https://github.com/olleolleolle))
|
|
48
|
+
- Only connect SecondaryRecord to secondary DB when MULTI\_DB\_TEST is set [\#318](https://github.com/drwl/annotaterb/pull/318) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
49
|
+
- Correct secondary database setup in dummy app [\#317](https://github.com/drwl/annotaterb/pull/317) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
50
|
+
- Remove duplicate ignore\_unknown\_models option definition [\#316](https://github.com/drwl/annotaterb/pull/316) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
51
|
+
- Fix column annotation alignment for CJK and fullwidth characters [\#315](https://github.com/drwl/annotaterb/pull/315) ([SergeyGildenshtern](https://github.com/SergeyGildenshtern))
|
|
52
|
+
- Added command example for applying annotations to README [\#313](https://github.com/drwl/annotaterb/pull/313) ([zackerms](https://github.com/zackerms))
|
|
53
|
+
- Generate changelog for v4.22.0 [\#311](https://github.com/drwl/annotaterb/pull/311) ([drwl](https://github.com/drwl))
|
|
54
|
+
- Add opt-in support for automatically annotating routes after migration tasks [\#293](https://github.com/drwl/annotaterb/pull/293) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
55
|
+
|
|
3
56
|
## [v4.22.0](https://github.com/drwl/annotaterb/tree/v4.22.0) (2026-02-12)
|
|
4
57
|
|
|
5
58
|
[Full Changelog](https://github.com/drwl/annotaterb/compare/v4.21.0...v4.22.0)
|
|
6
59
|
|
|
60
|
+
**Implemented enhancements:**
|
|
61
|
+
|
|
62
|
+
- Feature: ruby-lsp addon [\#175](https://github.com/drwl/annotaterb/issues/175)
|
|
63
|
+
- Mounting ActionCable leads to weird annotation [\#161](https://github.com/drwl/annotaterb/issues/161)
|
|
64
|
+
|
|
7
65
|
**Fixed bugs:**
|
|
8
66
|
|
|
9
67
|
- Yardoc formatting for comments on database attributes [\#162](https://github.com/drwl/annotaterb/issues/162)
|
|
@@ -13,8 +71,6 @@
|
|
|
13
71
|
- New `ignore_multi_database_name` option seems to be non-functional [\#303](https://github.com/drwl/annotaterb/issues/303)
|
|
14
72
|
- Changing sort options does not change annotations [\#294](https://github.com/drwl/annotaterb/issues/294)
|
|
15
73
|
- CLI script for annotaterb not installed or runnable [\#290](https://github.com/drwl/annotaterb/issues/290)
|
|
16
|
-
- Feature: ruby-lsp addon [\#175](https://github.com/drwl/annotaterb/issues/175)
|
|
17
|
-
- Mounting ActionCable leads to weird annotation [\#161](https://github.com/drwl/annotaterb/issues/161)
|
|
18
74
|
|
|
19
75
|
**Merged pull requests:**
|
|
20
76
|
|
|
@@ -22,7 +78,7 @@
|
|
|
22
78
|
- Run CI on CRuby 4.0 [\#308](https://github.com/drwl/annotaterb/pull/308) ([viralpraxis](https://github.com/viralpraxis))
|
|
23
79
|
- Generate changelog for v4.21.0 [\#307](https://github.com/drwl/annotaterb/pull/307) ([drwl](https://github.com/drwl))
|
|
24
80
|
- fix NoMethodError when using nested\_position with fixture files [\#298](https://github.com/drwl/annotaterb/pull/298) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
25
|
-
- fix: Respect configured sort [\#295](https://github.com/drwl/annotaterb/pull/295) ([patrickarnett](https://github.com/patrickarnett))
|
|
81
|
+
- fix: Respect configured sort [\#295](https://github.com/drwl/annotaterb/pull/295) ([patrickarnett](https://github.com/patrickarnett))
|
|
26
82
|
- Use `#lease_connection` if available [\#292](https://github.com/drwl/annotaterb/pull/292) ([viralpraxis](https://github.com/viralpraxis))
|
|
27
83
|
- refactor: simplify primary key check logic \(no functional changes\) [\#285](https://github.com/drwl/annotaterb/pull/285) ([OdenTakashi](https://github.com/OdenTakashi))
|
|
28
84
|
- Honor skip\_on\_db\_migrate config option when runnig migrate tasks [\#274](https://github.com/drwl/annotaterb/pull/274) ([martinechtner](https://github.com/martinechtner))
|
data/README.md
CHANGED
|
@@ -237,6 +237,122 @@ Annotaterb reads first the configuration file, if it exists, passes its content
|
|
|
237
237
|
|
|
238
238
|
For further details visit the [section in the migration guide](MIGRATION_GUIDE.md#automatic-annotations-after-running-database-migration-commands).
|
|
239
239
|
|
|
240
|
+
### Configuration options
|
|
241
|
+
|
|
242
|
+
Keys use snake_case and match the gem defaults in `AnnotateRb::Options`. CLI flags override values from the config file.
|
|
243
|
+
|
|
244
|
+
#### Position
|
|
245
|
+
|
|
246
|
+
| Option | Default | Description |
|
|
247
|
+
| --- | --- | --- |
|
|
248
|
+
| `position` | `before` | Fallback position for all `position_in_*` options. One of `before`, `top`, `after`, `bottom`, `before_doc`. |
|
|
249
|
+
| `position_in_class` | `before` | Position in model files. `before_doc` keeps class documentation adjacent to the class. |
|
|
250
|
+
| `position_in_factory` | `before` | Position in FactoryBot factory files. |
|
|
251
|
+
| `position_in_fixture` | `before` | Position in fixture files. |
|
|
252
|
+
| `position_in_test` | `before` | Position in test/spec files. |
|
|
253
|
+
| `position_in_routes` | `before` | Position in `config/routes.rb`. |
|
|
254
|
+
| `position_in_serializer` | `before` | Position in serializer files. |
|
|
255
|
+
| `position_in_additional_file_patterns` | `before` | Position in files matched by `additional_file_patterns`. |
|
|
256
|
+
| `nested_position` | `false` | Place annotations directly above nested classes/modules instead of at the top of the file. |
|
|
257
|
+
|
|
258
|
+
#### Schema annotation content
|
|
259
|
+
|
|
260
|
+
| Option | Default | Description |
|
|
261
|
+
| --- | --- | --- |
|
|
262
|
+
| `show_foreign_keys` | `true` | List foreign key constraints. |
|
|
263
|
+
| `show_complete_foreign_keys` | `false` | Use complete foreign key names. |
|
|
264
|
+
| `show_indexes` | `true` | List table indexes. |
|
|
265
|
+
| `show_indexes_comments` | `false` | Include index comments. |
|
|
266
|
+
| `show_indexes_include` | `false` | Include `INCLUDE` columns on indexes. |
|
|
267
|
+
| `simple_indexes` | `false` | Concat related indexes onto each column line. |
|
|
268
|
+
| `show_check_constraints` | `false` | List check constraints. |
|
|
269
|
+
| `show_enums` | `false` | Show PostgreSQL enum types. |
|
|
270
|
+
| `show_virtual_columns` | `false` | Show virtual/generated columns. |
|
|
271
|
+
| `include_version` | `false` | Include the migration version number. |
|
|
272
|
+
| `with_comment` | `true` | Include database comments (fallback for column/table comment flags). |
|
|
273
|
+
| `with_column_comments` | `true` | Include column comments. |
|
|
274
|
+
| `with_table_comments` | `true` | Include table comments. |
|
|
275
|
+
| `position_of_column_comment` | `with_name` | Column comment placement: `with_name` or `rightmost_column`. |
|
|
276
|
+
| `hide_default_column_types` | `""` | Comma-separated column types that omit defaults (e.g. `json,jsonb,hstore`). |
|
|
277
|
+
| `hide_limit_column_types` | `""` | Comma-separated column types that omit limits (e.g. `integer,boolean,text`). |
|
|
278
|
+
| `ignore_columns` | `null` | Regex of column names to skip. |
|
|
279
|
+
| `ignore_database_name` | `false` | Omit the database name from annotations. |
|
|
280
|
+
| `ignore_multi_database_name` | `false` | Omit the database name in multi-database setups. |
|
|
281
|
+
| `timestamp_columns` | `[created_at, updated_at]` | Column names treated as timestamps for classified sorting. |
|
|
282
|
+
| `classes_default_to_s` | `[]` | Class names whose default values are rendered with `to_s`. |
|
|
283
|
+
|
|
284
|
+
#### Sorting and format
|
|
285
|
+
|
|
286
|
+
| Option | Default | Description |
|
|
287
|
+
| --- | --- | --- |
|
|
288
|
+
| `sort` | `false` | Sort columns alphabetically. |
|
|
289
|
+
| `classified_sort` | `true` | Sort as id → other columns → timestamps → associations. |
|
|
290
|
+
| `grouped_polymorphic` | `false` | Group polymorphic associations when using `classified_sort`. |
|
|
291
|
+
| `format_markdown` | `false` | Render annotations as Markdown. |
|
|
292
|
+
| `format_rdoc` | `false` | Render annotations as RDoc. |
|
|
293
|
+
| `format_yard` | `false` | Render annotations as YARD. |
|
|
294
|
+
|
|
295
|
+
#### What to annotate / exclude
|
|
296
|
+
|
|
297
|
+
| Option | Default | Description |
|
|
298
|
+
| --- | --- | --- |
|
|
299
|
+
| `active_admin` | `false` | Annotate ActiveAdmin models. |
|
|
300
|
+
| `exclude_controllers` | `true` | Skip controller files. |
|
|
301
|
+
| `exclude_factories` | `false` | Skip factory files. |
|
|
302
|
+
| `exclude_fixtures` | `false` | Skip fixture files. |
|
|
303
|
+
| `exclude_helpers` | `true` | Skip helper files. |
|
|
304
|
+
| `exclude_scaffolds` | `true` | Skip scaffold files. |
|
|
305
|
+
| `exclude_serializers` | `false` | Skip serializer files. |
|
|
306
|
+
| `exclude_sti_subclasses` | `false` | Skip STI subclasses. |
|
|
307
|
+
| `exclude_tests` | `false` | Skip test/spec files. Can also be an array of symbols. |
|
|
308
|
+
| `ignore_model_sub_dir` | `false` | Ignore subdirectories under `model_dir`. |
|
|
309
|
+
| `ignore_unknown_models` | `false` | Suppress warnings for bad model files. |
|
|
310
|
+
|
|
311
|
+
#### Paths
|
|
312
|
+
|
|
313
|
+
| Option | Default | Description |
|
|
314
|
+
| --- | --- | --- |
|
|
315
|
+
| `model_dir` | `[app/models]` | Directories containing models. |
|
|
316
|
+
| `root_dir` | `[""]` | Root directories for multi-project layouts. |
|
|
317
|
+
| `additional_file_patterns` | `[]` | Extra paths/globs to annotate (supports `%MODEL_NAME%`). |
|
|
318
|
+
| `require` | `[]` | Extra files to require before loading models. |
|
|
319
|
+
|
|
320
|
+
#### Routes
|
|
321
|
+
|
|
322
|
+
| Option | Default | Description |
|
|
323
|
+
| --- | --- | --- |
|
|
324
|
+
| `ignore_routes` | `null` | Regex of routes to skip. |
|
|
325
|
+
| `timestamp` | `false` | Include a timestamp in route annotations. |
|
|
326
|
+
| `auto_annotate_routes_after_migrate` | `false` | Also annotate routes after DB migrate tasks. |
|
|
327
|
+
|
|
328
|
+
#### Wrappers and behavior
|
|
329
|
+
|
|
330
|
+
| Option | Default | Description |
|
|
331
|
+
| --- | --- | --- |
|
|
332
|
+
| `wrapper` | `null` | Text used for both opening and closing wrappers. |
|
|
333
|
+
| `wrapper_open` | `null` | Opening wrapper text (falls back to `wrapper`). |
|
|
334
|
+
| `wrapper_close` | `null` | Closing wrapper text (falls back to `wrapper`). |
|
|
335
|
+
| `force` | `false` | Rewrite annotations even when unchanged. |
|
|
336
|
+
| `frozen` | `false` | Exit non-zero if annotations would change. |
|
|
337
|
+
| `skip_on_db_migrate` | `false` | Skip automatic annotation after DB migrate tasks. |
|
|
338
|
+
| `debug` | `false` | Print resolved options for debugging. |
|
|
339
|
+
| `trace` | `false` | Print full stack traces when annotation fails. |
|
|
340
|
+
|
|
341
|
+
Example:
|
|
342
|
+
|
|
343
|
+
```yml
|
|
344
|
+
# .annotaterb.yml
|
|
345
|
+
position: after
|
|
346
|
+
show_foreign_keys: true
|
|
347
|
+
show_indexes: true
|
|
348
|
+
show_enums: true
|
|
349
|
+
classified_sort: true
|
|
350
|
+
model_dir:
|
|
351
|
+
- app/models
|
|
352
|
+
- app/models/concerns
|
|
353
|
+
skip_on_db_migrate: false
|
|
354
|
+
```
|
|
355
|
+
|
|
240
356
|
### Preserving class documentation comments
|
|
241
357
|
|
|
242
358
|
By default, when `position_in_class` is `before` (or `top`), AnnotateRb places the schema annotation immediately before the class declaration line. Any human-written documentation comment that was directly above the class is therefore pushed above the annotation.
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.
|
|
1
|
+
4.24.0
|
|
@@ -27,6 +27,8 @@ module AnnotateRb
|
|
|
27
27
|
IndexAnnotation::AnnotationBuilder.new(@model, @options).build,
|
|
28
28
|
ForeignKeyAnnotation::AnnotationBuilder.new(@model, @options).build,
|
|
29
29
|
CheckConstraintAnnotation::AnnotationBuilder.new(@model, @options).build,
|
|
30
|
+
UniqueConstraintAnnotation::AnnotationBuilder.new(@model, @options).build,
|
|
31
|
+
ExclusionConstraintAnnotation::AnnotationBuilder.new(@model, @options).build,
|
|
30
32
|
EnumAnnotation::AnnotationBuilder.new(@model, @options).build,
|
|
31
33
|
SchemaFooter.new
|
|
32
34
|
]
|
|
@@ -65,7 +67,7 @@ module AnnotateRb
|
|
|
65
67
|
table_name = @model.table_name
|
|
66
68
|
table_comment = @model.connection.try(:table_comment, @model.table_name)
|
|
67
69
|
max_size = @model.max_schema_info_width
|
|
68
|
-
database_name = @model.database_name if
|
|
70
|
+
database_name = @model.database_name if show_database_name?
|
|
69
71
|
|
|
70
72
|
_annotation = Annotation.new(@options,
|
|
71
73
|
version: version, table_name: table_name, table_comment: table_comment,
|
|
@@ -74,6 +76,11 @@ module AnnotateRb
|
|
|
74
76
|
|
|
75
77
|
private
|
|
76
78
|
|
|
79
|
+
# TODO: Consolidate ignore_database_name and ignore_multi_database_name; they serve the same purpose
|
|
80
|
+
def show_database_name?
|
|
81
|
+
!@options[:ignore_database_name] && multi_db_environment?
|
|
82
|
+
end
|
|
83
|
+
|
|
77
84
|
def multi_db_environment?
|
|
78
85
|
return false if @options[:ignore_multi_database_name]
|
|
79
86
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnnotateRb
|
|
4
|
+
module ModelAnnotator
|
|
5
|
+
module ExclusionConstraintAnnotation
|
|
6
|
+
class Annotation
|
|
7
|
+
HEADER_TEXT = "Exclusion Constraints"
|
|
8
|
+
|
|
9
|
+
def initialize(constraints)
|
|
10
|
+
@constraints = constraints
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def body
|
|
14
|
+
[
|
|
15
|
+
Components::BlankCommentLine.new,
|
|
16
|
+
Components::Header.new(HEADER_TEXT),
|
|
17
|
+
Components::BlankCommentLine.new,
|
|
18
|
+
*@constraints
|
|
19
|
+
]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_markdown
|
|
23
|
+
body.map(&:to_markdown).join("\n")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_rdoc
|
|
27
|
+
body.map(&:to_rdoc).join("\n")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_yard
|
|
31
|
+
body.map(&:to_yard).join("\n")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_default
|
|
35
|
+
body.map(&:to_default).join("\n")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnnotateRb
|
|
4
|
+
module ModelAnnotator
|
|
5
|
+
module ExclusionConstraintAnnotation
|
|
6
|
+
class AnnotationBuilder
|
|
7
|
+
def initialize(model, options)
|
|
8
|
+
@model = model
|
|
9
|
+
@options = options
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def build
|
|
13
|
+
return Components::NilComponent.new if !@options[:show_exclusion_constraints]
|
|
14
|
+
return Components::NilComponent.new unless @model.connection.respond_to?(:supports_exclusion_constraints?) &&
|
|
15
|
+
@model.connection.supports_exclusion_constraints? && @model.connection.respond_to?(:exclusion_constraints)
|
|
16
|
+
|
|
17
|
+
exclusion_constraints = @model.connection.exclusion_constraints(@model.table_name)
|
|
18
|
+
return Components::NilComponent.new if exclusion_constraints.empty?
|
|
19
|
+
|
|
20
|
+
max_size = exclusion_constraints.map { |exclusion_constraint| exclusion_constraint.name.size }.max + 1
|
|
21
|
+
|
|
22
|
+
constraints = exclusion_constraints.sort_by(&:name).map do |exclusion_constraint|
|
|
23
|
+
details = "(#{exclusion_constraint.expression})"
|
|
24
|
+
details += " USING #{exclusion_constraint.using}" if exclusion_constraint.using
|
|
25
|
+
details += " WHERE (#{exclusion_constraint.where})" if exclusion_constraint.where
|
|
26
|
+
if exclusion_constraint.deferrable
|
|
27
|
+
details += " DEFERRABLE INITIALLY #{exclusion_constraint.deferrable.to_s.upcase}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
ExclusionConstraintComponent.new(exclusion_constraint.name, details, max_size)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
_annotation = Annotation.new(constraints)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnnotateRb
|
|
4
|
+
module ModelAnnotator
|
|
5
|
+
module ExclusionConstraintAnnotation
|
|
6
|
+
class ExclusionConstraintComponent < Components::Base
|
|
7
|
+
attr_reader :name, :details, :max_size
|
|
8
|
+
|
|
9
|
+
def initialize(name, details, max_size)
|
|
10
|
+
@name = name
|
|
11
|
+
@details = details
|
|
12
|
+
@max_size = max_size
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_default
|
|
16
|
+
# standard:disable Lint/FormatParameterMismatch
|
|
17
|
+
sprintf("# %-#{max_size}.#{max_size}s %s", name, details).rstrip
|
|
18
|
+
# standard:enable Lint/FormatParameterMismatch
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_markdown
|
|
22
|
+
sprintf("# * `%s`: `%s`", name, details)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnnotateRb
|
|
4
|
+
module ModelAnnotator
|
|
5
|
+
module ExclusionConstraintAnnotation
|
|
6
|
+
autoload :AnnotationBuilder, "annotate_rb/model_annotator/exclusion_constraint_annotation/annotation_builder"
|
|
7
|
+
autoload :Annotation, "annotate_rb/model_annotator/exclusion_constraint_annotation/annotation"
|
|
8
|
+
autoload :ExclusionConstraintComponent, "annotate_rb/model_annotator/exclusion_constraint_annotation/exclusion_constraint_component"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -19,9 +19,19 @@ module AnnotateRb
|
|
|
19
19
|
SCHEMA_HEADER_EXACT = [
|
|
20
20
|
IndexAnnotation::Annotation::HEADER_TEXT,
|
|
21
21
|
ForeignKeyAnnotation::Annotation::HEADER_TEXT,
|
|
22
|
-
CheckConstraintAnnotation::Annotation::HEADER_TEXT
|
|
22
|
+
CheckConstraintAnnotation::Annotation::HEADER_TEXT,
|
|
23
|
+
UniqueConstraintAnnotation::Annotation::HEADER_TEXT,
|
|
24
|
+
ExclusionConstraintAnnotation::Annotation::HEADER_TEXT,
|
|
25
|
+
EnumAnnotation::Annotation::HEADER_TEXT
|
|
23
26
|
].freeze
|
|
24
27
|
|
|
28
|
+
# `format_markdown: true` renders each of the section headers above as
|
|
29
|
+
# "### <name>" instead of "<name>", so SCHEMA_HEADER_EXACT can't match it directly.
|
|
30
|
+
# There's no HEADER_TEXT constant for the columns table itself,
|
|
31
|
+
# so "Columns" is listed explicitly here.
|
|
32
|
+
MARKDOWN_HEADER_PREFIX = "### "
|
|
33
|
+
MARKDOWN_SECTION_HEADERS = (SCHEMA_HEADER_EXACT + ["Columns"]).freeze
|
|
34
|
+
|
|
25
35
|
class MalformedAnnotation < StandardError; end
|
|
26
36
|
|
|
27
37
|
class NoAnnotationFound < StandardError; end
|
|
@@ -118,7 +128,18 @@ module AnnotateRb
|
|
|
118
128
|
ending
|
|
119
129
|
end
|
|
120
130
|
|
|
121
|
-
#
|
|
131
|
+
# A line is part of the schema block if it matches one of the known
|
|
132
|
+
# header prefixes/exact texts, or if it looks like a tabular/list row
|
|
133
|
+
# of the annotation body:
|
|
134
|
+
#
|
|
135
|
+
# - Default/plain format: rows have >= 2 leading spaces after `#`
|
|
136
|
+
# (e.g. "# id :integer not null"); prose has at most one.
|
|
137
|
+
# - Markdown format (`format_markdown: true`) instead uses a single
|
|
138
|
+
# leading space after `#` for everything, so it needs its own
|
|
139
|
+
# detection: "### <name>" section headers (matched against
|
|
140
|
+
# MARKDOWN_SECTION_HEADERS with the prefix stripped), "|"-delimited
|
|
141
|
+
# table rows (header/divider/data), and "* `...`" bulleted list
|
|
142
|
+
# items for indexes/foreign keys/enums.
|
|
122
143
|
def schema_like?(comment)
|
|
123
144
|
return true if comment == DEFAULT_ANNOTATION_ENDING
|
|
124
145
|
|
|
@@ -128,6 +149,21 @@ module AnnotateRb
|
|
|
128
149
|
return true if SCHEMA_HEADER_PREFIXES.any? { |p| text.start_with?(p) }
|
|
129
150
|
return true if SCHEMA_HEADER_EXACT.include?(text)
|
|
130
151
|
|
|
152
|
+
# Markdown section headers, e.g. "### Columns", "### Indexes".
|
|
153
|
+
if text.start_with?(MARKDOWN_HEADER_PREFIX)
|
|
154
|
+
return MARKDOWN_SECTION_HEADERS.include?(text.delete_prefix(MARKDOWN_HEADER_PREFIX))
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Requires at least two | separators to identify Markdown tables.
|
|
158
|
+
# This prevents normal user comments containing a single | from being mistaken for a table.
|
|
159
|
+
return true if text.count("|") >= 2
|
|
160
|
+
|
|
161
|
+
# Markdown bulleted list items used for foreign keys/indexes/enums,
|
|
162
|
+
# e.g. "* `index_name`:" or the nested " * **`column`**". The
|
|
163
|
+
# backtick right after the bullet marker distinguishes these from
|
|
164
|
+
# an unrelated user comment that starts with a plain "* ".
|
|
165
|
+
return true if text.match?(/\A\s*\*\s+\*{0,2}`/)
|
|
166
|
+
|
|
131
167
|
comment.match?(/\A#\s{2,}\S/)
|
|
132
168
|
end
|
|
133
169
|
end
|
|
@@ -43,10 +43,20 @@ module AnnotateRb
|
|
|
43
43
|
begin
|
|
44
44
|
parser.parse(@input)
|
|
45
45
|
rescue Psych::SyntaxError => _e
|
|
46
|
-
# "Dynamic fixtures with ERB" exist in Rails
|
|
47
|
-
#
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
# "Dynamic fixtures with ERB" exist in Rails and cause Psych.parser to error.
|
|
47
|
+
#
|
|
48
|
+
# We deliberately do not evaluate the ERB and read line numbers off the
|
|
49
|
+
# result: evaluating runs arbitrary code, and the line numbers from the
|
|
50
|
+
# evaluated output do not map back to the original file (ERB tags spanning
|
|
51
|
+
# multiple lines shift the offsets), which would place annotations inside
|
|
52
|
+
# an ERB tag. Instead we derive the content bounds straight from the
|
|
53
|
+
# original lines so annotations land around the ERB body.
|
|
54
|
+
#
|
|
55
|
+
# Only fall back for actual ERB fixtures. Genuinely malformed YAML
|
|
56
|
+
# (no ERB tags) should keep surfacing the parse error rather than
|
|
57
|
+
# being silently annotated.
|
|
58
|
+
raise unless erb_fixture?
|
|
59
|
+
return record_erb_positions
|
|
50
60
|
end
|
|
51
61
|
|
|
52
62
|
stream = parser.handler.root
|
|
@@ -68,6 +78,35 @@ module AnnotateRb
|
|
|
68
78
|
@ends << [nil, stream.end_line]
|
|
69
79
|
end
|
|
70
80
|
end
|
|
81
|
+
|
|
82
|
+
# Locates the content bounds of an ERB fixture directly from the original
|
|
83
|
+
# lines, treating the ERB/YAML body as the doc. The start is the first
|
|
84
|
+
# non-blank, non-comment line so annotations are written above the ERB
|
|
85
|
+
# block (and after any leading comments), never inside a tag.
|
|
86
|
+
def record_erb_positions
|
|
87
|
+
lines = @input.split($/)
|
|
88
|
+
content_start = lines.index { |line| content_line?(line) }
|
|
89
|
+
|
|
90
|
+
if content_start.nil?
|
|
91
|
+
@starts << [nil, 0]
|
|
92
|
+
@ends << [nil, 0]
|
|
93
|
+
else
|
|
94
|
+
content_end = lines.rindex { |line| content_line?(line) }
|
|
95
|
+
@starts << [nil, content_start]
|
|
96
|
+
@ends << [nil, content_end + 1]
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def content_line?(line)
|
|
101
|
+
stripped = line.strip
|
|
102
|
+
!stripped.empty? && !stripped.start_with?("#")
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# True when the input contains an ERB tag, i.e. it is a dynamic fixture
|
|
106
|
+
# rather than plain (possibly malformed) YAML.
|
|
107
|
+
def erb_fixture?
|
|
108
|
+
@input.match?(/<%.*?%>/m)
|
|
109
|
+
end
|
|
71
110
|
end
|
|
72
111
|
end
|
|
73
112
|
end
|
data/lib/annotate_rb/model_annotator/foreign_key_annotation/foreign_key_component_builder.rb
CHANGED
|
@@ -32,6 +32,12 @@ module AnnotateRb
|
|
|
32
32
|
constraints_info = ""
|
|
33
33
|
constraints_info += "ON DELETE => #{foreign_key.on_delete} " if foreign_key.on_delete
|
|
34
34
|
constraints_info += "ON UPDATE => #{foreign_key.on_update} " if foreign_key.on_update
|
|
35
|
+
if foreign_key.respond_to?(:deferrable) && foreign_key.deferrable
|
|
36
|
+
# Rails 7.0's extract_foreign_key_deferrable returns `true` for the initially-immediate case;
|
|
37
|
+
# 7.1+ normalized this to `:immediate`. Map `true` back to IMMEDIATE so we don't emit "INITIALLY TRUE".
|
|
38
|
+
initially = (foreign_key.deferrable == true) ? "IMMEDIATE" : foreign_key.deferrable.to_s.upcase
|
|
39
|
+
constraints_info += "DEFERRABLE INITIALLY #{initially} "
|
|
40
|
+
end
|
|
35
41
|
constraints_info.strip
|
|
36
42
|
end
|
|
37
43
|
end
|
|
@@ -15,6 +15,9 @@ module AnnotateRb
|
|
|
15
15
|
indexes = @model.retrieve_indexes_from_table
|
|
16
16
|
return Components::NilComponent.new if indexes.empty?
|
|
17
17
|
|
|
18
|
+
indexes = reject_constraint_backed_indexes(indexes)
|
|
19
|
+
return Components::NilComponent.new if indexes.empty?
|
|
20
|
+
|
|
18
21
|
max_size = indexes.map { |index| index.name.size }.max + 1
|
|
19
22
|
|
|
20
23
|
indexes = indexes.sort_by(&:name).map do |index|
|
|
@@ -23,6 +26,32 @@ module AnnotateRb
|
|
|
23
26
|
|
|
24
27
|
_annotation = Annotation.new(indexes)
|
|
25
28
|
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# Mirrors ActiveRecord's schema_dumper#indexes_in_create: PostgreSQL's
|
|
33
|
+
# unique and exclusion constraints are backed by indexes with the same
|
|
34
|
+
# name, so those show up in `connection.indexes` too. Drop them here so
|
|
35
|
+
# they only appear under their dedicated sections.
|
|
36
|
+
def reject_constraint_backed_indexes(indexes)
|
|
37
|
+
connection = @model.connection
|
|
38
|
+
|
|
39
|
+
if connection.respond_to?(:supports_exclusion_constraints?) &&
|
|
40
|
+
connection.supports_exclusion_constraints? &&
|
|
41
|
+
connection.respond_to?(:exclusion_constraints)
|
|
42
|
+
excl_names = connection.exclusion_constraints(@model.table_name).map(&:name)
|
|
43
|
+
indexes = indexes.reject { |index| excl_names.include?(index.name) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
if connection.respond_to?(:supports_unique_constraints?) &&
|
|
47
|
+
connection.supports_unique_constraints? &&
|
|
48
|
+
connection.respond_to?(:unique_constraints)
|
|
49
|
+
unique_names = connection.unique_constraints(@model.table_name).map(&:name)
|
|
50
|
+
indexes = indexes.reject { |index| unique_names.include?(index.name) }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
indexes
|
|
54
|
+
end
|
|
26
55
|
end
|
|
27
56
|
end
|
|
28
57
|
end
|
|
@@ -68,8 +68,20 @@ module AnnotateRb
|
|
|
68
68
|
connection.table_comment(@klass.table_name).present?
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
+
# Returns column defaults for annotations.
|
|
72
|
+
#
|
|
73
|
+
# `Model#column_defaults` reflects `attribute :foo, default: X` overrides,
|
|
74
|
+
# which would incorrectly show the Ruby-side default in annotations
|
|
75
|
+
# instead of the DB schema default. To preserve model-level decorations
|
|
76
|
+
# such as `TimeZoneConverter` on datetime columns, we start from
|
|
77
|
+
# `column_defaults` and only substitute the DB schema value when a
|
|
78
|
+
# difference indicates an attribute-level override.
|
|
71
79
|
def column_defaults
|
|
72
|
-
@klass.column_defaults
|
|
80
|
+
@column_defaults ||= @klass.column_defaults.each_with_object({}) do |(name, value), result|
|
|
81
|
+
column = @klass.columns_hash[name]
|
|
82
|
+
schema_value = schema_default_for(column)
|
|
83
|
+
result[name] = (value == schema_value) ? value : schema_value
|
|
84
|
+
end
|
|
73
85
|
end
|
|
74
86
|
|
|
75
87
|
# Add columns managed by the globalize gem if this gem is being used.
|
|
@@ -263,6 +275,26 @@ module AnnotateRb
|
|
|
263
275
|
|
|
264
276
|
@options.get_state(cache_key)
|
|
265
277
|
end
|
|
278
|
+
|
|
279
|
+
private
|
|
280
|
+
|
|
281
|
+
def schema_default_for(column)
|
|
282
|
+
return nil if column.nil? || column.default.nil? || column.default_function
|
|
283
|
+
cast_type_for(column).deserialize(column.default)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Rails post-8.1 exposes `Column#cast_type` directly; Rails 8.1 introduced
|
|
287
|
+
# the transitional `Column#fetch_cast_type(connection)`; older versions
|
|
288
|
+
# required `connection.lookup_cast_type_from_column(column)`.
|
|
289
|
+
def cast_type_for(column)
|
|
290
|
+
if column.respond_to?(:cast_type)
|
|
291
|
+
column.cast_type
|
|
292
|
+
elsif column.respond_to?(:fetch_cast_type)
|
|
293
|
+
column.fetch_cast_type(connection)
|
|
294
|
+
else
|
|
295
|
+
connection.lookup_cast_type_from_column(column)
|
|
296
|
+
end
|
|
297
|
+
end
|
|
266
298
|
end
|
|
267
299
|
end
|
|
268
300
|
end
|
|
@@ -18,7 +18,7 @@ module AnnotateRb
|
|
|
18
18
|
parsed_file = FileParser::ParsedFile.new(old_content, "", parser_klass, options).parse
|
|
19
19
|
rescue FileParser::AnnotationFinder::MalformedAnnotation => e
|
|
20
20
|
warn "Unable to process #{file_name}: #{e.message}"
|
|
21
|
-
warn "\t" + e.backtrace.join("\n\t") if
|
|
21
|
+
warn "\t" + e.backtrace.join("\n\t") if options[:trace]
|
|
22
22
|
return false
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -31,7 +31,7 @@ module AnnotateRb
|
|
|
31
31
|
parsed_file = FileParser::ParsedFile.new(old_content, annotation, parser_klass, options, model_class_name: model_class_name).parse
|
|
32
32
|
rescue FileParser::AnnotationFinder::MalformedAnnotation => e
|
|
33
33
|
warn "Unable to process #{file_name}: #{e.message}"
|
|
34
|
-
warn "\t" + e.backtrace.join("\n\t") if
|
|
34
|
+
warn "\t" + e.backtrace.join("\n\t") if options[:trace]
|
|
35
35
|
return false
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnnotateRb
|
|
4
|
+
module ModelAnnotator
|
|
5
|
+
module UniqueConstraintAnnotation
|
|
6
|
+
class Annotation
|
|
7
|
+
HEADER_TEXT = "Unique Constraints"
|
|
8
|
+
|
|
9
|
+
def initialize(constraints)
|
|
10
|
+
@constraints = constraints
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def body
|
|
14
|
+
[
|
|
15
|
+
Components::BlankCommentLine.new,
|
|
16
|
+
Components::Header.new(HEADER_TEXT),
|
|
17
|
+
Components::BlankCommentLine.new,
|
|
18
|
+
*@constraints
|
|
19
|
+
]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_markdown
|
|
23
|
+
body.map(&:to_markdown).join("\n")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_rdoc
|
|
27
|
+
body.map(&:to_rdoc).join("\n")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_yard
|
|
31
|
+
body.map(&:to_yard).join("\n")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_default
|
|
35
|
+
body.map(&:to_default).join("\n")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnnotateRb
|
|
4
|
+
module ModelAnnotator
|
|
5
|
+
module UniqueConstraintAnnotation
|
|
6
|
+
class AnnotationBuilder
|
|
7
|
+
def initialize(model, options)
|
|
8
|
+
@model = model
|
|
9
|
+
@options = options
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def build
|
|
13
|
+
return Components::NilComponent.new if !@options[:show_unique_constraints]
|
|
14
|
+
return Components::NilComponent.new unless @model.connection.respond_to?(:supports_unique_constraints?) &&
|
|
15
|
+
@model.connection.supports_unique_constraints? && @model.connection.respond_to?(:unique_constraints)
|
|
16
|
+
|
|
17
|
+
unique_constraints = @model.connection.unique_constraints(@model.table_name)
|
|
18
|
+
return Components::NilComponent.new if unique_constraints.empty?
|
|
19
|
+
|
|
20
|
+
max_size = unique_constraints.map { |unique_constraint| unique_constraint.name.size }.max + 1
|
|
21
|
+
|
|
22
|
+
constraints = unique_constraints.sort_by(&:name).map do |unique_constraint|
|
|
23
|
+
columns = Array(unique_constraint.column)
|
|
24
|
+
details = "(#{columns.join(", ")})"
|
|
25
|
+
if unique_constraint.deferrable
|
|
26
|
+
details += " DEFERRABLE INITIALLY #{unique_constraint.deferrable.to_s.upcase}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
UniqueConstraintComponent.new(unique_constraint.name, details, max_size)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
_annotation = Annotation.new(constraints)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/annotate_rb/model_annotator/unique_constraint_annotation/unique_constraint_component.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnnotateRb
|
|
4
|
+
module ModelAnnotator
|
|
5
|
+
module UniqueConstraintAnnotation
|
|
6
|
+
class UniqueConstraintComponent < Components::Base
|
|
7
|
+
attr_reader :name, :details, :max_size
|
|
8
|
+
|
|
9
|
+
def initialize(name, details, max_size)
|
|
10
|
+
@name = name
|
|
11
|
+
@details = details
|
|
12
|
+
@max_size = max_size
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_default
|
|
16
|
+
# standard:disable Lint/FormatParameterMismatch
|
|
17
|
+
sprintf("# %-#{max_size}.#{max_size}s %s", name, details).rstrip
|
|
18
|
+
# standard:enable Lint/FormatParameterMismatch
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_markdown
|
|
22
|
+
sprintf("# * `%s`: `%s`", name, details)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnnotateRb
|
|
4
|
+
module ModelAnnotator
|
|
5
|
+
module UniqueConstraintAnnotation
|
|
6
|
+
autoload :AnnotationBuilder, "annotate_rb/model_annotator/unique_constraint_annotation/annotation_builder"
|
|
7
|
+
autoload :Annotation, "annotate_rb/model_annotator/unique_constraint_annotation/annotation"
|
|
8
|
+
autoload :UniqueConstraintComponent, "annotate_rb/model_annotator/unique_constraint_annotation/unique_constraint_component"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -27,6 +27,8 @@ module AnnotateRb
|
|
|
27
27
|
autoload :FileParser, "annotate_rb/model_annotator/file_parser"
|
|
28
28
|
autoload :ZeitwerkClassGetter, "annotate_rb/model_annotator/zeitwerk_class_getter"
|
|
29
29
|
autoload :CheckConstraintAnnotation, "annotate_rb/model_annotator/check_constraint_annotation"
|
|
30
|
+
autoload :UniqueConstraintAnnotation, "annotate_rb/model_annotator/unique_constraint_annotation"
|
|
31
|
+
autoload :ExclusionConstraintAnnotation, "annotate_rb/model_annotator/exclusion_constraint_annotation"
|
|
30
32
|
autoload :EnumAnnotation, "annotate_rb/model_annotator/enum_annotation"
|
|
31
33
|
autoload :FileToParserMapper, "annotate_rb/model_annotator/file_to_parser_mapper"
|
|
32
34
|
autoload :Components, "annotate_rb/model_annotator/components"
|
data/lib/annotate_rb/options.rb
CHANGED
|
@@ -42,11 +42,14 @@ module AnnotateRb
|
|
|
42
42
|
format_yard: false, # ModelAnnotator
|
|
43
43
|
frozen: false, # ModelAnnotator, but should be used by both
|
|
44
44
|
grouped_polymorphic: false, # ModelAnnotator
|
|
45
|
+
ignore_database_name: false, # ModelAnnotator
|
|
45
46
|
ignore_model_sub_dir: false, # ModelAnnotator
|
|
46
47
|
ignore_unknown_models: false, # ModelAnnotator
|
|
47
48
|
include_version: false, # ModelAnnotator
|
|
48
49
|
show_complete_foreign_keys: false, # ModelAnnotator
|
|
49
50
|
show_check_constraints: false, # ModelAnnotator
|
|
51
|
+
show_unique_constraints: false, # ModelAnnotator
|
|
52
|
+
show_exclusion_constraints: false, # ModelAnnotator
|
|
50
53
|
show_enums: false, # ModelAnnotator
|
|
51
54
|
show_foreign_keys: true, # ModelAnnotator
|
|
52
55
|
show_indexes: true, # ModelAnnotator
|
|
@@ -118,10 +121,13 @@ module AnnotateRb
|
|
|
118
121
|
:format_yard,
|
|
119
122
|
:frozen,
|
|
120
123
|
:grouped_polymorphic,
|
|
124
|
+
:ignore_database_name,
|
|
121
125
|
:ignore_model_sub_dir,
|
|
122
126
|
:ignore_unknown_models,
|
|
123
127
|
:include_version,
|
|
124
128
|
:show_check_constraints,
|
|
129
|
+
:show_unique_constraints,
|
|
130
|
+
:show_exclusion_constraints,
|
|
125
131
|
:show_enums,
|
|
126
132
|
:show_complete_foreign_keys,
|
|
127
133
|
:show_foreign_keys,
|
data/lib/annotate_rb/parser.rb
CHANGED
|
@@ -207,6 +207,16 @@ module AnnotateRb
|
|
|
207
207
|
@options[:show_check_constraints] = true
|
|
208
208
|
end
|
|
209
209
|
|
|
210
|
+
option_parser.on("--show-unique-constraints",
|
|
211
|
+
"List the table's unique constraints in the annotation") do
|
|
212
|
+
@options[:show_unique_constraints] = true
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
option_parser.on("--show-exclusion-constraints",
|
|
216
|
+
"List the table's exclusion constraints in the annotation") do
|
|
217
|
+
@options[:show_exclusion_constraints] = true
|
|
218
|
+
end
|
|
219
|
+
|
|
210
220
|
option_parser.on("--hide-limit-column-types VALUES",
|
|
211
221
|
"don't show limit for given column types, separated by commas (i.e., `integer,boolean,text`)") do |values|
|
|
212
222
|
@options[:hide_limit_column_types] = values.to_s
|
|
@@ -222,6 +232,11 @@ module AnnotateRb
|
|
|
222
232
|
@options[:ignore_unknown_models] = true
|
|
223
233
|
end
|
|
224
234
|
|
|
235
|
+
option_parser.on("--ignore-database-name",
|
|
236
|
+
"don't include the database name in the annotation") do
|
|
237
|
+
@options[:ignore_database_name] = true
|
|
238
|
+
end
|
|
239
|
+
|
|
225
240
|
option_parser.on("-I",
|
|
226
241
|
"--ignore-columns REGEX",
|
|
227
242
|
"don't annotate columns that match a given REGEX (i.e., `annotate -I '^(id|updated_at|created_at)'`") do |regex|
|
|
@@ -234,7 +249,7 @@ module AnnotateRb
|
|
|
234
249
|
end
|
|
235
250
|
|
|
236
251
|
option_parser.on("--without-comment",
|
|
237
|
-
"
|
|
252
|
+
"exclude database comments in model annotations") do
|
|
238
253
|
@options[:with_comment] = false
|
|
239
254
|
end
|
|
240
255
|
|
data/lib/annotate_rb/runner.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: annotaterb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.24.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew W. Lee
|
|
@@ -94,6 +94,10 @@ files:
|
|
|
94
94
|
- lib/annotate_rb/model_annotator/enum_annotation/annotation.rb
|
|
95
95
|
- lib/annotate_rb/model_annotator/enum_annotation/annotation_builder.rb
|
|
96
96
|
- lib/annotate_rb/model_annotator/enum_annotation/enum_component.rb
|
|
97
|
+
- lib/annotate_rb/model_annotator/exclusion_constraint_annotation.rb
|
|
98
|
+
- lib/annotate_rb/model_annotator/exclusion_constraint_annotation/annotation.rb
|
|
99
|
+
- lib/annotate_rb/model_annotator/exclusion_constraint_annotation/annotation_builder.rb
|
|
100
|
+
- lib/annotate_rb/model_annotator/exclusion_constraint_annotation/exclusion_constraint_component.rb
|
|
97
101
|
- lib/annotate_rb/model_annotator/file_name_resolver.rb
|
|
98
102
|
- lib/annotate_rb/model_annotator/file_parser.rb
|
|
99
103
|
- lib/annotate_rb/model_annotator/file_parser/annotation_finder.rb
|
|
@@ -124,6 +128,10 @@ files:
|
|
|
124
128
|
- lib/annotate_rb/model_annotator/single_file_annotator.rb
|
|
125
129
|
- lib/annotate_rb/model_annotator/single_file_annotator_instruction.rb
|
|
126
130
|
- lib/annotate_rb/model_annotator/single_file_remove_annotation_instruction.rb
|
|
131
|
+
- lib/annotate_rb/model_annotator/unique_constraint_annotation.rb
|
|
132
|
+
- lib/annotate_rb/model_annotator/unique_constraint_annotation/annotation.rb
|
|
133
|
+
- lib/annotate_rb/model_annotator/unique_constraint_annotation/annotation_builder.rb
|
|
134
|
+
- lib/annotate_rb/model_annotator/unique_constraint_annotation/unique_constraint_component.rb
|
|
127
135
|
- lib/annotate_rb/model_annotator/zeitwerk_class_getter.rb
|
|
128
136
|
- lib/annotate_rb/options.rb
|
|
129
137
|
- lib/annotate_rb/parser.rb
|