cypher-dsl 0.1.0.alpha.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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +32 -0
  3. data/LICENSE.txt +21 -0
  4. data/NOTICE +14 -0
  5. data/README.md +87 -0
  6. data/lib/cypher_dsl/aliased_expression.rb +16 -0
  7. data/lib/cypher_dsl/asterisk.rb +10 -0
  8. data/lib/cypher_dsl/case_expression.rb +37 -0
  9. data/lib/cypher_dsl/clauses/call.rb +8 -0
  10. data/lib/cypher_dsl/clauses/call_subquery.rb +9 -0
  11. data/lib/cypher_dsl/clauses/create.rb +8 -0
  12. data/lib/cypher_dsl/clauses/delete.rb +8 -0
  13. data/lib/cypher_dsl/clauses/finish.rb +8 -0
  14. data/lib/cypher_dsl/clauses/foreach.rb +8 -0
  15. data/lib/cypher_dsl/clauses/load_csv.rb +8 -0
  16. data/lib/cypher_dsl/clauses/match.rb +8 -0
  17. data/lib/cypher_dsl/clauses/merge.rb +8 -0
  18. data/lib/cypher_dsl/clauses/order.rb +8 -0
  19. data/lib/cypher_dsl/clauses/raw_return.rb +8 -0
  20. data/lib/cypher_dsl/clauses/remove.rb +8 -0
  21. data/lib/cypher_dsl/clauses/return.rb +8 -0
  22. data/lib/cypher_dsl/clauses/set.rb +8 -0
  23. data/lib/cypher_dsl/clauses/unwind.rb +8 -0
  24. data/lib/cypher_dsl/clauses/use.rb +8 -0
  25. data/lib/cypher_dsl/clauses/with.rb +8 -0
  26. data/lib/cypher_dsl/clauses.rb +25 -0
  27. data/lib/cypher_dsl/collect_expression.rb +28 -0
  28. data/lib/cypher_dsl/comparison.rb +27 -0
  29. data/lib/cypher_dsl/compound_condition.rb +34 -0
  30. data/lib/cypher_dsl/condition.rb +35 -0
  31. data/lib/cypher_dsl/conflicting_parameters_exception.rb +15 -0
  32. data/lib/cypher_dsl/constant_condition.rb +17 -0
  33. data/lib/cypher_dsl/count_expression.rb +16 -0
  34. data/lib/cypher_dsl/cypher.rb +210 -0
  35. data/lib/cypher_dsl/exists_condition.rb +15 -0
  36. data/lib/cypher_dsl/expression.rb +69 -0
  37. data/lib/cypher_dsl/expression_condition.rb +14 -0
  38. data/lib/cypher_dsl/function_invocation.rb +17 -0
  39. data/lib/cypher_dsl/functions.rb +182 -0
  40. data/lib/cypher_dsl/has_label_condition.rb +15 -0
  41. data/lib/cypher_dsl/label_expression.rb +40 -0
  42. data/lib/cypher_dsl/label_operation.rb +18 -0
  43. data/lib/cypher_dsl/list_comprehension.rb +40 -0
  44. data/lib/cypher_dsl/list_expression.rb +17 -0
  45. data/lib/cypher_dsl/list_operator.rb +24 -0
  46. data/lib/cypher_dsl/list_predicate.rb +32 -0
  47. data/lib/cypher_dsl/literal.rb +29 -0
  48. data/lib/cypher_dsl/map_expression.rb +32 -0
  49. data/lib/cypher_dsl/map_projection.rb +58 -0
  50. data/lib/cypher_dsl/merge_action.rb +11 -0
  51. data/lib/cypher_dsl/named_path.rb +59 -0
  52. data/lib/cypher_dsl/no_condition.rb +14 -0
  53. data/lib/cypher_dsl/node.rb +83 -0
  54. data/lib/cypher_dsl/operation.rb +22 -0
  55. data/lib/cypher_dsl/parameter.rb +40 -0
  56. data/lib/cypher_dsl/pattern_comprehension.rb +31 -0
  57. data/lib/cypher_dsl/pattern_expression.rb +16 -0
  58. data/lib/cypher_dsl/property.rb +24 -0
  59. data/lib/cypher_dsl/quantified_path_pattern.rb +37 -0
  60. data/lib/cypher_dsl/raw_expression.rb +15 -0
  61. data/lib/cypher_dsl/reduction.rb +33 -0
  62. data/lib/cypher_dsl/relationship.rb +97 -0
  63. data/lib/cypher_dsl/relationship_chain.rb +44 -0
  64. data/lib/cypher_dsl/relationship_pattern_condition.rb +14 -0
  65. data/lib/cypher_dsl/renderer/configuration.rb +66 -0
  66. data/lib/cypher_dsl/renderer/dialect.rb +20 -0
  67. data/lib/cypher_dsl/renderer/escaper.rb +31 -0
  68. data/lib/cypher_dsl/renderer/visitor/expressions.rb +274 -0
  69. data/lib/cypher_dsl/renderer/visitor/patterns.rb +125 -0
  70. data/lib/cypher_dsl/renderer/visitor.rb +298 -0
  71. data/lib/cypher_dsl/renderer.rb +28 -0
  72. data/lib/cypher_dsl/sort_item.rb +17 -0
  73. data/lib/cypher_dsl/standalone_call.rb +61 -0
  74. data/lib/cypher_dsl/statement.rb +56 -0
  75. data/lib/cypher_dsl/statement_builder.rb +294 -0
  76. data/lib/cypher_dsl/statement_catalog.rb +25 -0
  77. data/lib/cypher_dsl/subquery_with.rb +15 -0
  78. data/lib/cypher_dsl/symbolic_name.rb +48 -0
  79. data/lib/cypher_dsl/unary_operation.rb +16 -0
  80. data/lib/cypher_dsl/union_query.rb +29 -0
  81. data/lib/cypher_dsl/version.rb +5 -0
  82. data/lib/cypher_dsl.rb +13 -0
  83. metadata +140 -0
@@ -0,0 +1,294 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CypherDSL
4
+ # Builds a {Statement} clause by clause. Every method returns a new builder;
5
+ # the last clause stays open for refinement (WHERE on MATCH/WITH, ORDER BY,
6
+ # SKIP and LIMIT on RETURN/WITH) until the next clause is added.
7
+ #
8
+ # `and` is overloaded as in the Java API: after `where` it extends the
9
+ # condition, after `order_by` it adds another sort item.
10
+ class StatementBuilder
11
+ def initialize(clauses = [], mode = nil)
12
+ @clauses = clauses.freeze
13
+ @mode = mode
14
+ freeze
15
+ end
16
+
17
+ # --- reading ---------------------------------------------------------
18
+
19
+ # `match(pattern, …)` or, as in Java, `match(optional, pattern, …)` with a leading flag.
20
+ def match(*pattern_elements)
21
+ optional = [true, false].include?(pattern_elements.first) ? pattern_elements.shift : false
22
+ append(Clauses::Match.new(optional:, pattern_elements: pattern_elements.flatten.freeze, where: nil), :condition)
23
+ end
24
+
25
+ def optional_match(*pattern_elements) = match(true, *pattern_elements)
26
+
27
+ def where(condition)
28
+ if @clauses.last.is_a?(Clauses::CallSubquery)
29
+ raise ArgumentError, 'A CALL{} clause requires to WITH before you can add further conditions'
30
+ end
31
+
32
+ update_last(:condition) { |clause| clause.with(where: Condition.coerce(condition)) }
33
+ end
34
+
35
+ def and(argument)
36
+ case @mode
37
+ when :order then add_sort_item(argument)
38
+ when :condition then update_last(:condition) { |clause| clause.with(where: clause.where.and(argument)) }
39
+ else raise ArgumentError, '`and` needs a preceding WHERE or ORDER BY.'
40
+ end
41
+ end
42
+
43
+ def or(condition) = update_last(:condition) { |clause| clause.with(where: clause.where.or(condition)) }
44
+ def xor(condition) = update_last(:condition) { |clause| clause.with(where: clause.where.xor(condition)) }
45
+
46
+ # --- projecting ------------------------------------------------------
47
+
48
+ def returning(*expressions) = append(return_clause(false, expressions), :projection)
49
+ def returning_distinct(*expressions) = append(return_clause(true, expressions), :projection)
50
+
51
+ # A projection rendered without the RETURN keyword, for raw fragments that carry their own.
52
+ def returning_raw(*expressions) = append(Clauses::RawReturn.new(items: coerce_items(expressions)), :projection)
53
+
54
+ def with(*expressions)
55
+ append(Clauses::With.new(distinct: false, items: coerce_items(expressions), order: nil, skip: nil, limit: nil,
56
+ where: nil), :condition)
57
+ end
58
+
59
+ def with_distinct(*expressions)
60
+ append(Clauses::With.new(distinct: true, items: coerce_items(expressions), order: nil, skip: nil, limit: nil,
61
+ where: nil), :condition)
62
+ end
63
+
64
+ def order_by(*sort_items)
65
+ update_last(:order) { |clause| clause.with(order: Clauses::Order.new(items: coerce_sort_items(sort_items))) }
66
+ end
67
+
68
+ def ascending = update_last_sort_item(&:ascending)
69
+ def descending = update_last_sort_item(&:descending)
70
+
71
+ def skip(amount) = update_last(@mode) { |clause| clause.with(skip: optional_expression(amount)) }
72
+ def limit(amount) = update_last(@mode) { |clause| clause.with(limit: optional_expression(amount)) }
73
+ alias take limit # Arel spelling
74
+
75
+ # `unwind(list).as(:item)`; `as` completes the clause. Several arguments, or
76
+ # an array, form a list literal.
77
+ def unwind(*expressions)
78
+ single = expressions.size == 1 && !expressions.first.is_a?(Array)
79
+ OngoingUnwind.new(self, single ? coerce_items(expressions).first : ListExpression.of(expressions.flatten))
80
+ end
81
+
82
+ # --- updating --------------------------------------------------------
83
+
84
+ def create(*pattern_elements) = append(Clauses::Create.new(pattern_elements: pattern_elements.flatten.freeze), nil)
85
+
86
+ def merge(*pattern_elements)
87
+ append(Clauses::Merge.new(pattern_elements: pattern_elements.flatten.freeze, actions: [].freeze), nil)
88
+ end
89
+
90
+ # `on_match.set(…)` / `on_create.mutate(…)` after a MERGE.
91
+ def on_match = MergeActionBuilder.new(self, :on_match)
92
+ def on_create = MergeActionBuilder.new(self, :on_create)
93
+
94
+ # Accepts operations (`n.p.to(x)`, `n.mutate(map)`), a node followed by
95
+ # labels (`set(n, 'A', 'B')`), or an even list of target/value pairs.
96
+ def set(*arguments) = append(Clauses::Set.new(operations: operations_for_set(arguments)), nil)
97
+
98
+ # `SET target += expression`.
99
+ def mutate(target, expression) = set(Operation.new(target, '+=', Expression.coerce(expression)))
100
+
101
+ # Accepts properties, or a node followed by labels (`remove(n, 'A', 'B')`).
102
+ def remove(*arguments)
103
+ arguments = arguments.flatten
104
+ items = label_operation?(arguments) ? [LabelOperation.new(arguments.first, arguments.drop(1))] : arguments
105
+ append(Clauses::Remove.new(items: items.freeze), nil)
106
+ end
107
+
108
+ def delete(*expressions) = append(Clauses::Delete.new(detach: false, expressions: coerce_items(expressions)), nil)
109
+
110
+ def detach_delete(*expressions)
111
+ append(Clauses::Delete.new(detach: true, expressions: coerce_items(expressions)), nil)
112
+ end
113
+
114
+ # `foreach(:i).in(list).apply(clause, …)`.
115
+ def foreach(variable) = OngoingForeach.new(self, SymbolicName.of(variable))
116
+
117
+ # `call('db.labels').with_args(…).yield(…)` for a procedure, or
118
+ # `call(statement, imports…)` for a `CALL { subquery }`.
119
+ def call(*arguments)
120
+ return StandaloneCall.new(arguments, builder: self) unless arguments.first.is_a?(Statement)
121
+
122
+ statement, *imports = arguments
123
+ append(subquery_clause(statement, imports, in_transactions: false, rows: nil), nil)
124
+ end
125
+
126
+ # `CALL { subquery } IN TRANSACTIONS [OF n ROWS]`; `call_in_transactions(statement, [rows], imports…)`.
127
+ def call_in_transactions(statement, *arguments)
128
+ rows = arguments.first.is_a?(Integer) ? arguments.shift : nil
129
+ append(subquery_clause(statement, arguments, in_transactions: true, rows:), nil)
130
+ end
131
+
132
+ # `CALL (*) { raw cypher }`.
133
+ def call_raw_cypher(cypher)
134
+ body = RawExpression.new(cypher)
135
+ append(Clauses::CallSubquery.new(body:, imports: [], in_transactions: false, rows: nil), nil)
136
+ end
137
+
138
+ # `load_csv('file:///x.csv').as(:line)`.
139
+ def load_csv(uri, with_headers: false) = OngoingLoadCsv.new(self, uri.to_s, with_headers)
140
+
141
+ # The statement built so far as an `EXISTS { … }` condition.
142
+ def as_condition = ExistsCondition.new(build)
143
+
144
+ # --- finishing -------------------------------------------------------
145
+
146
+ # Continues with the clauses of another statement, e.g. after a `CALL … YIELD`.
147
+ def and_then(statement) = StatementBuilder.new(@clauses + statement.clauses, nil)
148
+
149
+ def finish = append(Clauses::Finish.new, nil)
150
+
151
+ def build = Statement.new(@clauses)
152
+ def explain = Statement.new(@clauses, prefix: 'EXPLAIN')
153
+ def profile = Statement.new(@clauses, prefix: 'PROFILE')
154
+
155
+ # Intermediate state of `unwind(expression)` waiting for `as(variable)`.
156
+ class OngoingUnwind
157
+ def initialize(builder, expression)
158
+ @builder = builder
159
+ @expression = expression
160
+ freeze
161
+ end
162
+
163
+ def as(variable)
164
+ @builder.send(:append, Clauses::Unwind.new(expression: @expression, variable: SymbolicName.of(variable)), nil)
165
+ end
166
+ end
167
+
168
+ # Intermediate states of `foreach(variable)`: `in(list)` then `apply(clauses…)`.
169
+ class OngoingForeach
170
+ def initialize(builder, variable, list = nil)
171
+ @builder = builder
172
+ @variable = variable
173
+ @list = list
174
+ freeze
175
+ end
176
+
177
+ def in(list) = OngoingForeach.new(@builder, @variable, Expression.coerce(list))
178
+
179
+ def apply(*clauses)
180
+ foreach = Clauses::Foreach.new(variable: @variable, list: @list, clauses: clauses.flatten.freeze)
181
+ @builder.send(:append, foreach, nil)
182
+ end
183
+ end
184
+
185
+ # Intermediate state of `load_csv(uri)` waiting for `as(alias)`.
186
+ class OngoingLoadCsv
187
+ def initialize(builder, uri, with_headers)
188
+ @builder = builder
189
+ @uri = uri
190
+ @with_headers = with_headers
191
+ freeze
192
+ end
193
+
194
+ def as(alias_name)
195
+ clause = Clauses::LoadCsv.new(uri: @uri, with_headers: @with_headers, alias_name: SymbolicName.of(alias_name))
196
+ @builder.send(:append, clause, nil)
197
+ end
198
+ end
199
+
200
+ # Intermediate state after `on_match` / `on_create`, waiting for `set` or `mutate`.
201
+ class MergeActionBuilder
202
+ def initialize(builder, type)
203
+ @builder = builder
204
+ @type = type
205
+ freeze
206
+ end
207
+
208
+ def set(*arguments) = @builder.send(:add_merge_action, @type, @builder.send(:operations_for_set, arguments))
209
+
210
+ def mutate(target, expression) = set(Operation.new(target, '+=', Expression.coerce(expression)))
211
+ end
212
+
213
+ private
214
+
215
+ attr_reader :clauses
216
+
217
+ def append(clause, mode) = StatementBuilder.new(@clauses + [clause], mode)
218
+
219
+ def subquery_clause(statement, imports, in_transactions:, rows:)
220
+ Clauses::CallSubquery.new(body: statement, imports: coerce_items(imports), in_transactions:, rows:)
221
+ end
222
+
223
+ def add_merge_action(type, operations)
224
+ update_last(nil) do |clause|
225
+ raise ArgumentError, 'ON CREATE / ON MATCH need a preceding MERGE.' unless clause.is_a?(Clauses::Merge)
226
+
227
+ clause.with(actions: clause.actions + [MergeAction.new(type:, operations:)])
228
+ end
229
+ end
230
+
231
+ def operations_for_set(arguments)
232
+ arguments = arguments.flatten
233
+ if arguments.any? { |argument| argument.is_a?(LabelOperation) && argument.remove? }
234
+ raise ArgumentError, 'REMOVE operations are not supported in a SET clause'
235
+ end
236
+ return [LabelOperation.new(arguments.first, arguments.drop(1))].freeze if label_operation?(arguments)
237
+ return arguments.freeze if arguments.all? { |argument| operation?(argument) }
238
+ raise ArgumentError, 'The list of expression to set must be even.' if arguments.size.odd?
239
+
240
+ arguments.each_slice(2).map { |target, value| Operation.new(target, '=', Expression.coerce(value)) }.freeze
241
+ end
242
+
243
+ def operation?(argument) = argument.is_a?(Operation) || argument.is_a?(LabelOperation)
244
+
245
+ def label_operation?(arguments)
246
+ arguments.size > 1 && arguments.first.is_a?(Node) &&
247
+ arguments.drop(1).all? { |argument| argument.is_a?(String) || argument.is_a?(Symbol) }
248
+ end
249
+
250
+ def optional_expression(value) = value.nil? ? nil : Expression.coerce(value)
251
+
252
+ def update_last(mode)
253
+ raise ArgumentError, 'There is no clause to refine yet.' if @clauses.empty?
254
+
255
+ StatementBuilder.new(@clauses[0...-1] + [yield(@clauses.last)], mode)
256
+ end
257
+
258
+ def return_clause(distinct, expressions)
259
+ Clauses::Return.new(distinct:, items: coerce_items(expressions), order: nil, skip: nil, limit: nil)
260
+ end
261
+
262
+ def add_sort_item(expression)
263
+ update_last(:order) do |clause|
264
+ clause.with(order: Clauses::Order.new(items: clause.order.items + coerce_sort_items([expression])))
265
+ end
266
+ end
267
+
268
+ def update_last_sort_item
269
+ update_last(:order) do |clause|
270
+ items = clause.order.items
271
+ clause.with(order: Clauses::Order.new(items: items[0...-1] + [yield(items.last)]))
272
+ end
273
+ end
274
+
275
+ # RETURN/WITH items: strings and symbols name variables, nodes and
276
+ # relationships stand for their (possibly generated) names, everything else
277
+ # is an expression.
278
+ def coerce_items(expressions)
279
+ expressions.flatten.map do |item|
280
+ case item
281
+ when String, Symbol then SymbolicName.of(item)
282
+ when Node, Relationship then item.required_symbolic_name
283
+ else Expression.coerce(item)
284
+ end
285
+ end.freeze
286
+ end
287
+
288
+ def coerce_sort_items(sort_items)
289
+ sort_items.flatten.map do |item|
290
+ item.is_a?(SortItem) ? item : SortItem.new(Expression.coerce(item), nil)
291
+ end.freeze
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CypherDSL
4
+ # What a statement uses: its parameter names, and the values of the
5
+ # parameters that carry one. Built from a rendering pass.
6
+ class StatementCatalog
7
+ attr_reader :parameters, :parameter_names
8
+
9
+ # `uses` maps each parameter name to every value it was given, in render
10
+ # order, with {Parameter::NO_VALUE} for unbound uses.
11
+ def self.from_uses(uses)
12
+ conflicts = uses.filter_map { |name, values| [name, values.uniq.to_set] if values.uniq.size > 1 }.to_h
13
+ raise ConflictingParametersException, conflicts unless conflicts.empty?
14
+
15
+ bound = uses.filter_map { |name, values| [name, values.first] unless values.first.equal?(Parameter::NO_VALUE) }
16
+ new(parameters: bound.to_h, parameter_names: uses.keys)
17
+ end
18
+
19
+ def initialize(parameters:, parameter_names:)
20
+ @parameters = parameters.freeze
21
+ @parameter_names = parameter_names.freeze
22
+ freeze
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CypherDSL
4
+ # `Cypher.subquery_with(imports…)`: imports for an EXISTS or COLLECT subquery,
5
+ # rendered as a leading `WITH` inside the braces.
6
+ class SubqueryWith
7
+ def initialize(imports)
8
+ @imports = imports.flatten.map { |import| Expression.coerce(import) }.freeze
9
+ freeze
10
+ end
11
+
12
+ def collect(statement) = CollectExpression.new(statement, @imports)
13
+ def exists(statement_or_pattern) = ExistsCondition.new(statement_or_pattern, @imports)
14
+ end
15
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CypherDSL
4
+ # A variable name, such as the `n` in `MATCH (n)`.
5
+ #
6
+ # An *unresolved* name has no value yet: it is handed out when an unnamed
7
+ # node or relationship needs a name, and the renderer generates one for it.
8
+ class SymbolicName
9
+ include Expression
10
+
11
+ attr_reader :value, :hint
12
+
13
+ def self.of(value)
14
+ value.is_a?(SymbolicName) ? value : new(value.to_s)
15
+ end
16
+
17
+ # A name to be generated at render time; `hint` seeds the generated name (letters only).
18
+ def self.unresolved(hint) = new(nil, hint: hint.to_s.gsub(/[^a-zA-Z]/, ''))
19
+
20
+ def initialize(value, hint: nil)
21
+ raise ArgumentError, 'A symbolic name must not be empty.' if value && value.empty?
22
+
23
+ @value = value
24
+ @hint = hint
25
+ freeze
26
+ end
27
+
28
+ def resolved? = !value.nil?
29
+
30
+ # A name is its own name; lets names stand in for named elements (e.g. `nodes(p)`).
31
+ def required_symbolic_name = self
32
+
33
+ # The map projection `name{…}`.
34
+ def project(*entries) = MapProjection.new(self, entries.flatten)
35
+
36
+ def property(*names) = Property.new(self, names)
37
+
38
+ # Resolved names are equal by value; unresolved ones only to themselves.
39
+ def ==(other)
40
+ return equal?(other) unless resolved?
41
+
42
+ other.is_a?(SymbolicName) && other.value == value
43
+ end
44
+ alias eql? ==
45
+ def hash = resolved? ? [self.class, value].hash : object_id.hash
46
+ def to_s = value || 'Unresolved SymbolicName'
47
+ end
48
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CypherDSL
4
+ # A prefix operation such as `-x` or `+x`.
5
+ class UnaryOperation
6
+ include Expression
7
+
8
+ attr_reader :operator, :expression
9
+
10
+ def initialize(operator, expression)
11
+ @operator = operator
12
+ @expression = expression
13
+ freeze
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CypherDSL
4
+ # Several statements combined with UNION or UNION ALL.
5
+ class UnionQuery < Statement
6
+ attr_reader :statements, :all
7
+
8
+ # Appends to an existing union when the first statement already is one of the same kind.
9
+ def self.create(statements, all:)
10
+ statements = statements.flatten
11
+ raise ArgumentError, 'A union needs at least two statements.' if statements.size < 2
12
+
13
+ first = statements.first
14
+ return new(statements, all:) unless first.is_a?(UnionQuery)
15
+ raise ArgumentError, 'Cannot mix union and union all!' unless first.all == all
16
+
17
+ new(first.statements + statements.drop(1), all:)
18
+ end
19
+
20
+ def initialize(statements, all:)
21
+ super([])
22
+ @statements = statements.freeze
23
+ @all = all
24
+ end
25
+
26
+ def result_statement? = true
27
+ def multi_part_query? = false
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CypherDSL
4
+ VERSION = '0.1.0.alpha.1'
5
+ end
data/lib/cypher_dsl.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zeitwerk'
4
+
5
+ loader = Zeitwerk::Loader.for_gem
6
+ loader.inflector.inflect('cypher_dsl' => 'CypherDSL')
7
+ loader.setup
8
+
9
+ # A Ruby DSL for building Cypher statements.
10
+ #
11
+ # The entry point is {CypherDSL::Cypher}; everything else is reached from there.
12
+ module CypherDSL
13
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cypher-dsl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.alpha.1
5
+ platform: ruby
6
+ authors:
7
+ - Heinrich Klobuczek
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: zeitwerk
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.6'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.6'
26
+ description: An immutable, part-aware builder and renderer for Cypher statements,
27
+ modelled on the design of Neo4j's Cypher-DSL for Java.
28
+ email:
29
+ - heinrich@mail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - CHANGELOG.md
35
+ - LICENSE.txt
36
+ - NOTICE
37
+ - README.md
38
+ - lib/cypher_dsl.rb
39
+ - lib/cypher_dsl/aliased_expression.rb
40
+ - lib/cypher_dsl/asterisk.rb
41
+ - lib/cypher_dsl/case_expression.rb
42
+ - lib/cypher_dsl/clauses.rb
43
+ - lib/cypher_dsl/clauses/call.rb
44
+ - lib/cypher_dsl/clauses/call_subquery.rb
45
+ - lib/cypher_dsl/clauses/create.rb
46
+ - lib/cypher_dsl/clauses/delete.rb
47
+ - lib/cypher_dsl/clauses/finish.rb
48
+ - lib/cypher_dsl/clauses/foreach.rb
49
+ - lib/cypher_dsl/clauses/load_csv.rb
50
+ - lib/cypher_dsl/clauses/match.rb
51
+ - lib/cypher_dsl/clauses/merge.rb
52
+ - lib/cypher_dsl/clauses/order.rb
53
+ - lib/cypher_dsl/clauses/raw_return.rb
54
+ - lib/cypher_dsl/clauses/remove.rb
55
+ - lib/cypher_dsl/clauses/return.rb
56
+ - lib/cypher_dsl/clauses/set.rb
57
+ - lib/cypher_dsl/clauses/unwind.rb
58
+ - lib/cypher_dsl/clauses/use.rb
59
+ - lib/cypher_dsl/clauses/with.rb
60
+ - lib/cypher_dsl/collect_expression.rb
61
+ - lib/cypher_dsl/comparison.rb
62
+ - lib/cypher_dsl/compound_condition.rb
63
+ - lib/cypher_dsl/condition.rb
64
+ - lib/cypher_dsl/conflicting_parameters_exception.rb
65
+ - lib/cypher_dsl/constant_condition.rb
66
+ - lib/cypher_dsl/count_expression.rb
67
+ - lib/cypher_dsl/cypher.rb
68
+ - lib/cypher_dsl/exists_condition.rb
69
+ - lib/cypher_dsl/expression.rb
70
+ - lib/cypher_dsl/expression_condition.rb
71
+ - lib/cypher_dsl/function_invocation.rb
72
+ - lib/cypher_dsl/functions.rb
73
+ - lib/cypher_dsl/has_label_condition.rb
74
+ - lib/cypher_dsl/label_expression.rb
75
+ - lib/cypher_dsl/label_operation.rb
76
+ - lib/cypher_dsl/list_comprehension.rb
77
+ - lib/cypher_dsl/list_expression.rb
78
+ - lib/cypher_dsl/list_operator.rb
79
+ - lib/cypher_dsl/list_predicate.rb
80
+ - lib/cypher_dsl/literal.rb
81
+ - lib/cypher_dsl/map_expression.rb
82
+ - lib/cypher_dsl/map_projection.rb
83
+ - lib/cypher_dsl/merge_action.rb
84
+ - lib/cypher_dsl/named_path.rb
85
+ - lib/cypher_dsl/no_condition.rb
86
+ - lib/cypher_dsl/node.rb
87
+ - lib/cypher_dsl/operation.rb
88
+ - lib/cypher_dsl/parameter.rb
89
+ - lib/cypher_dsl/pattern_comprehension.rb
90
+ - lib/cypher_dsl/pattern_expression.rb
91
+ - lib/cypher_dsl/property.rb
92
+ - lib/cypher_dsl/quantified_path_pattern.rb
93
+ - lib/cypher_dsl/raw_expression.rb
94
+ - lib/cypher_dsl/reduction.rb
95
+ - lib/cypher_dsl/relationship.rb
96
+ - lib/cypher_dsl/relationship_chain.rb
97
+ - lib/cypher_dsl/relationship_pattern_condition.rb
98
+ - lib/cypher_dsl/renderer.rb
99
+ - lib/cypher_dsl/renderer/configuration.rb
100
+ - lib/cypher_dsl/renderer/dialect.rb
101
+ - lib/cypher_dsl/renderer/escaper.rb
102
+ - lib/cypher_dsl/renderer/visitor.rb
103
+ - lib/cypher_dsl/renderer/visitor/expressions.rb
104
+ - lib/cypher_dsl/renderer/visitor/patterns.rb
105
+ - lib/cypher_dsl/sort_item.rb
106
+ - lib/cypher_dsl/standalone_call.rb
107
+ - lib/cypher_dsl/statement.rb
108
+ - lib/cypher_dsl/statement_builder.rb
109
+ - lib/cypher_dsl/statement_catalog.rb
110
+ - lib/cypher_dsl/subquery_with.rb
111
+ - lib/cypher_dsl/symbolic_name.rb
112
+ - lib/cypher_dsl/unary_operation.rb
113
+ - lib/cypher_dsl/union_query.rb
114
+ - lib/cypher_dsl/version.rb
115
+ homepage: https://github.com/neo4jrb/cypher-dsl
116
+ licenses:
117
+ - MIT
118
+ metadata:
119
+ source_code_uri: https://github.com/neo4jrb/cypher-dsl
120
+ changelog_uri: https://github.com/neo4jrb/cypher-dsl/blob/main/CHANGELOG.md
121
+ bug_tracker_uri: https://github.com/neo4jrb/cypher-dsl/issues
122
+ rubygems_mfa_required: 'true'
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '3.4'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubygems_version: 4.0.20
138
+ specification_version: 4
139
+ summary: A Ruby DSL (builder) for the Cypher query language
140
+ test_files: []