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.
- checksums.yaml +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +40 -0
- data/.yardopts +18 -0
- data/ACCESS_DOCS.md +116 -0
- data/ADVANCED_FEATURES_SUMMARY.md +245 -0
- data/CHANGELOG.md +498 -0
- data/CODE_OF_CONDUCT.md +122 -0
- data/CONTRIBUTING.md +307 -0
- data/DOCUMENTATION.md +204 -0
- data/DOCUMENTATION_GUIDE.md +194 -0
- data/LICENSE +22 -0
- data/README.md +1458 -0
- data/Rakefile +128 -0
- data/benchmark/README.md +591 -0
- data/benchmark/batch_generation.rb +63 -0
- data/benchmark/engine_comparison.rb +295 -0
- data/benchmark/single_record.rb +108 -0
- data/benchmark/streaming.rb +74 -0
- data/docs/ACTIVERECORD_INFERENCE.md +524 -0
- data/docs/API_SERVER.md +278 -0
- data/docs/CONFIG_FILE.md +315 -0
- data/docs/DATA_CONTRACTS.md +312 -0
- data/docs/ENHANCED_REPL.md +304 -0
- data/docs/FACTORY_BOT.md +271 -0
- data/docs/GITHUB_ACTION.md +420 -0
- data/docs/GRAPHQL_EXPORT.md +303 -0
- data/docs/GRAPHQL_FEDERATION.md +651 -0
- data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
- data/docs/LSP.md +189 -0
- data/docs/MIGRATION_GENERATOR.md +547 -0
- data/docs/MOCK_SERVER.md +280 -0
- data/docs/NATIVE_ENGINE.md +298 -0
- data/docs/OPENAPI_EXPORT.md +252 -0
- data/docs/PERFORMANCE_MODE.md +228 -0
- data/docs/PERSONAS.md +547 -0
- data/docs/PROPERTY_TESTING.md +284 -0
- data/docs/PROTOBUF_EXPORT.md +276 -0
- data/docs/QUALITY_METRICS.md +555 -0
- data/docs/QUICK_REFERENCE.md +88 -0
- data/docs/RAILS_ENGINE.md +404 -0
- data/docs/RAILS_INTEGRATION.md +454 -0
- data/docs/README.md +175 -0
- data/docs/REPL_QUICK_REFERENCE.md +149 -0
- data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
- data/docs/SCENARIOS.md +576 -0
- data/docs/SECURITY_TESTING.md +318 -0
- data/docs/SNAPSHOT_TESTING.md +308 -0
- data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
- data/docs/TERRAFORM_EXPORT.md +447 -0
- data/docs/TIME_TRAVEL.md +507 -0
- data/docs/USAGE_GUIDE.md +980 -0
- data/docs/WEBHOOK_SIMULATOR.md +579 -0
- data/docs/advanced_features.md +183 -0
- data/docs/api_reference.md +153 -0
- data/docs/behaviors.md +138 -0
- data/docs/best_practices.md +191 -0
- data/docs/dsl_reference.md +172 -0
- data/docs/examples.md +162 -0
- data/docs/generation_modes.md +125 -0
- data/docs/getting_started.md +92 -0
- data/docs/index.html +177 -0
- data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
- data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
- data/docs/troubleshooting.md +215 -0
- data/docs/type_reference.md +224 -0
- data/examples/hostile_mode_demo.rb +64 -0
- data/exe/synthra +6 -0
- data/ext/synthra_native/Cargo.lock +972 -0
- data/ext/synthra_native/Cargo.toml +46 -0
- data/ext/synthra_native/extconf.rb +41 -0
- data/ext/synthra_native/src/generator.rs +397 -0
- data/ext/synthra_native/src/lib.rs +229 -0
- data/ext/synthra_native/src/types.rs +1485 -0
- data/lib/generators/synthra/install_generator.rb +86 -0
- data/lib/generators/synthra/templates/api_response.dsl +15 -0
- data/lib/generators/synthra/templates/fake_data.rake +116 -0
- data/lib/generators/synthra/templates/synthra.yml +31 -0
- data/lib/generators/synthra/templates/synthra_support.rb +19 -0
- data/lib/generators/synthra/templates/user.dsl +11 -0
- data/lib/synthra/activerecord_inference.rb +394 -0
- data/lib/synthra/api.rb +381 -0
- data/lib/synthra/api_server.rb +718 -0
- data/lib/synthra/behaviors/applicator.rb +165 -0
- data/lib/synthra/behaviors/base.rb +155 -0
- data/lib/synthra/behaviors/close_connection.rb +60 -0
- data/lib/synthra/behaviors/deprecated.rb +100 -0
- data/lib/synthra/behaviors/failure.rb +69 -0
- data/lib/synthra/behaviors/latency.rb +103 -0
- data/lib/synthra/behaviors/partial_data.rb +83 -0
- data/lib/synthra/behaviors/randomize_order.rb +74 -0
- data/lib/synthra/behaviors/registry.rb +238 -0
- data/lib/synthra/behaviors/simulate_error.rb +79 -0
- data/lib/synthra/cli/commands/base.rb +105 -0
- data/lib/synthra/cli/commands/diff.rb +227 -0
- data/lib/synthra/cli/commands/docs.rb +67 -0
- data/lib/synthra/cli/commands/export.rb +150 -0
- data/lib/synthra/cli/commands/generate.rb +72 -0
- data/lib/synthra/cli/commands/import.rb +80 -0
- data/lib/synthra/cli/commands/lint.rb +53 -0
- data/lib/synthra/cli/commands/live.rb +57 -0
- data/lib/synthra/cli/commands/seed.rb +99 -0
- data/lib/synthra/cli/commands/validate.rb +28 -0
- data/lib/synthra/cli.rb +2471 -0
- data/lib/synthra/config_file.rb +129 -0
- data/lib/synthra/configuration.rb +281 -0
- data/lib/synthra/contracts_registry.rb +408 -0
- data/lib/synthra/database_seeder.rb +268 -0
- data/lib/synthra/deterministic_ids.rb +218 -0
- data/lib/synthra/documentation_generator.rb +414 -0
- data/lib/synthra/engine.rb +251 -0
- data/lib/synthra/errors.rb +1169 -0
- data/lib/synthra/export/base.rb +85 -0
- data/lib/synthra/export/csv.rb +101 -0
- data/lib/synthra/export/graphql.rb +266 -0
- data/lib/synthra/export/graphql_federation.rb +377 -0
- data/lib/synthra/export/graphviz.rb +258 -0
- data/lib/synthra/export/javascript.rb +327 -0
- data/lib/synthra/export/json_data.rb +61 -0
- data/lib/synthra/export/json_schema.rb +290 -0
- data/lib/synthra/export/openapi.rb +514 -0
- data/lib/synthra/export/protobuf.rb +483 -0
- data/lib/synthra/export/python.rb +560 -0
- data/lib/synthra/export/sql.rb +381 -0
- data/lib/synthra/export/sql_insert.rb +152 -0
- data/lib/synthra/export/terraform.rb +501 -0
- data/lib/synthra/export/type_mapping.rb +389 -0
- data/lib/synthra/export/typescript.rb +300 -0
- data/lib/synthra/export/xml_data.rb +104 -0
- data/lib/synthra/export/yaml_data.rb +56 -0
- data/lib/synthra/export.rb +404 -0
- data/lib/synthra/factory_bot_integration.rb +157 -0
- data/lib/synthra/field.rb +440 -0
- data/lib/synthra/functions/registry.rb +104 -0
- data/lib/synthra/generator/context.rb +372 -0
- data/lib/synthra/generator/engine.rb +336 -0
- data/lib/synthra/generator/faker_adapter.rb +425 -0
- data/lib/synthra/generator/modes.rb +444 -0
- data/lib/synthra/generator/resolver.rb +256 -0
- data/lib/synthra/generator/rng.rb +273 -0
- data/lib/synthra/generator/streamer.rb +63 -0
- data/lib/synthra/generator/uniqueness.rb +118 -0
- data/lib/synthra/initializer.rb +97 -0
- data/lib/synthra/limits.rb +279 -0
- data/lib/synthra/live_preview.rb +518 -0
- data/lib/synthra/loader_config.rb +78 -0
- data/lib/synthra/lsp/server.rb +689 -0
- data/lib/synthra/migration_generator.rb +301 -0
- data/lib/synthra/mixin.rb +174 -0
- data/lib/synthra/mock_server.rb +458 -0
- data/lib/synthra/native_engine.rb +304 -0
- data/lib/synthra/openapi_importer.rb +228 -0
- data/lib/synthra/output/json_formatter.rb +40 -0
- data/lib/synthra/output/ndjson_formatter.rb +55 -0
- data/lib/synthra/parser/ast.rb +1287 -0
- data/lib/synthra/parser/lexer.rb +1152 -0
- data/lib/synthra/parser/parser.rb +1664 -0
- data/lib/synthra/parser/tokens.rb +461 -0
- data/lib/synthra/performance_mode.rb +364 -0
- data/lib/synthra/personas.rb +397 -0
- data/lib/synthra/property_testing.rb +172 -0
- data/lib/synthra/quality_metrics.rb +405 -0
- data/lib/synthra/rails_test_helper.rb +248 -0
- data/lib/synthra/registry.rb +533 -0
- data/lib/synthra/relationships.rb +193 -0
- data/lib/synthra/repl/enhanced_repl.rb +607 -0
- data/lib/synthra/repl/formatter.rb +191 -0
- data/lib/synthra/scenarios.rb +423 -0
- data/lib/synthra/schema.rb +605 -0
- data/lib/synthra/schema_inheritance.rb +104 -0
- data/lib/synthra/schema_versioning.rb +212 -0
- data/lib/synthra/snapshot_testing.rb +199 -0
- data/lib/synthra/time_travel.rb +338 -0
- data/lib/synthra/type_definitions.rb +274 -0
- data/lib/synthra/types/address_location/addresses.rb +125 -0
- data/lib/synthra/types/address_location/airports.rb +200 -0
- data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
- data/lib/synthra/types/address_location/locations.rb +406 -0
- data/lib/synthra/types/base.rb +48 -0
- data/lib/synthra/types/commerce_products/commerce.rb +119 -0
- data/lib/synthra/types/commerce_products/companies.rb +71 -0
- data/lib/synthra/types/commerce_products/construction.rb +126 -0
- data/lib/synthra/types/commerce_products/products.rb +205 -0
- data/lib/synthra/types/core/collections.rb +513 -0
- data/lib/synthra/types/core/defaults.rb +76 -0
- data/lib/synthra/types/core/enums.rb +102 -0
- data/lib/synthra/types/core/identifiers.rb +445 -0
- data/lib/synthra/types/core/primitives.rb +586 -0
- data/lib/synthra/types/core/references.rb +466 -0
- data/lib/synthra/types/core/sequences.rb +304 -0
- data/lib/synthra/types/crypto/crypto.rb +162 -0
- data/lib/synthra/types/date_time/dates.rb +387 -0
- data/lib/synthra/types/finance_banking/banking.rb +424 -0
- data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
- data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
- data/lib/synthra/types/formula.rb +184 -0
- data/lib/synthra/types/health_medical/medical.rb +150 -0
- data/lib/synthra/types/hostile_payloads.rb +122 -0
- data/lib/synthra/types/json_array.rb +51 -0
- data/lib/synthra/types/media_entertainment/media.rb +62 -0
- data/lib/synthra/types/naughty_string.rb +30 -0
- data/lib/synthra/types/personal_names/chinese.rb +41 -0
- data/lib/synthra/types/personal_names/identifiers.rb +187 -0
- data/lib/synthra/types/personal_names/names.rb +246 -0
- data/lib/synthra/types/personal_names/national_id.rb +89 -0
- data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
- data/lib/synthra/types/regex.rb +248 -0
- data/lib/synthra/types/registry.rb +182 -0
- data/lib/synthra/types/repeating_element.rb +50 -0
- data/lib/synthra/types/scenario.rb +29 -0
- data/lib/synthra/types/technology_internet/apps.rb +67 -0
- data/lib/synthra/types/technology_internet/communication.rb +162 -0
- data/lib/synthra/types/technology_internet/devices.rb +80 -0
- data/lib/synthra/types/technology_internet/formats.rb +139 -0
- data/lib/synthra/types/technology_internet/networking.rb +143 -0
- data/lib/synthra/types/template.rb +92 -0
- data/lib/synthra/types/text_content/business.rb +128 -0
- data/lib/synthra/types/text_content/colors.rb +70 -0
- data/lib/synthra/types/text_content/misc.rb +237 -0
- data/lib/synthra/types/text_content/security.rb +130 -0
- data/lib/synthra/types/text_content/text_generation.rb +532 -0
- data/lib/synthra/types/travel/travel.rb +150 -0
- data/lib/synthra/utils/string_distance.rb +133 -0
- data/lib/synthra/validator/dsl_validator.rb +339 -0
- data/lib/synthra/validator/path_validator.rb +615 -0
- data/lib/synthra/version.rb +35 -0
- data/lib/synthra/webhook_simulator.rb +341 -0
- data/lib/synthra.rb +259 -0
- data/schemas/address.dsl +16 -0
- data/schemas/api_response.dsl +8 -0
- data/schemas/error_payload.dsl +9 -0
- data/schemas/order.dsl +10 -0
- data/schemas/order_item.dsl +8 -0
- data/schemas/payment.dsl +11 -0
- data/schemas/social_post.dsl +13 -0
- data/schemas/user.dsl +10 -0
- data/scripts/batch_fix_all.rb +96 -0
- data/scripts/delete_old_files.rb +32 -0
- data/scripts/fix_all_grouped_files.rb +137 -0
- data/scripts/fix_all_indentation.rb +48 -0
- data/scripts/fix_all_syntax.rb +124 -0
- data/scripts/fix_grouped_files.rb +184 -0
- data/scripts/fix_syntax_errors.rb +108 -0
- data/scripts/group_domain_types.rb +112 -0
- data/scripts/group_domain_types_fixed.rb +150 -0
- data/scripts/merge_domains_to_one_file.rb +68 -0
- data/scripts/move_existing_types.rb +130 -0
- data/scripts/split_grouped_types.rb +142 -0
- data/tech_docs/README.md +134 -0
- data/tech_docs/advanced/streaming.md +405 -0
- data/tech_docs/advanced/thread_safety.md +253 -0
- data/tech_docs/api/overview.md +485 -0
- data/tech_docs/appendices/type_chart.md +193 -0
- data/tech_docs/basic_concepts.md +383 -0
- data/tech_docs/behaviors/overview.md +346 -0
- data/tech_docs/dsl/complex_types.md +790 -0
- data/tech_docs/dsl/core_types.md +464 -0
- data/tech_docs/dsl/datetime_types.md +325 -0
- data/tech_docs/dsl/field_modifiers.md +414 -0
- data/tech_docs/dsl/grammar.md +431 -0
- data/tech_docs/dsl/schema_definition.md +399 -0
- data/tech_docs/export/README.md +276 -0
- data/tech_docs/installation.md +273 -0
- data/tech_docs/integration/ci_cd.md +707 -0
- data/tech_docs/integration/ci_cd_guide.md +579 -0
- data/tech_docs/integration/factory_bot.md +485 -0
- data/tech_docs/integration/rails.md +630 -0
- data/tech_docs/integration/rspec.md +449 -0
- data/tech_docs/modes/overview.md +350 -0
- data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
- data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
- data/tech_docs/quick_start.md +256 -0
- data/tech_docs/templates/README.md +805 -0
- data/tech_docs/tutorials/advanced.md +371 -0
- data/tech_docs/tutorials/getting_started.md +189 -0
- data/tech_docs/tutorials/intermediate.md +231 -0
- data/tech_docs/tutorials/template_gallery.md +569 -0
- data/tech_example/01_basic_usage.rb +238 -0
- data/tech_example/02_types_demo.rb +336 -0
- data/tech_example/04_cli_usage.md +429 -0
- data/tech_example/05_database_seeding.rb +283 -0
- data/tech_example/07_rspec_integration.rb +359 -0
- data/tech_example/10_custom_types.rb +387 -0
- data/tech_example/12_behaviors.rb +372 -0
- data/tech_example/13_twitter_dm_example.rb +120 -0
- data/tech_example/14_exact_json_structure.rb +253 -0
- data/tech_example/16_lsp_server.rb +56 -0
- data/tech_example/17_property_testing.rb +92 -0
- data/tech_example/18_enhanced_repl.rb +120 -0
- data/tech_example/19_security_fuzzing.rb +145 -0
- data/tech_example/NEW_FEATURES.md +169 -0
- data/tech_example/README.md +118 -0
- data/tech_example/schemas/api_response.dsl +123 -0
- data/tech_example/schemas/ecommerce.dsl +121 -0
- data/tech_example/schemas/twitter_dm.dsl +109 -0
- data/tech_example/schemas/user.dsl +36 -0
- data/vscode-extension/README.md +246 -0
- data/vscode-extension/language-configuration.json +31 -0
- data/vscode-extension/package.json +55 -0
- data/vscode-extension/snippets/fakedatadsl.json +198 -0
- data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
- 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)
|