activecypher 0.7.3 → 0.8.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/active_cypher/connection_adapters/abstract_bolt_adapter.rb +1 -0
  3. data/lib/active_cypher/connection_adapters/memgraph_adapter.rb +10 -1
  4. data/lib/active_cypher/connection_adapters/neo4j_adapter.rb +1 -1
  5. data/lib/active_cypher/connection_adapters/persistence_methods.rb +31 -14
  6. data/lib/active_cypher/relation.rb +1 -1
  7. data/lib/active_cypher/version.rb +1 -1
  8. data/lib/activecypher.rb +3 -1
  9. data/lib/cyrel/ast/call_node.rb +39 -0
  10. data/lib/cyrel/ast/clause_adapter.rb +38 -0
  11. data/lib/cyrel/ast/clause_node.rb +10 -0
  12. data/lib/cyrel/ast/compiler.rb +609 -0
  13. data/lib/cyrel/ast/create_node.rb +21 -0
  14. data/lib/cyrel/ast/delete_node.rb +22 -0
  15. data/lib/cyrel/ast/expression_node.rb +10 -0
  16. data/lib/cyrel/ast/foreach_node.rb +23 -0
  17. data/lib/cyrel/ast/limit_node.rb +21 -0
  18. data/lib/cyrel/ast/literal_node.rb +39 -0
  19. data/lib/cyrel/ast/load_csv_node.rb +24 -0
  20. data/lib/cyrel/ast/match_node.rb +23 -0
  21. data/lib/cyrel/ast/merge_node.rb +23 -0
  22. data/lib/cyrel/ast/node.rb +36 -0
  23. data/lib/cyrel/ast/optimized_nodes.rb +117 -0
  24. data/lib/cyrel/ast/order_by_node.rb +21 -0
  25. data/lib/cyrel/ast/pattern_node.rb +10 -0
  26. data/lib/cyrel/ast/query_integrated_compiler.rb +27 -0
  27. data/lib/cyrel/ast/remove_node.rb +21 -0
  28. data/lib/cyrel/ast/return_node.rb +21 -0
  29. data/lib/cyrel/ast/set_node.rb +20 -0
  30. data/lib/cyrel/ast/simple_cache.rb +50 -0
  31. data/lib/cyrel/ast/skip_node.rb +19 -0
  32. data/lib/cyrel/ast/union_node.rb +22 -0
  33. data/lib/cyrel/ast/unwind_node.rb +20 -0
  34. data/lib/cyrel/ast/where_node.rb +20 -0
  35. data/lib/cyrel/ast/with_node.rb +23 -0
  36. data/lib/cyrel/clause/unwind.rb +71 -0
  37. data/lib/cyrel/expression/literal.rb +9 -2
  38. data/lib/cyrel/expression/property_access.rb +1 -1
  39. data/lib/cyrel/pattern/node.rb +11 -1
  40. data/lib/cyrel/pattern/relationship.rb +21 -13
  41. data/lib/cyrel/query.rb +405 -91
  42. data/lib/cyrel.rb +132 -2
  43. metadata +29 -1
data/lib/cyrel.rb CHANGED
@@ -3,6 +3,18 @@
3
3
  module Cyrel
4
4
  module_function
5
5
 
6
+ # Cyrel DSL helper: creates a new query.
7
+ # Example: Cyrel.query.match(pattern)
8
+ def query
9
+ Query.new
10
+ end
11
+
12
+ # Cyrel DSL helper: alias for node creation.
13
+ # Example: Cyrel.n(:person, :Person, name: 'Alice')
14
+ def n(alias_name = nil, *labels, **properties)
15
+ Pattern::Node.new(alias_name, labels: labels, properties: properties)
16
+ end
17
+
6
18
  # Cyrel DSL helper: creates a CALL clause for a procedure.
7
19
  # Example: Cyrel.call('db.labels')
8
20
  def call(procedure)
@@ -16,11 +28,123 @@ module Cyrel
16
28
  end
17
29
 
18
30
  # Cyrel DSL helper: creates a node pattern.
19
- # Example: Cyrel.node(:n, labels: ['Person'], properties: {name: 'Alice'})
20
- def node(alias_name, labels: [], properties: {})
31
+ # Example: Cyrel.node(:n, :Person, name: 'Alice')
32
+ def node(alias_name = nil, *labels, **properties)
21
33
  Pattern::Node.new(alias_name, labels: labels, properties: properties)
22
34
  end
23
35
 
36
+ # Cyrel DSL helper: creates a relationship pattern.
37
+ # Example: Cyrel.rel(:r, :KNOWS, since: 2020)
38
+ def rel(alias_name = nil, *types, **properties)
39
+ length = properties.delete(:length)
40
+ Pattern::Relationship.new(alias_name: alias_name, types: types, properties: properties, length: length)
41
+ end
42
+
43
+ # Cyrel DSL helper: creates a path pattern with a DSL block.
44
+ # Example: Cyrel.path { node(:a) > rel(:r) > node(:b) }
45
+ def path(&)
46
+ builder = PathBuilder.new
47
+ builder.instance_eval(&)
48
+ Pattern::Path.new(builder.elements)
49
+ end
50
+
51
+ # Path builder DSL for constructing path patterns
52
+ class PathBuilder
53
+ attr_reader :elements
54
+
55
+ def initialize
56
+ @elements = []
57
+ @pending_direction = nil
58
+ end
59
+
60
+ def node(alias_name = nil, *labels, **properties)
61
+ # If there's a pending direction, we need to add a relationship first
62
+ if @pending_direction && @elements.any? && @elements.last.is_a?(Cyrel::Pattern::Node)
63
+ @elements << Cyrel::Pattern::Relationship.new(types: [], direction: @pending_direction)
64
+ @pending_direction = nil
65
+ end
66
+
67
+ n = Cyrel::Pattern::Node.new(alias_name, labels: labels, properties: properties)
68
+ @elements << n
69
+ self
70
+ end
71
+
72
+ def rel(alias_name = nil, *types, **properties)
73
+ length = properties.delete(:length)
74
+
75
+ # Check if we need to replace the last element (an anonymous relationship)
76
+ if @elements.last.is_a?(Cyrel::Pattern::Relationship) && @elements.last.types.empty?
77
+ # Replace the anonymous relationship with specified one, keeping direction
78
+ direction = @elements.last.direction
79
+ @elements.pop
80
+ else
81
+ direction = @pending_direction || :both
82
+ end
83
+
84
+ r = Cyrel::Pattern::Relationship.new(alias_name: alias_name, types: types, properties: properties, length: length, direction: direction)
85
+ @elements << r
86
+ @pending_direction = nil
87
+ self
88
+ end
89
+
90
+ def >(_other)
91
+ # When called like: node(:a) > rel(:r) > node(:b)
92
+ # The rel(:r) is evaluated first, then > is called
93
+ # So we need to modify the last relationship that was just added
94
+ if @elements.last.is_a?(Cyrel::Pattern::Relationship)
95
+ # Replace the last relationship with one that has the correct direction
96
+ last_rel = @elements.pop
97
+ new_rel = Cyrel::Pattern::Relationship.new(
98
+ alias_name: last_rel.alias_name,
99
+ types: last_rel.types,
100
+ properties: last_rel.properties,
101
+ length: last_rel.length,
102
+ direction: :outgoing
103
+ )
104
+ @elements << new_rel
105
+ else
106
+ @pending_direction = :outgoing
107
+ end
108
+ self
109
+ end
110
+
111
+ def <(_other)
112
+ # Same logic as > but for incoming direction
113
+ if @elements.last.is_a?(Cyrel::Pattern::Relationship)
114
+ last_rel = @elements.pop
115
+ new_rel = Cyrel::Pattern::Relationship.new(
116
+ alias_name: last_rel.alias_name,
117
+ types: last_rel.types,
118
+ properties: last_rel.properties,
119
+ length: last_rel.length,
120
+ direction: :incoming
121
+ )
122
+ @elements << new_rel
123
+ else
124
+ @pending_direction = :incoming
125
+ end
126
+ self
127
+ end
128
+
129
+ def -(_other)
130
+ # Same logic as > but for bidirectional
131
+ if @elements.last.is_a?(Cyrel::Pattern::Relationship)
132
+ last_rel = @elements.pop
133
+ new_rel = Cyrel::Pattern::Relationship.new(
134
+ alias_name: last_rel.alias_name,
135
+ types: last_rel.types,
136
+ properties: last_rel.properties,
137
+ length: last_rel.length,
138
+ direction: :both
139
+ )
140
+ @elements << new_rel
141
+ else
142
+ @pending_direction = :both
143
+ end
144
+ self
145
+ end
146
+ end
147
+
24
148
  # Cyrel DSL helper: starts a CREATE query.
25
149
  # Example: Cyrel.create(pattern)
26
150
  def create(pattern)
@@ -44,6 +168,12 @@ module Cyrel
44
168
  # Example: Cyrel.node_id(:n)
45
169
  def node_id(...) = Functions.node_id(...)
46
170
 
171
+ # Cyrel DSL helper: creates a function call expression.
172
+ # Example: Cyrel.function(:count, :*)
173
+ def function(name, *args)
174
+ Expression::FunctionCall.new(name, args)
175
+ end
176
+
47
177
  # Cyrel DSL helper: Cypher count() aggregation.
48
178
  # Example: Cyrel.count(:n)
49
179
  def count(...) = Functions.count(...)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activecypher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abdelkader Boudih
@@ -171,6 +171,33 @@ files:
171
171
  - lib/active_cypher/version.rb
172
172
  - lib/activecypher.rb
173
173
  - lib/cyrel.rb
174
+ - lib/cyrel/ast/call_node.rb
175
+ - lib/cyrel/ast/clause_adapter.rb
176
+ - lib/cyrel/ast/clause_node.rb
177
+ - lib/cyrel/ast/compiler.rb
178
+ - lib/cyrel/ast/create_node.rb
179
+ - lib/cyrel/ast/delete_node.rb
180
+ - lib/cyrel/ast/expression_node.rb
181
+ - lib/cyrel/ast/foreach_node.rb
182
+ - lib/cyrel/ast/limit_node.rb
183
+ - lib/cyrel/ast/literal_node.rb
184
+ - lib/cyrel/ast/load_csv_node.rb
185
+ - lib/cyrel/ast/match_node.rb
186
+ - lib/cyrel/ast/merge_node.rb
187
+ - lib/cyrel/ast/node.rb
188
+ - lib/cyrel/ast/optimized_nodes.rb
189
+ - lib/cyrel/ast/order_by_node.rb
190
+ - lib/cyrel/ast/pattern_node.rb
191
+ - lib/cyrel/ast/query_integrated_compiler.rb
192
+ - lib/cyrel/ast/remove_node.rb
193
+ - lib/cyrel/ast/return_node.rb
194
+ - lib/cyrel/ast/set_node.rb
195
+ - lib/cyrel/ast/simple_cache.rb
196
+ - lib/cyrel/ast/skip_node.rb
197
+ - lib/cyrel/ast/union_node.rb
198
+ - lib/cyrel/ast/unwind_node.rb
199
+ - lib/cyrel/ast/where_node.rb
200
+ - lib/cyrel/ast/with_node.rb
174
201
  - lib/cyrel/call_procedure.rb
175
202
  - lib/cyrel/clause.rb
176
203
  - lib/cyrel/clause/call.rb
@@ -185,6 +212,7 @@ files:
185
212
  - lib/cyrel/clause/return.rb
186
213
  - lib/cyrel/clause/set.rb
187
214
  - lib/cyrel/clause/skip.rb
215
+ - lib/cyrel/clause/unwind.rb
188
216
  - lib/cyrel/clause/where.rb
189
217
  - lib/cyrel/clause/with.rb
190
218
  - lib/cyrel/direction.rb