redgraph 0.2.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5a64b5cffa36368ac0664e813ab61f0329a055237b7e4acd473820d9c73409d
4
- data.tar.gz: 371cde906c0a80370e39763a9b3ba9f3fcb83cdd2c19e97f635bfea6e35c5540
3
+ metadata.gz: 2fd53776ff217146cd6ca4924da40a43f5bf929fad03b73b79f32d371ea955e8
4
+ data.tar.gz: 551afc973f8e732ad532e74395e6c73251f14d68db73f667a207b234bd64163b
5
5
  SHA512:
6
- metadata.gz: ac0481573ed2d41bb20de03ab1dc36d6781f5a121a865358e296654dc09abe168868104df92deeb623594b6d68363a0c9333268a059c7b8caf362504039e1431
7
- data.tar.gz: dcb4c293c0a1003926d8776930123c81a5d35981a0896d447a03cc8ee1082f837ce1d73a1f7ca664478980fb485eefb39dad120f703b4584d40ffd6a3ff509c2
6
+ metadata.gz: dd7f88ae09acb7f09b6c8de949d4f31bbc52b12e4b914f035de99c7cd9b409c14eac3e592f834cc968517b796fed0cf3a085f7eba4915e630b2e66c424ae9870
7
+ data.tar.gz: 979aac39193d3150441ddf5baca14772a35c6cfd00f09df42752277aed3d955869822b2d97150209f1e71ad5ab95e566dc645d15d3e8262675dd858bd6fbb1dd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [0.2.1]
2
+
3
+ - Add NodeModel#destroy method
4
+ - Add NodeModel.create method
5
+
1
6
  ## [0.2.0]
2
7
 
3
8
  - revamp the NodeModel mixin, the Node to model mapping is now handled by the `_type` property
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- redgraph (0.2.0)
4
+ redgraph (0.2.1)
5
5
  activesupport (>= 3.0.0)
6
6
  redis (~> 4)
7
7
 
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Redgraph
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/redgraph.svg)](https://badge.fury.io/rb/redgraph)
4
+ [![Code Climate](https://codeclimate.com/github/pzac/redgraph.svg)](https://codeclimate.com/github/pzac/redgraph)
5
+
3
6
  A simple RedisGraph library. This gem owes **a lot** to the existing [redisgraph-rb](https://github.com/RedisGraph/redisgraph-rb) gem, but tries to provide a friendlier interface, similar to the existing [Python](https://github.com/RedisGraph/redisgraph-py) and [Elixir](https://github.com/crflynn/redisgraph-ex) clients.
4
7
 
5
8
  ## Installation
@@ -24,92 +27,122 @@ The gem assumes you have a recent version of [RedisGraph](https://oss.redislabs.
24
27
 
25
28
  Basic usage:
26
29
 
27
- graph = Redgraph::Graph.new('movies', url: "redis://localhost:6379/1")
28
- => #<Redgraph::Graph:0x00007f8d5c2b7e38 @connection=#<Redis client v4.2.5 for redis://localhost:6379/1>, @graph_name="movies", @module_version=999999>
30
+ ```ruby
31
+ graph = Redgraph::Graph.new('movies', url: "redis://localhost:6379/1")
32
+ => #<Redgraph::Graph:0x00007f8d5c2b7e38 @connection=#<Redis client v4.2.5 for redis://localhost:6379/1>, @graph_name="movies", @module_version=999999>
33
+ ```
29
34
 
30
35
  Create a couple nodes:
31
36
 
32
- actor = Redgraph::Node.new(label: 'actor', properties: {name: "Al Pacino"})
33
- => #<Redgraph::Node:0x00007f8d5f95cf88 @label="actor", @properties={:name=>"Al Pacino"}>
34
- graph.add_node(actor)
35
- => #<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>
36
- film = Redgraph::Node.new(label: 'film', properties: {name: "Scarface"})
37
- => #<Redgraph::Node:0x00007f8d5f85ccc8 @label="film", @properties={:name=>"Scarface"}>
38
- graph.add_node(film)
39
- => #<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>
37
+ ```ruby
38
+ actor = Redgraph::Node.new(label: 'actor', properties: {name: "Al Pacino"})
39
+ => #<Redgraph::Node:0x00007f8d5f95cf88 @label="actor", @properties={:name=>"Al Pacino"}>
40
+ graph.add_node(actor)
41
+ => #<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>
42
+ film = Redgraph::Node.new(label: 'film', properties: {name: "Scarface"})
43
+ => #<Redgraph::Node:0x00007f8d5f85ccc8 @label="film", @properties={:name=>"Scarface"}>
44
+ graph.add_node(film)
45
+ => #<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>
46
+ ```
40
47
 
41
48
  Create an edge between those nodes:
42
49
 
43
- edge = Redgraph::Edge.new(src: actor, dest: film, type: 'ACTOR_IN', properties: {role: "Tony Montana"})
44
- => #<Redgraph::Edge:0x00007f8d5f9ae3d8 @dest=#<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>, @dest_id=1, @properties={:role=>"Tony Montana"}, @src=#<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>, @src_id=0, @type="ACTOR_IN">
45
- @graph.add_edge(edge)
46
- => #<Redgraph::Edge:0x00007f8d5f9ae3d8 @dest=#<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>, @dest_id=1, @id=0, @properties={:role=>"Tony Montana"}, @src=#<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>, @src_id=0, @type="ACTOR_IN">
50
+ ```ruby
51
+ edge = Redgraph::Edge.new(src: actor, dest: film, type: 'ACTOR_IN', properties: {role: "Tony Montana"})
52
+ => #<Redgraph::Edge:0x00007f8d5f9ae3d8 @dest=#<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>, @dest_id=1, @properties={:role=>"Tony Montana"}, @src=#<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>, @src_id=0, @type="ACTOR_IN">
53
+ @graph.add_edge(edge)
54
+ => #<Redgraph::Edge:0x00007f8d5f9ae3d8 @dest=#<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>, @dest_id=1, @id=0, @properties={:role=>"Tony Montana"}, @src=#<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>, @src_id=0, @type="ACTOR_IN">
55
+ ```
47
56
 
48
57
  You can merge nodes - the node will be created only if there isn't another with the same label and properties:
49
58
 
50
- graph.merge_node(film)
51
- => #<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>
59
+ ```ruby
60
+ graph.merge_node(film)
61
+ => #<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>
62
+ ```
52
63
 
53
64
  Same with edges:
54
65
 
55
- @graph.merge_edge(edge)
56
- => #<Redgraph::Edge:0x00007f8d5f9ae3d8 @dest=#<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>, @dest_id=1, @id=0, @properties={:role=>"Tony Montana"}, @src=#<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>, @src_id=0, @type="ACTOR_IN">
66
+ ```ruby
67
+ @graph.merge_edge(edge)
68
+ => #<Redgraph::Edge:0x00007f8d5f9ae3d8 @dest=#<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>, @dest_id=1, @id=0, @properties={:role=>"Tony Montana"}, @src=#<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>, @src_id=0, @type="ACTOR_IN">
69
+ ```
57
70
 
58
71
  Find a node by id:
59
72
 
60
- @graph.find_node_by_id(1)
61
- => #<Redgraph::Node:0x00007f8d5c2c6e88 @id=1, @label="film", @properties={"name"=>"Scarface"}>
73
+ ```ruby
74
+ @graph.find_node_by_id(1)
75
+ => #<Redgraph::Node:0x00007f8d5c2c6e88 @id=1, @label="film", @properties={"name"=>"Scarface"}>
76
+ ```
62
77
 
63
78
  To get all nodes:
64
79
 
65
- @graph.nodes
66
- => [#<Redgraph::Node:0x00007f8d5c2ee0a0 @id=0, @label="actor", @properties={"name"=>"Al Pacino"}>, #<Redgraph::Node:0x00007f8d5c2edfd8 @id=1, @label="film", @properties={"name"=>"Scarface"}>]
80
+ ```ruby
81
+ @graph.nodes
82
+ => [#<Redgraph::Node:0x00007f8d5c2ee0a0 @id=0, @label="actor", @properties={"name"=>"Al Pacino"}>, #<Redgraph::Node:0x00007f8d5c2edfd8 @id=1, @label="film", @properties={"name"=>"Scarface"}>]
83
+ ```
67
84
 
68
85
  Optional filters that can be combined:
69
86
 
70
- @graph.nodes(label: 'actor')
71
- @graph.nodes(properties: {name: "Al Pacino"})
72
- @graph.nodes(limit: 10, skip: 20)
87
+ ```ruby
88
+ @graph.nodes(label: 'actor')
89
+ @graph.nodes(properties: {name: "Al Pacino"})
90
+ @graph.nodes(limit: 10, skip: 20)
91
+ ```
73
92
 
74
93
  Counting nodes
75
94
 
76
- @graph.count_nodes(label: 'actor')
77
- => 1
95
+ ```ruby
96
+ @graph.count_nodes(label: 'actor')
97
+ => 1
98
+ ```
78
99
 
79
100
  Getting edges:
80
101
 
81
- @graph.edges
82
- @graph.edges(src: actor, dest: film)
83
- @graph.edges(kind: 'FRIEND_OF', limit: 10, skip: 20)
84
- @graph.count_edges
102
+ ```ruby
103
+ @graph.edges
104
+ @graph.edges(src: actor, dest: film)
105
+ @graph.edges(kind: 'FRIEND_OF', limit: 10, skip: 20)
106
+ @graph.count_edges
107
+ ```
85
108
 
86
109
  Running custom queries
87
110
 
88
- @graph.query("MATCH (src)-[edge:FRIEND_OF]->(dest) RETURN src, edge")
111
+ ```ruby
112
+ @graph.query("MATCH (src)-[edge:FRIEND_OF]->(dest) RETURN src, edge")
113
+ ```
89
114
 
90
115
  ### NodeModel
91
116
 
92
117
  You can use the `NodeModel` mixin for a limited ActiveRecord-like interface:
93
118
 
94
- class Actor
95
- include Redgraph::NodeModel
96
- self.graph = Redgraph::Graph.new("movies", url: $REDIS_URL)
97
- attribute :name
98
- end
119
+ ```ruby
120
+ class Actor
121
+ include Redgraph::NodeModel
122
+ self.graph = Redgraph::Graph.new("movies", url: $REDIS_URL)
123
+ attribute :name
124
+ end
125
+ ```
99
126
 
100
127
  And this will give you stuff such as
101
128
 
102
- Actor.count
103
- john = Actor.new(name: "John Travolta")
104
- john.add_to_graph # Will add the node to the graph
105
- john.add_relation(type: "ACTED_IN", node: film, properties: {role: "Tony Manero"})
129
+ ```ruby
130
+ Actor.count
131
+ john = Actor.new(name: "John Travolta")
132
+ john.add_to_graph # Will add the node to the graph
133
+ john.add_relation(type: "ACTED_IN", node: film, properties: {role: "Tony Manero"})
134
+ john.reload
135
+ john.destroy
136
+ Actor.create(name: "Al Pacino")
137
+ ```
106
138
 
107
139
  `NodeModel` models will automatically set a `_type` property to keep track of the object class.
108
140
 
109
141
  You will then be able to run custom queries such as:
110
142
 
111
- Actor.query("MATCH (node) RETURN node ORDER BY node.name")
112
-
143
+ ```ruby
144
+ Actor.query("MATCH (node) RETURN node ORDER BY node.name")
145
+ ```
113
146
  And the result rows object will be instances of the classes defined by the `_type` attribute.
114
147
 
115
148
  ## Development
data/lib/redgraph.rb CHANGED
@@ -21,4 +21,9 @@ module Redgraph
21
21
  "The order clause requires the node/edge alias prefix, ie order('node.foo') instead order('foo')"
22
22
  end
23
23
  end
24
+ class MissingGraphError < Error
25
+ def message
26
+ "A graph to use is not defined"
27
+ end
28
+ end
24
29
  end
@@ -7,6 +7,7 @@ module Redgraph
7
7
  class Graph
8
8
  include NodeMethods
9
9
  include EdgeMethods
10
+ include Util
10
11
 
11
12
  attr_accessor :connection, :graph_name
12
13
 
@@ -73,6 +73,24 @@ module Redgraph
73
73
  query(cmd).flatten[0] || 0
74
74
  end
75
75
 
76
+ def update_node(node)
77
+ return false unless node.persisted?
78
+ _set = node.properties.map do |(key, val)|
79
+ "node.#{key} = #{escape_value(val)}"
80
+ end.join(", ")
81
+
82
+ cmd = "MATCH (node) WHERE ID(node) = #{node.id} SET #{_set} RETURN node"
83
+ result = _query(cmd)
84
+ node_from_resultset_item(result.resultset.first["node"])
85
+ end
86
+
87
+ def destroy_node(node)
88
+ return false unless node.persisted?
89
+ cmd = "MATCH (node) WHERE ID(node) = #{node.id} DELETE node"
90
+ result = _query(cmd)
91
+ result.stats["nodes_deleted"] == 1
92
+ end
93
+
76
94
  private
77
95
 
78
96
  # Builds a Node object from the raw data
@@ -99,6 +117,7 @@ module Redgraph
99
117
  node
100
118
  end
101
119
 
120
+
102
121
  end
103
122
  end
104
123
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative 'node_model/class_methods'
3
+ require_relative 'node_model/graph_manipulation'
4
+ require_relative 'node_model/persistence'
3
5
 
4
6
  module Redgraph
5
7
  # This mixin allows you to use an interface similar to ActiveRecord
@@ -24,10 +26,12 @@ module Redgraph
24
26
  extend ActiveSupport::Concern
25
27
 
26
28
  included do |base|
29
+ include Persistence
30
+ include GraphManipulation
31
+
27
32
  @attribute_names = [:id]
28
33
 
29
- attr_accessor :id
30
- attr_accessor :_type
34
+ attr_accessor :id, :_type
31
35
 
32
36
  class << self
33
37
  attr_reader :attribute_names
@@ -35,7 +39,7 @@ module Redgraph
35
39
 
36
40
  def attribute(name)
37
41
  @attribute_names << name
38
- attr_reader(name)
42
+ attr_accessor(name)
39
43
  end
40
44
 
41
45
  private
@@ -76,32 +80,10 @@ module Redgraph
76
80
  self.class.attribute_names.to_h { |name| [name, public_send(name)] }
77
81
  end
78
82
 
79
- def persisted?
80
- id.present?
81
- end
82
-
83
- # Adds the node to the graph
84
- #
85
- # - allow_duplicates: if false it will create a node with the same type and properties only if
86
- # not present
87
- #
88
- def add_to_graph(allow_duplicates: true)
89
- item = allow_duplicates ? graph.add_node(to_node) : graph.merge_node(to_node)
90
- self.id = item.id
91
- self
92
- end
93
-
94
- # Adds a relation between the node and another node.
95
- #
96
- # - type: type of relation
97
- # - node: the destination node
98
- # - properties: optional properties hash
99
- # - allow_duplicates: if false it will create a relation between two nodes with the same type
100
- # and properties only if not present
101
- #
102
- def add_relation(type:, node:, properties: nil, allow_duplicates: true)
103
- edge = Edge.new(type: type, src: to_node, dest: node.to_node, properties: properties)
104
- allow_duplicates ? graph.add_edge(edge) : graph.merge_edge(edge)
83
+ def assign_attributes(attrs = {})
84
+ attrs.each do |name, value|
85
+ instance_variable_set("@#{name}", value)
86
+ end
105
87
  end
106
88
 
107
89
  def to_node
@@ -109,12 +91,6 @@ module Redgraph
109
91
  Redgraph::Node.new(id: id, label: label, properties: props)
110
92
  end
111
93
 
112
- # Converts a Node object into NodeModel
113
- #
114
- def reify_from_node(node)
115
- self.class.reify_from_node(node)
116
- end
117
-
118
94
  def ==(other)
119
95
  attributes == other.attributes && id == other.id
120
96
  end
@@ -3,12 +3,13 @@ module Redgraph
3
3
  module ClassMethods
4
4
  # Returns an array of nodes. Options:
5
5
  #
6
+ # - label: filter by label
6
7
  # - properties: filter by properties
7
8
  # - order: node.name ASC, node.year DESC
8
9
  # - limit: number of items
9
10
  # - skip: items offset (useful for pagination)
10
11
  #
11
- def all(properties: {}, limit: nil, skip: nil, order: nil)
12
+ def all(label: nil, properties: {}, limit: nil, skip: nil, order: nil)
12
13
  graph.nodes(label: label, properties: properties_plus_type(properties),
13
14
  limit: limit, skip: skip, order: nil).map do |node|
14
15
  reify_from_node(node)
@@ -19,7 +20,7 @@ module Redgraph
19
20
  #
20
21
  # - properties: filter by properties
21
22
  #
22
- def count(properties: nil)
23
+ def count(label: nil, properties: nil)
23
24
  graph.count_nodes(label: label, properties: properties_plus_type(properties))
24
25
  end
25
26
 
@@ -55,6 +56,8 @@ module Redgraph
55
56
  # Returns an array of rows.
56
57
  #
57
58
  def query(cmd)
59
+ raise MissingGraphError unless graph
60
+
58
61
  graph.query(cmd).map do |row|
59
62
  row.map do |item|
60
63
  item.is_a?(Node) ? reify_from_node(item) : item
@@ -62,6 +65,10 @@ module Redgraph
62
65
  end
63
66
  end
64
67
 
68
+ def create(properties)
69
+ new(**properties).add_to_graph
70
+ end
71
+
65
72
  private
66
73
 
67
74
  def default_label
@@ -0,0 +1,24 @@
1
+ module Redgraph
2
+ module NodeModel
3
+ module GraphManipulation
4
+ # Adds a relation between the node and another node.
5
+ #
6
+ # - type: type of relation
7
+ # - node: the destination node
8
+ # - properties: optional properties hash
9
+ # - allow_duplicates: if false it will create a relation between two nodes with the same type
10
+ # and properties only if not present
11
+ #
12
+ def add_relation(type:, node:, properties: nil, allow_duplicates: true)
13
+ edge = Edge.new(type: type, src: to_node, dest: node.to_node, properties: properties)
14
+ allow_duplicates ? graph.add_edge(edge) : graph.merge_edge(edge)
15
+ end
16
+
17
+ # Runs a custom query on the graph
18
+ #
19
+ def query(cmd)
20
+ self.class.query(cmd)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,56 @@
1
+ module Redgraph
2
+ module NodeModel
3
+ module Persistence
4
+ # Adds the node to the graph
5
+ #
6
+ # - allow_duplicates: if false it will create a node with the same type and properties only if
7
+ # not present
8
+ #
9
+ def add_to_graph(allow_duplicates: true)
10
+ raise MissingGraphError unless graph
11
+ item = allow_duplicates ? graph.add_node(to_node) : graph.merge_node(to_node)
12
+ self.id = item.id
13
+ self
14
+ end
15
+
16
+ # Creates a new record or updates the existing
17
+ #
18
+ def save
19
+ if persisted?
20
+ item = graph.update_node(to_node)
21
+ self.class.reify_from_node(item)
22
+ else
23
+ add_to_graph
24
+ end
25
+ end
26
+
27
+ def persisted?
28
+ id.present?
29
+ end
30
+
31
+ def reload
32
+ item = self.class.find(id)
33
+ @label = item.label
34
+ assign_attributes(item.attributes)
35
+ self
36
+ end
37
+
38
+ # Deletes the record from the graph
39
+ #
40
+ def destroy
41
+ @destroyed = true
42
+ if graph.destroy_node(self)
43
+ self
44
+ else
45
+ false
46
+ end
47
+ end
48
+
49
+ # Returns true if this object has been destroyed, otherwise returns false.
50
+ #
51
+ def destroyed?
52
+ !!@destroyed
53
+ end
54
+ end
55
+ end
56
+ end
@@ -29,9 +29,16 @@ module Redgraph
29
29
  @response = response
30
30
  @graph = graph
31
31
 
32
- @header_row = @response[0]
33
- @result_rows = @response[1]
34
- @query_statistics = @response[2]
32
+ case @response.size
33
+ when 3
34
+ @header_row = @response[0]
35
+ @result_rows = @response[1]
36
+ @query_statistics = @response[2]
37
+ when 1 # queries with no RETURN clause
38
+ @header_row = []
39
+ @result_rows = []
40
+ @query_statistics = @response[0]
41
+ end
35
42
  end
36
43
 
37
44
  def stats
@@ -121,6 +128,8 @@ module Redgraph
121
128
  case label
122
129
  when /^Nodes created/
123
130
  stats[:nodes_created] = value.to_i
131
+ when /^Nodes deleted/
132
+ stats[:nodes_deleted] = value.to_i
124
133
  when /^Relationships created/
125
134
  stats[:relationships_created] = value.to_i
126
135
  when /^Properties set/
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Redgraph
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.1"
5
5
  end
@@ -24,6 +24,11 @@ class NodeModelClassMethodsTest < Minitest::Test
24
24
  attribute :name
25
25
  end
26
26
 
27
+ class MissingGraphActor
28
+ include Redgraph::NodeModel
29
+ attribute :name
30
+ end
31
+
27
32
  # tests
28
33
  #
29
34
 
@@ -63,4 +68,26 @@ class NodeModelClassMethodsTest < Minitest::Test
63
68
  item = Actor.find("-1")
64
69
  assert_nil(item)
65
70
  end
71
+
72
+ def test_create
73
+ assert_equal(0, Actor.count)
74
+
75
+ actor = Actor.create(name: "Harrison Ford")
76
+
77
+ assert_equal(1, Actor.count)
78
+ assert_predicate(actor, :persisted?)
79
+ assert_equal("Harrison Ford", actor.name)
80
+ assert_equal("actor", actor.label)
81
+
82
+ found = Actor.find(actor.id)
83
+ assert_equal("Harrison Ford", found.name)
84
+ assert_equal("actor", found.label)
85
+ assert_equal(Actor.name, found._type)
86
+ end
87
+
88
+ def test_create_with_missing_graph
89
+ assert_raises(Redgraph::MissingGraphError) do
90
+ MissingGraphActor.create(name: "Harrison Ford")
91
+ end
92
+ end
66
93
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class NodeModelPersistenceTest < Minitest::Test
6
+ include TestHelpers
7
+
8
+ GRAPH = Redgraph::Graph.new("movies", url: $REDIS_URL)
9
+
10
+ def setup
11
+ @graph = GRAPH
12
+ end
13
+
14
+ def teardown
15
+ @graph.delete
16
+ end
17
+
18
+ # test classes
19
+ #
20
+
21
+ class Film
22
+ include Redgraph::NodeModel
23
+ self.graph = GRAPH
24
+ attribute :name
25
+ end
26
+
27
+ # tests
28
+ #
29
+
30
+ def test_save_new
31
+ assert_equal(0, Film.count)
32
+
33
+ film = Film.new(name: "Star Wars")
34
+ film.save
35
+
36
+ assert_predicate(film, :persisted?)
37
+ assert_equal(1, Film.count)
38
+ end
39
+
40
+ def test_save_existing
41
+ film = Film.create(name: "Star Wars")
42
+ film.name = "Commando"
43
+ film.save
44
+
45
+ assert_equal(1, Film.count)
46
+ item = Film.find(film.id)
47
+ assert_equal("Commando", item.name)
48
+ end
49
+
50
+ def test_reload
51
+ film = Film.create(name: "Star Wars")
52
+ copy = Film.find(film.id)
53
+
54
+ assert_equal("Star Wars", copy.name)
55
+
56
+ film.name = "Commando"
57
+ film.save
58
+
59
+ assert_equal("Star Wars", copy.name)
60
+ assert_equal("Commando", copy.reload.name)
61
+ end
62
+
63
+ def test_destroy
64
+ film = Film.create(name: "Star Wars")
65
+ assert_equal(1, Film.count)
66
+ film.destroy
67
+ assert_predicate(film, :destroyed?)
68
+ assert_equal(0, Film.count)
69
+ end
70
+ end
@@ -123,4 +123,14 @@ class NodeModelTest < Minitest::Test
123
123
  assert_kind_of(Film, items[1][0])
124
124
  end
125
125
 
126
+ def test_casting_query_from_model
127
+ film = Film.create(name: "Star Wars", year: 1977)
128
+ Actor.create(name: "Harrison Ford")
129
+
130
+ items = film.query("MATCH (node) RETURN node ORDER BY node.name")
131
+ assert_equal(2, items.size)
132
+ assert_kind_of(Actor, items[0][0])
133
+ assert_kind_of(Film, items[1][0])
134
+ end
135
+
126
136
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redgraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paolo Zaccagnini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-19 00:00:00.000000000 Z
11
+ date: 2021-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -63,6 +63,8 @@ files:
63
63
  - lib/redgraph/node.rb
64
64
  - lib/redgraph/node_model.rb
65
65
  - lib/redgraph/node_model/class_methods.rb
66
+ - lib/redgraph/node_model/graph_manipulation.rb
67
+ - lib/redgraph/node_model/persistence.rb
66
68
  - lib/redgraph/query_response.rb
67
69
  - lib/redgraph/util.rb
68
70
  - lib/redgraph/version.rb
@@ -75,6 +77,7 @@ files:
75
77
  - test/graph_test.rb
76
78
  - test/node_model_class_methods_test.rb
77
79
  - test/node_model_labels_test.rb
80
+ - test/node_model_persistence_test.rb
78
81
  - test/node_model_test.rb
79
82
  - test/redgraph_test.rb
80
83
  - test/test_helper.rb