class Eco::API::Common::People::DefaultParsers::DateParser < Eco::API::Common::Loaders::Parser attribute :date MIN_DATE = '1901-01-02'.freeze MAX_DATE = '2099-12-31'.freeze def parser(value, deps) parse_date(value, attr: deps['attr']) end def serializer(value, _deps) serialize_date(value) end private def parse_date(value, attr:) return value.map {|val| parse_date(val, attr: attr)}.compact if value.is_a?(Enumerable) return nil if value.nil? value = value.to_s.strip return nil if value.empty? if date?(value) Date.parse(value).then do |date| next date if valid_range?(date) wrong!(value, attr: attr, desc: 'Date out of range (1900-2099). Given: ') nil end else wrong!(value, attr: attr) nil end rescue TypeError, Date::Error nil end def serialize_date(value) return value.map {|val| serialize_date(val)}.compact if value.is_a?(Enumerable) return nil if value.nil? return nil if value.to_s.strip.empty? return value if value.is_a?(String) return nil unless [Date, Time].any? {|type| value.is_a?(type)} value&.strftime('%Y-%m-%d') rescue TypeError, Date::Error nil end def wrong!(value, attr:, desc: "Can't make a date out of") return if wrong(attr).key?(value) wrong(attr)[value] = value log(:warn) { "#{desc} '#{value}' for '#{attr}'" } end def wrong(attr = nil) @wrong ||= {} return @wrong if attr.nil? @wrong[attr] ||= {} end def date?(value) return true if value.nil? return true if value.to_s.strip.empty? Date.parse(value) true rescue TypeError, Date::Error false end def valid_range?(date) return true if date.nil? return false unless min_date <= date max_date >= date end def min_date @min_date ||= Date.parse(MIN_DATE) end def max_date @max_date ||= Date.parse(MAX_DATE) end end