neo4j.cr icon indicating copy to clipboard operation
neo4j.cr copied to clipboard

Union broken

Open ghost opened this issue 2 years ago • 2 comments

When using ? in exec_cast type, compiler returns with error:

There was a problem expanding macro 'macro_140737093397344'

Code in lib/neo4j/src/neo4j/bolt/from_bolt.cr:97:3

 97 | {% begin %}
      ^
Called macro defined in lib/neo4j/src/neo4j/bolt/from_bolt.cr:97:3

 97 | {% begin %}

Which expanded to:

 > 20 |
 > 21 |           node = value.as(::Neo4j::Node)
 > 22 |           return User.new(node) if node.labels.includes?("User")
                                  ^---
Error: expected argument #1 to 'User.new' to be Neo4j::PackStream::Unpacker, not Neo4j::Node

Overloads are:
 - User.new(name : ::String, bio : ::String, created_at : ::Time = Time.utc, id : ::UUID = UUID.random)
 - User.new(unpacker : ::Neo4j::PackStream::Unpacker)

Code:

require "neo4j"

neo4j_uri = URI.parse("bolt://neo4j:password@localhost:7687")

driver = Neo4j.connect(neo4j_uri, ssl: false)

abstract class Database::Model
  include Neo4j::Serializable::Node
end

abstract class Database::Relationship
  include Neo4j::Serializable::Relationship
end

class User < Database::Model
  getter id : UUID
  getter bio : String
  getter name : String
  getter created_at : Time

  def initialize(
    @name,
    @bio,
    @created_at = Time.utc,
    @id = UUID.random
  )
    @node_id = -1
    @node_labels = %w[]
  end
end

driver.session do |session|
  session.read_transaction do |read|
    query = <<-CYPHER
    MATCH (user:User { name: $name }) 
    RETURN null AS user
    CYPHER

    read.exec_cast(query, {"name" => "test"}, {User?}) do |(user)|
      pp user
    end
  end
end

ghost avatar Apr 02 '23 15:04 ghost

Thanks for the report. It looks like this may have been broken somewhere in the transition from Neo4j.map_node to include Neo4j::Serializable::Node because unions deserialize into Neo4j::Node first to get the labels, and it doesn't look like Neo4j::Serializable::Node provides that constructor, but Neo4j.map_node was originally designed around that path.

I'll see what I can do here. It might be a relatively simple fix, but there could be some complications — mainly that the mixin reads the Bolt protocol directly from the wire rather than from a pre-deserialized string in memory to save on allocations. So this may require reimplementing some of that.

jgaskins avatar Apr 04 '23 13:04 jgaskins

Any progress?

maksalees avatar Apr 09 '23 14:04 maksalees