lib/svelte_on_rails/lib/to_svelte.rb
module SvelteOnRails module Lib class SvelteAttributes def initialize @labels = {} end def calculate_instance(record, attributes, call_stack: 0, offset: nil, limit: nil) next_stack = call_stack + 1 if record.respond_to?(:each) recs2 = if offset || limit if (record.is_a?(ActiveRecord::Relation) || record.is_a?(ActiveRecord::Associations::CollectionProxy) rescue false) _recs = (offset ? record.offset(offset) : record) (limit ? _recs.limit(limit) : _recs) elsif record.respond_to?(:drop) && record.respond_to?(:take) # that might be a array _recs = offset ? record.drop(offset) : record limit ? _recs.take(limit) : _recs else raise "[svelte-on-rails:to_svelte] unknown class for records: #{record}" end else record end set_labels(record.first, attributes) values = recs2.map do |rec| calculate_instance(rec, attributes, call_stack: next_stack) end else # we have a single record values = {} set_labels(record, attributes) attributes.each do |attr| if attr.is_a? Hash # we have associations attr.each do |key, value| next if ['offset', 'limit'].include?(key.to_s) _offset, _limit, _value = extract_limit(value) _key = key.to_s # inspect association and set_labels reflect = record.class.reflect_on_association(_key) raise "invalid association: #{_key}" unless reflect set_labels(reflect, value) # values recs = record.send(_key) if recs.present? if recs.respond_to?(:each) values[_key] = calculate_instance( recs, value, call_stack: next_stack, offset: _offset, limit: _limit ) else values[_key] = calculate_instance( recs, value, call_stack: next_stack ) end end end else # we have attributes raise 'Invalid attribute' unless [Symbol, String].include?(attr.class) _key = attr.to_s values[_key] = record.send(_key) end end end if call_stack >= 1 values else { 'values' => values }.merge(@labels) end end def calculate_class(model, attributes, call_stack: 0) next_stack = call_stack + 1 set_labels(model, attributes) hash = attributes.find { |element| element.is_a?(Hash) } || {} hash.each do |key, value| reflect = model.reflect_on_association(key.to_s) if reflect calculate_class( reflect, value, call_stack: next_stack ) end end if call_stack == 0 @labels end end def calculate_relation(relation, attributes, call_stack: 0) set_labels(relation.klass, attributes) values = relation.map do |rec| calculate_instance(rec, attributes)['values'] end { 'values' => values }.merge(@labels) end private def extract_limit(attributes) _hash_args = attributes.grep(Hash).first.dup attr, lim = if _hash_args.present? hash_args = _hash_args.transform_keys { |key| key.to_s } # multiple arrays is not possible hash_remainder = hash_args.reject { |key, _| %w[offset limit].include?(key.to_s) } _attr = attributes.reject { |item| item.is_a?(Hash) } [ if hash_remainder.any? _attr + [hash_remainder] else _attr end, hash_args ] else [ attributes, {} ] end [ lim['offset'], lim['limit'], attr ] end def set_labels(record, keys) first_hash = keys.find { |element| element.is_a?(Hash) } _keys = keys.reject { |element| element.is_a?(Hash) } _keys += first_hash.keys if first_hash _keys.each do |attr| unless attr.respond_to?(:each) obj = if record.respond_to?(:human_attribute_name) record elsif record.class.respond_to?(:human_attribute_name) record.class end next unless obj @labels["#{obj.to_s.underscore}_labels"] ||= {} @labels["#{obj.to_s.underscore}_labels"][attr.to_s] ||= obj.human_attribute_name(attr) end end end end end end