florinpatrascu / bolt_sips

Neo4j driver for Elixir
Apache License 2.0
256 stars 49 forks source link

Response is not transformed #55

Closed Gollor closed 5 years ago

Gollor commented 5 years ago

Hi, it seems that the current verison of Bolt.Sips.Response.transform is not working correctly. When i do the next neo4j query...

    cypher = """
      MATCH (a:Person)
      WHERE a.uid = {uid}
      RETURN a
    """
    data = Bolt.query!(Bolt.conn(), cypher, %{uid: uid})
    (hd data)["a"]

I get the next response:

%Bolt.Sips.Types.Node{
  id: 55,
  labels: ["Person"],
  properties: %{
    "last_payment" => [sig: 70, fields: [1550835424, 283000000, 0]],
    "uid" => "test1112"
  }
}

So the DateTime doesn't get parsed correctly. Currently I solve this using the next code in my view:

    data = Enum.reduce(
      Map.to_list(person.properties), 
      %{}, 
      fn obj, acc -> 
        Map.put(acc, 
          elem(obj, 0),
          if is_binary(elem(obj, 1)) do 
            elem(obj, 1) 
          else # We expect :sig to be 70
            [seconds, nanoseconds, offset] = elem(obj, 1)[:fields]
            naive_dt = NaiveDateTime.add(
              ~N[1970-01-01 00:00:00.000],
              seconds * 1_000_000_000 + nanoseconds,
              :nanosecond
            )
            NaiveDateTime.to_iso8601(naive_dt) <> 
              Bolt.Sips.TypesHelper.formated_time_offset(offset)
          end) 
      end)

This is just a workaround using the code I stripped from your Bolt.Sips.Response class.

dominique-vassard commented 5 years ago

Hi, thanks for your interest and testing. I've found what the problem was: properties was not considered as potentially containing special types... PR is on its way!

florinpatrascu commented 5 years ago

thank you both, for finding and fixing this! PR was merged, but I'll publish the package when I get out from work. @Gollor - please use the masterbranch, in case you need this version before that. Thank you!

florinpatrascu commented 5 years ago

published: https://hex.pm/packages/bolt_sips/1.2.1-rc2

Gollor commented 5 years ago

Thank you for quick response! The solution works.

Though this makes me wonder if there is some way to easily encode Bolt structs into jsons. At the moment I have to do it manually via the next code:

data = if Map.has_key? data, "last_payment" do 
  Map.put(data, "last_payment", elem(Bolt.Sips.Types.DateTimeWithTZOffset.format_param(data["last_payment"]), 1))
else
  data
end

Is it possible to make some kind of extension to Jason library so it could correctly transform the type to the string? At the moment it separates the datetime and time offset separately. I tried to dive in a little but it seems Protocol.derive only allows to control the visibility of the fields, not how they are processed. Maybe Bolt.Sips should transform types into serialized strings at the response creation? Or choose the strategy depending on options passed.

florinpatrascu commented 5 years ago

@Gollor - thank you for feedback. Making an extension to a json library i.e. Jason, probably would be out of scope for us, from the driver's perspective. But we could see the value of some utilitarian functions that could help you when needed; maybe future improvements to the Bolt.Sips.TypesHelper module?! I'll close this issue now, but please feel free to open an improvement request, so that we can track it properly. Many thanks!!

florinpatrascu commented 5 years ago

@Gollor - we're talking about steps towards releasing the stable version of bolt_sips, and your your feedback about encoding types is discussed here: #57, in case you're interested?!