activecypher 0.0.0 → 0.3.0
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/active_cypher/associations/collection_proxy.rb +144 -0
- data/lib/active_cypher/associations.rb +537 -0
- data/lib/active_cypher/base.rb +47 -0
- data/lib/active_cypher/bolt/connection.rb +525 -0
- data/lib/active_cypher/bolt/driver.rb +144 -0
- data/lib/active_cypher/bolt/handlers.rb +10 -0
- data/lib/active_cypher/bolt/message_reader.rb +100 -0
- data/lib/active_cypher/bolt/message_writer.rb +53 -0
- data/lib/active_cypher/bolt/messaging.rb +307 -0
- data/lib/active_cypher/bolt/packstream.rb +319 -0
- data/lib/active_cypher/bolt/result.rb +82 -0
- data/lib/active_cypher/bolt/session.rb +201 -0
- data/lib/active_cypher/bolt/transaction.rb +211 -0
- data/lib/active_cypher/bolt/version_encoding.rb +41 -0
- data/lib/active_cypher/bolt.rb +7 -0
- data/lib/active_cypher/connection_adapters/abstract_adapter.rb +75 -0
- data/lib/active_cypher/connection_adapters/abstract_bolt_adapter.rb +178 -0
- data/lib/active_cypher/connection_adapters/memgraph_adapter.rb +44 -0
- data/lib/active_cypher/connection_adapters/neo4j_adapter.rb +58 -0
- data/lib/active_cypher/connection_factory.rb +130 -0
- data/lib/active_cypher/connection_handler.rb +9 -0
- data/lib/active_cypher/connection_pool.rb +123 -0
- data/lib/active_cypher/connection_url_resolver.rb +137 -0
- data/lib/active_cypher/cypher_config.rb +61 -0
- data/lib/active_cypher/generators/install_generator.rb +23 -0
- data/lib/active_cypher/generators/node_generator.rb +32 -0
- data/lib/active_cypher/generators/relationship_generator.rb +33 -0
- data/lib/active_cypher/generators/templates/application_graph_node.rb +5 -0
- data/lib/active_cypher/generators/templates/application_graph_relationship.rb +5 -0
- data/lib/active_cypher/generators/templates/cypher_databases.yml +16 -0
- data/lib/active_cypher/generators/templates/node.rb.erb +10 -0
- data/lib/active_cypher/generators/templates/relationship.rb.erb +11 -0
- data/lib/active_cypher/logging.rb +44 -0
- data/lib/active_cypher/model/abstract.rb +87 -0
- data/lib/active_cypher/model/attributes.rb +24 -0
- data/lib/active_cypher/model/callbacks.rb +44 -0
- data/lib/active_cypher/model/connection_handling.rb +76 -0
- data/lib/active_cypher/model/connection_owner.rb +50 -0
- data/lib/active_cypher/model/core.rb +45 -0
- data/lib/active_cypher/model/countable.rb +30 -0
- data/lib/active_cypher/model/destruction.rb +49 -0
- data/lib/active_cypher/model/inspectable.rb +28 -0
- data/lib/active_cypher/model/persistence.rb +182 -0
- data/lib/active_cypher/model/querying.rb +67 -0
- data/lib/active_cypher/railtie.rb +34 -0
- data/lib/active_cypher/relation.rb +190 -0
- data/lib/active_cypher/relationship.rb +233 -0
- data/lib/active_cypher/runtime_registry.rb +8 -0
- data/lib/active_cypher/scoping.rb +97 -0
- data/lib/active_cypher/utils/logger.rb +100 -0
- data/lib/active_cypher/version.rb +5 -0
- data/lib/activecypher.rb +108 -0
- data/lib/cyrel/call_procedure.rb +29 -0
- data/lib/cyrel/clause/call.rb +46 -0
- data/lib/cyrel/clause/call_subquery.rb +40 -0
- data/lib/cyrel/clause/create.rb +33 -0
- data/lib/cyrel/clause/delete.rb +41 -0
- data/lib/cyrel/clause/limit.rb +33 -0
- data/lib/cyrel/clause/match.rb +40 -0
- data/lib/cyrel/clause/merge.rb +34 -0
- data/lib/cyrel/clause/order_by.rb +78 -0
- data/lib/cyrel/clause/remove.rb +75 -0
- data/lib/cyrel/clause/return.rb +90 -0
- data/lib/cyrel/clause/set.rb +97 -0
- data/lib/cyrel/clause/skip.rb +34 -0
- data/lib/cyrel/clause/where.rb +42 -0
- data/lib/cyrel/clause/with.rb +94 -0
- data/lib/cyrel/clause.rb +25 -0
- data/lib/cyrel/direction.rb +18 -0
- data/lib/cyrel/expression/alias.rb +27 -0
- data/lib/cyrel/expression/base.rb +101 -0
- data/lib/cyrel/expression/case.rb +45 -0
- data/lib/cyrel/expression/comparison.rb +60 -0
- data/lib/cyrel/expression/exists.rb +42 -0
- data/lib/cyrel/expression/function_call.rb +57 -0
- data/lib/cyrel/expression/literal.rb +33 -0
- data/lib/cyrel/expression/logical.rb +38 -0
- data/lib/cyrel/expression/operator.rb +27 -0
- data/lib/cyrel/expression/pattern_comprehension.rb +44 -0
- data/lib/cyrel/expression/property_access.rb +25 -0
- data/lib/cyrel/expression.rb +56 -0
- data/lib/cyrel/functions.rb +116 -0
- data/lib/cyrel/node.rb +397 -0
- data/lib/cyrel/parameterizable.rb +20 -0
- data/lib/cyrel/pattern/node.rb +66 -0
- data/lib/cyrel/pattern/path.rb +41 -0
- data/lib/cyrel/pattern/relationship.rb +74 -0
- data/lib/cyrel/pattern.rb +8 -0
- data/lib/cyrel/query.rb +497 -0
- data/lib/cyrel/return_only.rb +26 -0
- data/lib/cyrel/types/hash_type.rb +22 -0
- data/lib/cyrel/types/symbol_type.rb +13 -0
- data/lib/cyrel.rb +72 -0
- data/sig/activecypher.rbs +4 -0
- metadata +172 -10
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cyrel
|
4
|
+
module Expression
|
5
|
+
# Represents a function call in Cypher (e.g., id(n), count(*), coalesce(a, b)).
|
6
|
+
class FunctionCall < Base
|
7
|
+
attr_reader :function_name, :arguments, :distinct
|
8
|
+
|
9
|
+
# @param function_name [Symbol, String] The name of the Cypher function.
|
10
|
+
# @param arguments [Array<Cyrel::Expression::Base, Object>] The arguments to the function.
|
11
|
+
# @param distinct [Boolean] Whether to use the DISTINCT keyword (e.g., count(DISTINCT n)).
|
12
|
+
def initialize(function_name, arguments = [], distinct: false)
|
13
|
+
@function_name = function_name.to_s # Store as string for consistency
|
14
|
+
@arguments = Array(arguments).map do |arg|
|
15
|
+
# Don't coerce ASTERISK or existing Expressions
|
16
|
+
if arg == Functions::ASTERISK || arg.is_a?(Expression::Base)
|
17
|
+
arg
|
18
|
+
else
|
19
|
+
Expression.coerce(arg) # Coerce only non-expression literals
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@distinct = distinct
|
23
|
+
end
|
24
|
+
|
25
|
+
# Renders the function call expression.
|
26
|
+
# @param query [Cyrel::Query] The query object for rendering arguments.
|
27
|
+
# @return [String] The Cypher string fragment (e.g., "id(n)", "count(DISTINCT n.prop)").
|
28
|
+
def render(query)
|
29
|
+
rendered_args = @arguments.map do |arg|
|
30
|
+
case arg
|
31
|
+
when Functions::ASTERISK
|
32
|
+
'*'
|
33
|
+
# Special handling for RawIdentifier when used as argument
|
34
|
+
when Clause::Return::RawIdentifier
|
35
|
+
arg.identifier # Render the raw identifier directly
|
36
|
+
when Expression::Base, ->(a) { a.respond_to?(:render) } # Check if it's an Expression or renderable
|
37
|
+
arg.render(query) # Render other expressions normally
|
38
|
+
else
|
39
|
+
# Parameterize other literal values
|
40
|
+
param_key = query.register_parameter(arg)
|
41
|
+
"$#{param_key}"
|
42
|
+
end
|
43
|
+
end.join(', ')
|
44
|
+
distinct_str = @distinct ? 'DISTINCT ' : ''
|
45
|
+
"#{@function_name}(#{distinct_str}#{rendered_args})"
|
46
|
+
end
|
47
|
+
|
48
|
+
# Creates an aliased version of this function call expression.
|
49
|
+
# Duplicates method from Base for robustness.
|
50
|
+
# @param alias_name [Symbol, String] The alias to assign.
|
51
|
+
# @return [Cyrel::Expression::Alias]
|
52
|
+
def as(alias_name)
|
53
|
+
Alias.new(self, alias_name)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cyrel
|
4
|
+
module Expression
|
5
|
+
# Represents a literal value (String, Number, Boolean, Nil, Array, Map) in a Cypher query.
|
6
|
+
# Literals are typically converted into parameters.
|
7
|
+
class Literal < Base
|
8
|
+
attr_reader :value
|
9
|
+
|
10
|
+
def initialize(value)
|
11
|
+
# We don't validate the type here extensively, assuming Neo4j driver
|
12
|
+
# or the database itself will handle type compatibility.
|
13
|
+
# We could add checks for common unsupported types if needed.
|
14
|
+
@value = value
|
15
|
+
end
|
16
|
+
|
17
|
+
# Renders the literal by registering it as a parameter.
|
18
|
+
# @param query [Cyrel::Query] The query object for parameter registration.
|
19
|
+
# @return [String] The parameter placeholder string (e.g., "$p1").
|
20
|
+
def render(query)
|
21
|
+
# Special handling for NULL as it doesn't use a parameter
|
22
|
+
return 'NULL' if @value.nil?
|
23
|
+
|
24
|
+
param_key = query.register_parameter(@value)
|
25
|
+
"$#{param_key}"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Override comparison methods for direct literal comparison if needed,
|
29
|
+
# although the Base class methods creating Comparison objects are generally preferred.
|
30
|
+
# Example: def ==(other) ... end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cyrel
|
4
|
+
module Expression
|
5
|
+
# Represents a logical operation (AND, OR, XOR, NOT).
|
6
|
+
class Logical < Base
|
7
|
+
attr_reader :left, :operator, :right
|
8
|
+
|
9
|
+
# @param left [Cyrel::Expression::Base, Object] The left operand (or the single operand for NOT).
|
10
|
+
# @param operator [Symbol] The logical operator symbol (:AND, :OR, :XOR, :NOT).
|
11
|
+
# @param right [Cyrel::Expression::Base, Object, nil] The right operand (nil for NOT).
|
12
|
+
def initialize(left, operator, right = nil)
|
13
|
+
@operator = operator.to_s.upcase.to_sym # Ensure uppercase symbol
|
14
|
+
raise ArgumentError, "Invalid logical operator: #{@operator}" unless %i[AND OR XOR NOT].include?(@operator)
|
15
|
+
|
16
|
+
@left = Expression.coerce(left)
|
17
|
+
@right = @operator == :NOT ? nil : Expression.coerce(right)
|
18
|
+
|
19
|
+
raise ArgumentError, "Operator #{@operator} requires two operands." if @operator != :NOT && @right.nil?
|
20
|
+
return unless @operator == :NOT && !right.nil?
|
21
|
+
|
22
|
+
raise ArgumentError, 'Operator NOT requires only one operand.'
|
23
|
+
end
|
24
|
+
|
25
|
+
# Renders the logical expression.
|
26
|
+
# @param query [Cyrel::Query] The query object for rendering operands.
|
27
|
+
# @return [String] The Cypher string fragment (e.g., "((n.age > $p1) AND (n.status = $p2))").
|
28
|
+
def render(query)
|
29
|
+
if @operator == :NOT
|
30
|
+
"(#{@operator} #{@left.render(query)})"
|
31
|
+
else
|
32
|
+
# Parentheses ensure correct precedence
|
33
|
+
"(#{@left.render(query)} #{@operator} #{@right.render(query)})"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cyrel
|
4
|
+
module Expression
|
5
|
+
# Represents a binary arithmetic operation (e.g., +, -, *, /, %, ^).
|
6
|
+
class Operator < Base
|
7
|
+
attr_reader :left, :operator, :right
|
8
|
+
|
9
|
+
# @param left [Cyrel::Expression::Base, Object] The left operand.
|
10
|
+
# @param operator [Symbol] The arithmetic operator symbol (e.g., :+, :*).
|
11
|
+
# @param right [Cyrel::Expression::Base, Object] The right operand.
|
12
|
+
def initialize(left, operator, right)
|
13
|
+
@left = Expression.coerce(left) # Ensure operands are Expression objects
|
14
|
+
@operator = operator
|
15
|
+
@right = Expression.coerce(right)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Renders the operator expression.
|
19
|
+
# @param query [Cyrel::Query] The query object for rendering operands.
|
20
|
+
# @return [String] The Cypher string fragment (e.g., "(n.age + $p1)").
|
21
|
+
def render(query)
|
22
|
+
# Parentheses ensure correct precedence
|
23
|
+
"(#{@left.render(query)} #{@operator} #{@right.render(query)})"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../expression'
|
4
|
+
require_relative '../pattern' # Need Path
|
5
|
+
|
6
|
+
module Cyrel
|
7
|
+
module Expression
|
8
|
+
# Represents a Pattern Comprehension in Cypher.
|
9
|
+
# Syntax: [ pattern WHERE condition | expression ]
|
10
|
+
# Simplified version for now: [ pattern | expression ]
|
11
|
+
class PatternComprehension < Base
|
12
|
+
attr_reader :pattern, :projection_expression # TODO: Add where_condition
|
13
|
+
|
14
|
+
# @param pattern [Cyrel::Pattern::Path, Cyrel::Pattern::Node, Cyrel::Pattern::Relationship]
|
15
|
+
# The pattern to iterate over.
|
16
|
+
# @param projection_expression [Cyrel::Expression::Base, Object]
|
17
|
+
# The expression evaluated for each match of the pattern.
|
18
|
+
def initialize(pattern, projection_expression)
|
19
|
+
unless pattern.is_a?(Cyrel::Pattern::Path) || pattern.is_a?(Cyrel::Pattern::Node) || pattern.is_a?(Cyrel::Pattern::Relationship)
|
20
|
+
raise ArgumentError,
|
21
|
+
"Pattern Comprehension pattern must be a Path, Node, or Relationship, got #{pattern.class}"
|
22
|
+
end
|
23
|
+
|
24
|
+
@pattern = pattern
|
25
|
+
@projection_expression = Expression.coerce(projection_expression)
|
26
|
+
# @where_condition = where_condition ? Expression.coerce(where_condition) : nil
|
27
|
+
end
|
28
|
+
|
29
|
+
# Renders the pattern comprehension expression.
|
30
|
+
# @param query [Cyrel::Query] The query object for rendering pattern and expression.
|
31
|
+
# @return [String] The Cypher string fragment.
|
32
|
+
def render(query)
|
33
|
+
pattern_str = @pattern.render(query)
|
34
|
+
# where_str = @where_condition ? " WHERE #{@where_condition.render(query)}" : ""
|
35
|
+
projection_str = @projection_expression.render(query)
|
36
|
+
|
37
|
+
"[#{pattern_str} | #{projection_str}]" # Simplified: missing WHERE support
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Helper function? Might be complex due to pattern definition.
|
42
|
+
# def self.comprehend(pattern, projection, where: nil) ... end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cyrel
|
4
|
+
module Expression
|
5
|
+
# Represents accessing a property on a variable (node or relationship alias).
|
6
|
+
# Example: n.name, r.since
|
7
|
+
class PropertyAccess < Base
|
8
|
+
attr_reader :variable, :property_name
|
9
|
+
|
10
|
+
# @param variable [Symbol, String] The alias of the node/relationship.
|
11
|
+
# @param property_name [Symbol, String] The name of the property to access.
|
12
|
+
def initialize(variable, property_name)
|
13
|
+
@variable = variable.to_sym
|
14
|
+
@property_name = property_name.to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
# Renders the property access expression.
|
18
|
+
# @param _query [Cyrel::Query] The query object (unused for simple property access).
|
19
|
+
# @return [String] The Cypher string fragment (e.g., "n.name").
|
20
|
+
def render(_query)
|
21
|
+
"#{@variable}.#{@property_name}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Subclasses are autoloaded by Zeitwerk based on constant usage.
|
4
|
+
# Explicit requires removed.
|
5
|
+
|
6
|
+
module Cyrel
|
7
|
+
# Namespace for classes representing expressions in Cypher queries.
|
8
|
+
# Expressions are parts of a query that evaluate to a value or condition.
|
9
|
+
# Examples: property access (n.name), literals ('string', 123),
|
10
|
+
# function calls (id(n)), operators (a + b), comparisons (a > b),
|
11
|
+
# logical combinations (a AND b).
|
12
|
+
module Expression
|
13
|
+
# Base class/module for all expression types.
|
14
|
+
# Defines the common interface, primarily the `render` method.
|
15
|
+
# Base class is defined in lib/cyrel/expression/base.rb and autoloaded.
|
16
|
+
|
17
|
+
# Forces values into Expression objects like a parent shoving their kid into piano lessons—
|
18
|
+
# not because it’s fun, but because one day AI will take all our jobs
|
19
|
+
# and at least they'll have music to cry to.
|
20
|
+
# @param value [Object] The value to coerce.
|
21
|
+
# @return [Cyrel::Expression::Base] An Expression object.
|
22
|
+
def self.coerce(value)
|
23
|
+
# Assumes Base and Literal are loaded (via Zeitwerk or explicit require)
|
24
|
+
value.is_a?(Base) ? value : Literal.new(value)
|
25
|
+
end
|
26
|
+
|
27
|
+
module_function
|
28
|
+
|
29
|
+
# Accesses a property on a node or relationship.
|
30
|
+
# This is the Cypher equivalent of saying "hey buddy" and hoping the database just knows.
|
31
|
+
# @param variable [Symbol, String] The alias of the node/relationship.
|
32
|
+
# @param property_name [Symbol, String] The name of the property to access.
|
33
|
+
# @return [Cyrel::Expression::PropertyAccess]
|
34
|
+
def prop(variable, property_name)
|
35
|
+
# Assumes PropertyAccess is loaded (via Zeitwerk or explicit require)
|
36
|
+
PropertyAccess.new(variable, property_name)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Helper function for creating Exists instances
|
40
|
+
# @param pattern [Cyrel::Pattern::Path, Cyrel::Pattern::Node, Cyrel::Pattern::Relationship]
|
41
|
+
# @return [Cyrel::Expression::Exists]
|
42
|
+
def exists(pattern)
|
43
|
+
# Assumes Exists is loaded (via Zeitwerk or explicit require)
|
44
|
+
Exists.new(pattern)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Wraps an expression in a Cypher NOT.
|
48
|
+
# Useful when your query — and your life — needs a little more denial.
|
49
|
+
# @param expression [Cyrel::Expression::Base, Object] The expression to negate.
|
50
|
+
# @return [Cyrel::Expression::Logical]
|
51
|
+
def not(expression)
|
52
|
+
# Assumes Logical is loaded (via Zeitwerk or explicit require)
|
53
|
+
Logical.new(expression, :NOT)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cyrel
|
4
|
+
# Provides helper methods for creating Cypher function call expressions.
|
5
|
+
module Functions
|
6
|
+
# Represents the Cypher '*' literal, often used in count(*).
|
7
|
+
# We use a specific object to differentiate it from a string literal "*".
|
8
|
+
ASTERISK = Object.new
|
9
|
+
# Special render for asterisk
|
10
|
+
def ASTERISK.render(_query) = '*'
|
11
|
+
# Act like an expression
|
12
|
+
def ASTERISK.is_a?(klass) = klass == Cyrel::Expression::Base || super
|
13
|
+
|
14
|
+
ASTERISK.freeze
|
15
|
+
|
16
|
+
module_function
|
17
|
+
|
18
|
+
# --- Common Cypher Functions ---
|
19
|
+
|
20
|
+
# Use elementId() instead of deprecated id()
|
21
|
+
def element_id(node_variable)
|
22
|
+
Expression::FunctionCall.new(:elementId, Clause::Return::RawIdentifier.new(node_variable.to_s))
|
23
|
+
end
|
24
|
+
|
25
|
+
alias id element_id
|
26
|
+
|
27
|
+
# Because apparently, COUNT(*) isn’t obvious enough.
|
28
|
+
# Handles the 'give me everything and make it snappy' use case.
|
29
|
+
def count(expression, distinct: false)
|
30
|
+
# Handle count(*) specifically
|
31
|
+
expr_arg = case expression
|
32
|
+
when :* then ASTERISK
|
33
|
+
when Symbol, String then Clause::Return::RawIdentifier.new(expression.to_s) # Convert symbol/string to RawIdentifier
|
34
|
+
else expression # Assume it's already an Expression object (like PropertyAccess)
|
35
|
+
end
|
36
|
+
Expression::FunctionCall.new(:count, expr_arg, distinct: distinct)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Retrieves labels from a node. You could also just... ask the node. But noooo.
|
40
|
+
# Instead, we call a function and pretend we're not slowly dying inside.
|
41
|
+
def labels(node_variable)
|
42
|
+
Expression::FunctionCall.new(:labels, node_variable)
|
43
|
+
end
|
44
|
+
|
45
|
+
def type(relationship_variable)
|
46
|
+
Expression::FunctionCall.new(:type, relationship_variable)
|
47
|
+
end
|
48
|
+
|
49
|
+
def properties(variable)
|
50
|
+
Expression::FunctionCall.new(:properties, variable)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the first non-null expression.
|
54
|
+
# The Cypher equivalent of settling.
|
55
|
+
def coalesce(*expressions)
|
56
|
+
Expression::FunctionCall.new(:coalesce, expressions)
|
57
|
+
end
|
58
|
+
|
59
|
+
def timestamp
|
60
|
+
Expression::FunctionCall.new(:timestamp)
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_string(expression)
|
64
|
+
Expression::FunctionCall.new(:toString, expression)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Converts a thing into an integer.
|
68
|
+
# Great for when your data is having an identity crisis and just wants to be whole again.
|
69
|
+
def to_integer(expression)
|
70
|
+
Expression::FunctionCall.new(:toInteger, expression)
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_float(expression)
|
74
|
+
Expression::FunctionCall.new(:toFloat, expression)
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_boolean(expression)
|
78
|
+
Expression::FunctionCall.new(:toBoolean, expression)
|
79
|
+
end
|
80
|
+
|
81
|
+
# --- Aggregation Functions ---
|
82
|
+
|
83
|
+
def sum(expression, distinct: false)
|
84
|
+
Expression::FunctionCall.new(:sum, expression, distinct: distinct)
|
85
|
+
end
|
86
|
+
|
87
|
+
def avg(expression, distinct: false)
|
88
|
+
Expression::FunctionCall.new(:avg, expression, distinct: distinct)
|
89
|
+
end
|
90
|
+
|
91
|
+
def min(expression)
|
92
|
+
Expression::FunctionCall.new(:min, expression)
|
93
|
+
end
|
94
|
+
|
95
|
+
def max(expression)
|
96
|
+
Expression::FunctionCall.new(:max, expression)
|
97
|
+
end
|
98
|
+
|
99
|
+
def collect(expression, distinct: false)
|
100
|
+
Expression::FunctionCall.new(:collect, expression, distinct: distinct)
|
101
|
+
end
|
102
|
+
|
103
|
+
# --- List Functions ---
|
104
|
+
# Add common list functions like size(), keys(), range(), etc. as needed
|
105
|
+
|
106
|
+
def size(expression)
|
107
|
+
Expression::FunctionCall.new(:size, expression)
|
108
|
+
end
|
109
|
+
|
110
|
+
# --- String Functions ---
|
111
|
+
# Add common string functions like substring(), replace(), toLower(), etc. as needed
|
112
|
+
|
113
|
+
# --- Spatial/Temporal/etc. Functions ---
|
114
|
+
# Add other function categories as required by ActiveCypher
|
115
|
+
end
|
116
|
+
end
|