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,547 @@
1
+ # Schema Migration Generator
2
+
3
+ FakeDataDSL can generate **ActiveRecord migrations** from your DSL schemas, keeping your database in sync with your data definitions. When schemas evolve, generate diff-based migrations automatically.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Generate migration from schema
9
+ fake_data_dsl migrate schemas/user.dsl -o db/migrate/
10
+
11
+ # Generate diff migration between versions
12
+ fake_data_dsl migrate --diff schemas/v1/user.dsl schemas/v2/user.dsl -o db/migrate/
13
+ ```
14
+
15
+ ```ruby
16
+ # Ruby API
17
+ schema = FakeDataDSL.load("schemas/user.dsl")
18
+ migration = FakeDataDSL::MigrationGenerator.create_table(schema)
19
+ puts migration
20
+ ```
21
+
22
+ ## Basic Usage
23
+
24
+ ### Generate Create Table Migration
25
+
26
+ ```ruby
27
+ # Input schema (user.dsl)
28
+ # User:
29
+ # id: uuid
30
+ # name: name
31
+ # email: email @unique
32
+ # role: enum(user, admin, moderator)
33
+ # active: boolean
34
+ # profile: Profile?
35
+ # created_at: timestamp
36
+ # updated_at: timestamp
37
+
38
+ schema = FakeDataDSL.load("schemas/user.dsl")
39
+ migration = FakeDataDSL::MigrationGenerator.create_table(schema)
40
+ ```
41
+
42
+ Output:
43
+
44
+ ```ruby
45
+ class CreateUsers < ActiveRecord::Migration[7.1]
46
+ def change
47
+ create_table :users, id: :uuid do |t|
48
+ t.string :name, null: false
49
+ t.string :email, null: false
50
+ t.string :role, null: false, default: 'user'
51
+ t.boolean :active, null: false, default: true
52
+ t.references :profile, type: :uuid, foreign_key: true
53
+
54
+ t.timestamps
55
+ end
56
+
57
+ add_index :users, :email, unique: true
58
+ add_index :users, :role
59
+ end
60
+ end
61
+ ```
62
+
63
+ ### Generate from Multiple Schemas
64
+
65
+ ```ruby
66
+ schemas = FakeDataDSL.load_all("schemas/")
67
+ migrations = FakeDataDSL::MigrationGenerator.from_files(schemas)
68
+
69
+ migrations.each do |name, content|
70
+ File.write("db/migrate/#{timestamp}_create_#{name}.rb", content)
71
+ end
72
+ ```
73
+
74
+ ## Type Mapping
75
+
76
+ ### DSL to ActiveRecord Types
77
+
78
+ | DSL Type | ActiveRecord Type | Column Options |
79
+ |----------|-------------------|----------------|
80
+ | `uuid` | `:uuid` | primary key or reference |
81
+ | `text` | `:string` | |
82
+ | `paragraph` | `:text` | |
83
+ | `number` | `:integer` | |
84
+ | `number(min..max)` | `:integer` | limit based on range |
85
+ | `float` | `:float` | |
86
+ | `money` | `:decimal` | precision: 10, scale: 2 |
87
+ | `boolean` | `:boolean` | |
88
+ | `date` | `:date` | |
89
+ | `timestamp` | `:datetime` | |
90
+ | `time` | `:time` | |
91
+ | `email` | `:string` | with email index |
92
+ | `phone` | `:string` | |
93
+ | `url` | `:string` | |
94
+ | `ip_address` | `:inet` | (PostgreSQL) |
95
+ | `json` | `:jsonb` | (PostgreSQL) |
96
+ | `enum(...)` | `:string` | with check constraint |
97
+ | `array(...)` | `:string[]` | (PostgreSQL) or `:text` |
98
+
99
+ ### Custom Type Mappings
100
+
101
+ ```ruby
102
+ FakeDataDSL::MigrationGenerator.configure do |config|
103
+ config.type_mappings = {
104
+ "money" => { type: :decimal, precision: 15, scale: 4 },
105
+ "slug" => { type: :string, limit: 255 },
106
+ "ip_address" => { type: :inet } # PostgreSQL only
107
+ }
108
+ end
109
+ ```
110
+
111
+ ## Constraints and Indexes
112
+
113
+ ### From Annotations
114
+
115
+ ```ruby
116
+ # In DSL
117
+ User:
118
+ id: uuid
119
+ email: email @unique
120
+ username: text @unique @indexed
121
+ role: enum(user, admin) @indexed
122
+ tenant_id: uuid @indexed
123
+ ```
124
+
125
+ Output includes:
126
+
127
+ ```ruby
128
+ add_index :users, :email, unique: true
129
+ add_index :users, :username, unique: true
130
+ add_index :users, :role
131
+ add_index :users, :tenant_id
132
+ ```
133
+
134
+ ### Composite Indexes
135
+
136
+ ```ruby
137
+ # In DSL
138
+ Order:
139
+ user_id: Ref(User.id) @indexed
140
+ created_at: timestamp
141
+
142
+ @index [:user_id, :created_at]
143
+ ```
144
+
145
+ Output:
146
+
147
+ ```ruby
148
+ add_index :orders, [:user_id, :created_at]
149
+ ```
150
+
151
+ ### Foreign Keys
152
+
153
+ ```ruby
154
+ # In DSL
155
+ Order:
156
+ user_id: Ref(User.id)
157
+ product_id: Ref(Product.id)
158
+ ```
159
+
160
+ Output:
161
+
162
+ ```ruby
163
+ t.references :user, type: :uuid, foreign_key: true, null: false
164
+ t.references :product, type: :uuid, foreign_key: true, null: false
165
+ ```
166
+
167
+ ## Schema Evolution
168
+
169
+ ### Diff-Based Migrations
170
+
171
+ When your schema changes, generate a migration for just the differences:
172
+
173
+ ```ruby
174
+ old_schema = FakeDataDSL.load("schemas/v1/user.dsl")
175
+ new_schema = FakeDataDSL.load("schemas/v2/user.dsl")
176
+
177
+ migration = FakeDataDSL::MigrationGenerator.diff(old_schema, new_schema)
178
+ ```
179
+
180
+ Example diff:
181
+
182
+ ```ruby
183
+ # v1
184
+ User:
185
+ id: uuid
186
+ name: name
187
+ email: email
188
+
189
+ # v2 (added avatar_url, removed legacy_field, changed age type)
190
+ User:
191
+ id: uuid
192
+ name: name
193
+ email: email
194
+ avatar_url: url
195
+ age: number # was: text
196
+ ```
197
+
198
+ Generated migration:
199
+
200
+ ```ruby
201
+ class MigrateUsersV1ToV2 < ActiveRecord::Migration[7.1]
202
+ def change
203
+ # Added columns
204
+ add_column :users, :avatar_url, :string
205
+
206
+ # Changed columns
207
+ change_column :users, :age, :integer
208
+
209
+ # Removed columns
210
+ remove_column :users, :legacy_field, :string
211
+ end
212
+ end
213
+ ```
214
+
215
+ ### Safe Migrations
216
+
217
+ For production-safe migrations:
218
+
219
+ ```ruby
220
+ migration = FakeDataDSL::MigrationGenerator.diff(old_schema, new_schema,
221
+ safe_mode: true
222
+ )
223
+ ```
224
+
225
+ Output with safety:
226
+
227
+ ```ruby
228
+ class MigrateUsersV1ToV2 < ActiveRecord::Migration[7.1]
229
+ # Disable DDL transactions for safety
230
+ disable_ddl_transaction!
231
+
232
+ def change
233
+ # Added columns (safe - no lock)
234
+ add_column :users, :avatar_url, :string
235
+
236
+ # Changed columns (may lock - add concurrently)
237
+ safety_assured do
238
+ change_column :users, :age, :integer
239
+ end
240
+
241
+ # Removed columns (safe - just marks as ignored)
242
+ safety_assured do
243
+ remove_column :users, :legacy_field, :string
244
+ end
245
+ end
246
+ end
247
+ ```
248
+
249
+ ## CLI Commands
250
+
251
+ ### Create Table
252
+
253
+ ```bash
254
+ # Single schema
255
+ fake_data_dsl migrate schemas/user.dsl -o db/migrate/
256
+
257
+ # All schemas in directory
258
+ fake_data_dsl migrate schemas/ --all -o db/migrate/
259
+
260
+ # With custom timestamp
261
+ fake_data_dsl migrate schemas/user.dsl -o db/migrate/ --timestamp 20260124120000
262
+ ```
263
+
264
+ ### Diff Migration
265
+
266
+ ```bash
267
+ # From two files
268
+ fake_data_dsl migrate --diff schemas/v1/user.dsl schemas/v2/user.dsl
269
+
270
+ # From git history
271
+ fake_data_dsl migrate --diff HEAD~1:schemas/user.dsl schemas/user.dsl
272
+
273
+ # Safe mode for production
274
+ fake_data_dsl migrate --diff old.dsl new.dsl --safe
275
+ ```
276
+
277
+ ### Options
278
+
279
+ | Option | Description |
280
+ |--------|-------------|
281
+ | `-o, --output DIR` | Output directory |
282
+ | `--timestamp TIME` | Migration timestamp |
283
+ | `--safe` | Generate safe migrations |
284
+ | `--dry-run` | Preview without writing |
285
+ | `--rails-version VER` | Rails/AR version (default: 7.1) |
286
+ | `--db-adapter ADAPTER` | Database adapter (postgresql, mysql, sqlite) |
287
+
288
+ ## Database-Specific Features
289
+
290
+ ### PostgreSQL
291
+
292
+ ```ruby
293
+ FakeDataDSL::MigrationGenerator.configure do |config|
294
+ config.database = :postgresql
295
+ end
296
+
297
+ # Enables:
298
+ # - UUID columns without extension (native in PG 13+)
299
+ # - JSONB columns
300
+ # - Array columns
301
+ # - Inet/Cidr columns
302
+ # - Enum types (native)
303
+ ```
304
+
305
+ Example with PostgreSQL features:
306
+
307
+ ```ruby
308
+ # In DSL
309
+ Product:
310
+ id: uuid
311
+ tags: array(text)
312
+ metadata: json
313
+ status: enum(draft, published, archived) @pg_enum
314
+
315
+ # Output
316
+ class CreateProducts < ActiveRecord::Migration[7.1]
317
+ def change
318
+ create_enum :product_status, %w[draft published archived]
319
+
320
+ create_table :products, id: :uuid do |t|
321
+ t.string :tags, array: true, default: []
322
+ t.jsonb :metadata, default: {}
323
+ t.enum :status, enum_type: :product_status, default: 'draft'
324
+ end
325
+ end
326
+ end
327
+ ```
328
+
329
+ ### MySQL
330
+
331
+ ```ruby
332
+ FakeDataDSL::MigrationGenerator.configure do |config|
333
+ config.database = :mysql
334
+ end
335
+
336
+ # Differences:
337
+ # - UUID stored as CHAR(36)
338
+ # - JSON instead of JSONB
339
+ # - No native arrays (serialized)
340
+ # - ENUM as native MySQL enum
341
+ ```
342
+
343
+ ### SQLite
344
+
345
+ ```ruby
346
+ FakeDataDSL::MigrationGenerator.configure do |config|
347
+ config.database = :sqlite
348
+ end
349
+
350
+ # Differences:
351
+ # - UUID stored as TEXT
352
+ # - JSON stored as TEXT
353
+ # - No native arrays
354
+ # - ENUM as TEXT with check constraint
355
+ ```
356
+
357
+ ## Rails Generator
358
+
359
+ ### Installation
360
+
361
+ ```bash
362
+ rails generate fake_data_dsl:install
363
+ ```
364
+
365
+ ### Generate Migration from Schema
366
+
367
+ ```bash
368
+ # From existing schema file
369
+ rails generate fake_data_dsl:migration User
370
+
371
+ # Creates: db/migrate/TIMESTAMP_create_users.rb
372
+ ```
373
+
374
+ ### Generate Migration from Model
375
+
376
+ ```bash
377
+ # Infer from ActiveRecord model and create diff
378
+ rails generate fake_data_dsl:sync_migration User
379
+
380
+ # Creates migration for any differences between model and schema
381
+ ```
382
+
383
+ ## API Reference
384
+
385
+ ### MigrationGenerator.create_table
386
+
387
+ ```ruby
388
+ FakeDataDSL::MigrationGenerator.create_table(schema, options = {})
389
+ ```
390
+
391
+ **Parameters:**
392
+ - `schema` - Schema object
393
+ - `options[:table_name]` - Override table name
394
+ - `options[:id_type]` - ID column type (:uuid, :bigint)
395
+ - `options[:timestamps]` - Include timestamps (default: true)
396
+ - `options[:rails_version]` - Rails version string
397
+
398
+ **Returns:** String containing migration code
399
+
400
+ ### MigrationGenerator.diff
401
+
402
+ ```ruby
403
+ FakeDataDSL::MigrationGenerator.diff(old_schema, new_schema, options = {})
404
+ ```
405
+
406
+ **Parameters:**
407
+ - `old_schema` - Previous schema version
408
+ - `new_schema` - New schema version
409
+ - `options[:safe_mode]` - Generate production-safe migration
410
+ - `options[:migration_name]` - Custom migration class name
411
+
412
+ **Returns:** String containing migration code
413
+
414
+ ### MigrationGenerator.from_files
415
+
416
+ ```ruby
417
+ FakeDataDSL::MigrationGenerator.from_files(schemas, options = {})
418
+ ```
419
+
420
+ **Parameters:**
421
+ - `schemas` - Array of Schema objects
422
+ - `options[:output_dir]` - Output directory
423
+ - `options[:order]` - :alphabetical, :dependency (default: :dependency)
424
+
425
+ **Returns:** Hash of { table_name => migration_content }
426
+
427
+ ## Configuration
428
+
429
+ ```ruby
430
+ FakeDataDSL::MigrationGenerator.configure do |config|
431
+ # Database adapter
432
+ config.database = :postgresql # :postgresql, :mysql, :sqlite
433
+
434
+ # Rails/ActiveRecord version
435
+ config.rails_version = "7.1"
436
+
437
+ # ID column type
438
+ config.default_id_type = :uuid # :uuid, :bigint, :integer
439
+
440
+ # Include timestamps by default
441
+ config.include_timestamps = true
442
+
443
+ # Custom type mappings
444
+ config.type_mappings = {
445
+ "money" => { type: :decimal, precision: 15, scale: 4 }
446
+ }
447
+
448
+ # Safe mode by default
449
+ config.safe_mode = Rails.env.production?
450
+
451
+ # Migration template (ERB)
452
+ config.template_path = "lib/templates/migration.erb"
453
+ end
454
+ ```
455
+
456
+ ## Best Practices
457
+
458
+ ### 1. Version Your Schemas
459
+
460
+ ```
461
+ schemas/
462
+ ├── v1/
463
+ │ ├── user.dsl
464
+ │ └── order.dsl
465
+ ├── v2/
466
+ │ ├── user.dsl
467
+ │ └── order.dsl
468
+ └── current/
469
+ ├── user.dsl -> ../v2/user.dsl
470
+ └── order.dsl -> ../v2/order.dsl
471
+ ```
472
+
473
+ ### 2. Review Generated Migrations
474
+
475
+ Always review before running:
476
+
477
+ ```bash
478
+ # Preview first
479
+ fake_data_dsl migrate schemas/user.dsl --dry-run
480
+
481
+ # Then generate
482
+ fake_data_dsl migrate schemas/user.dsl -o db/migrate/
483
+ ```
484
+
485
+ ### 3. Use Safe Mode in Production
486
+
487
+ ```ruby
488
+ # config/initializers/fake_data_dsl.rb
489
+ FakeDataDSL::MigrationGenerator.configure do |config|
490
+ config.safe_mode = Rails.env.production?
491
+ end
492
+ ```
493
+
494
+ ### 4. Keep Schema and Model in Sync
495
+
496
+ ```ruby
497
+ # In CI
498
+ RSpec.describe "Schema Sync" do
499
+ it "schema matches model" do
500
+ User.columns.each do |column|
501
+ expect(user_schema.fields).to include(column.name)
502
+ end
503
+ end
504
+ end
505
+ ```
506
+
507
+ ## Troubleshooting
508
+
509
+ ### Type Mismatch
510
+
511
+ ```ruby
512
+ # Error: Unknown type 'custom_type'
513
+
514
+ # Fix: Add custom mapping
515
+ FakeDataDSL::MigrationGenerator.configure do |config|
516
+ config.type_mappings["custom_type"] = { type: :string }
517
+ end
518
+ ```
519
+
520
+ ### Foreign Key Issues
521
+
522
+ ```ruby
523
+ # Error: Table 'profiles' doesn't exist
524
+
525
+ # Fix: Generate migrations in dependency order
526
+ migrations = FakeDataDSL::MigrationGenerator.from_files(schemas,
527
+ order: :dependency # Creates profiles before users
528
+ )
529
+ ```
530
+
531
+ ### UUID Extension
532
+
533
+ ```ruby
534
+ # For PostgreSQL < 13, enable uuid-ossp extension
535
+ class EnableUuidExtension < ActiveRecord::Migration[7.1]
536
+ def change
537
+ enable_extension 'pgcrypto' # or 'uuid-ossp'
538
+ end
539
+ end
540
+ ```
541
+
542
+ ## See Also
543
+
544
+ - [ActiveRecord Inference](ACTIVERECORD_INFERENCE.md)
545
+ - [Rails Engine](RAILS_ENGINE.md)
546
+ - [Data Contracts](DATA_CONTRACTS.md)
547
+ - [DSL Reference](dsl_reference.md)