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,325 @@
|
|
|
1
|
+
# Date & Time Types Reference
|
|
2
|
+
|
|
3
|
+
Complete guide to date and time types in FakeDataDSL.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Overview](#overview)
|
|
8
|
+
- [Date Types](#date-types)
|
|
9
|
+
- [Time Types](#time-types)
|
|
10
|
+
- [Duration Suffixes](#duration-suffixes)
|
|
11
|
+
- [Examples](#examples)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
FakeDataDSL provides several date and time types:
|
|
18
|
+
|
|
19
|
+
| Type | Description | Example Output |
|
|
20
|
+
|------|-------------|----------------|
|
|
21
|
+
| `date` | Random date | `"2024-06-15"` |
|
|
22
|
+
| `past_date` | Date in the past | `"2024-01-15"` |
|
|
23
|
+
| `future_date` | Date in the future | `"2025-06-15"` |
|
|
24
|
+
| `timestamp` | DateTime with time | `"2024-06-15T14:30:00Z"` |
|
|
25
|
+
| `now` | Current timestamp | `"2024-07-15T10:30:45Z"` |
|
|
26
|
+
| `datetime` | DateTime in range | `"2024-06-15T14:30:00Z"` |
|
|
27
|
+
| `time` | Time only | `"14:30:00"` |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Date Types
|
|
32
|
+
|
|
33
|
+
### date
|
|
34
|
+
|
|
35
|
+
Generates a random date.
|
|
36
|
+
|
|
37
|
+
```dsl
|
|
38
|
+
Event:
|
|
39
|
+
date: date
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Output format:** ISO 8601 (`YYYY-MM-DD`)
|
|
43
|
+
|
|
44
|
+
**Examples:**
|
|
45
|
+
- `"2024-06-15"`
|
|
46
|
+
- `"2023-12-01"`
|
|
47
|
+
- `"2025-03-22"`
|
|
48
|
+
|
|
49
|
+
### past_date
|
|
50
|
+
|
|
51
|
+
Generates a date in the past.
|
|
52
|
+
|
|
53
|
+
```dsl
|
|
54
|
+
User:
|
|
55
|
+
created_at: past_date
|
|
56
|
+
birthday: past_date(100y)
|
|
57
|
+
recent_login: past_date(7d)
|
|
58
|
+
last_month: past_date(1m)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| Argument | Type | Default | Description |
|
|
62
|
+
|----------|------|---------|-------------|
|
|
63
|
+
| Duration | String | `1y` | How far in the past |
|
|
64
|
+
|
|
65
|
+
**Duration suffixes:**
|
|
66
|
+
- `d` - days
|
|
67
|
+
- `m` - months
|
|
68
|
+
- `y` - years
|
|
69
|
+
|
|
70
|
+
**Generation modes:**
|
|
71
|
+
|
|
72
|
+
| Mode | Output |
|
|
73
|
+
|------|--------|
|
|
74
|
+
| `:random` | Random date within range |
|
|
75
|
+
| `:edge` | Min date, max date, boundary dates |
|
|
76
|
+
| `:invalid` | `nil`, invalid format, future date |
|
|
77
|
+
|
|
78
|
+
### future_date
|
|
79
|
+
|
|
80
|
+
Generates a date in the future.
|
|
81
|
+
|
|
82
|
+
```dsl
|
|
83
|
+
Task:
|
|
84
|
+
due_date: future_date
|
|
85
|
+
reminder: future_date(7d)
|
|
86
|
+
expiration: future_date(1y)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
| Argument | Type | Default | Description |
|
|
90
|
+
|----------|------|---------|-------------|
|
|
91
|
+
| Duration | String | `1y` | How far in the future |
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Time Types
|
|
96
|
+
|
|
97
|
+
### timestamp
|
|
98
|
+
|
|
99
|
+
Generates a full datetime timestamp.
|
|
100
|
+
|
|
101
|
+
```dsl
|
|
102
|
+
Event:
|
|
103
|
+
occurred_at: timestamp
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Output format:** ISO 8601 with time (`YYYY-MM-DDTHH:MM:SSZ`)
|
|
107
|
+
|
|
108
|
+
**Examples:**
|
|
109
|
+
- `"2024-06-15T14:30:00Z"`
|
|
110
|
+
- `"2023-12-01T09:15:30Z"`
|
|
111
|
+
|
|
112
|
+
### now
|
|
113
|
+
|
|
114
|
+
Generates the current timestamp.
|
|
115
|
+
|
|
116
|
+
```dsl
|
|
117
|
+
AuditLog:
|
|
118
|
+
created_at: now
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Output:** Current time in ISO 8601 format
|
|
122
|
+
|
|
123
|
+
### datetime
|
|
124
|
+
|
|
125
|
+
Generates a datetime within a specific range.
|
|
126
|
+
|
|
127
|
+
```dsl
|
|
128
|
+
Appointment:
|
|
129
|
+
scheduled_at: datetime(from: "2024-01-01", to: "2024-12-31")
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
| Argument | Type | Description |
|
|
133
|
+
|----------|------|-------------|
|
|
134
|
+
| `from` | String | Start date/datetime |
|
|
135
|
+
| `to` | String | End date/datetime |
|
|
136
|
+
|
|
137
|
+
### time
|
|
138
|
+
|
|
139
|
+
Generates a time only (no date).
|
|
140
|
+
|
|
141
|
+
```dsl
|
|
142
|
+
Schedule:
|
|
143
|
+
start_time: time
|
|
144
|
+
end_time: time
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Output format:** `HH:MM:SS`
|
|
148
|
+
|
|
149
|
+
**Examples:**
|
|
150
|
+
- `"14:30:00"`
|
|
151
|
+
- `"09:00:00"`
|
|
152
|
+
- `"23:59:59"`
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Duration Suffixes
|
|
157
|
+
|
|
158
|
+
Duration arguments accept these suffixes:
|
|
159
|
+
|
|
160
|
+
| Suffix | Unit | Example | Meaning |
|
|
161
|
+
|--------|------|---------|---------|
|
|
162
|
+
| `d` | Days | `30d` | 30 days |
|
|
163
|
+
| `m` | Months | `6m` | 6 months |
|
|
164
|
+
| `y` | Years | `2y` | 2 years |
|
|
165
|
+
|
|
166
|
+
### Examples
|
|
167
|
+
|
|
168
|
+
```dsl
|
|
169
|
+
Task:
|
|
170
|
+
# Days
|
|
171
|
+
due_in_week: future_date(7d)
|
|
172
|
+
due_in_month: future_date(30d)
|
|
173
|
+
|
|
174
|
+
# Months
|
|
175
|
+
quarterly_review: future_date(3m)
|
|
176
|
+
semi_annual: future_date(6m)
|
|
177
|
+
|
|
178
|
+
# Years
|
|
179
|
+
annual_renewal: future_date(1y)
|
|
180
|
+
long_term: future_date(5y)
|
|
181
|
+
|
|
182
|
+
User:
|
|
183
|
+
# Past dates
|
|
184
|
+
recent_activity: past_date(24h) # Not supported - use days
|
|
185
|
+
last_week: past_date(7d)
|
|
186
|
+
last_month: past_date(30d)
|
|
187
|
+
last_quarter: past_date(3m)
|
|
188
|
+
last_year: past_date(1y)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Examples
|
|
194
|
+
|
|
195
|
+
### User Lifecycle
|
|
196
|
+
|
|
197
|
+
```dsl
|
|
198
|
+
User:
|
|
199
|
+
created_at: past_date(3y)
|
|
200
|
+
email_verified_at: past_date(3y)
|
|
201
|
+
last_login: past_date(30d)
|
|
202
|
+
password_changed_at: past_date(90d)
|
|
203
|
+
subscription_expires: future_date(1y)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### E-commerce Order
|
|
207
|
+
|
|
208
|
+
```dsl
|
|
209
|
+
Order:
|
|
210
|
+
created_at: past_date(60d)
|
|
211
|
+
paid_at: past_date(60d)
|
|
212
|
+
shipped_at: past_date(45d)
|
|
213
|
+
delivered_at: past_date(30d)
|
|
214
|
+
return_deadline: future_date(30d)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Event Scheduling
|
|
218
|
+
|
|
219
|
+
```dsl
|
|
220
|
+
CalendarEvent:
|
|
221
|
+
start_date: date
|
|
222
|
+
start_time: time
|
|
223
|
+
end_date: date
|
|
224
|
+
end_time: time
|
|
225
|
+
created_at: past_date(30d)
|
|
226
|
+
reminder_at: future_date(1d)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Subscription Model
|
|
230
|
+
|
|
231
|
+
```dsl
|
|
232
|
+
Subscription:
|
|
233
|
+
started_at: past_date(2y)
|
|
234
|
+
current_period_start: past_date(30d)
|
|
235
|
+
current_period_end: future_date(30d)
|
|
236
|
+
trial_ends_at?: future_date(14d)
|
|
237
|
+
cancelled_at?: past_date(7d)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Audit Trail
|
|
241
|
+
|
|
242
|
+
```dsl
|
|
243
|
+
AuditLog:
|
|
244
|
+
timestamp: timestamp
|
|
245
|
+
event_time: now
|
|
246
|
+
|
|
247
|
+
HistoricalRecord:
|
|
248
|
+
effective_from: past_date(5y)
|
|
249
|
+
effective_to: future_date(1y)
|
|
250
|
+
recorded_at: timestamp
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Edge Cases by Mode
|
|
256
|
+
|
|
257
|
+
### Random Mode
|
|
258
|
+
- Dates within specified range
|
|
259
|
+
- Realistic timestamps
|
|
260
|
+
- Current time for `now`
|
|
261
|
+
|
|
262
|
+
### Edge Mode
|
|
263
|
+
- Unix epoch: `1970-01-01`
|
|
264
|
+
- Y2K: `2000-01-01`
|
|
265
|
+
- Y2038 problem: `2038-01-19`
|
|
266
|
+
- Leap year dates: `2024-02-29`
|
|
267
|
+
- End of year: `YYYY-12-31`
|
|
268
|
+
- Start of year: `YYYY-01-01`
|
|
269
|
+
|
|
270
|
+
### Invalid Mode
|
|
271
|
+
- `nil`
|
|
272
|
+
- Invalid format: `"not-a-date"`
|
|
273
|
+
- Wrong type: `12345`
|
|
274
|
+
- Invalid dates: `"2024-13-45"`, `"2024-02-30"`
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Best Practices
|
|
279
|
+
|
|
280
|
+
### 1. Use Appropriate Ranges
|
|
281
|
+
|
|
282
|
+
```dsl
|
|
283
|
+
# Good - realistic ranges
|
|
284
|
+
User:
|
|
285
|
+
birthday: past_date(100y)
|
|
286
|
+
created_at: past_date(5y)
|
|
287
|
+
last_login: past_date(30d)
|
|
288
|
+
|
|
289
|
+
# Avoid - unrealistic
|
|
290
|
+
User:
|
|
291
|
+
birthday: past_date(1000y)
|
|
292
|
+
last_login: past_date(100y)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 2. Order Dates Logically
|
|
296
|
+
|
|
297
|
+
```dsl
|
|
298
|
+
# Good - logical order
|
|
299
|
+
Order:
|
|
300
|
+
created_at: past_date(60d)
|
|
301
|
+
shipped_at: past_date(50d)
|
|
302
|
+
delivered_at: past_date(40d)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 3. Use Appropriate Types
|
|
306
|
+
|
|
307
|
+
```dsl
|
|
308
|
+
# Use date for date-only
|
|
309
|
+
birthday: date
|
|
310
|
+
|
|
311
|
+
# Use timestamp for full datetime
|
|
312
|
+
created_at: timestamp
|
|
313
|
+
|
|
314
|
+
# Use now for current time
|
|
315
|
+
updated_at: now
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Next Steps
|
|
321
|
+
|
|
322
|
+
- [Core Types](core_types.md) - All basic types
|
|
323
|
+
- [Complex Types](complex_types.md) - Arrays, objects
|
|
324
|
+
- [Field Modifiers](field_modifiers.md) - Optional, nullable
|
|
325
|
+
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
# Field Modifiers
|
|
2
|
+
|
|
3
|
+
Optional, nullable, and conditional field modifiers.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Optional Fields](#optional-fields)
|
|
8
|
+
- [Nullable Fields](#nullable-fields)
|
|
9
|
+
- [Combined Modifiers](#combined-modifiers)
|
|
10
|
+
- [Conditional Fields](#conditional-fields)
|
|
11
|
+
- [Unique Constraint](#unique-constraint)
|
|
12
|
+
- [Field Behaviors](#field-behaviors)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Optional Fields
|
|
17
|
+
|
|
18
|
+
### What is Optional?
|
|
19
|
+
|
|
20
|
+
Optional fields may not appear in the output at all.
|
|
21
|
+
|
|
22
|
+
### Syntax
|
|
23
|
+
|
|
24
|
+
Add `?` after the field name:
|
|
25
|
+
|
|
26
|
+
```dsl
|
|
27
|
+
User:
|
|
28
|
+
id: uuid # Always present
|
|
29
|
+
phone?: phone # May not appear
|
|
30
|
+
bio?: text # May not appear
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Probability
|
|
34
|
+
|
|
35
|
+
By default, optional fields appear ~50% of the time.
|
|
36
|
+
|
|
37
|
+
### Generated Output
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
# Without optional fields:
|
|
41
|
+
{ "id" => "550e8400-..." }
|
|
42
|
+
|
|
43
|
+
# With optional fields:
|
|
44
|
+
{ "id" => "550e8400-...", "phone" => "+1-555-123-4567" }
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Use Cases
|
|
48
|
+
|
|
49
|
+
- Incomplete user profiles
|
|
50
|
+
- Optional contact information
|
|
51
|
+
- Non-required form fields
|
|
52
|
+
- Sparse data simulation
|
|
53
|
+
|
|
54
|
+
```dsl
|
|
55
|
+
ContactInfo:
|
|
56
|
+
email: email # Required
|
|
57
|
+
phone?: phone # Optional
|
|
58
|
+
fax?: phone # Optional
|
|
59
|
+
twitter?: text(1..15) # Optional
|
|
60
|
+
linkedin?: url # Optional
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Nullable Fields
|
|
66
|
+
|
|
67
|
+
### What is Nullable?
|
|
68
|
+
|
|
69
|
+
Nullable fields always appear but may have a `null` value.
|
|
70
|
+
|
|
71
|
+
### Syntax
|
|
72
|
+
|
|
73
|
+
Add `?` after the type:
|
|
74
|
+
|
|
75
|
+
```dsl
|
|
76
|
+
User:
|
|
77
|
+
name: name # Never null
|
|
78
|
+
nickname: text? # May be null
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Probability
|
|
82
|
+
|
|
83
|
+
By default, nullable fields are null ~50% of the time.
|
|
84
|
+
|
|
85
|
+
### Generated Output
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
# With value:
|
|
89
|
+
{ "name" => "John", "nickname" => "Johnny" }
|
|
90
|
+
|
|
91
|
+
# With null:
|
|
92
|
+
{ "name" => "John", "nickname" => nil }
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Use Cases
|
|
96
|
+
|
|
97
|
+
- Database columns that allow NULL
|
|
98
|
+
- Cleared user data
|
|
99
|
+
- Pending information
|
|
100
|
+
- Optional relationships
|
|
101
|
+
|
|
102
|
+
```dsl
|
|
103
|
+
Employee:
|
|
104
|
+
id: uuid
|
|
105
|
+
name: name
|
|
106
|
+
manager_id: uuid? # May not have a manager
|
|
107
|
+
department: text? # May be unassigned
|
|
108
|
+
end_date: date? # Still employed if null
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Combined Modifiers
|
|
114
|
+
|
|
115
|
+
### Optional AND Nullable
|
|
116
|
+
|
|
117
|
+
A field can be both optional and nullable:
|
|
118
|
+
|
|
119
|
+
```dsl
|
|
120
|
+
User:
|
|
121
|
+
emergency_contact?: phone?
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
This means:
|
|
125
|
+
1. The field may not appear at all (optional)
|
|
126
|
+
2. If it appears, it may be null (nullable)
|
|
127
|
+
|
|
128
|
+
### Generated Output
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
# Not present at all (optional):
|
|
132
|
+
{ "id" => "...", "name" => "John" }
|
|
133
|
+
|
|
134
|
+
# Present but null:
|
|
135
|
+
{ "id" => "...", "name" => "John", "emergency_contact" => nil }
|
|
136
|
+
|
|
137
|
+
# Present with value:
|
|
138
|
+
{ "id" => "...", "name" => "John", "emergency_contact" => "+1-555-123-4567" }
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Probability Matrix
|
|
142
|
+
|
|
143
|
+
| Outcome | Probability |
|
|
144
|
+
|---------|-------------|
|
|
145
|
+
| Not present | ~50% |
|
|
146
|
+
| Present + null | ~25% |
|
|
147
|
+
| Present + value | ~25% |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Conditional Fields
|
|
152
|
+
|
|
153
|
+
### What is Conditional?
|
|
154
|
+
|
|
155
|
+
Conditional fields only appear when a condition is met.
|
|
156
|
+
|
|
157
|
+
### Syntax
|
|
158
|
+
|
|
159
|
+
```dsl
|
|
160
|
+
User:
|
|
161
|
+
field_name: type if condition_field
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### How It Works
|
|
165
|
+
|
|
166
|
+
The field only appears if `condition_field` is truthy:
|
|
167
|
+
- Not `nil`
|
|
168
|
+
- Not `false`
|
|
169
|
+
- Not empty string
|
|
170
|
+
|
|
171
|
+
```dsl
|
|
172
|
+
Order:
|
|
173
|
+
status: enum(pending, shipped, delivered)
|
|
174
|
+
|
|
175
|
+
# Only present when status has a value
|
|
176
|
+
tracking_number: text(20) if status
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Current Limitations
|
|
180
|
+
|
|
181
|
+
**Important:** Only truthiness checks are supported:
|
|
182
|
+
|
|
183
|
+
```dsl
|
|
184
|
+
# ✅ Supported - truthiness check
|
|
185
|
+
tracking_number: text if status
|
|
186
|
+
|
|
187
|
+
# ❌ NOT supported - equality comparison
|
|
188
|
+
tracking_number: text if status == "shipped"
|
|
189
|
+
|
|
190
|
+
# ❌ NOT supported - complex conditions
|
|
191
|
+
discount: number if total > 100
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Field Order Matters
|
|
195
|
+
|
|
196
|
+
Fields are processed alphabetically. The condition field must be generated before the conditional field:
|
|
197
|
+
|
|
198
|
+
```dsl
|
|
199
|
+
# ✅ Works - "premium" comes before "premium_features"
|
|
200
|
+
User:
|
|
201
|
+
premium: boolean
|
|
202
|
+
premium_features: object if premium
|
|
203
|
+
|
|
204
|
+
# ⚠️ May not work - "features" comes before "has_features"
|
|
205
|
+
User:
|
|
206
|
+
features: object if has_features
|
|
207
|
+
has_features: boolean
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Conditional Field Examples
|
|
211
|
+
|
|
212
|
+
```dsl
|
|
213
|
+
Subscription:
|
|
214
|
+
active: boolean
|
|
215
|
+
plan: enum(free, basic, premium)
|
|
216
|
+
|
|
217
|
+
# Only when active
|
|
218
|
+
renewal_date: future_date(1y) if active
|
|
219
|
+
|
|
220
|
+
# Only when has a plan
|
|
221
|
+
features: array(text, 1..10) if plan
|
|
222
|
+
|
|
223
|
+
Order:
|
|
224
|
+
status: enum(pending, processing, shipped, cancelled)
|
|
225
|
+
|
|
226
|
+
# Shipping info only for shipped orders
|
|
227
|
+
tracking_number: text(20) if status
|
|
228
|
+
carrier: enum(ups, fedex, usps) if status
|
|
229
|
+
estimated_delivery: future_date(14d) if status
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Unique Constraint
|
|
235
|
+
|
|
236
|
+
### What is Unique?
|
|
237
|
+
|
|
238
|
+
Ensures values are unique within a generation batch.
|
|
239
|
+
|
|
240
|
+
### Syntax
|
|
241
|
+
|
|
242
|
+
```dsl
|
|
243
|
+
User:
|
|
244
|
+
id: uuid(unique: true)
|
|
245
|
+
email: email(unique: true)
|
|
246
|
+
username: text(3..20, unique: true)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Scope
|
|
250
|
+
|
|
251
|
+
- **Per-batch**: Uniqueness within a single `generate_many` call
|
|
252
|
+
- **Per-engine**: Uniqueness across calls on same Engine instance
|
|
253
|
+
- **NOT global**: Different Engine instances track independently
|
|
254
|
+
|
|
255
|
+
### Example
|
|
256
|
+
|
|
257
|
+
```ruby
|
|
258
|
+
schema = FakeDataDSL.load('user.dsl')
|
|
259
|
+
|
|
260
|
+
# Unique within this batch
|
|
261
|
+
users = schema.generate_many(100)
|
|
262
|
+
# All 100 emails will be different
|
|
263
|
+
|
|
264
|
+
# New batch starts fresh
|
|
265
|
+
more_users = schema.generate_many(100)
|
|
266
|
+
# These emails may duplicate the first batch
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Uniqueness Errors
|
|
270
|
+
|
|
271
|
+
```ruby
|
|
272
|
+
begin
|
|
273
|
+
# Requesting more unique values than possible
|
|
274
|
+
users = schema.generate_many(1_000_000)
|
|
275
|
+
rescue FakeDataDSL::Errors::UniquenessError => e
|
|
276
|
+
puts "Could not generate unique value for #{e.field_name}"
|
|
277
|
+
end
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Unique with Types
|
|
281
|
+
|
|
282
|
+
```dsl
|
|
283
|
+
User:
|
|
284
|
+
id: uuid(unique: true) # UUID always unique anyway
|
|
285
|
+
email: email(unique: true) # Ensures no duplicate emails
|
|
286
|
+
username: text(3..10, unique: true) # Limited pool - may exhaust
|
|
287
|
+
|
|
288
|
+
Product:
|
|
289
|
+
sku: text(10, unique: true) # Product codes
|
|
290
|
+
barcode: number(1000000000000..9999999999999, unique: true)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Field Behaviors
|
|
296
|
+
|
|
297
|
+
### What are Field Behaviors?
|
|
298
|
+
|
|
299
|
+
Behaviors can be attached to individual fields to simulate conditions.
|
|
300
|
+
|
|
301
|
+
### Syntax
|
|
302
|
+
|
|
303
|
+
```dsl
|
|
304
|
+
User:
|
|
305
|
+
field_name: type @behavior value
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Available Behaviors
|
|
309
|
+
|
|
310
|
+
| Behavior | Description | Example |
|
|
311
|
+
|----------|-------------|---------|
|
|
312
|
+
| `@partial_data` | May be missing | `avatar: url @partial_data 30%` |
|
|
313
|
+
| `@latency` | Adds delay | `profile: object @latency 100ms` |
|
|
314
|
+
|
|
315
|
+
### Partial Data
|
|
316
|
+
|
|
317
|
+
```dsl
|
|
318
|
+
User:
|
|
319
|
+
id: uuid
|
|
320
|
+
name: name
|
|
321
|
+
email: email
|
|
322
|
+
|
|
323
|
+
# 30% chance this field is missing
|
|
324
|
+
avatar: url @partial_data 30%
|
|
325
|
+
|
|
326
|
+
# 50% chance this field is missing
|
|
327
|
+
phone: phone @partial_data 50%
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Latency on Field
|
|
331
|
+
|
|
332
|
+
```dsl
|
|
333
|
+
User:
|
|
334
|
+
id: uuid
|
|
335
|
+
name: name
|
|
336
|
+
|
|
337
|
+
# This specific field takes extra time
|
|
338
|
+
external_profile: object @latency 100..500ms
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Multiple Behaviors
|
|
342
|
+
|
|
343
|
+
```dsl
|
|
344
|
+
User:
|
|
345
|
+
avatar: url @partial_data 30% @latency 50ms
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Modifier Summary
|
|
351
|
+
|
|
352
|
+
| Modifier | Syntax | Effect |
|
|
353
|
+
|----------|--------|--------|
|
|
354
|
+
| Optional | `field?: type` | Field may not appear |
|
|
355
|
+
| Nullable | `field: type?` | Value may be null |
|
|
356
|
+
| Both | `field?: type?` | May not appear OR be null |
|
|
357
|
+
| Conditional | `field: type if x` | Only appears when x is truthy |
|
|
358
|
+
| Unique | `field: type(unique: true)` | Unique within batch |
|
|
359
|
+
| Behavior | `field: type @behavior` | Field-level simulation |
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Best Practices
|
|
364
|
+
|
|
365
|
+
### 1. Model Real Data
|
|
366
|
+
|
|
367
|
+
```dsl
|
|
368
|
+
# Match your database schema
|
|
369
|
+
User:
|
|
370
|
+
id: uuid # NOT NULL
|
|
371
|
+
email: email # NOT NULL, UNIQUE
|
|
372
|
+
phone: text? # NULL allowed
|
|
373
|
+
deleted_at: timestamp? # NULL when active
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### 2. Use Conditional for Relationships
|
|
377
|
+
|
|
378
|
+
```dsl
|
|
379
|
+
Employee:
|
|
380
|
+
role: enum(employee, manager, executive)
|
|
381
|
+
|
|
382
|
+
# Only managers have direct reports
|
|
383
|
+
direct_reports: array(Ref(Employee.id), 0..10) if role
|
|
384
|
+
|
|
385
|
+
# Only executives have budget
|
|
386
|
+
budget: money if role
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### 3. Combine for Realistic Sparsity
|
|
390
|
+
|
|
391
|
+
```dsl
|
|
392
|
+
UserProfile:
|
|
393
|
+
# Required
|
|
394
|
+
user_id: uuid
|
|
395
|
+
|
|
396
|
+
# Usually present but optional
|
|
397
|
+
display_name?: name
|
|
398
|
+
|
|
399
|
+
# Rarely filled
|
|
400
|
+
bio?: text(50..500)? # Optional AND nullable
|
|
401
|
+
website?: url?
|
|
402
|
+
|
|
403
|
+
# Only if verified
|
|
404
|
+
badge: enum(verified, partner) if verified_status
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## Next Steps
|
|
410
|
+
|
|
411
|
+
- [Complex Types](complex_types.md) - Arrays, objects, references
|
|
412
|
+
- [Behaviors](../behaviors/overview.md) - Schema-level behaviors
|
|
413
|
+
- [Generation Modes](../modes/overview.md) - Random, edge, invalid modes
|
|
414
|
+
|