synthra 0.1.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 (302) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +4 -0
  3. data/.rubocop.yml +40 -0
  4. data/.yardopts +18 -0
  5. data/ACCESS_DOCS.md +116 -0
  6. data/ADVANCED_FEATURES_SUMMARY.md +245 -0
  7. data/CHANGELOG.md +498 -0
  8. data/CODE_OF_CONDUCT.md +122 -0
  9. data/CONTRIBUTING.md +307 -0
  10. data/DOCUMENTATION.md +204 -0
  11. data/DOCUMENTATION_GUIDE.md +194 -0
  12. data/LICENSE +22 -0
  13. data/README.md +1458 -0
  14. data/Rakefile +128 -0
  15. data/benchmark/README.md +591 -0
  16. data/benchmark/batch_generation.rb +63 -0
  17. data/benchmark/engine_comparison.rb +295 -0
  18. data/benchmark/single_record.rb +108 -0
  19. data/benchmark/streaming.rb +74 -0
  20. data/docs/ACTIVERECORD_INFERENCE.md +524 -0
  21. data/docs/API_SERVER.md +278 -0
  22. data/docs/CONFIG_FILE.md +315 -0
  23. data/docs/DATA_CONTRACTS.md +312 -0
  24. data/docs/ENHANCED_REPL.md +304 -0
  25. data/docs/FACTORY_BOT.md +271 -0
  26. data/docs/GITHUB_ACTION.md +420 -0
  27. data/docs/GRAPHQL_EXPORT.md +303 -0
  28. data/docs/GRAPHQL_FEDERATION.md +651 -0
  29. data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
  30. data/docs/LSP.md +189 -0
  31. data/docs/MIGRATION_GENERATOR.md +547 -0
  32. data/docs/MOCK_SERVER.md +280 -0
  33. data/docs/NATIVE_ENGINE.md +298 -0
  34. data/docs/OPENAPI_EXPORT.md +252 -0
  35. data/docs/PERFORMANCE_MODE.md +228 -0
  36. data/docs/PERSONAS.md +547 -0
  37. data/docs/PROPERTY_TESTING.md +284 -0
  38. data/docs/PROTOBUF_EXPORT.md +276 -0
  39. data/docs/QUALITY_METRICS.md +555 -0
  40. data/docs/QUICK_REFERENCE.md +88 -0
  41. data/docs/RAILS_ENGINE.md +404 -0
  42. data/docs/RAILS_INTEGRATION.md +454 -0
  43. data/docs/README.md +175 -0
  44. data/docs/REPL_QUICK_REFERENCE.md +149 -0
  45. data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
  46. data/docs/SCENARIOS.md +576 -0
  47. data/docs/SECURITY_TESTING.md +318 -0
  48. data/docs/SNAPSHOT_TESTING.md +308 -0
  49. data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
  50. data/docs/TERRAFORM_EXPORT.md +447 -0
  51. data/docs/TIME_TRAVEL.md +507 -0
  52. data/docs/USAGE_GUIDE.md +980 -0
  53. data/docs/WEBHOOK_SIMULATOR.md +579 -0
  54. data/docs/advanced_features.md +183 -0
  55. data/docs/api_reference.md +153 -0
  56. data/docs/behaviors.md +138 -0
  57. data/docs/best_practices.md +191 -0
  58. data/docs/dsl_reference.md +172 -0
  59. data/docs/examples.md +162 -0
  60. data/docs/generation_modes.md +125 -0
  61. data/docs/getting_started.md +92 -0
  62. data/docs/index.html +177 -0
  63. data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
  64. data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
  65. data/docs/troubleshooting.md +215 -0
  66. data/docs/type_reference.md +224 -0
  67. data/examples/hostile_mode_demo.rb +64 -0
  68. data/exe/synthra +6 -0
  69. data/ext/synthra_native/Cargo.lock +972 -0
  70. data/ext/synthra_native/Cargo.toml +46 -0
  71. data/ext/synthra_native/extconf.rb +41 -0
  72. data/ext/synthra_native/src/generator.rs +397 -0
  73. data/ext/synthra_native/src/lib.rs +229 -0
  74. data/ext/synthra_native/src/types.rs +1485 -0
  75. data/lib/generators/synthra/install_generator.rb +86 -0
  76. data/lib/generators/synthra/templates/api_response.dsl +15 -0
  77. data/lib/generators/synthra/templates/fake_data.rake +116 -0
  78. data/lib/generators/synthra/templates/synthra.yml +31 -0
  79. data/lib/generators/synthra/templates/synthra_support.rb +19 -0
  80. data/lib/generators/synthra/templates/user.dsl +11 -0
  81. data/lib/synthra/activerecord_inference.rb +394 -0
  82. data/lib/synthra/api.rb +381 -0
  83. data/lib/synthra/api_server.rb +718 -0
  84. data/lib/synthra/behaviors/applicator.rb +165 -0
  85. data/lib/synthra/behaviors/base.rb +155 -0
  86. data/lib/synthra/behaviors/close_connection.rb +60 -0
  87. data/lib/synthra/behaviors/deprecated.rb +100 -0
  88. data/lib/synthra/behaviors/failure.rb +69 -0
  89. data/lib/synthra/behaviors/latency.rb +103 -0
  90. data/lib/synthra/behaviors/partial_data.rb +83 -0
  91. data/lib/synthra/behaviors/randomize_order.rb +74 -0
  92. data/lib/synthra/behaviors/registry.rb +238 -0
  93. data/lib/synthra/behaviors/simulate_error.rb +79 -0
  94. data/lib/synthra/cli/commands/base.rb +105 -0
  95. data/lib/synthra/cli/commands/diff.rb +227 -0
  96. data/lib/synthra/cli/commands/docs.rb +67 -0
  97. data/lib/synthra/cli/commands/export.rb +150 -0
  98. data/lib/synthra/cli/commands/generate.rb +72 -0
  99. data/lib/synthra/cli/commands/import.rb +80 -0
  100. data/lib/synthra/cli/commands/lint.rb +53 -0
  101. data/lib/synthra/cli/commands/live.rb +57 -0
  102. data/lib/synthra/cli/commands/seed.rb +99 -0
  103. data/lib/synthra/cli/commands/validate.rb +28 -0
  104. data/lib/synthra/cli.rb +2471 -0
  105. data/lib/synthra/config_file.rb +129 -0
  106. data/lib/synthra/configuration.rb +281 -0
  107. data/lib/synthra/contracts_registry.rb +408 -0
  108. data/lib/synthra/database_seeder.rb +268 -0
  109. data/lib/synthra/deterministic_ids.rb +218 -0
  110. data/lib/synthra/documentation_generator.rb +414 -0
  111. data/lib/synthra/engine.rb +251 -0
  112. data/lib/synthra/errors.rb +1169 -0
  113. data/lib/synthra/export/base.rb +85 -0
  114. data/lib/synthra/export/csv.rb +101 -0
  115. data/lib/synthra/export/graphql.rb +266 -0
  116. data/lib/synthra/export/graphql_federation.rb +377 -0
  117. data/lib/synthra/export/graphviz.rb +258 -0
  118. data/lib/synthra/export/javascript.rb +327 -0
  119. data/lib/synthra/export/json_data.rb +61 -0
  120. data/lib/synthra/export/json_schema.rb +290 -0
  121. data/lib/synthra/export/openapi.rb +514 -0
  122. data/lib/synthra/export/protobuf.rb +483 -0
  123. data/lib/synthra/export/python.rb +560 -0
  124. data/lib/synthra/export/sql.rb +381 -0
  125. data/lib/synthra/export/sql_insert.rb +152 -0
  126. data/lib/synthra/export/terraform.rb +501 -0
  127. data/lib/synthra/export/type_mapping.rb +389 -0
  128. data/lib/synthra/export/typescript.rb +300 -0
  129. data/lib/synthra/export/xml_data.rb +104 -0
  130. data/lib/synthra/export/yaml_data.rb +56 -0
  131. data/lib/synthra/export.rb +404 -0
  132. data/lib/synthra/factory_bot_integration.rb +157 -0
  133. data/lib/synthra/field.rb +440 -0
  134. data/lib/synthra/functions/registry.rb +104 -0
  135. data/lib/synthra/generator/context.rb +372 -0
  136. data/lib/synthra/generator/engine.rb +336 -0
  137. data/lib/synthra/generator/faker_adapter.rb +425 -0
  138. data/lib/synthra/generator/modes.rb +444 -0
  139. data/lib/synthra/generator/resolver.rb +256 -0
  140. data/lib/synthra/generator/rng.rb +273 -0
  141. data/lib/synthra/generator/streamer.rb +63 -0
  142. data/lib/synthra/generator/uniqueness.rb +118 -0
  143. data/lib/synthra/initializer.rb +97 -0
  144. data/lib/synthra/limits.rb +279 -0
  145. data/lib/synthra/live_preview.rb +518 -0
  146. data/lib/synthra/loader_config.rb +78 -0
  147. data/lib/synthra/lsp/server.rb +689 -0
  148. data/lib/synthra/migration_generator.rb +301 -0
  149. data/lib/synthra/mixin.rb +174 -0
  150. data/lib/synthra/mock_server.rb +458 -0
  151. data/lib/synthra/native_engine.rb +304 -0
  152. data/lib/synthra/openapi_importer.rb +228 -0
  153. data/lib/synthra/output/json_formatter.rb +40 -0
  154. data/lib/synthra/output/ndjson_formatter.rb +55 -0
  155. data/lib/synthra/parser/ast.rb +1287 -0
  156. data/lib/synthra/parser/lexer.rb +1152 -0
  157. data/lib/synthra/parser/parser.rb +1664 -0
  158. data/lib/synthra/parser/tokens.rb +461 -0
  159. data/lib/synthra/performance_mode.rb +364 -0
  160. data/lib/synthra/personas.rb +397 -0
  161. data/lib/synthra/property_testing.rb +172 -0
  162. data/lib/synthra/quality_metrics.rb +405 -0
  163. data/lib/synthra/rails_test_helper.rb +248 -0
  164. data/lib/synthra/registry.rb +533 -0
  165. data/lib/synthra/relationships.rb +193 -0
  166. data/lib/synthra/repl/enhanced_repl.rb +607 -0
  167. data/lib/synthra/repl/formatter.rb +191 -0
  168. data/lib/synthra/scenarios.rb +423 -0
  169. data/lib/synthra/schema.rb +605 -0
  170. data/lib/synthra/schema_inheritance.rb +104 -0
  171. data/lib/synthra/schema_versioning.rb +212 -0
  172. data/lib/synthra/snapshot_testing.rb +199 -0
  173. data/lib/synthra/time_travel.rb +338 -0
  174. data/lib/synthra/type_definitions.rb +274 -0
  175. data/lib/synthra/types/address_location/addresses.rb +125 -0
  176. data/lib/synthra/types/address_location/airports.rb +200 -0
  177. data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
  178. data/lib/synthra/types/address_location/locations.rb +406 -0
  179. data/lib/synthra/types/base.rb +48 -0
  180. data/lib/synthra/types/commerce_products/commerce.rb +119 -0
  181. data/lib/synthra/types/commerce_products/companies.rb +71 -0
  182. data/lib/synthra/types/commerce_products/construction.rb +126 -0
  183. data/lib/synthra/types/commerce_products/products.rb +205 -0
  184. data/lib/synthra/types/core/collections.rb +513 -0
  185. data/lib/synthra/types/core/defaults.rb +76 -0
  186. data/lib/synthra/types/core/enums.rb +102 -0
  187. data/lib/synthra/types/core/identifiers.rb +445 -0
  188. data/lib/synthra/types/core/primitives.rb +586 -0
  189. data/lib/synthra/types/core/references.rb +466 -0
  190. data/lib/synthra/types/core/sequences.rb +304 -0
  191. data/lib/synthra/types/crypto/crypto.rb +162 -0
  192. data/lib/synthra/types/date_time/dates.rb +387 -0
  193. data/lib/synthra/types/finance_banking/banking.rb +424 -0
  194. data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
  195. data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
  196. data/lib/synthra/types/formula.rb +184 -0
  197. data/lib/synthra/types/health_medical/medical.rb +150 -0
  198. data/lib/synthra/types/hostile_payloads.rb +122 -0
  199. data/lib/synthra/types/json_array.rb +51 -0
  200. data/lib/synthra/types/media_entertainment/media.rb +62 -0
  201. data/lib/synthra/types/naughty_string.rb +30 -0
  202. data/lib/synthra/types/personal_names/chinese.rb +41 -0
  203. data/lib/synthra/types/personal_names/identifiers.rb +187 -0
  204. data/lib/synthra/types/personal_names/names.rb +246 -0
  205. data/lib/synthra/types/personal_names/national_id.rb +89 -0
  206. data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
  207. data/lib/synthra/types/regex.rb +248 -0
  208. data/lib/synthra/types/registry.rb +182 -0
  209. data/lib/synthra/types/repeating_element.rb +50 -0
  210. data/lib/synthra/types/scenario.rb +29 -0
  211. data/lib/synthra/types/technology_internet/apps.rb +67 -0
  212. data/lib/synthra/types/technology_internet/communication.rb +162 -0
  213. data/lib/synthra/types/technology_internet/devices.rb +80 -0
  214. data/lib/synthra/types/technology_internet/formats.rb +139 -0
  215. data/lib/synthra/types/technology_internet/networking.rb +143 -0
  216. data/lib/synthra/types/template.rb +92 -0
  217. data/lib/synthra/types/text_content/business.rb +128 -0
  218. data/lib/synthra/types/text_content/colors.rb +70 -0
  219. data/lib/synthra/types/text_content/misc.rb +237 -0
  220. data/lib/synthra/types/text_content/security.rb +130 -0
  221. data/lib/synthra/types/text_content/text_generation.rb +532 -0
  222. data/lib/synthra/types/travel/travel.rb +150 -0
  223. data/lib/synthra/utils/string_distance.rb +133 -0
  224. data/lib/synthra/validator/dsl_validator.rb +339 -0
  225. data/lib/synthra/validator/path_validator.rb +615 -0
  226. data/lib/synthra/version.rb +35 -0
  227. data/lib/synthra/webhook_simulator.rb +341 -0
  228. data/lib/synthra.rb +259 -0
  229. data/schemas/address.dsl +16 -0
  230. data/schemas/api_response.dsl +8 -0
  231. data/schemas/error_payload.dsl +9 -0
  232. data/schemas/order.dsl +10 -0
  233. data/schemas/order_item.dsl +8 -0
  234. data/schemas/payment.dsl +11 -0
  235. data/schemas/social_post.dsl +13 -0
  236. data/schemas/user.dsl +10 -0
  237. data/scripts/batch_fix_all.rb +96 -0
  238. data/scripts/delete_old_files.rb +32 -0
  239. data/scripts/fix_all_grouped_files.rb +137 -0
  240. data/scripts/fix_all_indentation.rb +48 -0
  241. data/scripts/fix_all_syntax.rb +124 -0
  242. data/scripts/fix_grouped_files.rb +184 -0
  243. data/scripts/fix_syntax_errors.rb +108 -0
  244. data/scripts/group_domain_types.rb +112 -0
  245. data/scripts/group_domain_types_fixed.rb +150 -0
  246. data/scripts/merge_domains_to_one_file.rb +68 -0
  247. data/scripts/move_existing_types.rb +130 -0
  248. data/scripts/split_grouped_types.rb +142 -0
  249. data/tech_docs/README.md +134 -0
  250. data/tech_docs/advanced/streaming.md +405 -0
  251. data/tech_docs/advanced/thread_safety.md +253 -0
  252. data/tech_docs/api/overview.md +485 -0
  253. data/tech_docs/appendices/type_chart.md +193 -0
  254. data/tech_docs/basic_concepts.md +383 -0
  255. data/tech_docs/behaviors/overview.md +346 -0
  256. data/tech_docs/dsl/complex_types.md +790 -0
  257. data/tech_docs/dsl/core_types.md +464 -0
  258. data/tech_docs/dsl/datetime_types.md +325 -0
  259. data/tech_docs/dsl/field_modifiers.md +414 -0
  260. data/tech_docs/dsl/grammar.md +431 -0
  261. data/tech_docs/dsl/schema_definition.md +399 -0
  262. data/tech_docs/export/README.md +276 -0
  263. data/tech_docs/installation.md +273 -0
  264. data/tech_docs/integration/ci_cd.md +707 -0
  265. data/tech_docs/integration/ci_cd_guide.md +579 -0
  266. data/tech_docs/integration/factory_bot.md +485 -0
  267. data/tech_docs/integration/rails.md +630 -0
  268. data/tech_docs/integration/rspec.md +449 -0
  269. data/tech_docs/modes/overview.md +350 -0
  270. data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
  271. data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
  272. data/tech_docs/quick_start.md +256 -0
  273. data/tech_docs/templates/README.md +805 -0
  274. data/tech_docs/tutorials/advanced.md +371 -0
  275. data/tech_docs/tutorials/getting_started.md +189 -0
  276. data/tech_docs/tutorials/intermediate.md +231 -0
  277. data/tech_docs/tutorials/template_gallery.md +569 -0
  278. data/tech_example/01_basic_usage.rb +238 -0
  279. data/tech_example/02_types_demo.rb +336 -0
  280. data/tech_example/04_cli_usage.md +429 -0
  281. data/tech_example/05_database_seeding.rb +283 -0
  282. data/tech_example/07_rspec_integration.rb +359 -0
  283. data/tech_example/10_custom_types.rb +387 -0
  284. data/tech_example/12_behaviors.rb +372 -0
  285. data/tech_example/13_twitter_dm_example.rb +120 -0
  286. data/tech_example/14_exact_json_structure.rb +253 -0
  287. data/tech_example/16_lsp_server.rb +56 -0
  288. data/tech_example/17_property_testing.rb +92 -0
  289. data/tech_example/18_enhanced_repl.rb +120 -0
  290. data/tech_example/19_security_fuzzing.rb +145 -0
  291. data/tech_example/NEW_FEATURES.md +169 -0
  292. data/tech_example/README.md +118 -0
  293. data/tech_example/schemas/api_response.dsl +123 -0
  294. data/tech_example/schemas/ecommerce.dsl +121 -0
  295. data/tech_example/schemas/twitter_dm.dsl +109 -0
  296. data/tech_example/schemas/user.dsl +36 -0
  297. data/vscode-extension/README.md +246 -0
  298. data/vscode-extension/language-configuration.json +31 -0
  299. data/vscode-extension/package.json +55 -0
  300. data/vscode-extension/snippets/fakedatadsl.json +198 -0
  301. data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
  302. metadata +478 -0
@@ -0,0 +1,524 @@
1
+ # ActiveRecord Schema Inference
2
+
3
+ FakeDataDSL can **automatically infer DSL schemas from your ActiveRecord models**, eliminating the need to manually define schemas for existing database tables.
4
+
5
+ ## Quick Start
6
+
7
+ ```ruby
8
+ # Infer schema from a single model
9
+ schema = FakeDataDSL::ActiveRecordInference.infer(User)
10
+
11
+ # Infer schemas from all models
12
+ FakeDataDSL::ActiveRecordInference.discover_all!
13
+
14
+ # Generate fake data directly from model
15
+ user_data = FakeDataDSL.from_model(User).generate
16
+ ```
17
+
18
+ ## Basic Usage
19
+
20
+ ### Single Model Inference
21
+
22
+ ```ruby
23
+ # Given an ActiveRecord model:
24
+ class User < ApplicationRecord
25
+ # Table: users
26
+ # Columns: id (uuid), name (string), email (string),
27
+ # age (integer), active (boolean), created_at (datetime)
28
+ end
29
+
30
+ # Infer the schema
31
+ schema = FakeDataDSL::ActiveRecordInference.infer(User)
32
+
33
+ # The inferred schema is equivalent to:
34
+ # User:
35
+ # id: uuid
36
+ # name: name
37
+ # email: email
38
+ # age: number
39
+ # active: boolean
40
+ # created_at: timestamp
41
+ ```
42
+
43
+ ### Generate from Model
44
+
45
+ ```ruby
46
+ # Direct generation (no schema file needed)
47
+ user = FakeDataDSL.from_model(User).generate
48
+ # => { id: "550e8400-...", name: "John Doe", email: "john@example.com", ... }
49
+
50
+ # Generate multiple
51
+ users = FakeDataDSL.from_model(User).generate_many(10)
52
+
53
+ # With overrides
54
+ admin = FakeDataDSL.from_model(User).generate(role: "admin")
55
+ ```
56
+
57
+ ## Smart Type Inference
58
+
59
+ ### Column Name Patterns
60
+
61
+ The inference engine uses column names to determine appropriate types:
62
+
63
+ | Column Pattern | Inferred Type |
64
+ |----------------|---------------|
65
+ | `*email*` | `email` |
66
+ | `*phone*`, `*mobile*` | `phone` |
67
+ | `*url*`, `*website*`, `*link*` | `url` |
68
+ | `*password*` | `password` |
69
+ | `*name*` | `name` |
70
+ | `*first_name*` | `first_name` |
71
+ | `*last_name*` | `last_name` |
72
+ | `*address*` | `address` |
73
+ | `*city*` | `city` |
74
+ | `*country*` | `country` |
75
+ | `*zip*`, `*postal*` | `zip_code` |
76
+ | `*latitude*`, `*lat*` | `latitude` |
77
+ | `*longitude*`, `*lng*` | `longitude` |
78
+ | `*avatar*`, `*image*`, `*photo*` | `image_url` |
79
+ | `*description*`, `*bio*`, `*about*` | `paragraph` |
80
+ | `*title*`, `*subject*` | `sentence` |
81
+ | `*company*`, `*organization*` | `company` |
82
+ | `*ip*` | `ip_address` |
83
+ | `*token*`, `*api_key*` | `secure_token` |
84
+ | `*uuid*` | `uuid` |
85
+ | `*slug*` | `slug` |
86
+ | `*color*` | `hex_color` |
87
+
88
+ ### Column Type Mapping
89
+
90
+ | ActiveRecord Type | DSL Type |
91
+ |-------------------|----------|
92
+ | `string` | `text` |
93
+ | `text` | `paragraph` |
94
+ | `integer` | `number` |
95
+ | `bigint` | `number` |
96
+ | `float` | `float` |
97
+ | `decimal` | `money` |
98
+ | `boolean` | `boolean` |
99
+ | `date` | `date` |
100
+ | `datetime` | `timestamp` |
101
+ | `time` | `time` |
102
+ | `uuid` | `uuid` |
103
+ | `json`, `jsonb` | `json` |
104
+ | `binary` | `binary` |
105
+ | `inet` | `ip_address` |
106
+
107
+ ## Association Inference
108
+
109
+ ### Belongs To
110
+
111
+ ```ruby
112
+ class Order < ApplicationRecord
113
+ belongs_to :user
114
+ belongs_to :product
115
+ end
116
+
117
+ schema = FakeDataDSL::ActiveRecordInference.infer(Order)
118
+ # Generates:
119
+ # Order:
120
+ # user_id: Ref(User.id)
121
+ # product_id: Ref(Product.id)
122
+ ```
123
+
124
+ ### Has Many / Has One
125
+
126
+ ```ruby
127
+ class User < ApplicationRecord
128
+ has_many :orders
129
+ has_one :profile
130
+ end
131
+
132
+ # By default, has_many/has_one are not included in the schema
133
+ # Use options to include them:
134
+ schema = FakeDataDSL::ActiveRecordInference.infer(User, include_associations: true)
135
+ # Generates:
136
+ # User:
137
+ # orders: array(Order, 0..5)
138
+ # profile: Profile?
139
+ ```
140
+
141
+ ### Polymorphic Associations
142
+
143
+ ```ruby
144
+ class Comment < ApplicationRecord
145
+ belongs_to :commentable, polymorphic: true
146
+ end
147
+
148
+ schema = FakeDataDSL::ActiveRecordInference.infer(Comment)
149
+ # Generates:
150
+ # Comment:
151
+ # commentable_type: enum(Post, Article, Video)
152
+ # commentable_id: uuid
153
+ ```
154
+
155
+ ## Validation Inference
156
+
157
+ ### Presence Validations
158
+
159
+ ```ruby
160
+ class User < ApplicationRecord
161
+ validates :name, presence: true
162
+ validates :bio, presence: false # Optional
163
+ end
164
+
165
+ schema = FakeDataDSL::ActiveRecordInference.infer(User)
166
+ # Generates:
167
+ # User:
168
+ # name: name # Required (no ?)
169
+ # bio: paragraph? # Optional (has ?)
170
+ ```
171
+
172
+ ### Numericality Validations
173
+
174
+ ```ruby
175
+ class Product < ApplicationRecord
176
+ validates :price, numericality: { greater_than: 0, less_than: 10000 }
177
+ validates :quantity, numericality: { only_integer: true, in: 0..1000 }
178
+ end
179
+
180
+ schema = FakeDataDSL::ActiveRecordInference.infer(Product)
181
+ # Generates:
182
+ # Product:
183
+ # price: money(range: 0.01..9999.99)
184
+ # quantity: number(0..1000)
185
+ ```
186
+
187
+ ### Inclusion Validations
188
+
189
+ ```ruby
190
+ class User < ApplicationRecord
191
+ validates :role, inclusion: { in: %w[user admin moderator] }
192
+ validates :status, inclusion: { in: %w[active inactive pending] }
193
+ end
194
+
195
+ schema = FakeDataDSL::ActiveRecordInference.infer(User)
196
+ # Generates:
197
+ # User:
198
+ # role: enum(user, admin, moderator)
199
+ # status: enum(active, inactive, pending)
200
+ ```
201
+
202
+ ### Length Validations
203
+
204
+ ```ruby
205
+ class Post < ApplicationRecord
206
+ validates :title, length: { minimum: 5, maximum: 100 }
207
+ validates :body, length: { minimum: 50 }
208
+ end
209
+
210
+ schema = FakeDataDSL::ActiveRecordInference.infer(Post)
211
+ # Generates:
212
+ # Post:
213
+ # title: text(length: 5..100)
214
+ # body: paragraph(min_length: 50)
215
+ ```
216
+
217
+ ### Format Validations
218
+
219
+ ```ruby
220
+ class User < ApplicationRecord
221
+ validates :username, format: { with: /\A[a-z0-9_]+\z/ }
222
+ end
223
+
224
+ schema = FakeDataDSL::ActiveRecordInference.infer(User)
225
+ # Generates:
226
+ # User:
227
+ # username: regex("[a-z0-9_]+")
228
+ ```
229
+
230
+ ## Enum Inference
231
+
232
+ ```ruby
233
+ class Order < ApplicationRecord
234
+ enum status: { pending: 0, processing: 1, shipped: 2, delivered: 3 }
235
+ enum priority: [:low, :medium, :high]
236
+ end
237
+
238
+ schema = FakeDataDSL::ActiveRecordInference.infer(Order)
239
+ # Generates:
240
+ # Order:
241
+ # status: enum(pending, processing, shipped, delivered)
242
+ # priority: enum(low, medium, high)
243
+ ```
244
+
245
+ ## Discovery Options
246
+
247
+ ### Full Discovery
248
+
249
+ ```ruby
250
+ # Discover all models in app/models
251
+ FakeDataDSL::ActiveRecordInference.discover_all!
252
+
253
+ # With options
254
+ FakeDataDSL::ActiveRecordInference.discover_all!(
255
+ include_sti: true, # Include STI subclasses
256
+ include_concerns: false, # Skip models with only concerns
257
+ exclude: [AdminUser, Audit], # Skip specific models
258
+ namespace: "App::Models" # Only discover in namespace
259
+ )
260
+ ```
261
+
262
+ ### Single Model Options
263
+
264
+ ```ruby
265
+ schema = FakeDataDSL::ActiveRecordInference.infer(User,
266
+ include_associations: true, # Include has_many, has_one
267
+ include_validations: true, # Infer from validations
268
+ include_timestamps: true, # Include created_at, updated_at
269
+ skip_columns: [:password_digest, :encrypted_password],
270
+ custom_mappings: {
271
+ "legacy_id" => "number",
272
+ "metadata" => "json"
273
+ }
274
+ )
275
+ ```
276
+
277
+ ## Custom Type Mappings
278
+
279
+ ### Global Mappings
280
+
281
+ ```ruby
282
+ # config/initializers/fake_data_dsl.rb
283
+ FakeDataDSL::ActiveRecordInference.configure do |config|
284
+ # Add custom column name patterns
285
+ config.column_patterns = {
286
+ /ssn|social_security/i => "ssn",
287
+ /iban/i => "iban",
288
+ /credit_card/i => "credit_card"
289
+ }
290
+
291
+ # Add custom type mappings
292
+ config.type_mappings = {
293
+ "citext" => "text",
294
+ "hstore" => "json"
295
+ }
296
+ end
297
+ ```
298
+
299
+ ### Per-Model Mappings
300
+
301
+ ```ruby
302
+ schema = FakeDataDSL::ActiveRecordInference.infer(User,
303
+ custom_mappings: {
304
+ "legacy_status" => "enum(active, inactive)",
305
+ "settings" => "json"
306
+ }
307
+ )
308
+ ```
309
+
310
+ ## Saving Inferred Schemas
311
+
312
+ ### To File
313
+
314
+ ```ruby
315
+ # Save single schema
316
+ schema = FakeDataDSL::ActiveRecordInference.infer(User)
317
+ schema.save_to("db/schemas/user.dsl")
318
+
319
+ # Save all discovered schemas
320
+ FakeDataDSL::ActiveRecordInference.discover_all!
321
+ FakeDataDSL.save_all_schemas("db/schemas/")
322
+ ```
323
+
324
+ ### Generated Schema Format
325
+
326
+ ```ruby
327
+ # db/schemas/user.dsl (auto-generated)
328
+ # Generated from User model on 2026-01-24
329
+ # Do not edit manually - regenerate with:
330
+ # rails generate fake_data_dsl:schema User
331
+
332
+ User:
333
+ @inferred_from ActiveRecord::User
334
+
335
+ id: uuid
336
+ name: name
337
+ email: email @unique
338
+ role: enum(user, admin, moderator)
339
+ active: boolean(true:90%)
340
+ profile_id: Ref(Profile.id)?
341
+ created_at: timestamp
342
+ updated_at: timestamp
343
+ ```
344
+
345
+ ## Rails Generator
346
+
347
+ ### Generate Schema from Model
348
+
349
+ ```bash
350
+ # Generate schema for User model
351
+ rails generate fake_data_dsl:schema User
352
+
353
+ # Generate for multiple models
354
+ rails generate fake_data_dsl:schema User Order Product
355
+
356
+ # Generate for all models
357
+ rails generate fake_data_dsl:schema --all
358
+
359
+ # With options
360
+ rails generate fake_data_dsl:schema User --include-associations --skip-timestamps
361
+ ```
362
+
363
+ ### Generator Options
364
+
365
+ | Option | Description |
366
+ |--------|-------------|
367
+ | `--include-associations` | Include has_many/has_one |
368
+ | `--skip-timestamps` | Exclude created_at/updated_at |
369
+ | `--skip-validations` | Don't infer from validations |
370
+ | `--output-dir DIR` | Output directory (default: db/schemas) |
371
+ | `--force` | Overwrite existing files |
372
+
373
+ ## Bidirectional Sync
374
+
375
+ ### Schema → Model Comparison
376
+
377
+ ```ruby
378
+ # Compare inferred schema with existing schema file
379
+ diff = FakeDataDSL::ActiveRecordInference.compare(User, "db/schemas/user.dsl")
380
+
381
+ diff.added_fields # Fields in model but not schema
382
+ diff.removed_fields # Fields in schema but not model
383
+ diff.changed_fields # Fields with different types
384
+ ```
385
+
386
+ ### Auto-Update Schemas
387
+
388
+ ```ruby
389
+ # Update schema file to match model
390
+ FakeDataDSL::ActiveRecordInference.sync!(User, "db/schemas/user.dsl")
391
+
392
+ # Sync all schemas
393
+ FakeDataDSL::ActiveRecordInference.sync_all!("db/schemas/")
394
+ ```
395
+
396
+ ## Rake Tasks
397
+
398
+ ```bash
399
+ # Infer schema for a model
400
+ rake fake_data_dsl:infer[User]
401
+
402
+ # Infer all models
403
+ rake fake_data_dsl:infer:all
404
+
405
+ # Compare schemas with models
406
+ rake fake_data_dsl:compare
407
+
408
+ # Sync schemas with models
409
+ rake fake_data_dsl:sync
410
+ ```
411
+
412
+ ## API Reference
413
+
414
+ ### ActiveRecordInference.infer
415
+
416
+ ```ruby
417
+ FakeDataDSL::ActiveRecordInference.infer(model, options = {})
418
+ ```
419
+
420
+ **Parameters:**
421
+ - `model` - ActiveRecord model class
422
+ - `options` - Hash of options
423
+
424
+ **Options:**
425
+ - `:include_associations` - Include has_many/has_one (default: false)
426
+ - `:include_validations` - Infer from validations (default: true)
427
+ - `:include_timestamps` - Include created_at/updated_at (default: true)
428
+ - `:skip_columns` - Array of columns to skip
429
+ - `:custom_mappings` - Hash of column => type mappings
430
+
431
+ **Returns:** `FakeDataDSL::Schema`
432
+
433
+ ### ActiveRecordInference.discover_all!
434
+
435
+ ```ruby
436
+ FakeDataDSL::ActiveRecordInference.discover_all!(options = {})
437
+ ```
438
+
439
+ **Parameters:**
440
+ - `options` - Hash of options
441
+
442
+ **Options:**
443
+ - `:include_sti` - Include STI subclasses (default: false)
444
+ - `:exclude` - Array of models to skip
445
+ - `:namespace` - Only discover in namespace
446
+
447
+ **Returns:** Array of registered schema names
448
+
449
+ ## Best Practices
450
+
451
+ ### 1. Version Control Inferred Schemas
452
+
453
+ ```ruby
454
+ # Keep generated schemas in version control
455
+ # db/schemas/user.dsl
456
+ ```
457
+
458
+ ### 2. Override Smart Inference
459
+
460
+ ```ruby
461
+ # When inference isn't perfect, add manual overrides
462
+ schema = FakeDataDSL::ActiveRecordInference.infer(User,
463
+ custom_mappings: {
464
+ "legacy_code" => "regex('[A-Z]{3}[0-9]{4}')"
465
+ }
466
+ )
467
+ ```
468
+
469
+ ### 3. Use Comments for Clarity
470
+
471
+ Generated schemas include comments:
472
+
473
+ ```ruby
474
+ # db/schemas/user.dsl
475
+ # Generated from User model
476
+ # Last updated: 2026-01-24
477
+
478
+ User:
479
+ # Primary key
480
+ id: uuid
481
+
482
+ # User identity
483
+ name: name
484
+ email: email @unique
485
+ ```
486
+
487
+ ## Troubleshooting
488
+
489
+ ### Model Not Found
490
+
491
+ ```ruby
492
+ # Ensure model is loaded
493
+ Rails.application.eager_load!
494
+
495
+ # Then infer
496
+ FakeDataDSL::ActiveRecordInference.infer(User)
497
+ ```
498
+
499
+ ### Wrong Type Inferred
500
+
501
+ ```ruby
502
+ # Use custom mapping
503
+ schema = FakeDataDSL::ActiveRecordInference.infer(User,
504
+ custom_mappings: {
505
+ "status_code" => "number(100..599)" # Not inferred as enum
506
+ }
507
+ )
508
+ ```
509
+
510
+ ### Missing Associations
511
+
512
+ ```ruby
513
+ # Enable association inference
514
+ schema = FakeDataDSL::ActiveRecordInference.infer(User,
515
+ include_associations: true
516
+ )
517
+ ```
518
+
519
+ ## See Also
520
+
521
+ - [Rails Engine](RAILS_ENGINE.md)
522
+ - [DSL Reference](dsl_reference.md)
523
+ - [Migration Generator](MIGRATION_GENERATOR.md)
524
+ - [Type Reference](type_reference.md)