diff --git a/Gemfile.lock b/Gemfile.lock index 2db8f75..ce36fcc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,7 +3,7 @@ PATH specs: ar_sync (1.0.3) activerecord - ar_serializer (= 1.0.0) + ar_serializer GEM remote: https://rubygems.org/ @@ -21,7 +21,7 @@ GEM i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - ar_serializer (1.0.0) + ar_serializer (1.1.0) activerecord top_n_loader arel (9.0.0) @@ -37,7 +37,7 @@ GEM rake (12.3.2) sqlite3 (1.3.13) thread_safe (0.3.6) - top_n_loader (1.0.0) + top_n_loader (1.0.1) activerecord tzinfo (1.2.5) thread_safe (~> 0.1) @@ -53,4 +53,4 @@ DEPENDENCIES sqlite3 BUNDLED WITH - 1.16.1 + 2.1.2 diff --git a/ar_sync.gemspec b/ar_sync.gemspec index d9b6022..904a356 100644 --- a/ar_sync.gemspec +++ b/ar_sync.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.add_dependency 'activerecord' - spec.add_dependency 'ar_serializer', '1.0.0' + spec.add_dependency 'ar_serializer' %w[rake pry sqlite3 activerecord-import].each do |gem_name| spec.add_development_dependency gem_name end diff --git a/lib/ar_sync/class_methods.rb b/lib/ar_sync/class_methods.rb index 9dab500..f0ee62c 100644 --- a/lib/ar_sync/class_methods.rb +++ b/lib/ar_sync/class_methods.rb @@ -64,14 +64,14 @@ def _sync_has_many(name, order: :asc, limit: nil, preload: nil, association: nil raise "order not in [:asc, :desc] : #{order}" unless %i[asc desc].include? order if data_block.nil? && preload.nil? underscore_name = name.to_s.underscore.to_sym - preload = lambda do |records, _context, params| + preload = lambda do |records, _context, **params| ArSerializer::Field.preload_association( self, records, association || underscore_name, order: (!limit && params && params[:order]) || order, limit: [params && params[:limit]&.to_i, limit].compact.min ) end - data_block = lambda do |preloaded, _context, params| + data_block = lambda do |preloaded, _context, **params| records = preloaded ? preloaded[id] || [] : send(name) next records unless limit || order == :asc ArSync::CollectionWithOrder.new( @@ -80,7 +80,7 @@ def _sync_has_many(name, order: :asc, limit: nil, preload: nil, association: nil limit: [params && params[:limit]&.to_i, limit].compact.min ) end - serializer_data_block = lambda do |preloaded, _context, _params| + serializer_data_block = lambda do |preloaded, _context, **_params| preloaded ? preloaded[id] || [] : send(name) end params_type = { limit?: :int, order?: [{ :* => %w[asc desc] }, 'asc', 'desc'] } diff --git a/lib/ar_sync/instance_methods.rb b/lib/ar_sync/instance_methods.rb index ee19492..c052291 100644 --- a/lib/ar_sync/instance_methods.rb +++ b/lib/ar_sync/instance_methods.rb @@ -33,10 +33,10 @@ def _sync_current_parents_info def _serializer_field_value(name) field = self.class._serializer_field_info name preloadeds = field.preloaders.map do |preloader| - args = [[self], nil, {}] + args = [[self], nil] preloader.call(*(preloader.arity < 0 ? args : args.take(preloader.arity))) end - instance_exec(*preloadeds, nil, {}, &field.data_block) + instance_exec(*preloadeds, nil, &field.data_block) end def _sync_current_belongs_to_info diff --git a/lib/ar_sync/type_script.rb b/lib/ar_sync/type_script.rb index 9996352..777ba03 100644 --- a/lib/ar_sync/type_script.rb +++ b/lib/ar_sync/type_script.rb @@ -10,17 +10,14 @@ def self.generate_typed_files(api_class, dir:, comment: nil) end def self.generate_type_definition(api_class) + types = ArSerializer::TypeScript.related_serializer_types([api_class]).reject { |t| t.type == api_class } [ - ArSerializer::TypeScript.generate_type_definition(api_related_classes(api_class)), + types.map { |t| data_type_definition t }, + types.map { |t| query_type_definition t }, request_type_definition(api_class) ].join "\n" end - def self.api_related_classes(api_class) - classes = ArSerializer::TypeScript.related_serializer_types([api_class]).map(&:type) - classes - [api_class] - end - def self.request_type_definition(api_class) type = ArSerializer::GraphQL::TypeClass.from api_class definitions = [] @@ -98,4 +95,42 @@ def self.generate_hooks_script } CODE end + + def self.query_type_definition(type) + field_definitions = type.fields.map do |field| + association_type = field.type.association_type + if association_type + qname = "Type#{association_type.name}Query" + if field.args.empty? + "#{field.name}?: true | #{qname} | { attributes?: #{qname} }" + else + "#{field.name}?: true | #{qname} | { params: #{field.args_ts_type}; attributes?: #{qname} }" + end + else + "#{field.name}?: true" + end + end + field_definitions << "'*'?: true" + query_type_name = "Type#{type.name}Query" + base_query_type_name = "Type#{type.name}QueryBase" + <<~TYPE + export type #{query_type_name} = keyof (#{base_query_type_name}) | Readonly<(keyof (#{base_query_type_name}))[]> | #{base_query_type_name} + export interface #{base_query_type_name} { + #{field_definitions.map { |line| " #{line}" }.join("\n")} + } + TYPE + end + + def self.data_type_definition(type) + field_definitions = [] + type.fields.each do |field| + field_definitions << "#{field.name}: #{field.type.ts_type}" + end + field_definitions << "_meta?: { name: '#{type.name}'; query: Type#{type.name}QueryBase }" + <<~TYPE + export interface Type#{type.name} { + #{field_definitions.map { |line| " #{line}" }.join("\n")} + } + TYPE + end end