neo4j-core 4.0.7 → 5.0.0.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ext/kernel.rb +9 -0
- data/lib/neo4j/label.rb +2 -1
- data/lib/neo4j/node.rb +8 -11
- data/lib/neo4j/property_container.rb +2 -7
- data/lib/neo4j/property_validator.rb +1 -1
- data/lib/neo4j/session.rb +24 -11
- data/lib/neo4j/tasks/config_server.rb +4 -1
- data/lib/neo4j/tasks/neo4j_server.rake +86 -109
- data/lib/neo4j/transaction.rb +17 -16
- data/lib/neo4j-core/cypher_translator.rb +1 -1
- data/lib/neo4j-core/query.rb +103 -47
- data/lib/neo4j-core/query_clauses.rb +177 -109
- data/lib/neo4j-core/query_find_in_batches.rb +19 -11
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-core.rb +3 -0
- data/lib/neo4j-embedded/cypher_response.rb +20 -5
- data/lib/neo4j-embedded/embedded_node.rb +26 -28
- data/lib/neo4j-embedded/embedded_session.rb +7 -6
- data/lib/neo4j-embedded/embedded_transaction.rb +2 -2
- data/lib/neo4j-embedded/label.rb +65 -0
- data/lib/neo4j-embedded/property.rb +5 -5
- data/lib/neo4j-embedded/to_java.rb +7 -13
- data/lib/neo4j-embedded.rb +1 -0
- data/lib/neo4j-server/cypher_node.rb +57 -67
- data/lib/neo4j-server/cypher_node_uncommited.rb +1 -1
- data/lib/neo4j-server/cypher_relationship.rb +10 -6
- data/lib/neo4j-server/cypher_response.rb +87 -51
- data/lib/neo4j-server/cypher_session.rb +80 -93
- data/lib/neo4j-server/cypher_transaction.rb +42 -33
- data/lib/neo4j-server/label.rb +40 -0
- data/lib/neo4j-server/resource.rb +11 -12
- data/lib/neo4j-server.rb +2 -0
- data/neo4j-core.gemspec +4 -1
- metadata +50 -6
- data/lib/neo4j-core/graph_json.rb +0 -35
| @@ -12,8 +12,11 @@ module Neo4j | |
| 12 12 |  | 
| 13 13 | 
             
                  class Clause
         | 
| 14 14 | 
             
                    include CypherTranslator
         | 
| 15 | 
            +
                    UNDERSCORE = '_'
         | 
| 16 | 
            +
                    COMMA_SPACE = ', '
         | 
| 17 | 
            +
                    AND = ' AND '
         | 
| 15 18 |  | 
| 16 | 
            -
                     | 
| 19 | 
            +
                    attr_accessor :params, :arg
         | 
| 17 20 |  | 
| 18 21 | 
             
                    def initialize(arg, options = {})
         | 
| 19 22 | 
             
                      @arg = arg
         | 
| @@ -54,19 +57,23 @@ module Neo4j | |
| 54 57 | 
             
                      label = label_from_key_and_value(key, value, options[:prefer] || :var)
         | 
| 55 58 | 
             
                      attributes = attributes_from_key_and_value(key, value)
         | 
| 56 59 |  | 
| 57 | 
            -
                       | 
| 60 | 
            +
                      prefix_value = value
         | 
| 61 | 
            +
                      if value.is_a?(Hash)
         | 
| 62 | 
            +
                        prefix_value = if value.values.any? { |v| v.is_a?(Hash) }
         | 
| 63 | 
            +
                                         value.keys.join(UNDERSCORE)
         | 
| 64 | 
            +
                                       end
         | 
| 65 | 
            +
                      end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                      prefix_array = [key, prefix_value].tap(&:compact!).join(UNDERSCORE)
         | 
| 68 | 
            +
                      formatted_attributes = attributes_string(attributes, "#{prefix_array}#{UNDERSCORE}")
         | 
| 69 | 
            +
                      "(#{var}#{format_label(label)}#{formatted_attributes})"
         | 
| 58 70 | 
             
                    end
         | 
| 59 71 |  | 
| 60 72 | 
             
                    def var_from_key_and_value(key, value, prefer = :var)
         | 
| 61 73 | 
             
                      case value
         | 
| 62 | 
            -
                      when String, Symbol, Class, Module
         | 
| 63 | 
            -
                        key
         | 
| 74 | 
            +
                      when String, Symbol, Class, Module, NilClass, Array then key
         | 
| 64 75 | 
             
                      when Hash
         | 
| 65 | 
            -
                        if value | 
| 66 | 
            -
                          key if prefer == :var
         | 
| 67 | 
            -
                        else
         | 
| 68 | 
            -
                          key
         | 
| 69 | 
            -
                        end
         | 
| 76 | 
            +
                        key if _use_key_for_var?(value, prefer)
         | 
| 70 77 | 
             
                      else
         | 
| 71 78 | 
             
                        fail ArgError, value
         | 
| 72 79 | 
             
                      end
         | 
| @@ -74,22 +81,29 @@ module Neo4j | |
| 74 81 |  | 
| 75 82 | 
             
                    def label_from_key_and_value(key, value, prefer = :var)
         | 
| 76 83 | 
             
                      case value
         | 
| 77 | 
            -
                      when String, Symbol
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                      when Class, Module
         | 
| 80 | 
            -
                        defined?(value::CYPHER_LABEL) ? value::CYPHER_LABEL : value.name
         | 
| 84 | 
            +
                      when String, Symbol, Array, NilClass then value
         | 
| 85 | 
            +
                      when Class, Module then value.name
         | 
| 81 86 | 
             
                      when Hash
         | 
| 82 87 | 
             
                        if value.values.map(&:class) == [Hash]
         | 
| 83 88 | 
             
                          value.first.first
         | 
| 84 89 | 
             
                        else
         | 
| 85 | 
            -
                          key if  | 
| 90 | 
            +
                          key if !_use_key_for_var?(value, prefer)
         | 
| 86 91 | 
             
                        end
         | 
| 87 92 | 
             
                      else
         | 
| 88 93 | 
             
                        fail ArgError, value
         | 
| 89 94 | 
             
                      end
         | 
| 90 95 | 
             
                    end
         | 
| 91 96 |  | 
| 92 | 
            -
                    def  | 
| 97 | 
            +
                    def _use_key_for_var?(value, prefer)
         | 
| 98 | 
            +
                      _nested_value_hash?(value) || prefer == :var
         | 
| 99 | 
            +
                    end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                    def _nested_value_hash?(value)
         | 
| 102 | 
            +
                      value.values.any? { |v| v.is_a?(Hash) }
         | 
| 103 | 
            +
                    end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
             | 
| 106 | 
            +
                    def attributes_from_key_and_value(_key, value)
         | 
| 93 107 | 
             
                      return nil unless value.is_a?(Hash)
         | 
| 94 108 |  | 
| 95 109 | 
             
                      if value.values.map(&:class) == [Hash]
         | 
| @@ -100,28 +114,41 @@ module Neo4j | |
| 100 114 | 
             
                    end
         | 
| 101 115 |  | 
| 102 116 | 
             
                    class << self
         | 
| 103 | 
            -
                       | 
| 117 | 
            +
                      def keyword
         | 
| 118 | 
            +
                        self::KEYWORD
         | 
| 119 | 
            +
                      end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                      def keyword_downcase
         | 
| 122 | 
            +
                        keyword.downcase
         | 
| 123 | 
            +
                      end
         | 
| 104 124 |  | 
| 105 125 | 
             
                      def from_args(args, options = {})
         | 
| 106 | 
            -
                        args.flatten | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 126 | 
            +
                        args.flatten!
         | 
| 127 | 
            +
                        args.map { |arg| from_arg(arg, options) }.tap(&:compact!)
         | 
| 128 | 
            +
                      end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                      def from_arg(arg, options = {})
         | 
| 131 | 
            +
                        new(arg, options) if !arg.respond_to?(:empty?) || !arg.empty?
         | 
| 109 132 | 
             
                      end
         | 
| 110 133 |  | 
| 111 134 | 
             
                      def to_cypher(clauses)
         | 
| 135 | 
            +
                        @question_mark_param_index = 1
         | 
| 136 | 
            +
             | 
| 112 137 | 
             
                        string = clause_string(clauses)
         | 
| 113 138 | 
             
                        string.strip!
         | 
| 114 139 |  | 
| 115 | 
            -
                        "#{ | 
| 140 | 
            +
                        "#{keyword} #{string}" if string.size > 0
         | 
| 116 141 | 
             
                      end
         | 
| 117 142 | 
             
                    end
         | 
| 118 143 |  | 
| 119 144 | 
             
                    private
         | 
| 120 145 |  | 
| 121 146 | 
             
                    def key_value_string(key, value, previous_keys = [], force_equals = false)
         | 
| 122 | 
            -
                      param = (previous_keys << key).join( | 
| 123 | 
            -
                      param. | 
| 147 | 
            +
                      param = (previous_keys << key).join(UNDERSCORE)
         | 
| 148 | 
            +
                      param.tr_s!('^a-zA-Z0-9', UNDERSCORE)
         | 
| 124 149 | 
             
                      param.gsub!(/^_+|_+$/, '')
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                      value = value.first if value.is_a?(Array) && value.size == 1
         | 
| 125 152 | 
             
                      @params[param.to_sym] = value
         | 
| 126 153 |  | 
| 127 154 | 
             
                      if !value.is_a?(Array) || force_equals
         | 
| @@ -131,34 +158,39 @@ module Neo4j | |
| 131 158 | 
             
                      end
         | 
| 132 159 | 
             
                    end
         | 
| 133 160 |  | 
| 134 | 
            -
                    def format_label( | 
| 135 | 
            -
                       | 
| 136 | 
            -
             | 
| 137 | 
            -
                      if !label_string.empty? && label_string[0] != ':'
         | 
| 138 | 
            -
                        label_string = "`#{label_string}`" unless label_string.match(' ')
         | 
| 139 | 
            -
                        label_string = ":#{label_string}"
         | 
| 161 | 
            +
                    def format_label(label_arg)
         | 
| 162 | 
            +
                      if label_arg.is_a?(Array)
         | 
| 163 | 
            +
                        return label_arg.map { |arg| format_label(arg) }.join
         | 
| 140 164 | 
             
                      end
         | 
| 141 | 
            -
             | 
| 165 | 
            +
             | 
| 166 | 
            +
                      label_arg = label_arg.to_s
         | 
| 167 | 
            +
                      label_arg.strip!
         | 
| 168 | 
            +
                      if !label_arg.empty? && label_arg[0] != ':'
         | 
| 169 | 
            +
                        label_arg = "`#{label_arg}`" unless label_arg.match(' ')
         | 
| 170 | 
            +
                        label_arg = ":#{label_arg}"
         | 
| 171 | 
            +
                      end
         | 
| 172 | 
            +
                      label_arg
         | 
| 142 173 | 
             
                    end
         | 
| 143 174 |  | 
| 144 | 
            -
                    def attributes_string(attributes)
         | 
| 175 | 
            +
                    def attributes_string(attributes, prefix = '')
         | 
| 145 176 | 
             
                      return '' if not attributes
         | 
| 146 177 |  | 
| 147 178 | 
             
                      attributes_string = attributes.map do |key, value|
         | 
| 148 | 
            -
                         | 
| 149 | 
            -
             | 
| 150 | 
            -
             | 
| 151 | 
            -
             | 
| 152 | 
            -
             | 
| 153 | 
            -
             | 
| 154 | 
            -
             | 
| 179 | 
            +
                        if value.to_s.match(/^{.+}$/)
         | 
| 180 | 
            +
                          "#{key}: #{value}"
         | 
| 181 | 
            +
                        else
         | 
| 182 | 
            +
                          param_key = "#{prefix}#{key}".gsub('::', '_')
         | 
| 183 | 
            +
                          @params[param_key.to_sym] = value
         | 
| 184 | 
            +
                          "#{key}: {#{param_key}}"
         | 
| 185 | 
            +
                        end
         | 
| 186 | 
            +
                      end.join(Clause::COMMA_SPACE)
         | 
| 155 187 |  | 
| 156 188 | 
             
                      " {#{attributes_string}}"
         | 
| 157 189 | 
             
                    end
         | 
| 158 190 | 
             
                  end
         | 
| 159 191 |  | 
| 160 192 | 
             
                  class StartClause < Clause
         | 
| 161 | 
            -
                     | 
| 193 | 
            +
                    KEYWORD = 'START'
         | 
| 162 194 |  | 
| 163 195 | 
             
                    def from_symbol(value)
         | 
| 164 196 | 
             
                      from_string(value.to_s)
         | 
| @@ -175,33 +207,20 @@ module Neo4j | |
| 175 207 |  | 
| 176 208 | 
             
                    class << self
         | 
| 177 209 | 
             
                      def clause_string(clauses)
         | 
| 178 | 
            -
                        clauses.map!(&:value).join( | 
| 210 | 
            +
                        clauses.map!(&:value).join(Clause::COMMA_SPACE)
         | 
| 179 211 | 
             
                      end
         | 
| 180 212 | 
             
                    end
         | 
| 181 213 | 
             
                  end
         | 
| 182 214 |  | 
| 183 215 | 
             
                  class WhereClause < Clause
         | 
| 184 | 
            -
                     | 
| 216 | 
            +
                    KEYWORD = 'WHERE'
         | 
| 185 217 |  | 
| 186 218 | 
             
                    def from_key_and_value(key, value, previous_keys = [])
         | 
| 187 219 | 
             
                      case value
         | 
| 188 | 
            -
                      when Hash
         | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 | 
            -
                            @params[clause_id] = v.to_i
         | 
| 193 | 
            -
                            "ID(#{key}) = {#{clause_id}}"
         | 
| 194 | 
            -
                          else
         | 
| 195 | 
            -
                            "#{key}.#{from_key_and_value(k, v, previous_keys + [key])}"
         | 
| 196 | 
            -
                          end
         | 
| 197 | 
            -
                        end.join(' AND ')
         | 
| 198 | 
            -
                      when NilClass
         | 
| 199 | 
            -
                        "#{key} IS NULL"
         | 
| 200 | 
            -
                      when Regexp
         | 
| 201 | 
            -
                        pattern = (value.casefold? ? '(?i)' : '') + value.source
         | 
| 202 | 
            -
                        "#{key} =~ #{escape_value(pattern.gsub(/\\/, '\\\\\\'))}"
         | 
| 203 | 
            -
                      when Array
         | 
| 204 | 
            -
                        key_value_string(key, value, previous_keys)
         | 
| 220 | 
            +
                      when Hash then hash_key_value_string(key, value, previous_keys)
         | 
| 221 | 
            +
                      when NilClass then "#{key} IS NULL"
         | 
| 222 | 
            +
                      when Regexp then regexp_key_value_string(key, value)
         | 
| 223 | 
            +
                      when Array then key_value_string(key, value, previous_keys)
         | 
| 205 224 | 
             
                      else
         | 
| 206 225 | 
             
                        key_value_string(key, value, previous_keys)
         | 
| 207 226 | 
             
                      end
         | 
| @@ -209,14 +228,62 @@ module Neo4j | |
| 209 228 |  | 
| 210 229 | 
             
                    class << self
         | 
| 211 230 | 
             
                      def clause_string(clauses)
         | 
| 212 | 
            -
                        clauses.map(&:value).flatten.map {|value| "(#{value})" }.join( | 
| 231 | 
            +
                        clauses.map!(&:value).tap(&:flatten!).map! { |value| "(#{value})" }.join(Clause::AND)
         | 
| 232 | 
            +
                      end
         | 
| 233 | 
            +
                    end
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                    private
         | 
| 236 | 
            +
             | 
| 237 | 
            +
                    def hash_key_value_string(key, value, previous_keys)
         | 
| 238 | 
            +
                      value.map do |k, v|
         | 
| 239 | 
            +
                        if k.to_sym == :neo_id
         | 
| 240 | 
            +
                          v = Array(v).map { |item| (item.respond_to?(:neo_id) ? item.neo_id : item).to_i }
         | 
| 241 | 
            +
                          key_value_string("ID(#{key})", v)
         | 
| 242 | 
            +
                        else
         | 
| 243 | 
            +
                          "#{key}.#{from_key_and_value(k, v, previous_keys + [key])}"
         | 
| 244 | 
            +
                        end
         | 
| 245 | 
            +
                      end.join(AND)
         | 
| 246 | 
            +
                    end
         | 
| 247 | 
            +
             | 
| 248 | 
            +
                    def regexp_key_value_string(key, value)
         | 
| 249 | 
            +
                      pattern = (value.casefold? ? '(?i)' : '') + value.source
         | 
| 250 | 
            +
                      "#{key} =~ #{escape_value(pattern.gsub(/\\/, '\\\\\\'))}"
         | 
| 251 | 
            +
                    end
         | 
| 252 | 
            +
             | 
| 253 | 
            +
                    class << self
         | 
| 254 | 
            +
                      ARG_HAS_QUESTION_MARK_REGEX = /(^|\s)\?(\s|$)/
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                      def from_args(args, options = {})
         | 
| 257 | 
            +
                        query_string, params = args
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                        if query_string.is_a?(String) && (query_string.match(ARG_HAS_QUESTION_MARK_REGEX) || params.is_a?(Hash))
         | 
| 260 | 
            +
                          if !params.is_a?(Hash)
         | 
| 261 | 
            +
                            question_mark_params_param = self.question_mark_params_param
         | 
| 262 | 
            +
                            query_string.gsub!(ARG_HAS_QUESTION_MARK_REGEX, "\\1{#{question_mark_params_param}}\\2")
         | 
| 263 | 
            +
                            params = {question_mark_params_param.to_sym => params}
         | 
| 264 | 
            +
                          end
         | 
| 265 | 
            +
             | 
| 266 | 
            +
                          clause = from_arg(query_string, options).tap do |clause|
         | 
| 267 | 
            +
                            clause.params.merge!(params)
         | 
| 268 | 
            +
                          end
         | 
| 269 | 
            +
             | 
| 270 | 
            +
                          [clause]
         | 
| 271 | 
            +
                        else
         | 
| 272 | 
            +
                          super
         | 
| 273 | 
            +
                        end
         | 
| 274 | 
            +
                      end
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                      def question_mark_params_param
         | 
| 277 | 
            +
                        result = "question_mark_param#{@question_mark_param_index}"
         | 
| 278 | 
            +
                        @question_mark_param_index += 1
         | 
| 279 | 
            +
                        result
         | 
| 213 280 | 
             
                      end
         | 
| 214 281 | 
             
                    end
         | 
| 215 282 | 
             
                  end
         | 
| 216 283 |  | 
| 217 284 |  | 
| 218 285 | 
             
                  class MatchClause < Clause
         | 
| 219 | 
            -
                     | 
| 286 | 
            +
                    KEYWORD = 'MATCH'
         | 
| 220 287 |  | 
| 221 288 | 
             
                    def from_symbol(value)
         | 
| 222 289 | 
             
                      from_string(value.to_s)
         | 
| @@ -228,17 +295,17 @@ module Neo4j | |
| 228 295 |  | 
| 229 296 | 
             
                    class << self
         | 
| 230 297 | 
             
                      def clause_string(clauses)
         | 
| 231 | 
            -
                        clauses.map!(&:value).join( | 
| 298 | 
            +
                        clauses.map!(&:value).join(Clause::COMMA_SPACE)
         | 
| 232 299 | 
             
                      end
         | 
| 233 300 | 
             
                    end
         | 
| 234 301 | 
             
                  end
         | 
| 235 302 |  | 
| 236 303 | 
             
                  class OptionalMatchClause < MatchClause
         | 
| 237 | 
            -
                     | 
| 304 | 
            +
                    KEYWORD = 'OPTIONAL MATCH'
         | 
| 238 305 | 
             
                  end
         | 
| 239 306 |  | 
| 240 307 | 
             
                  class WithClause < Clause
         | 
| 241 | 
            -
                     | 
| 308 | 
            +
                    KEYWORD = 'WITH'
         | 
| 242 309 |  | 
| 243 310 | 
             
                    def from_symbol(value)
         | 
| 244 311 | 
             
                      from_string(value.to_s)
         | 
| @@ -250,23 +317,23 @@ module Neo4j | |
| 250 317 |  | 
| 251 318 | 
             
                    class << self
         | 
| 252 319 | 
             
                      def clause_string(clauses)
         | 
| 253 | 
            -
                        clauses.map!(&:value).join( | 
| 320 | 
            +
                        clauses.map!(&:value).join(Clause::COMMA_SPACE)
         | 
| 254 321 | 
             
                      end
         | 
| 255 322 | 
             
                    end
         | 
| 256 323 | 
             
                  end
         | 
| 257 324 |  | 
| 258 325 | 
             
                  class UsingClause < Clause
         | 
| 259 | 
            -
                     | 
| 326 | 
            +
                    KEYWORD = 'USING'
         | 
| 260 327 |  | 
| 261 328 | 
             
                    class << self
         | 
| 262 329 | 
             
                      def clause_string(clauses)
         | 
| 263 | 
            -
                        clauses.map!(&:value).join(" #{ | 
| 330 | 
            +
                        clauses.map!(&:value).join(" #{keyword} ")
         | 
| 264 331 | 
             
                      end
         | 
| 265 332 | 
             
                    end
         | 
| 266 333 | 
             
                  end
         | 
| 267 334 |  | 
| 268 335 | 
             
                  class CreateClause < Clause
         | 
| 269 | 
            -
                     | 
| 336 | 
            +
                    KEYWORD = 'CREATE'
         | 
| 270 337 |  | 
| 271 338 | 
             
                    def from_string(value)
         | 
| 272 339 | 
             
                      value
         | 
| @@ -298,15 +365,15 @@ module Neo4j | |
| 298 365 | 
             
                  end
         | 
| 299 366 |  | 
| 300 367 | 
             
                  class CreateUniqueClause < CreateClause
         | 
| 301 | 
            -
                     | 
| 368 | 
            +
                    KEYWORD = 'CREATE UNIQUE'
         | 
| 302 369 | 
             
                  end
         | 
| 303 370 |  | 
| 304 371 | 
             
                  class MergeClause < CreateClause
         | 
| 305 | 
            -
                     | 
| 372 | 
            +
                    KEYWORD = 'MERGE'
         | 
| 306 373 | 
             
                  end
         | 
| 307 374 |  | 
| 308 375 | 
             
                  class DeleteClause < Clause
         | 
| 309 | 
            -
                     | 
| 376 | 
            +
                    KEYWORD = 'DELETE'
         | 
| 310 377 |  | 
| 311 378 | 
             
                    def from_symbol(value)
         | 
| 312 379 | 
             
                      from_string(value.to_s)
         | 
| @@ -314,13 +381,13 @@ module Neo4j | |
| 314 381 |  | 
| 315 382 | 
             
                    class << self
         | 
| 316 383 | 
             
                      def clause_string(clauses)
         | 
| 317 | 
            -
                        clauses.map!(&:value).join( | 
| 384 | 
            +
                        clauses.map!(&:value).join(Clause::COMMA_SPACE)
         | 
| 318 385 | 
             
                      end
         | 
| 319 386 | 
             
                    end
         | 
| 320 387 | 
             
                  end
         | 
| 321 388 |  | 
| 322 389 | 
             
                  class OrderClause < Clause
         | 
| 323 | 
            -
                     | 
| 390 | 
            +
                    KEYWORD = 'ORDER BY'
         | 
| 324 391 |  | 
| 325 392 | 
             
                    def from_symbol(value)
         | 
| 326 393 | 
             
                      from_string(value.to_s)
         | 
| @@ -332,38 +399,32 @@ module Neo4j | |
| 332 399 | 
             
                        "#{key}.#{value}"
         | 
| 333 400 | 
             
                      when Array
         | 
| 334 401 | 
             
                        value.map do |v|
         | 
| 335 | 
            -
                           | 
| 336 | 
            -
                            from_key_and_value(key, v)
         | 
| 337 | 
            -
                          else
         | 
| 338 | 
            -
                            "#{key}.#{v}"
         | 
| 339 | 
            -
                          end
         | 
| 402 | 
            +
                          v.is_a?(Hash) ?  from_key_and_value(key, v) : "#{key}.#{v}"
         | 
| 340 403 | 
             
                        end
         | 
| 341 404 | 
             
                      when Hash
         | 
| 342 | 
            -
                        value.map  | 
| 343 | 
            -
                          "#{key}.#{k} #{v.upcase}"
         | 
| 344 | 
            -
                        end
         | 
| 405 | 
            +
                        value.map { |k, v| "#{key}.#{k} #{v.upcase}" }
         | 
| 345 406 | 
             
                      end
         | 
| 346 407 | 
             
                    end
         | 
| 347 408 |  | 
| 348 409 | 
             
                    class << self
         | 
| 349 410 | 
             
                      def clause_string(clauses)
         | 
| 350 | 
            -
                        clauses.map!(&:value).join( | 
| 411 | 
            +
                        clauses.map!(&:value).join(Clause::COMMA_SPACE)
         | 
| 351 412 | 
             
                      end
         | 
| 352 413 | 
             
                    end
         | 
| 353 414 | 
             
                  end
         | 
| 354 415 |  | 
| 355 416 | 
             
                  class LimitClause < Clause
         | 
| 356 | 
            -
                     | 
| 417 | 
            +
                    KEYWORD = 'LIMIT'
         | 
| 357 418 |  | 
| 358 419 | 
             
                    def from_string(value)
         | 
| 359 | 
            -
                      clause_id = "#{self.class. | 
| 360 | 
            -
                      @params[clause_id] = value.to_i
         | 
| 420 | 
            +
                      clause_id = "#{self.class.keyword_downcase}_#{value}"
         | 
| 421 | 
            +
                      @params[clause_id.to_sym] = value.to_i
         | 
| 361 422 | 
             
                      "{#{clause_id}}"
         | 
| 362 423 | 
             
                    end
         | 
| 363 424 |  | 
| 364 425 | 
             
                    def from_integer(value)
         | 
| 365 | 
            -
                      clause_id = "#{self.class. | 
| 366 | 
            -
                      @params[clause_id] = value
         | 
| 426 | 
            +
                      clause_id = "#{self.class.keyword_downcase}_#{value}"
         | 
| 427 | 
            +
                      @params[clause_id.to_sym] = value
         | 
| 367 428 | 
             
                      "{#{clause_id}}"
         | 
| 368 429 | 
             
                    end
         | 
| 369 430 |  | 
| @@ -375,17 +436,17 @@ module Neo4j | |
| 375 436 | 
             
                  end
         | 
| 376 437 |  | 
| 377 438 | 
             
                  class SkipClause < Clause
         | 
| 378 | 
            -
                     | 
| 439 | 
            +
                    KEYWORD = 'SKIP'
         | 
| 379 440 |  | 
| 380 441 | 
             
                    def from_string(value)
         | 
| 381 | 
            -
                      clause_id = "#{self.class. | 
| 382 | 
            -
                      @params[clause_id] = value.to_i
         | 
| 442 | 
            +
                      clause_id = "#{self.class.keyword_downcase}_#{value}"
         | 
| 443 | 
            +
                      @params[clause_id.to_sym] = value.to_i
         | 
| 383 444 | 
             
                      "{#{clause_id}}"
         | 
| 384 445 | 
             
                    end
         | 
| 385 446 |  | 
| 386 447 | 
             
                    def from_integer(value)
         | 
| 387 | 
            -
                      clause_id = "#{self.class. | 
| 388 | 
            -
                      @params[clause_id] = value
         | 
| 448 | 
            +
                      clause_id = "#{self.class.keyword_downcase}_#{value}"
         | 
| 449 | 
            +
                      @params[clause_id.to_sym] = value
         | 
| 389 450 | 
             
                      "{#{clause_id}}"
         | 
| 390 451 | 
             
                    end
         | 
| 391 452 |  | 
| @@ -397,21 +458,20 @@ module Neo4j | |
| 397 458 | 
             
                  end
         | 
| 398 459 |  | 
| 399 460 | 
             
                  class SetClause < Clause
         | 
| 400 | 
            -
                     | 
| 461 | 
            +
                    KEYWORD = 'SET'
         | 
| 401 462 |  | 
| 402 463 | 
             
                    def from_key_and_value(key, value)
         | 
| 403 464 | 
             
                      case value
         | 
| 404 | 
            -
                      when String, Symbol
         | 
| 405 | 
            -
                        "#{key} = #{value}"
         | 
| 465 | 
            +
                      when String, Symbol then "#{key}:`#{value}`"
         | 
| 406 466 | 
             
                      when Hash
         | 
| 407 467 | 
             
                        if @options[:set_props]
         | 
| 408 | 
            -
                          attribute_string = value.map { |k, v| "#{k}: #{v.inspect}" }.join( | 
| 468 | 
            +
                          attribute_string = value.map { |k, v| "#{k}: #{v.inspect}" }.join(Clause::COMMA_SPACE)
         | 
| 409 469 | 
             
                          "#{key} = {#{attribute_string}}"
         | 
| 410 470 | 
             
                        else
         | 
| 411 | 
            -
                          value.map  | 
| 412 | 
            -
                            key_value_string("#{key}.`#{k}`", v, ['setter'], true)
         | 
| 413 | 
            -
                          end
         | 
| 471 | 
            +
                          value.map { |k, v| key_value_string("#{key}.`#{k}`", v, ['setter'], true) }
         | 
| 414 472 | 
             
                        end
         | 
| 473 | 
            +
                      when Array then value.map { |v| from_key_and_value(key, v) }
         | 
| 474 | 
            +
                      when NilClass then []
         | 
| 415 475 | 
             
                      else
         | 
| 416 476 | 
             
                        fail ArgError, value
         | 
| 417 477 | 
             
                      end
         | 
| @@ -419,13 +479,13 @@ module Neo4j | |
| 419 479 |  | 
| 420 480 | 
             
                    class << self
         | 
| 421 481 | 
             
                      def clause_string(clauses)
         | 
| 422 | 
            -
                        clauses.map!(&:value).join( | 
| 482 | 
            +
                        clauses.map!(&:value).join(Clause::COMMA_SPACE)
         | 
| 423 483 | 
             
                      end
         | 
| 424 484 | 
             
                    end
         | 
| 425 485 | 
             
                  end
         | 
| 426 486 |  | 
| 427 487 | 
             
                  class OnCreateSetClause < SetClause
         | 
| 428 | 
            -
                     | 
| 488 | 
            +
                    KEYWORD = 'ON CREATE SET'
         | 
| 429 489 |  | 
| 430 490 | 
             
                    def initialize(*args)
         | 
| 431 491 | 
             
                      super
         | 
| @@ -434,20 +494,24 @@ module Neo4j | |
| 434 494 | 
             
                  end
         | 
| 435 495 |  | 
| 436 496 | 
             
                  class OnMatchSetClause < OnCreateSetClause
         | 
| 437 | 
            -
                     | 
| 497 | 
            +
                    KEYWORD = 'ON MATCH SET'
         | 
| 438 498 | 
             
                  end
         | 
| 439 499 |  | 
| 440 500 | 
             
                  class RemoveClause < Clause
         | 
| 441 | 
            -
                     | 
| 501 | 
            +
                    KEYWORD = 'REMOVE'
         | 
| 442 502 |  | 
| 443 503 | 
             
                    def from_key_and_value(key, value)
         | 
| 444 504 | 
             
                      case value
         | 
| 445 505 | 
             
                      when /^:/
         | 
| 446 | 
            -
                        "#{key} | 
| 506 | 
            +
                        "#{key}:`#{value[1..-1]}`"
         | 
| 447 507 | 
             
                      when String
         | 
| 448 508 | 
             
                        "#{key}.#{value}"
         | 
| 449 509 | 
             
                      when Symbol
         | 
| 450 | 
            -
                        "#{key} | 
| 510 | 
            +
                        "#{key}:`#{value}`"
         | 
| 511 | 
            +
                      when Array
         | 
| 512 | 
            +
                        value.map do |v|
         | 
| 513 | 
            +
                          from_key_and_value(key, v)
         | 
| 514 | 
            +
                        end
         | 
| 451 515 | 
             
                      else
         | 
| 452 516 | 
             
                        fail ArgError, value
         | 
| 453 517 | 
             
                      end
         | 
| @@ -455,13 +519,13 @@ module Neo4j | |
| 455 519 |  | 
| 456 520 | 
             
                    class << self
         | 
| 457 521 | 
             
                      def clause_string(clauses)
         | 
| 458 | 
            -
                        clauses.map!(&:value).join( | 
| 522 | 
            +
                        clauses.map!(&:value).join(Clause::COMMA_SPACE)
         | 
| 459 523 | 
             
                      end
         | 
| 460 524 | 
             
                    end
         | 
| 461 525 | 
             
                  end
         | 
| 462 526 |  | 
| 463 527 | 
             
                  class UnwindClause < Clause
         | 
| 464 | 
            -
                     | 
| 528 | 
            +
                    KEYWORD = 'UNWIND'
         | 
| 465 529 |  | 
| 466 530 | 
             
                    def from_key_and_value(key, value)
         | 
| 467 531 | 
             
                      case value
         | 
| @@ -482,7 +546,7 @@ module Neo4j | |
| 482 546 | 
             
                  end
         | 
| 483 547 |  | 
| 484 548 | 
             
                  class ReturnClause < Clause
         | 
| 485 | 
            -
                     | 
| 549 | 
            +
                    KEYWORD = 'RETURN'
         | 
| 486 550 |  | 
| 487 551 | 
             
                    def from_symbol(value)
         | 
| 488 552 | 
             
                      from_string(value.to_s)
         | 
| @@ -493,9 +557,13 @@ module Neo4j | |
| 493 557 | 
             
                      when Array
         | 
| 494 558 | 
             
                        value.map do |v|
         | 
| 495 559 | 
             
                          from_key_and_value(key, v)
         | 
| 496 | 
            -
                        end.join( | 
| 560 | 
            +
                        end.join(Clause::COMMA_SPACE)
         | 
| 497 561 | 
             
                      when String, Symbol
         | 
| 498 | 
            -
                         | 
| 562 | 
            +
                        if value.to_sym == :neo_id
         | 
| 563 | 
            +
                          "ID(#{key})"
         | 
| 564 | 
            +
                        else
         | 
| 565 | 
            +
                          "#{key}.#{value}"
         | 
| 566 | 
            +
                        end
         | 
| 499 567 | 
             
                      else
         | 
| 500 568 | 
             
                        fail ArgError, value
         | 
| 501 569 | 
             
                      end
         | 
| @@ -503,7 +571,7 @@ module Neo4j | |
| 503 571 |  | 
| 504 572 | 
             
                    class << self
         | 
| 505 573 | 
             
                      def clause_string(clauses)
         | 
| 506 | 
            -
                        clauses.map!(&:value).join( | 
| 574 | 
            +
                        clauses.map!(&:value).join(Clause::COMMA_SPACE)
         | 
| 507 575 | 
             
                      end
         | 
| 508 576 | 
             
                    end
         | 
| 509 577 | 
             
                  end
         | 
| @@ -2,8 +2,7 @@ module Neo4j | |
| 2 2 | 
             
              module Core
         | 
| 3 3 | 
             
                module QueryFindInBatches
         | 
| 4 4 | 
             
                  def find_in_batches(node_var, prop_var, options = {})
         | 
| 5 | 
            -
                     | 
| 6 | 
            -
                    fail ArgumentError, "Invalid keys: #{invalid_keys.join(', ')}" if not invalid_keys.empty?
         | 
| 5 | 
            +
                    validate_find_in_batches_options!(options)
         | 
| 7 6 |  | 
| 8 7 | 
             
                    batch_size = options.delete(:batch_size) || 1000
         | 
| 9 8 |  | 
| @@ -13,15 +12,7 @@ module Neo4j | |
| 13 12 |  | 
| 14 13 | 
             
                    while records.any?
         | 
| 15 14 | 
             
                      records_size = records.size
         | 
| 16 | 
            -
                      primary_key_offset =  | 
| 17 | 
            -
                                             records.last.send(node_var).send(prop_var)
         | 
| 18 | 
            -
                                           rescue NoMethodError
         | 
| 19 | 
            -
                                             begin
         | 
| 20 | 
            -
                                               records.last.send(node_var)[prop_var.to_sym]
         | 
| 21 | 
            -
                                             rescue NoMethodError
         | 
| 22 | 
            -
                                               records.last.send("#{node_var}.#{prop_var}") # In case we're explicitly returning it
         | 
| 23 | 
            -
                                             end
         | 
| 24 | 
            -
                                           end
         | 
| 15 | 
            +
                      primary_key_offset = primary_key_offset(records.last, node_var, prop_var)
         | 
| 25 16 |  | 
| 26 17 | 
             
                      yield records
         | 
| 27 18 |  | 
| @@ -36,6 +27,23 @@ module Neo4j | |
| 36 27 | 
             
                      batch.each { |result| yield result }
         | 
| 37 28 | 
             
                    end
         | 
| 38 29 | 
             
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  private
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def validate_find_in_batches_options!(options)
         | 
| 34 | 
            +
                    invalid_keys = options.keys.map(&:to_sym) - [:batch_size]
         | 
| 35 | 
            +
                    fail ArgumentError, "Invalid keys: #{invalid_keys.join(', ')}" if not invalid_keys.empty?
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def primary_key_offset(last_record, node_var, prop_var)
         | 
| 39 | 
            +
                    last_record.send(node_var).send(prop_var)
         | 
| 40 | 
            +
                  rescue NoMethodError
         | 
| 41 | 
            +
                    begin
         | 
| 42 | 
            +
                      last_record.send(node_var)[prop_var.to_sym]
         | 
| 43 | 
            +
                    rescue NoMethodError
         | 
| 44 | 
            +
                      last_record.send("#{node_var}.#{prop_var}") # In case we're explicitly returning it
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
                  end
         | 
| 39 47 | 
             
                end
         | 
| 40 48 | 
             
              end
         | 
| 41 49 | 
             
            end
         | 
    
        data/lib/neo4j-core/version.rb
    CHANGED
    
    
    
        data/lib/neo4j-core.rb
    CHANGED
    
    
| @@ -12,26 +12,31 @@ module Neo4j | |
| 12 12 | 
             
                  include Enumerable
         | 
| 13 13 |  | 
| 14 14 | 
             
                  # @return the original result from the Neo4j Cypher Engine, once forward read only !
         | 
| 15 | 
            -
                  attr_reader :source
         | 
| 15 | 
            +
                  attr_reader :source, :unwrapped
         | 
| 16 16 |  | 
| 17 | 
            -
                  def initialize(source, query)
         | 
| 17 | 
            +
                  def initialize(source, query, unwrapped = nil)
         | 
| 18 18 | 
             
                    @source = source
         | 
| 19 | 
            -
                    @struct = Struct.new(*source.columns.to_a.map(&:to_sym))
         | 
| 19 | 
            +
                    @struct = Struct.new(*source.columns.to_a.map!(&:to_sym)) unless source.columns.empty?
         | 
| 20 20 | 
             
                    @unread = true
         | 
| 21 21 | 
             
                    @query = query
         | 
| 22 | 
            +
                    @unwrapped = unwrapped
         | 
| 22 23 | 
             
                  end
         | 
| 23 24 |  | 
| 24 25 | 
             
                  def to_s
         | 
| 25 26 | 
             
                    @query
         | 
| 26 27 | 
             
                  end
         | 
| 27 28 |  | 
| 29 | 
            +
                  def unwrapped?
         | 
| 30 | 
            +
                    !!unwrapped
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 28 33 | 
             
                  def inspect
         | 
| 29 34 | 
             
                    "Enumerable query: '#{@query}'"
         | 
| 30 35 | 
             
                  end
         | 
| 31 36 |  | 
| 32 37 | 
             
                  # @return [Array<Symbol>] the columns in the query result
         | 
| 33 38 | 
             
                  def columns
         | 
| 34 | 
            -
                    @source.columns.map(&:to_sym)
         | 
| 39 | 
            +
                    @source.columns.map!(&:to_sym)
         | 
| 35 40 | 
             
                  end
         | 
| 36 41 |  | 
| 37 42 | 
             
                  def each
         | 
| @@ -40,13 +45,23 @@ module Neo4j | |
| 40 45 | 
             
                    if block_given?
         | 
| 41 46 | 
             
                      @source.each do |row|
         | 
| 42 47 | 
             
                        yield(row.each_with_object(@struct.new) do |(column, value), result|
         | 
| 43 | 
            -
                          result[column.to_sym] = (value | 
| 48 | 
            +
                          result[column.to_sym] = unwrap(value)
         | 
| 44 49 | 
             
                        end)
         | 
| 45 50 | 
             
                      end
         | 
| 46 51 | 
             
                    else
         | 
| 47 52 | 
             
                      Enumerator.new(self)
         | 
| 48 53 | 
             
                    end
         | 
| 49 54 | 
             
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  private
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  def unwrap(value)
         | 
| 59 | 
            +
                    if !value.nil? && value.respond_to?(:to_a)
         | 
| 60 | 
            +
                      value.map { |v| unwrap(v) }
         | 
| 61 | 
            +
                    else
         | 
| 62 | 
            +
                      (!value.respond_to?(:wrapper) || unwrapped?) ? value : value.wrapper
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
                  end
         | 
| 50 65 | 
             
                end
         | 
| 51 66 | 
             
              end
         | 
| 52 67 | 
             
            end
         |