lib/eco/api/common/people/person_entry.rb in eco-helpers-0.8.3 vs lib/eco/api/common/people/person_entry.rb in eco-helpers-0.8.4

- old
+ new

@@ -1,10 +1,11 @@ module Eco module API module Common module People class PersonEntry + # This class is meant to provide a common interface to access entries of source data that come in different formats. # @note # - if `data` is a `Person` object, its behaviour is `serialise`. # - if `data` is **not** a `Person` object, it does a `parse`. # - currently **in rework**, so there may be subtle differences that make it temporarily unstable (yet it is reliable). @@ -15,25 +16,25 @@ # @param logger [Common::Session::Logger, ::Logger] object to manage logs. def initialize(data, person_parser:, attr_map:, dependencies: {}, logger: ::Logger.new(IO::NULL)) raise "Constructor needs a PersonParser. Given: #{parser}" if !person_parser.is_a?(Eco::API::Common::People::PersonParser) raise "Expecting Mapper object. Given: #{attr_map}" if attr_map && !attr_map.is_a?(Eco::Data::Mapper) - @source = data + @source = data @person_parser = person_parser - @deps = dependencies - @logger = logger - @attr_map = attr_map + @deps = dependencies + @logger = logger + @attr_map = attr_map @emap = PersonEntryAttributeMapper.new(@source, person_parser: @person_parser, attr_map: @attr_map, logger: @logger) if parsing? @external_entry = data - @serialized_entry = mapped_entry(@external_entry) - @internal_entry = internal_entry(@serialized_entry) + @serialized_entry = _mapped_entry(@external_entry) + @internal_entry = _internal_entry(@serialized_entry) else # SERIALIZING @person = data - @internal_entry = internal_entry(@person) - @serialized_entry = mapped_entry(@internal_entry) + @internal_entry = _internal_entry(@person) + @serialized_entry = _mapped_entry(@internal_entry) #@external_entry = external_entry end end # To know if currently the object is in parse or serialize mode. @@ -97,11 +98,11 @@ # @param person [Person] the person we want to set the core values to. # @param exclude [String, Array<String>] core attributes that should not be set/changed to the person. def set_core(person, exclude: nil) scoped_attrs = @emap.core_attrs - into_a(exclude) @internal_entry.slice(*scoped_attrs).each do |attr, value| - set_to_core(person, attr, value) + _set_to_core(person, attr, value) end end # Setter to fill in all the schema `details` fields of the `Person` that are present in the `Entry`. # @note it only sets those details properties defined in the entry. @@ -110,11 +111,11 @@ # @param exclude [String, Array<String>] schema field attributes that should not be set/changed to the person. def set_details(person, exclude: nil) person.add_details(@person_parser.schema) if !person.details || !person.details.schema_id scoped_attrs = @emap.details_attrs - into_a(exclude) @internal_entry.slice(*scoped_attrs).each do |attr, value| - set_to_details(person, attr, value) + _set_to_details(person, attr, value) end end # Setter to fill in the `account` properties of the `Person` that are present in the `Entry`. # @note it only sets those account properties defined in the entry. @@ -124,11 +125,11 @@ def set_account(person, exclude: nil) person.account = {} if !person.account person.account.permissions_preset = nil unless person.account.permissions_preset = "custom" scoped_attrs = @emap.account_attrs - into_a(exclude) @internal_entry.slice(*scoped_attrs).each do |attr, value| - set_to_account(person, attr, value) + _set_to_account(person, attr, value) end end # Entry represented in a `Hash` with **external** attribute names and values thereof. # @note normally used to obtain a **serialized entry**. @@ -146,18 +147,54 @@ hash[ext_attr] = @serialized_entry[attr] end end end + def internal_entry + @internal_entry + end + + def doc + return @person.doc if instance_variable_defined?(:@person) && @person + + core_attrs = @emap.core_attrs + details_attrs = @emap.details_attrs + account_attrs = @emap.account_attrs + + internal_entry.slice(*core_attrs).tap do |core_hash| + unless details_attrs.empty? + schema_id = @person_parser.schema.id + details_fields = @person_parser.schema.doc["fields"].each_with_object([]) do |fld, flds| + if details_attrs.include?(fld.alt_id) + flds << fld.merge("value" => internal_entry[fld.alt_id]).slice("id", "alt_id", "type", "name", "shared", "multiple", "value") + end + end + core_hash.merge!({ + "details" => { + "schema_id" => schema_id, + "fields" => details_fields + } + }) + end + + unless account_attrs.empty? + account_hash = internal_entry.slice(*account_attrs) + core_hash.merge!({ + "account" => account_hash + }) + end + end + end + private - def set_to_core(person, attr, value) + def _set_to_core(person, attr, value) value = value&.downcase if attr == "email" person.send("#{attr}=", value&.strip) end - def set_to_account(person, attr, value) + def _set_to_account(person, attr, value) return if !person.account multiple = ["policy_group_ids", "filter_tags"].include?(attr) if multiple value = @person_parser.parse(:multiple, value) value = value.map { |v| v&.upcase } if attr == "filter_tags" @@ -167,11 +204,11 @@ end person.account.send("#{attr}=", value) end - def set_to_details(person, attr, value) + def _set_to_details(person, attr, value) return if !person.details unless field = person.details.get_field(attr) fatal("Field '#{attr}' does not exist in details of schema: '#{person.details.schema_id}'") end value = nil if value.to_s.empty? @@ -182,22 +219,22 @@ end person.details[attr] = value end - def get_from_core (person, attr) + def _get_from_core (person, attr) person.send(attr) end - def get_from_account (person, attr) + def _get_from_account (person, attr) return nil if !person.account multiple = ["policy_group_ids", "filter_tags"].include?(attr) value = person.account.send(attr) @person_parser.serialize(:multiple, value) if multiple end - def get_from_details(person, attr) + def _get_from_details(person, attr) return nil if !person.details || !person&.details&.schema_id unless field = person.details.get_field(attr) fatal("Field '#{attr}' does not exist in details of schema: '#{person.details.schema_id}'") end value = person.details[attr] @@ -208,20 +245,20 @@ # MAPPED ENTRY (when and where applicable) # To obtain an entry with internal names but external values. # @param data [Hash] external or raw entry (when parsing) or internal or parsed entry (when serializing). # @return [Hash] entry with **internal names** and **external values**. - def mapped_entry(data) - return aliased_entry(data) if parsing? - serialized_entry(data) + def _mapped_entry(data) + return _aliased_entry(data) if parsing? + _serialized_entry(data) end # Parsing helper that aliases attribute names (from internal to external names) # @note **Parse**: here we aliase internal attribute names into external ones. # @param ext_entry [Hash] entry in raw, with **external** names and values. # @return [Hash] entry with **internal names** and **external values**. - def aliased_entry(ext_entry) + def _aliased_entry(ext_entry) aliased_hash = @emap.aliased_attrs.map do |attr| [attr, ext_entry[@emap.to_external(attr)]] end.to_h ext_entry.slice(*@emap.direct_attrs).merge(aliased_hash) @@ -236,11 +273,11 @@ # @note **Serializing**: # 1. here we tranform internal into external **values**. # 2. when running the serializers, it overrides existing keys. # @param unserialized_entry [Hash] entry with **internal** names and values. # @return [Hash] entry with **internal names** and **external values**. - def serialized_entry(unserialized_entry) + def _serialized_entry(unserialized_entry) serial_attrs = @person_parser.defined_attrs.reduce({}) do |serial_hash, attr| deps = @deps[attr] || {} serial_attr = @person_parser.serialize(attr, @person, deps: deps) serial_hash.merge(hash_attr(attr, serial_attr)) end @@ -248,19 +285,19 @@ end # To obtain an entry with internal names but external values. # @param data [Hash, Ecoportal::API::V1::Person] alised_entry (when parsing) or person (when serializing). # @return [Hash] the `internal entry` with the **internal** attributes names and values. - def internal_entry(data) - return parsed_entry(data) if parsing? - unserialized_entry(data) + def _internal_entry(data) + return _parsed_entry(data) if parsing? + _unserialized_entry(data) end # Parsing helper that just **parses the values** that have a parser/serializer defined. # @param aliased_entry [Hash] the entry with the _internal attribute_ names but the _external values_. # @return [Hash] the `internal entry` with the **internal** attributes names and values. - def parsed_entry(aliased_entry) + def _parsed_entry(aliased_entry) parsed = @person_parser.defined_attrs.map do |attr| value = @person_parser.parse(attr, aliased_entry) [attr, value] end.to_h aliased_entry.merge(parsed) @@ -272,22 +309,22 @@ # - `core` -> _overrides_ -> `account` -> _overrides_ -> `details` # - to keep things consistent, the `internal entry` hash has keys in this order: # - `core`, `account`, `details`. # @param person [Ecoportal::API::V1::Person] the `Person` object to transform into an _internal entry_. # @return [Hash] the `internal entry` with the **internal** attributes names and values. - def unserialized_entry(person) + def _unserialized_entry(person) core_hash = @person_parser.target_attrs_core.reduce({}) do |hash, attr| - value = get_from_core(person, attr) + value = _get_from_core(person, attr) hash.merge(hash_attr(attr, value)) end details_hash = @person_parser.target_attrs_details.reduce({}) do |hash, attr| - value = get_from_details(person, attr) + value = _get_from_details(person, attr) hash.merge(hash_attr(attr, value)) end account_hash = @person_parser.target_attrs_account.reduce({}) do |hash, attr| - value = get_from_account(person, attr) + value = _get_from_account(person, attr) hash.merge(hash_attr(attr, value)) end # merge by core overriding account and details rh = details_hash.merge(account_hash).merge(core_hash)