@@ -8,15 +8,38 @@ module ShopifyToolkit::MetaobjectStatements
88 include ShopifyToolkit ::AdminClient
99 include ShopifyToolkit ::MetaobjectUtilities
1010
11+ @@pending_field_validations = [ ]
12+
1113 def self . log_time ( method_name )
1214 current_method = instance_method ( method_name )
1315 define_method ( method_name ) do |*args , **kwargs , &block |
1416 say_with_time ( "#{ method_name } (#{ args . map ( &:inspect ) . join ( ', ' ) } )" ) { current_method . bind ( self ) . call ( *args , **kwargs , &block ) }
1517 end
1618 end
1719
18- # create_metafield :products, :my_metafield, :single_line_text_field, name: "Prova"
19- # @param namespace: if nil the metafield will be app-specific (default: :custom)
20+ def apply_pending_field_validations
21+ return if @@pending_field_validations . empty?
22+
23+ say "Applying #{ @@pending_field_validations . size } pending field validations"
24+
25+ @@pending_field_validations . reject! do |item |
26+ metaobject_type = item [ :metaobject_type ]
27+ field_key = item [ :field_key ]
28+ validations = item [ :validations ]
29+
30+ begin
31+ success = add_field_validations_to_metaobject ( metaobject_type , field_key , validations , item )
32+ unless success
33+ say "-- Deferring field '#{ field_key } ' in '#{ metaobject_type } ' (missing dependencies)"
34+ end
35+ success
36+ rescue StandardError => e
37+ say "-- Failed to process field '#{ field_key } ' in '#{ metaobject_type } ': #{ e . message } "
38+ true # Remove from array (don't retry errors)
39+ end
40+ end
41+ end
42+
2043 log_time \
2144 def create_metaobject_definition ( type , **options )
2245 # Skip creation if metaobject already exists
@@ -29,27 +52,116 @@ def create_metaobject_definition(type, **options)
2952 # Transform options for GraphQL API
3053 definition = options . merge ( type : type . to_s )
3154
32- # Convert field_definitions to fieldDefinitions and transform field structure
33- if options [ :field_definitions ]
34- definition [ :fieldDefinitions ] = options [ :field_definitions ] . map do |field |
35- field_def = {
36- key : field [ :key ] . to_s ,
37- name : field [ :name ] ,
38- type : field [ :type ] . to_s
39- }
40- field_def [ :description ] = field [ :description ] if field [ :description ]
41- field_def [ :required ] = field [ :required ] if field [ :required ]
55+ begin
56+ # Convert field_definitions to fieldDefinitions and transform field structure
57+ if options [ :field_definitions ]
58+ definition [ :fieldDefinitions ] = options [ :field_definitions ] . filter_map do |field |
59+ field_def = build_field_definition ( field )
60+ field_needs_validations = is_metaobject_reference_type? ( field [ :type ] )
61+
62+ if field [ :validations ]
63+ begin
64+ converted_validations = convert_validations_types_to_gids ( field [ :validations ] )
65+ field_def [ :validations ] = converted_validations if converted_validations &.any?
66+ rescue RuntimeError => e
67+ if e . message . include? ( "not found" )
68+ @@pending_field_validations << {
69+ metaobject_type : type ,
70+ field_key : field [ :key ] ,
71+ field_definition : field ,
72+ validations : field [ :validations ]
73+ }
74+ say "Deferring field '#{ field [ :key ] } ' in '#{ type } ' (missing dependency)"
75+
76+ if field_needs_validations
77+ next # Skip this field entirely
78+ end
79+ end
80+ end
81+ elsif field_needs_validations
82+ next # Skip fields that need validations but don't have any
83+ end
84+
85+ field_def
86+ end
87+
88+ definition . delete ( :field_definitions )
89+ end
90+
91+ # Remove admin access to avoid API restrictions
92+ if definition [ :access ] &.is_a? ( Hash )
93+ definition [ :access ] = definition [ :access ] . dup
94+ definition [ :access ] . delete ( "admin" ) if definition [ :access ] [ "admin" ]
95+ definition . delete ( :access ) if definition [ :access ] . empty?
96+ end
4297
43- # Convert validations from types to GIDs if present
44- if field [ :validations ]
45- converted_validations = convert_validations_types_to_gids ( field [ :validations ] )
46- field_def [ :validations ] = converted_validations if converted_validations &. any ?
98+ # Clean up empty validations arrays that cause API errors
99+ if definition [ :fieldDefinitions ]
100+ definition [ :fieldDefinitions ] . each do | field_def |
101+ field_def . delete ( :validations ) if field_def [ :validations ] &. empty ?
47102 end
103+ end
104+
105+ result = create_metaobject_definition_immediate ( definition )
106+ result
107+ end
108+ end
48109
49- field_def
110+ def add_field_validations_to_metaobject ( metaobject_type , field_key , validations , item = nil )
111+ # Get the existing metaobject definition
112+ existing_gid = get_metaobject_definition_gid ( metaobject_type )
113+ unless existing_gid
114+ say "Error: Cannot add validations to '#{ metaobject_type } ' - metaobject not found"
115+ return false
116+ end
117+
118+ begin
119+ converted_validations = convert_validations_types_to_gids ( validations )
120+
121+ if converted_validations &.any?
122+ # Use the passed item, or try to find it (for backward compatibility)
123+ if item . nil?
124+ item = @@pending_field_validations . find { |pending_item |
125+ pending_item [ :metaobject_type ] == metaobject_type && pending_item [ :field_key ] == field_key
126+ }
127+ end
128+
129+ if item && item [ :field_definition ]
130+ field_def = item [ :field_definition ]
131+ new_field = build_field_definition ( field_def , converted_validations )
132+
133+ field_operation = { create : new_field }
134+ update_metaobject_definition ( metaobject_type , fieldDefinitions : [ field_operation ] )
135+
136+ say "Added field '#{ field_key } ' to '#{ metaobject_type } '"
137+ return true
138+ else
139+ return false
140+ end
141+ else
142+ return false
50143 end
144+
145+ rescue RuntimeError
146+ return false # Keep trying later or don't retry errors
51147 end
148+ end
149+
150+ private
151+
152+ def build_field_definition ( field , validations = nil )
153+ field_def = {
154+ key : field [ :key ] . to_s ,
155+ name : field [ :name ] ,
156+ type : field [ :type ] . to_s
157+ }
158+ field_def [ :description ] = field [ :description ] if field [ :description ]
159+ field_def [ :required ] = field [ :required ] if field [ :required ]
160+ field_def [ :validations ] = validations if validations &.any?
161+ field_def
162+ end
52163
164+ def create_metaobject_definition_immediate ( definition )
53165 # https://shopify.dev/docs/api/admin-graphql/2024-10/mutations/metaobjectDefinitionCreate
54166 query =
55167 "# GraphQL
0 commit comments