propel_api 0.3.1.2 → 0.3.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e5a2cb9edf143dc6d0f7582e01e51abe3c1ea0cf7e37c0ba9077fe38be5c9fb
4
- data.tar.gz: c13fe800d5804bb1fc9846c35baff955e38680ea099e8167b5c00fa66309c6ce
3
+ metadata.gz: 57d463a766fd115825dccf217caabd982bf849c9aac5a9dfafc7ef11b2a75c04
4
+ data.tar.gz: 171026f0732372a319fb79946d3c7991293542a7b080bda4559b28427017b741
5
5
  SHA512:
6
- metadata.gz: 53fea1d7c31195a2411974a1a3149e2757b77574824639616a8af0b1f80b8e5234b6dead7663f46c84575b07a8ad7560d53ea06fca1dd328f31e0a15214620e9
7
- data.tar.gz: e635decc36265a721ca638ff706383cce7e55b87a0bcef1f64c7bf3c6a549facc7845d5aaf29579914264a0ec2ba08493f159b65972ccb20b28fe4952b3fe200
6
+ metadata.gz: 0576b9c86f00a1dde3691dfafc7049d6ffcc58c0717c98cab5739b3bee7c354046f711f3eaf061caa11f6c43c29f43008e988c55d706e84dfaa57e8ca0266de4
7
+ data.tar.gz: fd24e624bd103eb1bdd96c4e85701198b77964716ebf35d267b1d08f75ee7fc8f6016b85c5374eedc111bb7371af8210779874050db707c906290129fdc1d828
data/CHANGELOG.md CHANGED
@@ -10,6 +10,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10
10
  ### Planned Features
11
11
  - GraphQL adapter support
12
12
 
13
+ ## [0.3.1.4] - 2025-09-11
14
+
15
+ ### 🐛 Critical Bug Fixes
16
+ - **Polymorphic Parents Parsing Regression**: Fixed `NoMethodError: undefined method 'strip' for Array`
17
+ - Reverted to original, working `parse_polymorphic_parent_types` implementation
18
+ - Fixed overcomplicated parsing logic that incorrectly assumed Thor gives Arrays
19
+ - Thor consistently provides comma-separated String values that need simple `.split(',')` handling
20
+ - Resolves crash when using `--parents` option with polymorphic generators
21
+
22
+ ### 📖 Documentation Improvements
23
+ - **--parents Flag Usage Guide**: Added comprehensive documentation for correct --parents syntax
24
+ - Fixed misleading error messages that suggested unsupported syntax
25
+ - Added clear examples of correct vs incorrect --parents usage
26
+ - Enhanced README with detailed usage guide and common pitfalls
27
+ - Updated all generator descriptions to show required field_name:Parent1,Parent2 syntax
28
+
29
+ ## [0.3.1.3] - 2025-09-11
30
+
31
+ ### 🐛 Bug Fixes
32
+ - **Polymorphic Association Facet Includes**: Fixed facet includes for polymorphic associations in model templates
33
+ - Polymorphic associations are now properly included in `details` facet for eager loading
34
+ - Enhanced model template to handle polymorphic associations in facet includes correctly
35
+ - Fixed Schedule model and similar polymorphic association issues
36
+ - **Data Integrity Test Fixes**: Improved model test template for more reliable data integrity tests
37
+ - Fixed hardcoded test expectations to match actual test data creation
38
+ - Better handling of polymorphic associations in integrity tests
39
+ - Enhanced test data generation for name/title fields to use realistic values (e.g., "integrity_test")
40
+ - Added proper JSON/JSONB field testing support
41
+
13
42
  ## [0.3.1.2] - 2025-09-11
14
43
 
15
44
  ### 🎉 New Features
@@ -27,20 +56,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
27
56
  - Command-line flag support for per-generator control
28
57
  - Backward compatible with existing configurations
29
58
 
30
- ### 🐛 Bug Fixes
31
- - **Polymorphic Association Facet Includes**: Fixed facet includes for polymorphic associations in model templates
32
- - Polymorphic associations are now properly included in `details` facet for eager loading
33
- - Enhanced model template to handle polymorphic associations in facet includes correctly
34
- - Fixed Schedule model and similar polymorphic association issues
35
- - **Data Integrity Test Fixes**: Improved model test template for more reliable data integrity tests
36
- - Fixed hardcoded test expectations to match actual test data creation
37
- - Better handling of polymorphic associations in integrity tests
38
- - Enhanced test data generation for name/title fields to use realistic values
39
- - Added proper JSON/JSONB field testing support
40
- - **HTTP Status Code Consistency**: Fixed tokens controller to use consistent HTTP status codes
41
- - Changed validation errors from `:unprocessable_content` (422) to `:bad_request` (400)
42
- - Better alignment with standard HTTP parameter validation practices
43
- - Improved error handling consistency across authentication endpoints
44
59
 
45
60
  ## [0.3.1.1] - 2025-09-11
46
61
 
@@ -92,7 +107,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
92
107
  - **Integration Test Templates**: Enhanced error handling and parameter validation in generated integration tests
93
108
 
94
109
  ### ⚠️ Breaking Changes
95
- - **REQUIRED --parents for Polymorphic**: Polymorphic associations now require explicit `--parents Parent1,Parent2` declaration. Auto-discovery fallback has been removed. Generator will block with confirmation if --parents is missing.
110
+ - **REQUIRED --parents for Polymorphic**: Polymorphic associations now require explicit `--parents field_name:Parent1,Parent2` declaration. Auto-discovery fallback has been removed. Generator will block with confirmation if --parents is missing.
96
111
 
97
112
  ## [0.3.0] - 2025-01-15
98
113
 
data/README.md CHANGED
@@ -55,10 +55,10 @@ rails generate propel_api:resource User name:string email:string role:string
55
55
  rails generate propel_api:resource Article title:string content:text user:references category:references
56
56
 
57
57
  # 🎉 NEW: Polymorphic associations (v0.3.0) - REQUIRES --parents flag
58
- rails generate propel_api:resource Comment content:text commentable:references{polymorphic} --parents Post,Video,Product
58
+ rails generate propel_api:resource Comment content:text commentable:references{polymorphic} --parents commentable:Post,Video,Product
59
59
 
60
60
  # Polymorphic with tenancy
61
- rails generate propel_api:resource Review rating:integer comment:text review_parent:polymorphic --parents Product,Agency
61
+ rails generate propel_api:resource Review rating:integer comment:text review_parent:polymorphic --parents review_parent:Product,Agency
62
62
 
63
63
  # With Graphiti adapter
64
64
  rails generate propel_api Product name:string price:decimal --adapter=graphiti
@@ -81,10 +81,10 @@ PropelApi now provides comprehensive support for polymorphic associations with a
81
81
 
82
82
  ```bash
83
83
  # Generate a Comment that can belong to Posts, Videos, or Products
84
- rails generate propel_api:resource Comment body:text commentable:references{polymorphic} --parents Post,Video,Product
84
+ rails generate propel_api:resource Comment body:text commentable:references{polymorphic} --parents commentable:Post,Video,Product
85
85
 
86
- # Generate a Review with full tenancy support
87
- rails generate propel_api:resource Review rating:integer comment:text review_parent:references{polymorphic} --parents Product,Agency
86
+ # Generate a Review with full tenancy support
87
+ rails generate propel_api:resource Review rating:integer comment:text review_parent:references{polymorphic} --parents review_parent:Product,Agency
88
88
  ```
89
89
 
90
90
  ### Key Features
@@ -94,7 +94,8 @@ rails generate propel_api:resource Review rating:integer comment:text review_par
94
94
  - No need for complex quote escaping or nested syntax
95
95
 
96
96
  #### 🎯 Required Parent Specification
97
- - `--parents Parent1,Parent2,Parent3` defines valid parent models (REQUIRED for polymorphic associations)
97
+ - `--parents field_name:Parent1,Parent2,Parent3` defines valid parent models (REQUIRED for polymorphic associations)
98
+ - Field name must match the polymorphic association name (e.g., `commentable`, `schedule_parent`)
98
99
  - Automatically generates varied test data using different parent types
99
100
  - Generator will block with confirmation if --parents is not provided
100
101
 
@@ -139,6 +140,58 @@ class Api::V1::CommentsController < Api::V1::ApiController
139
140
  end
140
141
  ```
141
142
 
143
+ ### --parents Flag Usage Guide
144
+
145
+ ⚠️ **IMPORTANT**: The `--parents` flag requires specific syntax to work correctly.
146
+
147
+ #### ✅ **Correct Syntax:**
148
+ ```bash
149
+ # Single polymorphic field
150
+ --parents field_name:Parent1,Parent2,Parent3
151
+
152
+ # Real examples:
153
+ --parents commentable:Post,Photo,Video
154
+ --parents schedule_parent:User,Room,MeetingLink
155
+ --parents review_parent:Product,Agency
156
+
157
+ # Multiple polymorphic fields
158
+ --parents commentable:Post,Photo schedule_parent:User,Room
159
+ ```
160
+
161
+ #### ❌ **Incorrect Syntax (Will Fail):**
162
+ ```bash
163
+ # Missing field name (Thor can't parse this)
164
+ --parents Post,Photo,Video
165
+
166
+ # Array brackets (not supported)
167
+ --parents commentable:[Post,Photo,Video]
168
+
169
+ # JSON-like syntax (not supported)
170
+ --parents "{commentable: [Post,Photo,Video]}"
171
+ ```
172
+
173
+ #### 🔑 **Key Rules:**
174
+ 1. **Always include field name**: `field_name:Parent1,Parent2`
175
+ 2. **Field name must match polymorphic association**: If your field is `commentable:polymorphic`, use `--parents commentable:...`
176
+ 3. **Use commas to separate parent types**: `Post,Photo,Video` not `Post Photo Video`
177
+ 4. **Whitespace is automatically cleaned**: `Post, Photo, Video` works fine
178
+
179
+ ### Complete Usage Examples
180
+
181
+ ```bash
182
+ # Standard resource with polymorphic association
183
+ rails generate propel_api:resource Comment content:text commentable:polymorphic --parents commentable:Post,Photo,Video
184
+
185
+ # Multi-tenant polymorphic resource
186
+ rails generate propel_api:resource Review rating:integer organization:references agency:references review_parent:polymorphic --parents review_parent:Product,Agency,User
187
+
188
+ # Schedule system with polymorphic parent
189
+ rails generate propel_api:resource Schedule name:string start_time:datetime schedule_parent:polymorphic --parents schedule_parent:User,Room,MeetingLink
190
+
191
+ # Multiple polymorphic associations in one resource
192
+ rails generate propel_api:resource Attachment file_name:string attachable:polymorphic owner:polymorphic --parents attachable:Post,Comment,Email owner:User,Agency
193
+ ```
194
+
142
195
  ### Breaking Changes from v0.2.x
143
196
 
144
197
  ⚠️ **Migration Required**: The polymorphic syntax and test generation has been completely rewritten for better reliability and Rails compatibility.
@@ -148,7 +201,7 @@ end
148
201
 
149
202
  The new approach provides:
150
203
  - More reliable test generation
151
- - Better fixture management
204
+ - Better fixture management
152
205
  - Cleaner, more maintainable code
153
206
  - Full Rails compatibility
154
207
 
@@ -52,7 +52,7 @@ module PropelApi
52
52
  class_option :parents,
53
53
  type: :hash,
54
54
  default: {},
55
- desc: "Specify parent types for polymorphic associations (e.g., --parents commentable:Post,Photo,Video)"
55
+ desc: "Specify parent types for polymorphic associations. REQUIRED syntax: --parents model_polymorphic_name:Parent1,Parent2,Parent3 (e.g., --parents commentable:Post,Photo,Video)"
56
56
 
57
57
  def validate_model_exists
58
58
  # Ensure attributes are parsed before validation
@@ -544,7 +544,14 @@ module PropelApi
544
544
  polymorphic_attrs = @attributes.select { |attr| attr.type == :references && attr.respond_to?(:polymorphic?) && attr.polymorphic? }
545
545
 
546
546
  polymorphic_attrs.map do |attr|
547
- parent_types = polymorphic_parent_types[attr.name.to_s] || discover_available_models.first(1)
547
+ parent_types = polymorphic_parent_types[attr.name.to_s] || discover_available_models.first(3)
548
+
549
+ # Fallback to User if no parent types specified and no models auto-discovered
550
+ if parent_types.empty?
551
+ say "Warning: No parent types specified for polymorphic association '#{attr.name}' and no models found to auto-discover.", :yellow
552
+ say "Falling back to 'User' as parent type. Use --parents #{attr.name}:Parent1,Parent2,Parent3 to specify parent types.", :yellow
553
+ parent_types = ['User']
554
+ end
548
555
 
549
556
  # Create one association entry per polymorphic field with all parent types
550
557
  {
@@ -554,7 +561,7 @@ module PropelApi
554
561
  parent_types: parent_types,
555
562
  # For fixture generation, we'll use the first parent type for fixture "one", second for "two", etc.
556
563
  primary_parent_type: parent_types.first,
557
- primary_parent_table: parent_types.first.underscore.pluralize
564
+ primary_parent_table: parent_types.first&.underscore&.pluralize
558
565
  }
559
566
  end
560
567
  end
@@ -572,6 +579,10 @@ module PropelApi
572
579
  fixture_name = case parent_type.underscore
573
580
  when 'agency'
574
581
  ['marketing_agency', 'tech_agency', 'sales_agency'][fixture_index] || 'marketing_agency'
582
+ when 'user'
583
+ ['john_user', 'jane_user', 'confirmed_user'][fixture_index] || 'john_user'
584
+ when 'organization'
585
+ ['acme_org', 'tech_startup', 'acme_org'][fixture_index] || 'acme_org'
575
586
  else
576
587
  ['one', 'two', 'three'][fixture_index] || 'one'
577
588
  end
@@ -600,15 +611,18 @@ module PropelApi
600
611
  def discover_available_models
601
612
  # Auto-discover available models from app/models directory
602
613
  models_dir = File.join(destination_root, 'app/models')
603
- return ['Post'] unless File.directory?(models_dir) # Fallback
614
+ return [] unless File.directory?(models_dir) # No fallback - return empty array
604
615
 
605
616
  model_files = Dir[File.join(models_dir, '*.rb')]
606
- model_files.map do |file|
617
+ models = model_files.map do |file|
607
618
  File.basename(file, '.rb').camelize
608
619
  end.reject do |model|
609
620
  # Skip common non-domain models
610
621
  %w[ApplicationRecord Concerns].include?(model)
611
622
  end.sort
623
+
624
+ # Ensure we always return at least one model as fallback
625
+ models.empty? ? [] : models
612
626
  end
613
627
  end
614
628
  end
@@ -74,7 +74,7 @@ module PropelApi
74
74
  class_option :parents,
75
75
  type: :hash,
76
76
  default: {},
77
- desc: "Specify parent types for polymorphic associations (e.g., --parents commentable:Post,Photo,Video)"
77
+ desc: "Specify parent types for polymorphic associations. REQUIRED syntax: --parents field_name:Parent1,Parent2,Parent3 (e.g., --parents commentable:Post,Photo,Video)"
78
78
 
79
79
  def create_migration
80
80
  initialize_propel_api_settings
@@ -97,13 +97,13 @@ one:
97
97
  <%= attribute.name %>: "2024-06-15 10:30:00"
98
98
  <% elsif attribute.type == :time -%>
99
99
  <%= attribute.name %>: "10:30:00"
100
- <% elsif attribute.type == :json || attribute.name.to_s.match?(/^(metadata|settings)$/) -%>
100
+ <% elsif attribute.type == :json || attribute.type == :jsonb -%>
101
101
  <% if attribute.name == 'metadata' -%>
102
102
  <%= attribute.name %>: { resource_type: "<%= singular_table_name %>", category: "test", tags: ["fixture", "one"], attributes: { priority: "high", status_info: { verified: true, active: true } } }
103
103
  <% elsif attribute.name == 'settings' -%>
104
104
  <%= attribute.name %>: { ui_preferences: { theme: "light", language: "en", notifications: { email: true, sms: false, push: true } }, feature_flags: { beta_features: false, analytics: true } }
105
105
  <% else -%>
106
- <%= attribute.name %>: { test_data: "fixture_one" }
106
+ <%= attribute.name %>: { field_type: "jsonb_field", test_data: { string_value: "sample_text_one", numeric_value: 42, boolean_value: true, array_value: ["item1", "item2", "item3"], nested_object: { property: "value", settings: ["option1", "option2"] } }, metadata: { generated_by: "test_fixture", field_name: "<%= attribute.name %>", fixture_id: "one" } }
107
107
  <% end -%>
108
108
  <% else -%>
109
109
  <%= attribute.name %>: "test_value_one"
@@ -201,13 +201,13 @@ two:
201
201
  <%= attribute.name %>: "2023-12-25 15:45:00"
202
202
  <% elsif attribute.type == :time -%>
203
203
  <%= attribute.name %>: "15:45:00"
204
- <% elsif attribute.type == :json || attribute.name.to_s.match?(/^(metadata|settings)$/) -%>
204
+ <% elsif attribute.type == :json || attribute.type == :jsonb -%>
205
205
  <% if attribute.name == 'metadata' -%>
206
206
  <%= attribute.name %>: { resource_type: "<%= singular_table_name %>", category: "premium", tags: ["fixture", "two"], attributes: { priority: "medium", status_info: { verified: false, active: true } } }
207
207
  <% elsif attribute.name == 'settings' -%>
208
208
  <%= attribute.name %>: { ui_preferences: { theme: "dark", language: "fr", notifications: { email: true, sms: true, push: false } }, feature_flags: { beta_features: true, analytics: false } }
209
209
  <% else -%>
210
- <%= attribute.name %>: { test_data: "fixture_two" }
210
+ <%= attribute.name %>: { field_type: "jsonb_field", test_data: { string_value: "sample_text_two", numeric_value: 84, boolean_value: false, array_value: ["item4", "item5", "item6"], nested_object: { property: "different_value", settings: ["option3", "option4"] } }, metadata: { generated_by: "test_fixture", field_name: "<%= attribute.name %>", fixture_id: "two" } }
211
211
  <% end -%>
212
212
  <% else -%>
213
213
  <%= attribute.name %>: "test_value_two"
@@ -305,13 +305,13 @@ three:
305
305
  <%= attribute.name %>: "2025-03-10 08:15:00"
306
306
  <% elsif attribute.type == :time -%>
307
307
  <%= attribute.name %>: "08:15:00"
308
- <% elsif attribute.type == :json || attribute.name.to_s.match?(/^(metadata|settings)$/) -%>
308
+ <% elsif attribute.type == :json || attribute.type == :jsonb -%>
309
309
  <% if attribute.name == 'metadata' -%>
310
310
  <%= attribute.name %>: { resource_type: "<%= singular_table_name %>", category: "basic", tags: ["fixture", "three"], attributes: { priority: "low", status_info: { verified: true, active: false } } }
311
311
  <% elsif attribute.name == 'settings' -%>
312
312
  <%= attribute.name %>: { ui_preferences: { theme: "auto", language: "es", notifications: { email: false, sms: true, push: true } }, feature_flags: { beta_features: false, analytics: true } }
313
313
  <% else -%>
314
- <%= attribute.name %>: { test_data: "fixture_three" }
314
+ <%= attribute.name %>: { field_type: "jsonb_field", test_data: { string_value: "sample_text_three", numeric_value: 126, boolean_value: true, array_value: ["item7", "item8", "item9"], nested_object: { property: "final_value", settings: ["option5", "option6"] } }, metadata: { generated_by: "test_fixture", field_name: "<%= attribute.name %>", fixture_id: "three" } }
315
315
  <% end -%>
316
316
  <% else -%>
317
317
  <%= attribute.name %>: "test_value_three"
@@ -89,7 +89,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
89
89
  <%= attribute.name %>: "password123"<%= ',' if index < attributes.length - 1 %>
90
90
  <% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
91
91
  <%= attribute.name %>: "https://workflow.example.com"<%= ',' if index < attributes.length - 1 %>
92
- <% elsif attribute.name.to_s.end_with?('_type') -%>
92
+ <% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
93
93
  <%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
94
94
  <% else -%>
95
95
  <%= attribute.name %>: "Workflow Test <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
@@ -104,7 +104,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
104
104
  <%= attribute.name %>: 100.50<%= ',' if index < attributes.length - 1 %>
105
105
  <% elsif attribute.type == :datetime -%>
106
106
  <%= attribute.name %>: Time.current<%= ',' if index < attributes.length - 1 %>
107
- <% elsif attribute.type == :json || attribute.name.to_s.match?(/^(metadata|settings)$/) -%>
107
+ <% elsif attribute.type == :json || attribute.type == :jsonb -%>
108
108
  <% if attribute.name == 'metadata' -%>
109
109
  <%= attribute.name %>: { resource_type: "<%= singular_table_name %>", category: "test", tags: ["integration", "auto_generated"], attributes: { priority: "medium", status_info: { verified: true, active: true } } }<%= ',' if index < attributes.length - 1 %>
110
110
  <% elsif attribute.name == 'settings' -%>
@@ -117,7 +117,24 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
117
117
  feature_flags: { beta_features: false, analytics: true }
118
118
  }<%= ',' if index < attributes.length - 1 %>
119
119
  <% else -%>
120
- <%= attribute.name %>: {}<%= ',' if index < attributes.length - 1 %>
120
+ <%= attribute.name %>: {
121
+ field_type: "jsonb_field",
122
+ test_data: {
123
+ string_value: "api_test_data",
124
+ numeric_value: 123,
125
+ boolean_value: true,
126
+ array_value: ["test1", "test2", "test3"],
127
+ nested_object: {
128
+ property: "api_value",
129
+ settings: ["api_option1", "api_option2"]
130
+ }
131
+ },
132
+ metadata: {
133
+ generated_by: "integration_test",
134
+ field_name: "<%= attribute.name %>",
135
+ test_id: "workflow_test"
136
+ }
137
+ }<%= ',' if index < attributes.length - 1 %>
121
138
  <% end -%>
122
139
 
123
140
  <% elsif !reference_names.include?(attribute.name) -%>
@@ -161,6 +178,8 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
161
178
  <% elsif attribute.name.to_s.match?(/password/) -%>
162
179
  # Password fields should NOT be returned in API responses for security
163
180
  assert_not_includes created_<%= singular_table_name %>.keys, '<%= attribute.name %>', "Password fields should be filtered from API responses"
181
+ <% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
182
+ assert_equal "https://workflow.example.com", created_<%= singular_table_name %>['<%= attribute.name %>']
164
183
  <% else -%>
165
184
  assert_equal "Workflow Test <%= attribute.name.humanize %>", created_<%= singular_table_name %>['<%= attribute.name %>']
166
185
  <% end -%>
@@ -173,12 +192,12 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
173
192
  <% elsif attribute.type == :decimal || attribute.type == :float -%>
174
193
  # Rails conventionally serializes decimal/float values as strings in JSON
175
194
  assert_equal "100.5", created_<%= singular_table_name %>['<%= attribute.name %>']
176
- <% elsif attribute.type == :datetime || attribute.type == :timestamp || attribute.name.to_s.match?(/_at$/) -%>
195
+ <% elsif attribute.type == :datetime || attribute.type == :timestamp || (attribute.name.to_s.match?(/_at$/) && attribute.type != :json && attribute.type != :jsonb) -%>
177
196
  # Datetime fields should be properly formatted ISO timestamps, not exact values
178
197
  if created_<%= singular_table_name %>['<%= attribute.name %>'].present?
179
198
  assert_match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/, created_<%= singular_table_name %>['<%= attribute.name %>'], "<%= attribute.name %> should be ISO timestamp format")
180
199
  end
181
- <% elsif attribute.type == :json || attribute.name.to_s.match?(/^(metadata|settings)$/) -%>
200
+ <% elsif attribute.type == :json || attribute.type == :jsonb -%>
182
201
  <% if attribute.name == 'metadata' -%>
183
202
  # Metadata field should be a hash with generic structure
184
203
  assert_kind_of Hash, created_<%= singular_table_name %>['<%= attribute.name %>'], "Metadata should be a JSON object"
@@ -201,7 +220,35 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
201
220
  assert_includes created_<%= singular_table_name %>['<%= attribute.name %>']['ui_preferences'].keys, "notifications", "UI preferences should contain notifications"
202
221
  assert_kind_of Hash, created_<%= singular_table_name %>['<%= attribute.name %>']['ui_preferences']['notifications'], "Notifications should be a hash"
203
222
  <% else -%>
204
- assert_kind_of Hash, created_<%= singular_table_name %>['<%= attribute.name %>'], "<%= attribute.name %> should be a JSON object"
223
+ # Generic JSON field should have standard test structure
224
+ assert_kind_of Hash, created_<%= singular_table_name %>['<%= attribute.name %>'], "<%= attribute.name.humanize %> should be a JSON object"
225
+
226
+ # Verify main structure
227
+ assert_includes created_<%= singular_table_name %>['<%= attribute.name %>'].keys, "field_type", "<%= attribute.name.humanize %> should contain field_type"
228
+ assert_includes created_<%= singular_table_name %>['<%= attribute.name %>'].keys, "test_data", "<%= attribute.name.humanize %> should contain test_data"
229
+ assert_includes created_<%= singular_table_name %>['<%= attribute.name %>'].keys, "metadata", "<%= attribute.name.humanize %> should contain metadata"
230
+
231
+ # Verify test_data structure (tests all JSON data types)
232
+ test_data = created_<%= singular_table_name %>['<%= attribute.name %>']['test_data']
233
+ assert_kind_of Hash, test_data, "test_data should be a hash"
234
+ assert_includes test_data.keys, "string_value", "test_data should contain string_value"
235
+ assert_includes test_data.keys, "numeric_value", "test_data should contain numeric_value"
236
+ assert_includes test_data.keys, "boolean_value", "test_data should contain boolean_value"
237
+ assert_includes test_data.keys, "array_value", "test_data should contain array_value"
238
+ assert_includes test_data.keys, "nested_object", "test_data should contain nested_object"
239
+
240
+ # Verify data types
241
+ assert_kind_of String, test_data['string_value'], "string_value should be a string"
242
+ assert_kind_of Integer, test_data['numeric_value'], "numeric_value should be a number"
243
+ assert_kind_of Array, test_data['array_value'], "array_value should be an array"
244
+ assert_kind_of Hash, test_data['nested_object'], "nested_object should be a hash"
245
+
246
+ # Verify metadata structure
247
+ metadata = created_<%= singular_table_name %>['<%= attribute.name %>']['metadata']
248
+ assert_kind_of Hash, metadata, "metadata should be a hash"
249
+ assert_includes metadata.keys, "generated_by", "metadata should contain generated_by"
250
+ assert_includes metadata.keys, "field_name", "metadata should contain field_name"
251
+ assert_equal "<%= attribute.name %>", metadata['field_name'], "metadata field_name should match attribute name"
205
252
  <% end -%>
206
253
  <% else -%>
207
254
  assert_equal "workflow_test", created_<%= singular_table_name %>['<%= attribute.name %>']
@@ -599,7 +646,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
599
646
  <%= attribute.name %>: "org1_secure_password"<%= ',' if index < attributes.length - 1 %>
600
647
  <% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
601
648
  <%= attribute.name %>: "https://org1.example.com"<%= ',' if index < attributes.length - 1 %>
602
- <% elsif attribute.name.to_s.end_with?('_type') -%>
649
+ <% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
603
650
  <%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
604
651
  <% else -%>
605
652
  <%= attribute.name %>: "Org 1 <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
@@ -612,7 +659,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
612
659
  <%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
613
660
  <% elsif attribute.type == :decimal || attribute.type == :float -%>
614
661
  <%= attribute.name %>: 11.1<%= ',' if index < attributes.length - 1 %>
615
- <% elsif attribute.type == :json || attribute.name.to_s.match?(/^(metadata|settings)$/) -%>
662
+ <% elsif attribute.type == :json || attribute.type == :jsonb -%>
616
663
  <% if attribute.name == 'metadata' -%>
617
664
  <%= attribute.name %>: {
618
665
  resource_type: "<%= singular_table_name %>",
@@ -626,7 +673,24 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
626
673
  <% elsif attribute.name == 'settings' -%>
627
674
  <%= attribute.name %>: { dark_mode: false, notifications: { email: true, sms: true } }<%= ',' if index < attributes.length - 1 %>
628
675
  <% else -%>
629
- <%= attribute.name %>: {}<%= ',' if index < attributes.length - 1 %>
676
+ <%= attribute.name %>: {
677
+ field_type: "jsonb_field",
678
+ test_data: {
679
+ string_value: "api_test_data",
680
+ numeric_value: 123,
681
+ boolean_value: true,
682
+ array_value: ["test1", "test2", "test3"],
683
+ nested_object: {
684
+ property: "api_value",
685
+ settings: ["api_option1", "api_option2"]
686
+ }
687
+ },
688
+ metadata: {
689
+ generated_by: "integration_test",
690
+ field_name: "<%= attribute.name %>",
691
+ test_id: "workflow_test"
692
+ }
693
+ }<%= ',' if index < attributes.length - 1 %>
630
694
  <% end -%>
631
695
  <% else -%>
632
696
  <%= attribute.name %>: "org1_value"<%= ',' if index < attributes.length - 1 %>
@@ -649,7 +713,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
649
713
  <%= attribute.name %>: "org2_secure_password"<%= ',' if index < attributes.length - 1 %>
650
714
  <% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
651
715
  <%= attribute.name %>: "https://org2.example.com"<%= ',' if index < attributes.length - 1 %>
652
- <% elsif attribute.name.to_s.end_with?('_type') -%>
716
+ <% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
653
717
  <%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
654
718
  <% else -%>
655
719
  <%= attribute.name %>: "Org 2 <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
@@ -662,7 +726,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
662
726
  <%= attribute.name %>: false<%= ',' if index < attributes.length - 1 %>
663
727
  <% elsif attribute.type == :decimal || attribute.type == :float -%>
664
728
  <%= attribute.name %>: 22.2<%= ',' if index < attributes.length - 1 %>
665
- <% elsif attribute.type == :json || attribute.name.to_s.match?(/^(metadata|settings)$/) -%>
729
+ <% elsif attribute.type == :json || attribute.type == :jsonb -%>
666
730
  <% if attribute.name == 'metadata' -%>
667
731
  <%= attribute.name %>: {
668
732
  resource_type: "<%= singular_table_name %>",
@@ -676,7 +740,24 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
676
740
  <% elsif attribute.name == 'settings' -%>
677
741
  <%= attribute.name %>: { dark_mode: true, notifications: { email: false, sms: true } }<%= ',' if index < attributes.length - 1 %>
678
742
  <% else -%>
679
- <%= attribute.name %>: {}<%= ',' if index < attributes.length - 1 %>
743
+ <%= attribute.name %>: {
744
+ field_type: "jsonb_field",
745
+ test_data: {
746
+ string_value: "api_test_data",
747
+ numeric_value: 123,
748
+ boolean_value: true,
749
+ array_value: ["test1", "test2", "test3"],
750
+ nested_object: {
751
+ property: "api_value",
752
+ settings: ["api_option1", "api_option2"]
753
+ }
754
+ },
755
+ metadata: {
756
+ generated_by: "integration_test",
757
+ field_name: "<%= attribute.name %>",
758
+ test_id: "workflow_test"
759
+ }
760
+ }<%= ',' if index < attributes.length - 1 %>
680
761
  <% end -%>
681
762
  <% else -%>
682
763
  <%= attribute.name %>: "org2_value"<%= ',' if index < attributes.length - 1 %>
@@ -809,7 +890,7 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
809
890
  <%= attribute.name %>: "concurrent@example.com"<%= ',' if index < attributes.length - 1 %>
810
891
  <% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
811
892
  <%= attribute.name %>: "https://concurrent.example.com"<%= ',' if index < attributes.length - 1 %>
812
- <% elsif attribute.name.to_s.end_with?('_type') -%>
893
+ <% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
813
894
  <%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
814
895
  <% else -%>
815
896
  <%= attribute.name %>: "Concurrent Test <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
@@ -822,7 +903,7 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
822
903
  <%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
823
904
  <% elsif attribute.type == :decimal || attribute.type == :float -%>
824
905
  <%= attribute.name %>: 50.5<%= ',' if index < attributes.length - 1 %>
825
- <% elsif attribute.type == :json || attribute.name.to_s.match?(/^(metadata|settings)$/) -%>
906
+ <% elsif attribute.type == :json || attribute.type == :jsonb -%>
826
907
  <% if attribute.name == 'metadata' -%>
827
908
  <%= attribute.name %>: {
828
909
  resource_type: "<%= singular_table_name %>",
@@ -843,7 +924,24 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
843
924
  feature_flags: { beta_features: false, analytics: true }
844
925
  }<%= ',' if index < attributes.length - 1 %>
845
926
  <% else -%>
846
- <%= attribute.name %>: {}<%= ',' if index < attributes.length - 1 %>
927
+ <%= attribute.name %>: {
928
+ field_type: "jsonb_field",
929
+ test_data: {
930
+ string_value: "api_test_data",
931
+ numeric_value: 123,
932
+ boolean_value: true,
933
+ array_value: ["test1", "test2", "test3"],
934
+ nested_object: {
935
+ property: "api_value",
936
+ settings: ["api_option1", "api_option2"]
937
+ }
938
+ },
939
+ metadata: {
940
+ generated_by: "integration_test",
941
+ field_name: "<%= attribute.name %>",
942
+ test_id: "workflow_test"
943
+ }
944
+ }<%= ',' if index < attributes.length - 1 %>
847
945
  <% end -%>
848
946
  <% else -%>
849
947
  <%= attribute.name %>: "concurrent_test"<%= ',' if index < attributes.length - 1 %>
@@ -928,7 +1026,7 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
928
1026
  <%= attribute.name %>: "bulk#{i}@example.com"<%= ',' if index < attributes.length - 1 %>
929
1027
  <% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
930
1028
  <%= attribute.name %>: "https://bulk#{i}.example.com"<%= ',' if index < attributes.length - 1 %>
931
- <% elsif attribute.name.to_s.end_with?('_type') -%>
1029
+ <% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
932
1030
  <%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
933
1031
  <% else -%>
934
1032
  <%= attribute.name %>: "Bulk Test <%= attribute.name.humanize %> #{i}"<%= ',' if index < attributes.length - 1 %>
@@ -941,7 +1039,7 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
941
1039
  <%= attribute.name %>: i.even?<%= ',' if index < attributes.length - 1 %>
942
1040
  <% elsif attribute.type == :decimal || attribute.type == :float -%>
943
1041
  <%= attribute.name %>: i * 10.5<%= ',' if index < attributes.length - 1 %>
944
- <% elsif attribute.type == :json || attribute.name.to_s.match?(/^(metadata|settings)$/) -%>
1042
+ <% elsif attribute.type == :json || attribute.type == :jsonb -%>
945
1043
  <% if attribute.name == 'metadata' -%>
946
1044
  <%= attribute.name %>: {
947
1045
  resource_type: "<%= singular_table_name %>",
@@ -955,7 +1053,24 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
955
1053
  <% elsif attribute.name == 'settings' -%>
956
1054
  <%= attribute.name %>: { dark_mode: i.even?, notifications: { email: true, sms: i.even? } }<%= ',' if index < attributes.length - 1 %>
957
1055
  <% else -%>
958
- <%= attribute.name %>: {}<%= ',' if index < attributes.length - 1 %>
1056
+ <%= attribute.name %>: {
1057
+ field_type: "jsonb_field",
1058
+ test_data: {
1059
+ string_value: "api_test_data",
1060
+ numeric_value: 123,
1061
+ boolean_value: true,
1062
+ array_value: ["test1", "test2", "test3"],
1063
+ nested_object: {
1064
+ property: "api_value",
1065
+ settings: ["api_option1", "api_option2"]
1066
+ }
1067
+ },
1068
+ metadata: {
1069
+ generated_by: "integration_test",
1070
+ field_name: "<%= attribute.name %>",
1071
+ test_id: "workflow_test"
1072
+ }
1073
+ }<%= ',' if index < attributes.length - 1 %>
959
1074
  <% end -%>
960
1075
  <% else -%>
961
1076
  <%= attribute.name %>: "bulk_#{i}"<%= ',' if index < attributes.length - 1 %>
data/lib/propel_api.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module PropelApi
2
- VERSION = "0.3.1.2"
2
+ VERSION = "0.3.1.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: propel_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1.2
4
+ version: 0.3.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Martin, Rafael Pivato, Chi Putera