From db52b35ab6aa1b0bb9ece5cc10052d9c836c0745 Mon Sep 17 00:00:00 2001 From: Marin Tomic Date: Thu, 4 Oct 2018 11:57:23 +0200 Subject: [PATCH] Convert AST to LCP Reviewers: teon.banek, llugovic Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1628 --- .gitignore | 2 + src/CMakeLists.txt | 3 +- src/lisp/lcp.lisp | 245 +- src/query/frontend/ast/ast.capnp | 466 --- src/query/frontend/ast/ast.cpp | 2745 +---------------- src/query/frontend/ast/ast.hpp | 2644 ---------------- src/query/frontend/ast/ast.lcp | 2507 +++++++++++++++ .../frontend/ast/cypher_main_visitor.cpp | 10 +- .../frontend/ast/cypher_main_visitor.hpp | 4 +- .../frontend/semantic/symbol_generator.cpp | 4 +- src/query/frontend/semantic/symbol_table.hpp | 6 +- src/query/interpret/eval.hpp | 8 +- src/query/plan/distributed.cpp | 8 +- src/query/plan/distributed_ops.cpp | 7 +- src/query/plan/distributed_ops.lcp | 3 +- src/query/plan/operator.cpp | 6 +- src/query/plan/operator.lcp | 55 +- src/query/plan/rule_based_planner.cpp | 2 +- src/storage/serialization.capnp | 2 +- tests/unit/cypher_main_visitor.cpp | 8 +- tests/unit/distributed_query_plan.cpp | 6 +- tests/unit/query_common.hpp | 4 +- tests/unit/query_plan_bag_semantics.cpp | 20 +- tests/unit/query_planner.cpp | 2 +- 24 files changed, 2717 insertions(+), 6050 deletions(-) delete mode 100644 src/query/frontend/ast/ast.capnp delete mode 100644 src/query/frontend/ast/ast.hpp create mode 100644 src/query/frontend/ast/ast.lcp diff --git a/.gitignore b/.gitignore index e4012589a..d8a3e73a7 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,8 @@ src/distributed/token_sharing_rpc_messages.capnp src/distributed/token_sharing_rpc_messages.hpp src/distributed/updates_rpc_messages.capnp src/distributed/updates_rpc_messages.hpp +src/query/frontend/ast/ast.capnp +src/query/frontend/ast/ast.hpp src/query/plan/distributed_ops.capnp src/query/plan/distributed_ops.hpp src/query/plan/operator.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d2052abb6..1da443c57 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -117,6 +117,8 @@ add_capnp(distributed/dynamic_worker_rpc_messages.capnp) # distributed_ops.lcp is leading the capnp code generation, so we don't need # to generate any capnp for operator.lcp +add_lcp(query/frontend/ast/ast.lcp CAPNP_SCHEMA @0xb107d3d6b4b1600b) +add_capnp(query/frontend/ast/ast.capnp) add_lcp(query/plan/operator.lcp) add_lcp(query/plan/distributed_ops.lcp CAPNP_SCHEMA @0xe5cae8d045d30c42 DEPENDS query/plan/operator.lcp) @@ -134,7 +136,6 @@ add_custom_target(generate_lcp DEPENDS ${generated_lcp_files}) add_capnp(communication/rpc/messages.capnp) add_capnp(durability/recovery.capnp) -add_capnp(query/frontend/ast/ast.capnp) add_capnp(query/frontend/semantic/symbol.capnp) add_capnp(query/serialization.capnp) add_capnp(storage/serialization.capnp) diff --git a/src/lisp/lcp.lisp b/src/lisp/lcp.lisp index d8d46c4aa..0d52b1878 100644 --- a/src/lisp/lcp.lisp +++ b/src/lisp/lcp.lisp @@ -272,6 +272,7 @@ produces: ;; Extra arguments to the generated save function. List of (name cpp-type). (save-args nil :read-only t) (load-args nil :read-only t) + (construct nil :read-only t) ;; Explicit instantiation of template to generate schema with enum. (type-args nil :read-only t) ;; In case of multiple inheritance, list of classes which should be handled @@ -291,7 +292,8 @@ produces: (private :initarg :private :initform nil :accessor cpp-class-private) (capnp-opts :type (or null capnp-opts) :initarg :capnp-opts :initform nil :reader cpp-class-capnp-opts) - (inner-types :initarg :inner-types :initform nil :reader cpp-class-inner-types)) + (inner-types :initarg :inner-types :initform nil :reader cpp-class-inner-types) + (abstractp :initarg :abstractp :initform nil :reader cpp-class-abstractp)) (:documentation "Meta information on a C++ class (or struct).")) (defvar *cpp-classes* nil "List of defined classes from LCP file") @@ -759,7 +761,7 @@ encoded as union inheritance in Cap'n Proto." (write-line (capnp-schema inner) s))) (when union-subclasses (with-cpp-block-output (s :name "union") - (when union-parents + (when (not (cpp-class-abstractp cpp-class)) ;; Allow instantiating classes in the middle of inheritance ;; hierarchy. (format s " ~A @~A :Void;~%" @@ -935,7 +937,7 @@ Proto schema." (format nil "Save(~A, &~A~{, ~A~});" member-name member-builder extra-args)))))) -(defun capnp-save-members (cpp-class &key instance-access) +(defun capnp-save-members (cpp-class builder &key instance-access) "Generate Cap'n Proto saving code for members of CPP-CLASS. INSTANCE-ACCESS is a C++ string which is prefixed to member access. For example, INSTANCE-ACCESS could be `my_struct->`" @@ -954,7 +956,7 @@ Proto schema." (cond ((and (not (cpp-member-capnp-save member)) (capnp-primitive-type-p (capnp-type-of-member member))) - (format s " builder->set~A(~A);~%" capnp-name member-access)) + (format s " ~A->set~A(~A);~%" builder capnp-name member-access)) (t ;; Enclose larger save code in new scope (with-cpp-block-output (s) @@ -965,9 +967,9 @@ Proto schema." ""))) (if (and (cpp-member-capnp-init member) (not (find-cpp-enum (cpp-member-type member)))) - (format s " auto ~A = builder->init~A(~A);~%" - member-builder capnp-name size) - (setf member-builder "builder"))) + (format s " auto ~A = ~A->init~A(~A);~%" + member-builder builder capnp-name size) + (setf member-builder builder))) (if (cpp-member-capnp-save member) (format s " ~A~%" (cpp-code (funcall (cpp-member-capnp-save member) @@ -976,84 +978,60 @@ Proto schema." member-builder capnp-name) s)))))))))) -(defun capnp-save-parents (cpp-class save-parent) - "Generate Cap'n Proto code for serializing parent classes of CPP-CLASS. -SAVE-PARENT is a function which generates the code for serializing a parent. -It takes a parent class symbol." - (declare (type cpp-class cpp-class)) - (declare (type (function (symbol) string) save-parent)) - (multiple-value-bind (direct-union-parents compose-parents) - (capnp-union-and-compose-parents cpp-class) - (declare (ignore direct-union-parents)) - ;; Handle the union inheritance calls first. - (with-output-to-string (s) - (let ((parents (capnp-union-parents-rec cpp-class))) - (when parents - (let ((first-parent (first parents))) - (write-line (funcall save-parent first-parent) s)) - (if (or compose-parents (cpp-class-members cpp-class)) - (progn - (format s " auto ~A_builder = base_builder->~{get~A().~}init~A();~%" - (cpp-variable-name (cpp-type-base-name cpp-class)) - (mapcar #'cpp-type-name (cdr (reverse parents))) - (cpp-type-name cpp-class)) - (format s " auto *builder = &~A_builder;~%" - (cpp-variable-name (cpp-type-base-name cpp-class)))) - (format s " base_builder->~{get~A().~}init~A();~%" - (mapcar #'cpp-type-name (cdr (reverse parents))) - (cpp-type-name cpp-class))) - (when (capnp-union-subclasses cpp-class) - ;; We are in the middle of inheritance hierarchy, so set our - ;; union Void field. - (format s " builder->set~A();" (cpp-type-name cpp-class))))) - ;; Now handle composite inheritance calls. - (dolist (parent compose-parents) - (with-cpp-block-output (s) - (let* ((builder (format nil "~A_builder" (cpp-variable-name parent)))) - (format s " auto ~A = builder->init~A();~%" builder (cpp-type-name parent)) - (format s " auto *builder = &~A;~%" builder) - (write-line (funcall save-parent parent) s))))))) - (defun capnp-save-function-code (cpp-class) "Generate Cap'n Proto save code for CPP-CLASS." (declare (type cpp-class cpp-class)) - (labels ((save-class (cpp-class cpp-out) - "Output the serialization code for members of this and parent class." - (write-line (capnp-save-parents cpp-class #'save-parent) cpp-out) - ;; Set the template instantiations - (when (and (capnp-opts-type-args (cpp-class-capnp-opts cpp-class)) - (/= 1 (list-length (cpp-type-type-params cpp-class)))) - (error "Don't know how to save templated class ~A" (cpp-type-base-name cpp-class))) - (let ((type-param (first (mapcar #'cpp-type-name (cpp-type-type-params cpp-class))))) - (dolist (type-arg (mapcar #'cpp-type-name - (capnp-opts-type-args (cpp-class-capnp-opts cpp-class)))) - (write-string - (raw-cpp-string - #>cpp - if (std::is_same<${type-arg}, ${type-param}>::value) { - builder->set${type-arg}(); - } - cpp<#) - cpp-out))) - (write-line (capnp-save-members cpp-class :instance-access "self.") cpp-out)) - (save-parent (parent) - "Generate serialization code for parent class." - (let ((cpp-class (find-cpp-class parent))) - (with-output-to-string (s) - (with-cpp-block-output (s) - (format s "// Save base class ~A~%" (cpp-type-name parent)) - (save-class cpp-class s)))))) + (labels ((save-class (cpp-class builder cpp-out &key (force-builder nil)) + "Output the serialization code for CPP-CLASS and its parent classes." + (let* ((compose-parents (nth-value 1 (capnp-union-and-compose-parents cpp-class))) + (parents (capnp-union-parents-rec cpp-class)) + (first-parent (find-cpp-class (first parents)))) + (when first-parent + (with-cpp-block-output (cpp-out) + (format cpp-out "// Save parent class ~A~%" (cpp-type-name first-parent)) + (save-class first-parent builder cpp-out))) + ;; Initialize CPP-CLASS builder + (when parents + (if (or force-builder compose-parents (cpp-class-members cpp-class)) + (progn + (format cpp-out "auto ~A_builder = ~A->~{get~A().~}init~A();~%" + (cpp-variable-name (cpp-type-base-name cpp-class)) + builder + (mapcar #'cpp-type-name (cdr (reverse parents))) + (cpp-type-name cpp-class)) + (format cpp-out "auto *builder = &~A_builder;~%" + (cpp-variable-name (cpp-type-base-name cpp-class))) + (setf builder "builder")) + (format cpp-out "~A->~{get~A().~}init~A();~%" + builder + (mapcar #'cpp-type-name (cdr (reverse parents))) + (cpp-type-name cpp-class)))) + ;; Save composed parent classes + (dolist (parent compose-parents) + (with-cpp-block-output (cpp-out) + (let* ((parent-builder (format nil "~A_builder" (cpp-variable-name parent)))) + (format cpp-out "// Save composed class ~A~%" (cpp-type-name parent)) + (format cpp-out "auto ~A = ~A->init~A();~%" + parent-builder builder (cpp-type-name parent)) + (format cpp-out "Save(self, &~A~{, ~A~});" + parent-builder + (mapcar (lambda (name-and-type) + (cpp-variable-name (first name-and-type))) + (capnp-extra-args (find-cpp-class parent) :save)))))) + ;; Save members + (write-string (capnp-save-members cpp-class builder :instance-access "self.") cpp-out)))) (with-output-to-string (cpp-out) - (let ((subclasses (direct-subclasses-of cpp-class))) + (let ((subclasses (capnp-union-subclasses cpp-class)) + (builder (if (capnp-union-parents-rec cpp-class) + "base_builder" + "builder"))) (when subclasses (write-line "// Forward serialization to most derived type" cpp-out) (dolist (subclass subclasses) (let ((derived-name (cpp-type-name subclass)) (save-args (format nil "~A~{, ~A~}" - (if (capnp-union-parents-rec cpp-class) - "base_builder" - "builder") + builder (mapcar (lambda (name-and-type) (cpp-variable-name (first name-and-type))) (capnp-extra-args cpp-class :save)))) @@ -1077,8 +1055,18 @@ It takes a parent class symbol." return Save(*derived, ${save-args}); } cpp<#) - cpp-out)))))) - (save-class cpp-class cpp-out)))) + cpp-out))))) + (cond + ((cpp-class-abstractp cpp-class) + (format cpp-out + "LOG(FATAL) << \"Should not get here -- `~A` should be an abstract class!\";" + (cpp-type-name cpp-class))) + ((capnp-union-subclasses cpp-class) + ;; We are in the middle of inheritance hierarchy, so set our + ;; union Void field. + (save-class cpp-class builder cpp-out :force-builder t) + (format cpp-out "builder->set~A();~%" (cpp-type-name cpp-class))) + (t (save-class cpp-class builder cpp-out))))))) (defun capnp-save-function-definition (cpp-class) "Generate Cap'n Proto save function." @@ -1124,7 +1112,7 @@ It takes a parent class symbol." 'reader) (format nil "const capnp::~A::Reader &" top-parent-class))) (out-arg (list 'self - (if (or parents (direct-subclasses-of cpp-class)) + (if (or parents (capnp-union-subclasses cpp-class)) (format nil "std::unique_ptr<~A> *" (cpp-type-decl cpp-class :namespace nil)) (format nil "~A *" (cpp-type-decl cpp-class :namespace nil)))))) (cpp-function-declaration @@ -1178,7 +1166,7 @@ reader variable. CAPNP-NAME is the name of the member in Cap'n Proto schema." (format nil "Load(&~A, ~A~{, ~A~});" member-name member-reader extra-args)))))) -(defun capnp-load-members (cpp-class &key instance-access) +(defun capnp-load-members (cpp-class reader &key instance-access) "Generate Cap'n Proto loading code for members of CPP-CLASS. INSTANCE-ACCESS is a C++ string which will be prefixed to member access. For example, INSTANCE-ACCESS could be `my_struct->`" @@ -1196,14 +1184,14 @@ example, INSTANCE-ACCESS could be `my_struct->`" (cond ((and (not (cpp-member-capnp-load member)) (capnp-primitive-type-p (capnp-type-of-member member))) - (format s " ~A = reader.get~A();~%" member-access capnp-name)) + (format s " ~A = ~A.get~A();~%" member-access reader capnp-name)) (t ;; Enclose larger load code in new scope (with-cpp-block-output (s) (if (and (cpp-member-capnp-init member) (not (find-cpp-enum (cpp-member-type member)))) - (format s " auto ~A = reader.get~A();~%" member-reader capnp-name) - (setf member-reader "reader")) + (format s " auto ~A = ~A.get~A();~%" member-reader reader capnp-name) + (setf member-reader reader)) (if (cpp-member-capnp-load member) (format s " ~A~%" (cpp-code (funcall (cpp-member-capnp-load member) @@ -1212,56 +1200,56 @@ example, INSTANCE-ACCESS could be `my_struct->`" (cpp-member-type member) member-reader capnp-name) s)))))))))) -(defun capnp-load-parents (cpp-class load-parent) - "Generate Cap'n Proto code for loading parent classes of CPP-CLASS. -LOAD-PARENT is a function which generates the code for loading parent members. -It takes a parent class symbol." - (declare (type cpp-class cpp-class)) - (declare (type (function (symbol) string) load-parent)) - (with-output-to-string (s) - (multiple-value-bind (direct-union-parents compose-parents) - (capnp-union-and-compose-parents cpp-class) - (declare (ignore direct-union-parents)) - ;; Handle the union inheritance calls first. - (let ((parents (capnp-union-parents-rec cpp-class))) - (when parents - (let ((first-parent (first parents))) - (write-line (funcall load-parent first-parent) s)) - (when (or compose-parents (cpp-class-members cpp-class)) - (format s " auto reader = base_reader.~{get~A().~}get~A();~%" - (mapcar #'cpp-type-name (cdr (reverse parents))) - (cpp-type-name cpp-class))) - ;; Now handle composite inheritance calls. - (dolist (parent compose-parents) - (with-cpp-block-output (s) - (let ((reader (format nil "~A_reader" (cpp-variable-name parent)))) - (format s " auto ~A = reader.get~A();~%" reader (cpp-type-name parent)) - (format s " const auto &reader = ~A;" reader) - (write-line (funcall load-parent parent) s))))))))) - (defun capnp-load-function-code (cpp-class) - "Generate Cap'n Proto loadd code for CPP-CLASS." + "Generate Cap'n Proto load code for CPP-CLASS." (declare (type cpp-class cpp-class)) - (let ((instance-access (if (or (direct-subclasses-of cpp-class) + (let ((instance-access (if (or (capnp-union-subclasses cpp-class) (capnp-union-parents-rec cpp-class)) "self->get()->" "self->"))) - (labels ((load-class (cpp-class) - (with-output-to-string (s) - (write-line (capnp-load-parents cpp-class #'load-parent) s) - (write-line (capnp-load-members cpp-class :instance-access instance-access) s))) - (load-parent (parent) - (with-output-to-string (s) - (with-cpp-block-output (s) - (format s "// Load base class ~A~%" (cpp-type-name parent)) - (write-line (load-class (find-cpp-class parent)) s))))) + (labels ((load-class (cpp-class reader cpp-out) + (let* ((compose-parents (nth-value 1 (capnp-union-and-compose-parents cpp-class))) + (parents (capnp-union-parents-rec cpp-class)) + (first-parent (find-cpp-class (first parents)))) + (when first-parent + (with-cpp-block-output (cpp-out) + (format cpp-out "// Load parent class ~A~%" (cpp-type-name first-parent)) + (load-class first-parent reader cpp-out))) + ;; Initialize CPP-CLASS reader + (when (and parents (or compose-parents (cpp-class-members cpp-class))) + (progn + (format cpp-out "auto reader = ~A.~{get~A().~}get~A();" + reader + (mapcar #'cpp-type-name (cdr (reverse parents))) + (cpp-type-name cpp-class)) + (setf reader "reader"))) + ;; Load composed parent classes + (dolist (parent compose-parents) + (with-cpp-block-output (cpp-out) + (let ((parent-reader (format nil "~A_reader" (cpp-variable-name parent)))) + (format cpp-out "// Load composed class ~A~%" (cpp-type-name parent)) + (format cpp-out "auto ~A = ~A.get~A();~%" + parent-reader reader (cpp-type-name parent)) + (format cpp-out "Load(self->get(), ~A~{, ~A~});~%" + parent-reader + (mapcar (lambda (name-and-type) + (cpp-variable-name (first name-and-type))) + (capnp-extra-args (find-cpp-class parent) :load)))))) + ;; Load members + (write-string (capnp-load-members cpp-class reader :instance-access instance-access) cpp-out)))) (with-output-to-string (s) (cond ((and (capnp-union-and-compose-parents cpp-class) (not (direct-subclasses-of cpp-class))) ;; CPP-CLASS is the most derived class, so construct and load. - (format s "*self = std::make_unique<~A>();~%" (cpp-type-decl cpp-class :namespace nil)) - (write-line (load-class cpp-class) s)) + (if (and (cpp-class-capnp-opts cpp-class) + (capnp-opts-construct (cpp-class-capnp-opts cpp-class))) + (write-line (funcall + (capnp-opts-construct (cpp-class-capnp-opts cpp-class)) + (cpp-type-decl cpp-class :namespace nil)) + s) + (format s "*self = std::make_unique<~A>();~%" (cpp-type-decl cpp-class :namespace nil))) + (load-class cpp-class "base_reader" s)) ((capnp-union-subclasses cpp-class) ;; Forward the load to most derived class by switching on reader.which() (let ((parents (capnp-union-parents-rec cpp-class))) @@ -1297,19 +1285,19 @@ It takes a parent class symbol." ;; Regular forward to derived (load-derived (cpp-type-name subclass)))) (write-line "break;" s)) - (when (capnp-union-and-compose-parents cpp-class) + (when (not (cpp-class-abstractp cpp-class)) ;; We are in the middle of the hierarchy, so allow constructing and loading us. (with-cpp-block-output (s :name (format nil "case capnp::~A::~A:" (cpp-type-name cpp-class) (cpp-constant-name (cpp-type-base-name cpp-class)))) (format s "*self = std::make_unique<~A>();~%" (cpp-type-decl cpp-class :namespace nil)) - (write-line (load-class cpp-class) s))))) + (load-class cpp-class "base_reader" s))))) (t ;; Regular load for absolutely no inheritance class (assert (not (capnp-union-subclasses cpp-class))) (assert (not (capnp-union-and-compose-parents cpp-class))) - (write-line (load-class cpp-class) s))))))) + (load-class cpp-class "reader" s))))))) (defun capnp-load-function-definition (cpp-class) "Generate Cap'n Proto load function." @@ -1382,6 +1370,7 @@ element." (declare (type string capnp-type cpp-type) (type (or null string) lambda-code)) ;; TODO: Why not use our `capnp-save-default' for this? + ;; TODO: namespace doesn't work for enums nested in classes (let* ((namespace (format nil "~{~A::~}" (cpp-type-namespace (parse-cpp-type-declaration cpp-type)))) (lambda-code (if lambda-code @@ -1554,6 +1543,8 @@ Currently supported class-options are: * :serialize -- only :capnp is a valid value. Setting :capnp will generate the Cap'n Proto serialization code for the class members. You may specifiy additional options after :capnp to fill the `CAPNP-OPTS' slots. + * :abstractp -- if t, marks that this class cannot be instantiated + (currently only useful in serialization code) Larger example: @@ -1590,7 +1581,8 @@ Generates C++: (class-name (if (consp name) (car name) name)) (type-params (when (consp name) (cdr name))) (class (gensym (format nil "CLASS-~A" name))) - (serialize (cdr (assoc :serialize options)))) + (serialize (cdr (assoc :serialize options))) + (abstractp (second (assoc :abstractp options)))) `(let ((,class (let ((*cpp-inner-types* nil) (*cpp-enclosing-class* ',class-name)) @@ -1606,6 +1598,7 @@ Generates C++: :capnp-opts ,(when (member :capnp serialize) `(and *capnp-serialize-p* (make-capnp-opts ,@(cdr (member :capnp serialize))))) + :abstractp ,abstractp :namespace (reverse *cpp-namespaces*) ;; Set inner types at the end. This works ;; because CL standard specifies order of diff --git a/src/query/frontend/ast/ast.capnp b/src/query/frontend/ast/ast.capnp deleted file mode 100644 index 9795d716b..000000000 --- a/src/query/frontend/ast/ast.capnp +++ /dev/null @@ -1,466 +0,0 @@ -@0xb107d3d6b4b1600b; - -using Cxx = import "/capnp/c++.capnp"; -$Cxx.namespace("query::capnp"); - -using Storage = import "/storage/serialization.capnp"; -using Symbols = import "/query/frontend/semantic/symbol.capnp"; - -struct Tree { - uid @0 :Int64; - - union { - expression @1 :Expression; - where @2 :Where; - namedExpression @3 :NamedExpression; - patternAtom @4 :PatternAtom; - pattern @5 :Pattern; - clause @6 :Clause; - singleQuery @7 :SingleQuery; - cypherUnion @8 :CypherUnion; - query @9 :Query; - } -} - -struct Expression { - union { - binaryOperator @0 :BinaryOperator; - unaryOperator @1 :UnaryOperator; - baseLiteral @2 :BaseLiteral; - listSlicingOperator @3 :ListSlicingOperator; - ifOperator @4 :IfOperator; - identifier @5 :Identifier; - propertyLookup @6 :PropertyLookup; - labelsTest @7 :LabelsTest; - function @8 :Function; - reduce @9 :Reduce; - all @10 :All; - single @11 :Single; - parameterLookup @12 :ParameterLookup; - extract @13 :Extract; - } -} - -struct Where { - expression @0 :Tree; -} - -struct NamedExpression { - name @0 :Text; - expression @1 :Tree; - tokenPosition @2 :Int32; -} - -struct PatternAtom { - union { - nodeAtom @0 :NodeAtom; - edgeAtom @1 :EdgeAtom; - } - identifier @2 :Tree; -} - -struct Pair(First, Second) { - first @0 :First; - second @1 :Second; -} - -struct NodeAtom { - properties @0 :List(Entry); - struct Entry { - key @0 :Pair(Text, Storage.Common); - value @1 :Tree; - } - - labels @1 :List(Storage.Common); -} - -struct EdgeAtom { - enum Type { - single @0; - depthFirst @1; - breadthFirst @2; - weightedShortestPath @3; - } - type @0 :Type; - - enum Direction { - in @0; - out @1; - both @2; - } - direction @1 :Direction; - - properties @2 :List(Entry); - struct Entry { - key @0 :Pair(Text, Storage.Common); - value @1 :Tree; - } - - lowerBound @3 :Tree; - upperBound @4 :Tree; - - filterLambda @5 :Lambda; - weightLambda @6 :Lambda; - struct Lambda { - innerEdge @0 :Tree; - innerNode @1 :Tree; - expression @2 :Tree; - } - - totalWeight @7 :Tree; - edgeTypes @8 :List(Storage.Common); -} - -struct Pattern { - identifier @0 :Tree; - atoms @1 :List(Tree); -} - -struct Clause { - union { - create @0 :Create; - match @1 :Match; - return @2 :Return; - with @3 :With; - delete @4 :Delete; - setProperty @5 :SetProperty; - setProperties @6 :SetProperties; - setLabels @7 :SetLabels; - removeProperty @8 :RemoveProperty; - removeLabels @9 :RemoveLabels; - merge @10 :Merge; - unwind @11 :Unwind; - createIndex @12 :CreateIndex; - authQuery @13 :AuthQuery; - createStream @14 :CreateStream; - dropStream @15 :DropStream; - showStreams @16 :ShowStreams; - startStopStream @17 :StartStopStream; - startStopAllStreams @18 :StartStopAllStreams; - testStream @19 :TestStream; - } -} - -struct SingleQuery { - clauses @0 :List(Tree); -} - -struct CypherUnion { - singleQuery @0 :Tree; - distinct @1 :Bool; - unionSymbols @2 :List(Symbols.Symbol); -} - -struct Query { - singleQuery @0 :Tree; - cypherUnions @1 :List(Tree); - explain @2 :Bool; -} - -struct BinaryOperator { - union { - orOperator @0 :OrOperator; - xorOperator @1 :XorOperator; - andOperator @2 :AndOperator; - additionOperator @3 :AdditionOperator; - subtractionOperator @4 :SubtractionOperator; - multiplicationOperator @5 :MultiplicationOperator; - divisionOperator @6 :DivisionOperator; - modOperator @7 :ModOperator; - notEqualOperator @8 :NotEqualOperator; - equalOperator @9 :EqualOperator; - lessOperator @10 :LessOperator; - greaterOperator @11 :GreaterOperator; - lessEqualOperator @12 :LessEqualOperator; - greaterEqualOperator @13 :GreaterEqualOperator; - inListOperator @14 :InListOperator; - subscriptOperator @15 :SubscriptOperator; - aggregation @16 :Aggregation; - } - expression1 @17 :Tree; - expression2 @18 :Tree; -} - -struct OrOperator {} -struct XorOperator {} -struct AndOperator {} -struct AdditionOperator {} -struct SubtractionOperator {} -struct MultiplicationOperator {} -struct DivisionOperator {} -struct ModOperator {} -struct NotEqualOperator {} -struct EqualOperator {} -struct LessOperator {} -struct GreaterOperator {} -struct LessEqualOperator {} -struct GreaterEqualOperator {} -struct InListOperator {} -struct SubscriptOperator {} -struct Aggregation { - enum Op { - count @0; - min @1; - max @2; - sum @3; - avg @4 ; - collectList @5; - collectMap @6; - } - op @0 :Op; -} - -struct UnaryOperator { - union { - notOperator @0 :NotOperator; - unaryPlusOperator @1 :UnaryPlusOperator; - unaryMinusOperator @2 :UnaryMinusOperator; - isNullOperator @3 :IsNullOperator; - } - expression @4 :Tree; -} - -struct NotOperator {} -struct UnaryPlusOperator {} -struct UnaryMinusOperator {} -struct IsNullOperator {} - -struct BaseLiteral { - union { - primitiveLiteral @0 :PrimitiveLiteral; - listLiteral @1 :ListLiteral; - mapLiteral @2 :MapLiteral; - } -} - -struct PrimitiveLiteral { - tokenPosition @0 :Int32; - value @1 :Storage.PropertyValue; -} - -struct ListLiteral { - elements @0 :List(Tree); -} - -struct MapLiteral { - elements @0 :List(Entry); - struct Entry { - key @0 :Pair(Text, Storage.Common); - value @1 :Tree; - } -} - -struct ListSlicingOperator { - list @0 :Tree; - lowerBound @1 :Tree; - upperBound @2 :Tree; -} - -struct IfOperator { - condition @0 :Tree; - thenExpression @1 :Tree; - elseExpression @2 :Tree; -} - -struct Identifier { - name @0 :Text; - userDeclared @1 :Bool; -} - -struct PropertyLookup { - expression @0 :Tree; - propertyName @1 :Text; - property @2 :Storage.Common; -} - -struct LabelsTest { - expression @0 :Tree; - labels @1 :List(Storage.Common); -} - -struct Function { - functionName @0 :Text; - arguments @1 :List(Tree); -} - -struct Reduce { - accumulator @0 :Tree; - initializer @1 :Tree; - identifier @2 :Tree; - list @3 :Tree; - expression @4 :Tree; -} - -struct Extract { - identifier @0 :Tree; - list @1 :Tree; - expression @2 :Tree; -} - -struct All { - identifier @0 :Tree; - listExpression @1 :Tree; - where @2 :Tree; -} - -struct Single { - identifier @0 :Tree; - listExpression @1 :Tree; - where @2 :Tree; -} - -struct ParameterLookup { - tokenPosition @0 :Int32; -} - -struct Create { - patterns @0 :List(Tree); -} - -struct Match { - patterns @0 :List(Tree); - where @1 :Tree; - optional @2 :Bool; -} - -enum Ordering { - asc @0; - desc @1; -} - -struct ReturnBody { - distinct @0 :Bool; - allIdentifiers @1 :Bool; - namedExpressions @2 :List(Tree); - orderBy @3 :List(Pair); - - struct Pair { - ordering @0 :Ordering; - expression @1 :Tree; - } - - skip @4 :Tree; - limit @5 :Tree; -} - -struct Return { - returnBody @0 :ReturnBody; -} - -struct With { - returnBody @0 :ReturnBody; - where @1 :Tree; -} - -struct Delete { - detach @0 :Bool; - expressions @1 :List(Tree); -} - -struct SetProperty { - propertyLookup @0 :Tree; - expression @1 :Tree; -} - -struct SetProperties { - identifier @0 :Tree; - expression @1 :Tree; - update @2 :Bool; -} - -struct SetLabels { - identifier @0 :Tree; - labels @1 :List(Storage.Common); -} - -struct RemoveProperty { - propertyLookup @0 :Tree; -} - -struct RemoveLabels { - identifier @0 :Tree; - labels @1 :List(Storage.Common); -} - -struct Merge { - pattern @0 :Tree; - onMatch @1 :List(Tree); - onCreate @2 :List(Tree); -} - -struct Unwind { - namedExpression @0 :Tree; -} - -struct CreateIndex { - label @0 :Storage.Common; - property @1 :Storage.Common; -} - -struct AuthQuery { - enum Action { - createRole @0; - dropRole @1; - showRoles @2; - createUser @3; - setPassword @4; - dropUser @5; - showUsers @6; - setRole @7; - clearRole @8; - grantPrivilege @9; - denyPrivilege @10; - revokePrivilege @11; - showPrivileges @12; - showRoleForUser @13; - showUsersForRole @14; - } - enum Privilege { - create @0; - delete @1; - match @2; - merge @3; - set @4; - remove @5; - index @6; - auth @7; - stream @8; - } - action @0 :Action; - user @1 :Text; - role @2 :Text; - userOrRole @3 :Text; - password @4 :Tree; - privileges @5 :List(Privilege); -} - -struct CreateStream { - streamName @0 :Text; - streamUri @1 :Tree; - streamTopic @2 :Tree; - transformUri @3 :Tree; - batchIntervalInMs @4 :Tree; - batchSize @5 :Tree; -} - -struct DropStream { - streamName @0: Text; -} - -struct ShowStreams {} - -struct StartStopStream { - streamName @0 :Text; - isStart @1 :Bool; - limitBatches @2: Tree; -} - -struct StartStopAllStreams { - isStart @0 :Bool; -} - -struct TestStream { - streamName @0 :Text; - limitBatches @1: Tree; -} - diff --git a/src/query/frontend/ast/ast.cpp b/src/query/frontend/ast/ast.cpp index f335b3d7b..2b9206e48 100644 --- a/src/query/frontend/ast/ast.cpp +++ b/src/query/frontend/ast/ast.cpp @@ -9,11 +9,12 @@ namespace query { AstStorage::AstStorage() { std::unique_ptr root(new Query(next_uid_++)); + root_idx_ = 0; storage_.emplace_back(std::move(root)); } Query *AstStorage::query() const { - return dynamic_cast(storage_[0].get()); + return dynamic_cast(storage_[root_idx_].get()); } ReturnBody CloneReturnBody(AstStorage &storage, const ReturnBody &body) { @@ -24,7 +25,8 @@ ReturnBody CloneReturnBody(AstStorage &storage, const ReturnBody &body) { new_body.named_expressions.push_back(named_expr->Clone(storage)); } for (auto order : body.order_by) { - new_body.order_by.emplace_back(order.first, order.second->Clone(storage)); + new_body.order_by.push_back( + SortItem{order.ordering, order.expression->Clone(storage)}); } new_body.skip = body.skip ? body.skip->Clone(storage) : nullptr; new_body.limit = body.limit ? body.limit->Clone(storage) : nullptr; @@ -32,2741 +34,14 @@ ReturnBody CloneReturnBody(AstStorage &storage, const ReturnBody &body) { } // Capnproto serialization. - Tree *AstStorage::Load(const capnp::Tree::Reader &tree, std::vector *loaded_uids) { - auto uid = tree.getUid(); - - // Check if element already deserialized and if yes, return existing - // element from storage. - if (utils::Contains(*loaded_uids, uid)) { - auto found = std::find_if(storage_.begin(), storage_.end(), - [&](const auto &n) { return n->uid() == uid; }); - DCHECK(found != storage_.end()); - return found->get(); - } - - Tree *ret = nullptr; - switch (tree.which()) { - case capnp::Tree::EXPRESSION: { - auto expr_reader = tree.getExpression(); - ret = Expression::Construct(expr_reader, this); - ret->Load(tree, this, loaded_uids); - break; - } - case capnp::Tree::WHERE: { - auto where_reader = tree.getWhere(); - ret = Where::Construct(where_reader, this); - ret->Load(tree, this, loaded_uids); - break; - } - case capnp::Tree::CLAUSE: { - auto clause_reader = tree.getClause(); - ret = Clause::Construct(clause_reader, this); - ret->Load(tree, this, loaded_uids); - break; - } - case capnp::Tree::CYPHER_UNION: { - auto cu_reader = tree.getCypherUnion(); - ret = CypherUnion::Construct(cu_reader, this); - ret->Load(tree, this, loaded_uids); - break; - } - case capnp::Tree::NAMED_EXPRESSION: { - auto ne_reader = tree.getNamedExpression(); - ret = NamedExpression::Construct(ne_reader, this); - ret->Load(tree, this, loaded_uids); - break; - } - case capnp::Tree::PATTERN: { - auto pattern_reader = tree.getPattern(); - ret = Pattern::Construct(pattern_reader, this); - ret->Load(tree, this, loaded_uids); - break; - } - case capnp::Tree::PATTERN_ATOM: { - auto pa_reader = tree.getPatternAtom(); - ret = PatternAtom::Construct(pa_reader, this); - ret->Load(tree, this, loaded_uids); - break; - } - case capnp::Tree::QUERY: { - this->query()->Load(tree, this, loaded_uids); - ret = this->query(); - break; - } - case capnp::Tree::SINGLE_QUERY: { - auto single_reader = tree.getSingleQuery(); - ret = SingleQuery::Construct(single_reader, this); - ret->Load(tree, this, loaded_uids); - break; - } - } - DCHECK(ret != nullptr); - loaded_uids->emplace_back(ret->uid_); - auto previous_max = std::max_element( - storage_.begin(), storage_.end(), - [](const std::unique_ptr &a, const std::unique_ptr &b) { - return a->uid() < b->uid(); - }); - next_uid_ = (*previous_max)->uid() + 1; - return ret; -} - -// Tree. -void Tree::Save(capnp::Tree::Builder *tree_builder, - std::vector *saved_uids) { - tree_builder->setUid(uid_); -} - -bool Tree::IsSaved(const std::vector &saved_uids) { - return utils::Contains(saved_uids, uid_); -} - -void Tree::Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) { - uid_ = reader.getUid(); -} - -void Tree::AddToSaved(std::vector *saved_uids) { - saved_uids->emplace_back(uid_); -} - -// Expression. -void Expression::Save(capnp::Tree::Builder *tree_builder, - std::vector *saved_uids) { - Tree::Save(tree_builder, saved_uids); - if (IsSaved(*saved_uids)) { - return; - } - auto expr_builder = tree_builder->initExpression(); - Save(&expr_builder, saved_uids); - AddToSaved(saved_uids); -} - -Expression *Expression::Construct(const capnp::Expression::Reader &reader, - AstStorage *storage) { - switch (reader.which()) { - case capnp::Expression::BINARY_OPERATOR: { - auto bop_reader = reader.getBinaryOperator(); - return BinaryOperator::Construct(bop_reader, storage); - } - case capnp::Expression::UNARY_OPERATOR: { - auto uop_reader = reader.getUnaryOperator(); - return UnaryOperator::Construct(uop_reader, storage); - } - case capnp::Expression::BASE_LITERAL: { - auto bl_reader = reader.getBaseLiteral(); - return BaseLiteral::Construct(bl_reader, storage); - } - case capnp::Expression::LIST_SLICING_OPERATOR: { - auto lso_reader = reader.getListSlicingOperator(); - return ListSlicingOperator::Construct(lso_reader, storage); - } - case capnp::Expression::IF_OPERATOR: { - auto if_reader = reader.getIfOperator(); - return IfOperator::Construct(if_reader, storage); - } - case capnp::Expression::ALL: { - auto all_reader = reader.getAll(); - return All::Construct(all_reader, storage); - } - case capnp::Expression::FUNCTION: { - auto func_reader = reader.getFunction(); - return Function::Construct(func_reader, storage); - } - case capnp::Expression::IDENTIFIER: { - auto id_reader = reader.getIdentifier(); - return Identifier::Construct(id_reader, storage); - } - case capnp::Expression::LABELS_TEST: { - auto labels_reader = reader.getLabelsTest(); - return LabelsTest::Construct(labels_reader, storage); - } - case capnp::Expression::PARAMETER_LOOKUP: { - auto pl_reader = reader.getParameterLookup(); - return ParameterLookup::Construct(pl_reader, storage); - } - case capnp::Expression::PROPERTY_LOOKUP: { - auto pl_reader = reader.getPropertyLookup(); - return PropertyLookup::Construct(pl_reader, storage); - } - case capnp::Expression::REDUCE: { - auto reduce_reader = reader.getReduce(); - return Reduce::Construct(reduce_reader, storage); - } - case capnp::Expression::SINGLE: { - auto single_reader = reader.getSingle(); - return Single::Construct(single_reader, storage); - } - case capnp::Expression::EXTRACT: { - auto extract_reader = reader.getExtract(); - return Extract::Construct(extract_reader, storage); - } - } -} - -// Base Literal. -void BaseLiteral::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto base_literal_builder = expr_builder->initBaseLiteral(); - Save(&base_literal_builder, saved_uids); -} - -BaseLiteral *BaseLiteral::Construct(const capnp::BaseLiteral::Reader &reader, - AstStorage *storage) { - switch (reader.which()) { - case capnp::BaseLiteral::PRIMITIVE_LITERAL: { - auto literal = reader.getPrimitiveLiteral(); - return PrimitiveLiteral::Construct(literal, storage); - } - case capnp::BaseLiteral::LIST_LITERAL: { - auto literal = reader.getListLiteral(); - return ListLiteral::Construct(literal, storage); - } - case capnp::BaseLiteral::MAP_LITERAL: { - auto literal = reader.getMapLiteral(); - return MapLiteral::Construct(literal, storage); - } - } -} - -// Primitive Literal. -void PrimitiveLiteral::Save(capnp::BaseLiteral::Builder *base_literal_builder, - std::vector *saved_uids) { - BaseLiteral::Save(base_literal_builder, saved_uids); - auto primitive_literal_builder = base_literal_builder->initPrimitiveLiteral(); - primitive_literal_builder.setTokenPosition(token_position_); - auto property_value_builder = primitive_literal_builder.getValue(); - storage::SaveCapnpPropertyValue(value_, &property_value_builder); -} - -void PrimitiveLiteral::Load(const capnp::Tree::Reader &reader, - AstStorage *storage, - std::vector *loaded_uids) { - BaseLiteral::Load(reader, storage, loaded_uids); - auto pl_reader = - reader.getExpression().getBaseLiteral().getPrimitiveLiteral(); - auto typed_value_reader = pl_reader.getValue(); - storage::LoadCapnpPropertyValue(typed_value_reader, &value_); - token_position_ = pl_reader.getTokenPosition(); -} - -PrimitiveLiteral *PrimitiveLiteral::Construct( - const capnp::PrimitiveLiteral::Reader &reader, AstStorage *storage) { - return storage->Create(); -} - -// List Literal. -void ListLiteral::Save(capnp::BaseLiteral::Builder *base_literal_builder, - std::vector *saved_uids) { - BaseLiteral::Save(base_literal_builder, saved_uids); - auto list_literal_builder = base_literal_builder->initListLiteral(); - ::capnp::List::Builder tree_builders = - list_literal_builder.initElements(elements_.size()); - for (size_t i = 0; i < elements_.size(); ++i) { - auto tree_builder = tree_builders[i]; - elements_[i]->Save(&tree_builder, saved_uids); - } -} - -void ListLiteral::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - BaseLiteral::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getBaseLiteral().getListLiteral(); - for (const auto tree_reader : reader.getElements()) { - auto tree = storage->Load(tree_reader, loaded_uids); - elements_.push_back(dynamic_cast(tree)); - } -} - -ListLiteral *ListLiteral::Construct(const capnp::ListLiteral::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// Map Literal. -void MapLiteral::Save(capnp::BaseLiteral::Builder *base_literal_builder, - std::vector *saved_uids) { - BaseLiteral::Save(base_literal_builder, saved_uids); - auto map_literal_builder = base_literal_builder->initMapLiteral(); - ::capnp::List::Builder map_builder = - map_literal_builder.initElements(elements_.size()); - size_t i = 0; - for (auto &entry : elements_) { - auto entry_builder = map_builder[i]; - auto key_builder = entry_builder.getKey(); - key_builder.setFirst(entry.first.first); - auto storage_property_builder = key_builder.getSecond(); - storage::Save(entry.first.second, &storage_property_builder); - auto value_builder = entry_builder.getValue(); - if (entry.second) entry.second->Save(&value_builder, saved_uids); - ++i; - } -} - -void MapLiteral::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - BaseLiteral::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getBaseLiteral().getMapLiteral(); - for (auto entry_reader : reader.getElements()) { - auto key_pair_reader = entry_reader.getKey(); - auto key_first = key_pair_reader.getFirst().cStr(); - auto storage_property_reader = key_pair_reader.getSecond(); - storage::Property key_second; - storage::Load(&key_second, storage_property_reader); - const auto value_reader = entry_reader.getValue(); - auto value = storage->Load(value_reader, loaded_uids); - auto key = std::make_pair(key_first, key_second); - // TODO Maybe check for nullptr expression? - elements_.emplace(key, dynamic_cast(value)); - } -} - -MapLiteral *MapLiteral::Construct(const capnp::MapLiteral::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// Binary Operator. -void BinaryOperator::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initBinaryOperator(); - Save(&builder, saved_uids); -} - -void BinaryOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - if (expression1_) { - auto expr1_builder = builder->getExpression1(); - expression1_->Save(&expr1_builder, saved_uids); - } - if (expression2_) { - auto expr2_builder = builder->getExpression2(); - expression2_->Save(&expr2_builder, saved_uids); - } -} - -void BinaryOperator::Load(const capnp::Tree::Reader &reader, - AstStorage *storage, std::vector *loaded_uids) { - Expression::Load(reader, storage, loaded_uids); - auto bop_reader = reader.getExpression().getBinaryOperator(); - if (bop_reader.hasExpression1()) { - const auto expr1_reader = bop_reader.getExpression1(); - expression1_ = - dynamic_cast(storage->Load(expr1_reader, loaded_uids)); - } - if (bop_reader.hasExpression2()) { - const auto expr2_reader = bop_reader.getExpression2(); - expression2_ = - dynamic_cast(storage->Load(expr2_reader, loaded_uids)); - } -} - -BinaryOperator *BinaryOperator::Construct( - const capnp::BinaryOperator::Reader &reader, AstStorage *storage) { - switch (reader.which()) { - case capnp::BinaryOperator::ADDITION_OPERATOR: { - auto literal = reader.getAdditionOperator(); - return AdditionOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::AGGREGATION: { - auto literal = reader.getAggregation(); - return Aggregation::Construct(literal, storage); - } - case capnp::BinaryOperator::AND_OPERATOR: { - auto literal = reader.getAndOperator(); - return AndOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::DIVISION_OPERATOR: { - auto literal = reader.getDivisionOperator(); - return DivisionOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::EQUAL_OPERATOR: { - auto literal = reader.getEqualOperator(); - return EqualOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::GREATER_EQUAL_OPERATOR: { - auto literal = reader.getGreaterEqualOperator(); - return GreaterEqualOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::GREATER_OPERATOR: { - auto literal = reader.getGreaterOperator(); - return GreaterOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::IN_LIST_OPERATOR: { - auto literal = reader.getInListOperator(); - return InListOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::LESS_EQUAL_OPERATOR: { - auto literal = reader.getLessEqualOperator(); - return LessEqualOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::LESS_OPERATOR: { - auto literal = reader.getLessOperator(); - return LessOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::SUBSCRIPT_OPERATOR: { - auto literal = reader.getSubscriptOperator(); - return SubscriptOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::MOD_OPERATOR: { - auto literal = reader.getModOperator(); - return ModOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::MULTIPLICATION_OPERATOR: { - auto literal = reader.getMultiplicationOperator(); - return MultiplicationOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::NOT_EQUAL_OPERATOR: { - auto literal = reader.getNotEqualOperator(); - return NotEqualOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::OR_OPERATOR: { - auto literal = reader.getOrOperator(); - return OrOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::SUBTRACTION_OPERATOR: { - auto literal = reader.getSubtractionOperator(); - return SubtractionOperator::Construct(literal, storage); - } - case capnp::BinaryOperator::XOR_OPERATOR: { - auto literal = reader.getXorOperator(); - return XorOperator::Construct(literal, storage); - } - } -} - -void OrOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initOrOperator(); -} - -OrOperator *OrOperator::Construct(const capnp::OrOperator::Reader &, - AstStorage *storage) { - return storage->Create(); -} - -void XorOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initXorOperator(); -} - -XorOperator *XorOperator::Construct(const capnp::XorOperator::Reader &, - AstStorage *storage) { - return storage->Create(); -} - -void AndOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initAndOperator(); -} - -AndOperator *AndOperator::Construct(const capnp::AndOperator::Reader &, - AstStorage *storage) { - return storage->Create(); -} - -void AdditionOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initAdditionOperator(); -} - -AdditionOperator *AdditionOperator::Construct( - const capnp::AdditionOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -void SubtractionOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initSubtractionOperator(); -} - -SubtractionOperator *SubtractionOperator::Construct( - capnp::SubtractionOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -void MultiplicationOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initMultiplicationOperator(); -} - -MultiplicationOperator *MultiplicationOperator::Construct( - capnp::MultiplicationOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -void DivisionOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initDivisionOperator(); -} - -DivisionOperator *DivisionOperator::Construct( - const capnp::DivisionOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -void ModOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initModOperator(); -} - -ModOperator *ModOperator::Construct(const capnp::ModOperator::Reader &, - AstStorage *storage) { - return storage->Create(); -} - -void NotEqualOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initNotEqualOperator(); -} - -NotEqualOperator *NotEqualOperator::Construct( - const capnp::NotEqualOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -void EqualOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initEqualOperator(); -} - -EqualOperator *EqualOperator::Construct(const capnp::EqualOperator::Reader &, - AstStorage *storage) { - return storage->Create(); -} - -void LessOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initLessOperator(); -} - -LessOperator *LessOperator::Construct(const capnp::LessOperator::Reader &, - AstStorage *storage) { - return storage->Create(); -} - -void GreaterOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initGreaterOperator(); -} - -GreaterOperator *GreaterOperator::Construct( - const capnp::GreaterOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -void LessEqualOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initLessEqualOperator(); -} - -LessEqualOperator *LessEqualOperator::Construct( - const capnp::LessEqualOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -void GreaterEqualOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initGreaterEqualOperator(); -} - -GreaterEqualOperator *GreaterEqualOperator::Construct( - const capnp::GreaterEqualOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -void InListOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initInListOperator(); -} - -InListOperator *InListOperator::Construct(const capnp::InListOperator::Reader &, - AstStorage *storage) { - return storage->Create(); -} - -void SubscriptOperator::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - builder->initSubscriptOperator(); -} - -SubscriptOperator *SubscriptOperator::Construct( - capnp::SubscriptOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -void Aggregation::Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) { - BinaryOperator::Save(builder, saved_uids); - auto ag_builder = builder->initAggregation(); - switch (op_) { - case Op::AVG: - ag_builder.setOp(capnp::Aggregation::Op::AVG); - break; - case Op::COLLECT_LIST: - ag_builder.setOp(capnp::Aggregation::Op::COLLECT_LIST); - break; - case Op::COLLECT_MAP: - ag_builder.setOp(capnp::Aggregation::Op::COLLECT_MAP); - break; - case Op::COUNT: - ag_builder.setOp(capnp::Aggregation::Op::COUNT); - break; - case Op::MAX: - ag_builder.setOp(capnp::Aggregation::Op::MAX); - break; - case Op::MIN: - ag_builder.setOp(capnp::Aggregation::Op::MIN); - break; - case Op::SUM: - ag_builder.setOp(capnp::Aggregation::Op::SUM); - break; - } -} - -Aggregation *Aggregation::Construct(const capnp::Aggregation::Reader &reader, - AstStorage *storage) { - Op op; - switch (reader.getOp()) { - case capnp::Aggregation::Op::AVG: - op = Op::AVG; - break; - case capnp::Aggregation::Op::COLLECT_LIST: - op = Op::COLLECT_LIST; - break; - case capnp::Aggregation::Op::COLLECT_MAP: - op = Op::COLLECT_MAP; - break; - case capnp::Aggregation::Op::COUNT: - op = Op::COUNT; - break; - case capnp::Aggregation::Op::MAX: - op = Op::MAX; - break; - case capnp::Aggregation::Op::MIN: - op = Op::MIN; - break; - case capnp::Aggregation::Op::SUM: - op = Op::SUM; - break; - } - return storage->Create(op); -} - -// Unary Operator. -void UnaryOperator::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initUnaryOperator(); - Save(&builder, saved_uids); -} - -void UnaryOperator::Save(capnp::UnaryOperator::Builder *builder, - std::vector *saved_uids) { - if (expression_) { - auto expr_builder = builder->getExpression(); - expression_->Save(&expr_builder, saved_uids); - } -} - -void UnaryOperator::Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) { - Expression::Load(reader, storage, loaded_uids); - if (reader.hasExpression()) { - const auto expr_reader = - reader.getExpression().getUnaryOperator().getExpression(); - expression_ = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); - } -} - -UnaryOperator *UnaryOperator::Construct( - const capnp::UnaryOperator::Reader &reader, AstStorage *storage) { - switch (reader.which()) { - case capnp::UnaryOperator::IS_NULL_OPERATOR: { - auto op = reader.getIsNullOperator(); - return IsNullOperator::Construct(op, storage); - } - case capnp::UnaryOperator::NOT_OPERATOR: { - auto op = reader.getNotOperator(); - return NotOperator::Construct(op, storage); - } - case capnp::UnaryOperator::UNARY_MINUS_OPERATOR: { - auto op = reader.getUnaryMinusOperator(); - return UnaryMinusOperator::Construct(op, storage); - } - case capnp::UnaryOperator::UNARY_PLUS_OPERATOR: { - auto op = reader.getUnaryPlusOperator(); - return UnaryPlusOperator::Construct(op, storage); - } - } -} - -// IsNull Operator. -void IsNullOperator::Save(capnp::UnaryOperator::Builder *builder, - std::vector *saved_uids) { - UnaryOperator::Save(builder, saved_uids); - builder->initIsNullOperator(); -} - -IsNullOperator *IsNullOperator::Construct(const capnp::IsNullOperator::Reader &, - AstStorage *storage) { - return storage->Create(); -} - -// Not Operator. -void NotOperator::Save(capnp::UnaryOperator::Builder *builder, - std::vector *saved_uids) { - UnaryOperator::Save(builder, saved_uids); - builder->initNotOperator(); -} - -NotOperator *NotOperator::Construct(const capnp::NotOperator::Reader &, - AstStorage *storage) { - return storage->Create(); -} - -// UnaryPlus Operator. -void UnaryPlusOperator::Save(capnp::UnaryOperator::Builder *builder, - std::vector *saved_uids) { - UnaryOperator::Save(builder, saved_uids); - builder->initUnaryPlusOperator(); -} - -UnaryPlusOperator *UnaryPlusOperator::Construct( - const capnp::UnaryPlusOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -// UnaryMinus Operator. -void UnaryMinusOperator::Save(capnp::UnaryOperator::Builder *builder, - std::vector *saved_uids) { - UnaryOperator::Save(builder, saved_uids); - builder->initUnaryMinusOperator(); -} - -UnaryMinusOperator *UnaryMinusOperator::Construct( - capnp::UnaryMinusOperator::Reader &, AstStorage *storage) { - return storage->Create(); -} - -// ListSlicing Operator. -void ListSlicingOperator::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initListSlicingOperator(); - Save(&builder, saved_uids); -} - -void ListSlicingOperator::Save(capnp::ListSlicingOperator::Builder *builder, - std::vector *saved_uids) { - if (list_) { - auto list_builder = builder->getList(); - list_->Save(&list_builder, saved_uids); - } - if (lower_bound_) { - auto lb_builder = builder->getLowerBound(); - lower_bound_->Save(&lb_builder, saved_uids); - } - if (upper_bound_) { - auto up_builder = builder->getUpperBound(); - upper_bound_->Save(&up_builder, saved_uids); - } -} - -void ListSlicingOperator::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, - std::vector *loaded_uids) { - Expression::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getListSlicingOperator(); - if (reader.hasList()) { - const auto list_reader = reader.getList(); - list_ = dynamic_cast(storage->Load(list_reader, loaded_uids)); - } - if (reader.hasUpperBound()) { - const auto ub_reader = reader.getUpperBound(); - upper_bound_ = - dynamic_cast(storage->Load(ub_reader, loaded_uids)); - } - if (reader.hasLowerBound()) { - const auto lb_reader = reader.getLowerBound(); - lower_bound_ = - dynamic_cast(storage->Load(lb_reader, loaded_uids)); - } -} - -ListSlicingOperator *ListSlicingOperator::Construct( - const capnp::ListSlicingOperator::Reader &reader, AstStorage *storage) { - return storage->Create(nullptr, nullptr, nullptr); -} - -// If Operator. -void IfOperator::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initIfOperator(); - Save(&builder, saved_uids); -} - -void IfOperator::Save(capnp::IfOperator::Builder *builder, - std::vector *saved_uids) { - auto condition_builder = builder->getCondition(); - condition_->Save(&condition_builder, saved_uids); - auto then_builder = builder->getThenExpression(); - then_expression_->Save(&then_builder, saved_uids); - auto else_builder = builder->getElseExpression(); - else_expression_->Save(&else_builder, saved_uids); -} - -void IfOperator::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Expression::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getIfOperator(); - const auto condition_reader = reader.getCondition(); - condition_ = - dynamic_cast(storage->Load(condition_reader, loaded_uids)); - const auto then_reader = reader.getThenExpression(); - then_expression_ = - dynamic_cast(storage->Load(then_reader, loaded_uids)); - const auto else_reader = reader.getElseExpression(); - else_expression_ = - dynamic_cast(storage->Load(else_reader, loaded_uids)); -} - -IfOperator *IfOperator::Construct(const capnp::IfOperator::Reader &reader, - AstStorage *storage) { - return storage->Create(nullptr, nullptr, nullptr); -} - -// All -void All::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initAll(); - Save(&builder, saved_uids); -} - -void All::Save(capnp::All::Builder *builder, std::vector *saved_uids) { - auto identifier_builder = builder->getIdentifier(); - identifier_->Save(&identifier_builder, saved_uids); - auto expr_builder = builder->getListExpression(); - list_expression_->Save(&expr_builder, saved_uids); - auto where_builder = builder->getWhere(); - where_->Save(&where_builder, saved_uids); -} - -void All::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Expression::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getAll(); - const auto id_reader = reader.getIdentifier(); - identifier_ = - dynamic_cast(storage->Load(id_reader, loaded_uids)); - const auto expr_reader = reader.getListExpression(); - list_expression_ = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); - const auto where_reader = reader.getWhere(); - where_ = dynamic_cast(storage->Load(where_reader, loaded_uids)); -} - -All *All::Construct(const capnp::All::Reader &reader, AstStorage *storage) { - return storage->Create(nullptr, nullptr, nullptr); -} - -// Function -void Function::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initFunction(); - Save(&builder, saved_uids); -} - -void Function::Save(capnp::Function::Builder *builder, - std::vector *saved_uids) { - builder->setFunctionName(function_name_); - ::capnp::List::Builder tree_builders = - builder->initArguments(arguments_.size()); - for (size_t i = 0; i < arguments_.size(); ++i) { - auto tree_builder = tree_builders[i]; - arguments_[i]->Save(&tree_builder, saved_uids); - } -} - -void Function::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Expression::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getFunction(); - function_name_ = reader.getFunctionName().cStr(); - for (const auto tree_reader : reader.getArguments()) { - auto tree = storage->Load(tree_reader, loaded_uids); - arguments_.push_back(dynamic_cast(tree)); - } - function_ = NameToFunction(function_name_); -} - -Function *Function::Construct(const capnp::Function::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// Identifier -void Identifier::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initIdentifier(); - Save(&builder, saved_uids); -} - -void Identifier::Save(capnp::Identifier::Builder *builder, - std::vector *saved_uids) { - builder->setName(name_); - builder->setUserDeclared(user_declared_); -} - -Identifier *Identifier::Construct(const capnp::Identifier::Reader &reader, - AstStorage *storage) { - auto name = reader.getName().cStr(); - auto user_declared = reader.getUserDeclared(); - return storage->Create(name, user_declared); -} - -// LabelsTest -void LabelsTest::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initLabelsTest(); - Save(&builder, saved_uids); -} - -void LabelsTest::Save(capnp::LabelsTest::Builder *builder, - std::vector *saved_uids) { - if (expression_) { - auto expr_builder = builder->initExpression(); - expression_->Save(&expr_builder, saved_uids); - } - auto common_builders = builder->initLabels(labels_.size()); - for (size_t i = 0; i < labels_.size(); ++i) { - auto common_builder = common_builders[i]; - storage::Save(labels_[i], &common_builder); - } -} - -void LabelsTest::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Expression::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getLabelsTest(); - if (reader.hasExpression()) { - const auto expr_reader = reader.getExpression(); - expression_ = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); - } - for (auto label_reader : reader.getLabels()) { - storage::Label label; - storage::Load(&label, label_reader); - labels_.push_back(label); - } -} - -LabelsTest *LabelsTest::Construct(const capnp::LabelsTest::Reader &reader, - AstStorage *storage) { - return storage->Create(nullptr, std::vector()); -} - -// ParameterLookup -void ParameterLookup::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initParameterLookup(); - Save(&builder, saved_uids); -} - -void ParameterLookup::Save(capnp::ParameterLookup::Builder *builder, - std::vector *saved_uids) { - builder->setTokenPosition(token_position_); -} - -ParameterLookup *ParameterLookup::Construct( - const capnp::ParameterLookup::Reader &reader, AstStorage *storage) { - auto token_position = reader.getTokenPosition(); - return storage->Create(token_position); -} - -// PropertyLookup -void PropertyLookup::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initPropertyLookup(); - Save(&builder, saved_uids); -} - -void PropertyLookup::Save(capnp::PropertyLookup::Builder *builder, - std::vector *saved_uids) { - if (expression_) { - auto expr_builder = builder->initExpression(); - expression_->Save(&expr_builder, saved_uids); - } - builder->setPropertyName(property_name_); - auto storage_property_builder = builder->initProperty(); - storage::Save(property_, &storage_property_builder); -} - -void PropertyLookup::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Expression::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getPropertyLookup(); - if (reader.hasExpression()) { - const auto expr_reader = reader.getExpression(); - expression_ = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); - } - property_name_ = reader.getPropertyName().cStr(); - auto storage_property_reader = reader.getProperty(); - storage::Load(&property_, storage_property_reader); -} - -PropertyLookup *PropertyLookup::Construct( - const capnp::PropertyLookup::Reader &reader, AstStorage *storage) { - return storage->Create(nullptr, "", storage::Property()); -} - -// Reduce -void Reduce::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initReduce(); - Save(&builder, saved_uids); -} - -void Reduce::Save(capnp::Reduce::Builder *builder, - std::vector *saved_uids) { - auto acc_builder = builder->initAccumulator(); - accumulator_->Save(&acc_builder, saved_uids); - auto init_builder = builder->initInitializer(); - initializer_->Save(&init_builder, saved_uids); - auto id_builder = builder->initIdentifier(); - identifier_->Save(&id_builder, saved_uids); - auto list_builder = builder->initList(); - list_->Save(&list_builder, saved_uids); - auto expr_builder = builder->initExpression(); - expression_->Save(&expr_builder, saved_uids); -} - -void Reduce::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Expression::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getReduce(); - const auto acc_reader = reader.getAccumulator(); - accumulator_ = - dynamic_cast(storage->Load(acc_reader, loaded_uids)); - const auto init_reader = reader.getInitializer(); - initializer_ = - dynamic_cast(storage->Load(init_reader, loaded_uids)); - const auto id_reader = reader.getIdentifier(); - identifier_ = - dynamic_cast(storage->Load(id_reader, loaded_uids)); - const auto list_reader = reader.getList(); - list_ = dynamic_cast(storage->Load(list_reader, loaded_uids)); - const auto expr_reader = reader.getExpression(); - expression_ = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); -} - -Reduce *Reduce::Construct(const capnp::Reduce::Reader &reader, - AstStorage *storage) { - return storage->Create(nullptr, nullptr, nullptr, nullptr, nullptr); -} - -// Extract -void Extract::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initExtract(); - Save(&builder, saved_uids); -} - -void Extract::Save(capnp::Extract::Builder *builder, - std::vector *saved_uids) { - auto id_builder = builder->initIdentifier(); - identifier_->Save(&id_builder, saved_uids); - auto list_builder = builder->initList(); - list_->Save(&list_builder, saved_uids); - auto expr_builder = builder->initExpression(); - expression_->Save(&expr_builder, saved_uids); -} - -void Extract::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Expression::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getExtract(); - const auto id_reader = reader.getIdentifier(); - identifier_ = - dynamic_cast(storage->Load(id_reader, loaded_uids)); - const auto list_reader = reader.getList(); - list_ = dynamic_cast(storage->Load(list_reader, loaded_uids)); - const auto expr_reader = reader.getExpression(); - expression_ = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); -} - -Extract *Extract::Construct(const capnp::Extract::Reader &reader, - AstStorage *storage) { - return storage->Create(nullptr, nullptr, nullptr); -} - -// Single -void Single::Save(capnp::Expression::Builder *expr_builder, - std::vector *saved_uids) { - Expression::Save(expr_builder, saved_uids); - auto builder = expr_builder->initSingle(); - Save(&builder, saved_uids); -} - -void Single::Save(capnp::Single::Builder *builder, - std::vector *saved_uids) { - auto where_builder = builder->initWhere(); - where_->Save(&where_builder, saved_uids); - auto id_builder = builder->initIdentifier(); - identifier_->Save(&id_builder, saved_uids); - auto expr_builder = builder->initListExpression(); - list_expression_->Save(&expr_builder, saved_uids); -} - -void Single::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Expression::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getExpression().getSingle(); - const auto id_reader = reader.getIdentifier(); - identifier_ = - dynamic_cast(storage->Load(id_reader, loaded_uids)); - const auto list_reader = reader.getListExpression(); - list_expression_ = - dynamic_cast(storage->Load(list_reader, loaded_uids)); - const auto where_reader = reader.getWhere(); - where_ = dynamic_cast(storage->Load(where_reader, loaded_uids)); -} - -Single *Single::Construct(const capnp::Single::Reader &reader, - AstStorage *storage) { - return storage->Create(nullptr, nullptr, nullptr); -} - -// Where -void Where::Save(capnp::Tree::Builder *tree_builder, - std::vector *saved_uids) { - Tree::Save(tree_builder, saved_uids); - if (IsSaved(*saved_uids)) { - return; - } - auto builder = tree_builder->initWhere(); - Save(&builder, saved_uids); - AddToSaved(saved_uids); -} - -void Where::Save(capnp::Where::Builder *builder, std::vector *saved_uids) { - if (expression_) { - auto expr_builder = builder->initExpression(); - expression_->Save(&expr_builder, saved_uids); - } -} - -void Where::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Tree::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getWhere(); - if (reader.hasExpression()) { - const auto expr_reader = reader.getExpression(); - expression_ = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); - } -} - -Where *Where::Construct(const capnp::Where::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// Clause. -void Clause::Save(capnp::Tree::Builder *tree_builder, - std::vector *saved_uids) { - Tree::Save(tree_builder, saved_uids); - if (IsSaved(*saved_uids)) { - return; - } - auto clause_builder = tree_builder->initClause(); - Save(&clause_builder, saved_uids); - AddToSaved(saved_uids); -} - -Clause *Clause::Construct(const capnp::Clause::Reader &reader, - AstStorage *storage) { - switch (reader.which()) { - case capnp::Clause::CREATE: { - auto create_reader = reader.getCreate(); - return Create::Construct(create_reader, storage); - } - case capnp::Clause::CREATE_INDEX: { - auto ci_reader = reader.getCreateIndex(); - return CreateIndex::Construct(ci_reader, storage); - } - case capnp::Clause::DELETE: { - auto del_reader = reader.getDelete(); - return Delete::Construct(del_reader, storage); - } - case capnp::Clause::MATCH: { - auto match_reader = reader.getMatch(); - return Match::Construct(match_reader, storage); - } - case capnp::Clause::MERGE: { - auto merge_reader = reader.getMerge(); - return Merge::Construct(merge_reader, storage); - } - case capnp::Clause::REMOVE_LABELS: { - auto rl_reader = reader.getRemoveLabels(); - return RemoveLabels::Construct(rl_reader, storage); - } - case capnp::Clause::REMOVE_PROPERTY: { - auto rp_reader = reader.getRemoveProperty(); - return RemoveProperty::Construct(rp_reader, storage); - } - case capnp::Clause::RETURN: { - auto ret_reader = reader.getReturn(); - return Return::Construct(ret_reader, storage); - } - case capnp::Clause::SET_LABELS: { - auto sl_reader = reader.getSetLabels(); - return SetLabels::Construct(sl_reader, storage); - } - case capnp::Clause::SET_PROPERTY: { - auto sp_reader = reader.getSetProperty(); - return SetProperty::Construct(sp_reader, storage); - } - case capnp::Clause::SET_PROPERTIES: { - auto sp_reader = reader.getSetProperties(); - return SetProperties::Construct(sp_reader, storage); - } - case capnp::Clause::UNWIND: { - auto unwind_reader = reader.getUnwind(); - return Unwind::Construct(unwind_reader, storage); - } - case capnp::Clause::WITH: { - auto with_reader = reader.getWith(); - return With::Construct(with_reader, storage); - } - case capnp::Clause::AUTH_QUERY: { - auto aq_reader = reader.getAuthQuery(); - return AuthQuery::Construct(aq_reader, storage); - } - case capnp::Clause::CREATE_STREAM: { - auto cs_reader = reader.getCreateStream(); - return CreateStream::Construct(cs_reader, storage); - } - case capnp::Clause::DROP_STREAM: { - auto ds_reader = reader.getDropStream(); - return DropStream::Construct(ds_reader, storage); - } - case capnp::Clause::SHOW_STREAMS: { - auto ss_reader = reader.getShowStreams(); - return ShowStreams::Construct(ss_reader, storage); - } - case capnp::Clause::START_STOP_STREAM: { - auto sss_reader = reader.getStartStopStream(); - return StartStopStream::Construct(sss_reader, storage); - } - case capnp::Clause::START_STOP_ALL_STREAMS: { - auto ssas_reader = reader.getStartStopAllStreams(); - return StartStopAllStreams::Construct(ssas_reader, storage); - } - case capnp::Clause::TEST_STREAM: { - auto ts_reader = reader.getTestStream(); - return TestStream::Construct(ts_reader, storage); - } - } -} - -// Create. -void Create::Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) { - Clause::Save(builder, saved_uids); - auto create_builder = builder->initCreate(); - Create::Save(&create_builder, saved_uids); -} - -void Create::Save(capnp::Create::Builder *builder, - std::vector *saved_uids) { - ::capnp::List::Builder tree_builders = - builder->initPatterns(patterns_.size()); - for (size_t i = 0; i < patterns_.size(); ++i) { - auto tree_builder = tree_builders[i]; - patterns_[i]->Save(&tree_builder, saved_uids); - } -} - -void Create::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getCreate(); - for (const auto pattern_reader : reader.getPatterns()) { - auto tree = storage->Load(pattern_reader, loaded_uids); - patterns_.push_back(dynamic_cast(tree)); - } -} - -Create *Create::Construct(const capnp::Create::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// CreateIndex. -void CreateIndex::Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) { - Clause::Save(builder, saved_uids); - auto create_builder = builder->initCreateIndex(); - CreateIndex::Save(&create_builder, saved_uids); -} - -void CreateIndex::Save(capnp::CreateIndex::Builder *builder, - std::vector *saved_uids) { - auto label_builder = builder->getLabel(); - storage::Save(label_, &label_builder); - auto property_builder = builder->getProperty(); - storage::Save(property_, &property_builder); -} - -CreateIndex *CreateIndex::Construct(const capnp::CreateIndex::Reader &reader, - AstStorage *storage) { - auto label_reader = reader.getLabel(); - storage::Label label; - storage::Load(&label, label_reader); - auto property_reader = reader.getProperty(); - storage::Property property; - storage::Load(&property, property_reader); - return storage->Create(label, property); -} - -// CreateStream. -void CreateStream::Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) { - Clause::Save(builder, saved_uids); - auto create_builder = builder->initCreateStream(); - CreateStream::Save(&create_builder, saved_uids); -} - -void CreateStream::Save(capnp::CreateStream::Builder *builder, - std::vector *saved_uids) { - builder->setStreamName(stream_name_); - - auto stream_uri_builder = builder->getStreamUri(); - stream_uri_->Save(&stream_uri_builder, saved_uids); - - auto stream_topic_builder = builder->getStreamTopic(); - stream_topic_->Save(&stream_topic_builder, saved_uids); - - auto transform_uri_builder = builder->getTransformUri(); - transform_uri_->Save(&transform_uri_builder, saved_uids); - - if (batch_interval_in_ms_) { - auto batch_interval_builder = builder->getBatchIntervalInMs(); - batch_interval_in_ms_->Save(&batch_interval_builder, saved_uids); - } - - if (batch_size_) { - auto batch_size_builder = builder->getBatchSize(); - batch_size_->Save(&batch_size_builder, saved_uids); - } -} - -void CreateStream::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getCreateStream(); - stream_name_ = reader.getStreamName(); - - const auto stream_uri_reader = reader.getStreamUri(); - stream_uri_ = - dynamic_cast(storage->Load(stream_uri_reader, loaded_uids)); - - const auto stream_topic_reader = reader.getStreamTopic(); - stream_topic_ = dynamic_cast( - storage->Load(stream_topic_reader, loaded_uids)); - - const auto transform_uri_reader = reader.getTransformUri(); - transform_uri_ = dynamic_cast( - storage->Load(transform_uri_reader, loaded_uids)); - - batch_interval_in_ms_ = nullptr; - if (reader.hasBatchIntervalInMs()) { - const auto batch_interval_reader = reader.getBatchIntervalInMs(); - batch_interval_in_ms_ = dynamic_cast( - storage->Load(batch_interval_reader, loaded_uids)); - } - - batch_size_ = nullptr; - if (reader.hasBatchSize()) { - const auto batch_size_reader = reader.getBatchSize(); - batch_size_ = dynamic_cast( - storage->Load(batch_size_reader, loaded_uids)); - } -} - -CreateStream *CreateStream::Construct(const capnp::CreateStream::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// DropStream. -void DropStream::Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) { - Clause::Save(builder, saved_uids); - auto drop_builder = builder->initDropStream(); - DropStream::Save(&drop_builder, saved_uids); -} - -void DropStream::Save(capnp::DropStream::Builder *builder, - std::vector *saved_uids) { - builder->setStreamName(stream_name_); -} - -void DropStream::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getDropStream(); - stream_name_ = reader.getStreamName(); -} - -DropStream *DropStream::Construct(const capnp::DropStream::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// ShowStreams. -void ShowStreams::Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) { - Clause::Save(builder, saved_uids); - auto show_builder = builder->initShowStreams(); - ShowStreams::Save(&show_builder, saved_uids); -} - -void ShowStreams::Save(capnp::ShowStreams::Builder *builder, - std::vector *saved_uids) {} - -void ShowStreams::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); -} - -ShowStreams *ShowStreams::Construct(const capnp::ShowStreams::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// StartStopStream. -void StartStopStream::Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) { - Clause::Save(builder, saved_uids); - auto start_stop_builder = builder->initStartStopStream(); - StartStopStream::Save(&start_stop_builder, saved_uids); -} - -void StartStopStream::Save(capnp::StartStopStream::Builder *builder, - std::vector *saved_uids) { - builder->setStreamName(stream_name_); - builder->setIsStart(is_start_); - if (limit_batches_) { - auto limit_batches_builder = builder->getLimitBatches(); - limit_batches_->Save(&limit_batches_builder, saved_uids); - } -} - -void StartStopStream::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getStartStopStream(); - stream_name_ = reader.getStreamName(); - is_start_ = reader.getIsStart(); - limit_batches_ = nullptr; - if (reader.hasLimitBatches()) { - const auto limit_batches_reader = reader.getLimitBatches(); - limit_batches_ = dynamic_cast( - storage->Load(limit_batches_reader, loaded_uids)); - } -} - -StartStopStream *StartStopStream::Construct( - const capnp::StartStopStream::Reader &reader, AstStorage *storage) { - return storage->Create(); -} - -// StartStopAllStreams. -void StartStopAllStreams::Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) { - Clause::Save(builder, saved_uids); - auto start_stop_all_builder = builder->initStartStopAllStreams(); - StartStopAllStreams::Save(&start_stop_all_builder, saved_uids); -} - -void StartStopAllStreams::Save(capnp::StartStopAllStreams::Builder *builder, - std::vector *saved_uids) { - builder->setIsStart(is_start_); -} - -void StartStopAllStreams::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, - std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getStartStopAllStreams(); - is_start_ = reader.getIsStart(); -} - -StartStopAllStreams *StartStopAllStreams::Construct( - const capnp::StartStopAllStreams::Reader &reader, AstStorage *storage) { - return storage->Create(); -} - -// TestStream. -void TestStream::Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) { - Clause::Save(builder, saved_uids); - auto test_builder = builder->initTestStream(); - TestStream::Save(&test_builder, saved_uids); -} - -void TestStream::Save(capnp::TestStream::Builder *builder, - std::vector *saved_uids) { - builder->setStreamName(stream_name_); - if (limit_batches_) { - auto limit_batches_builder = builder->getLimitBatches(); - limit_batches_->Save(&limit_batches_builder, saved_uids); - } -} - -void TestStream::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getTestStream(); - stream_name_ = reader.getStreamName(); - limit_batches_ = nullptr; - if (reader.hasLimitBatches()) { - const auto limit_batches_reader = reader.getLimitBatches(); - limit_batches_ = dynamic_cast( - storage->Load(limit_batches_reader, loaded_uids)); - } -} - -TestStream *TestStream::Construct(const capnp::TestStream::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// Delete. -void Delete::Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) { - Clause::Save(builder, saved_uids); - auto del_builder = builder->initDelete(); - Delete::Save(&del_builder, saved_uids); -} - -void Delete::Save(capnp::Delete::Builder *builder, - std::vector *saved_uids) { - ::capnp::List::Builder tree_builders = - builder->initExpressions(expressions_.size()); - for (size_t i = 0; i < expressions_.size(); ++i) { - auto tree_builder = tree_builders[i]; - expressions_[i]->Save(&tree_builder, saved_uids); - } - builder->setDetach(detach_); -} - -void Delete::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getDelete(); - for (const auto tree_reader : reader.getExpressions()) { - auto tree = storage->Load(tree_reader, loaded_uids); - expressions_.push_back(dynamic_cast(tree)); - } - detach_ = reader.getDetach(); -} - -Delete *Delete::Construct(const capnp::Delete::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// Match. -void Match::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initMatch(); - Match::Save(&builder, saved_uids); -} - -void Match::Save(capnp::Match::Builder *builder, std::vector *saved_uids) { - ::capnp::List::Builder tree_builders = - builder->initPatterns(patterns_.size()); - for (size_t i = 0; i < patterns_.size(); ++i) { - auto tree_builder = tree_builders[i]; - patterns_[i]->Save(&tree_builder, saved_uids); - } - - if (where_) { - auto where_builder = builder->initWhere(); - where_->Save(&where_builder, saved_uids); - } - builder->setOptional(optional_); -} - -void Match::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getMatch(); - for (const auto tree_reader : reader.getPatterns()) { - auto tree = storage->Load(tree_reader, loaded_uids); - patterns_.push_back(dynamic_cast(tree)); - } - if (reader.hasWhere()) { - const auto where_reader = reader.getWhere(); - where_ = dynamic_cast(storage->Load(where_reader, loaded_uids)); - } - optional_ = reader.getOptional(); -} - -Match *Match::Construct(const capnp::Match::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// Merge. -void Merge::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initMerge(); - Merge::Save(&builder, saved_uids); -} - -void Merge::Save(capnp::Merge::Builder *builder, std::vector *saved_uids) { - ::capnp::List::Builder match_builder = - builder->initOnMatch(on_match_.size()); - for (size_t i = 0; i < on_match_.size(); ++i) { - auto tree_builder = match_builder[i]; - on_match_[i]->Save(&tree_builder, saved_uids); - } - - ::capnp::List::Builder create_builder = - builder->initOnCreate(on_create_.size()); - for (size_t i = 0; i < on_create_.size(); ++i) { - auto tree_builder = create_builder[i]; - on_create_[i]->Save(&tree_builder, saved_uids); - } - - if (pattern_) { - auto pattern_builder = builder->getPattern(); - pattern_->Save(&pattern_builder, saved_uids); - } -} - -void Merge::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getMerge(); - for (const auto tree_reader : reader.getOnMatch()) { - auto tree = storage->Load(tree_reader, loaded_uids); - on_match_.push_back(dynamic_cast(tree)); - } - - for (const auto tree_reader : reader.getOnCreate()) { - auto tree = storage->Load(tree_reader, loaded_uids); - on_create_.push_back(dynamic_cast(tree)); - } - if (reader.hasPattern()) { - const auto pattern_reader = reader.getPattern(); - pattern_ = - dynamic_cast(storage->Load(pattern_reader, loaded_uids)); - } -} -Merge *Merge::Construct(const capnp::Merge::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// RemoveLabels. -void RemoveLabels::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initRemoveLabels(); - RemoveLabels::Save(&builder, saved_uids); -} - -void RemoveLabels::Save(capnp::RemoveLabels::Builder *builder, - std::vector *saved_uids) { - if (identifier_) { - auto id_builder = builder->getIdentifier(); - identifier_->Save(&id_builder, saved_uids); - } - auto common_builders = builder->initLabels(labels_.size()); - for (size_t i = 0; i < labels_.size(); ++i) { - auto common_builder = common_builders[i]; - storage::Save(labels_[i], &common_builder); - } -} - -void RemoveLabels::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getRemoveLabels(); - if (reader.hasIdentifier()) { - const auto id_reader = reader.getIdentifier(); - identifier_ = - dynamic_cast(storage->Load(id_reader, loaded_uids)); - } - for (auto label_reader : reader.getLabels()) { - storage::Label label; - storage::Load(&label, label_reader); - labels_.push_back(label); - } -} - -RemoveLabels *RemoveLabels::Construct(const capnp::RemoveLabels::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// RemoveProperty. -void RemoveProperty::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initRemoveProperty(); - RemoveProperty::Save(&builder, saved_uids); -} - -void RemoveProperty::Save(capnp::RemoveProperty::Builder *builder, - std::vector *saved_uids) { - if (property_lookup_) { - auto pl_builder = builder->getPropertyLookup(); - property_lookup_->Save(&pl_builder, saved_uids); - } -} - -void RemoveProperty::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getRemoveProperty(); - if (reader.hasPropertyLookup()) { - const auto pl_reader = reader.getPropertyLookup(); - property_lookup_ = - dynamic_cast(storage->Load(pl_reader, loaded_uids)); - } -} - -RemoveProperty *RemoveProperty::Construct( - const capnp::RemoveProperty::Reader &reader, AstStorage *storage) { - return storage->Create(); -} - -// Return. -void Return::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initReturn(); - Return::Save(&builder, saved_uids); -} - -void SaveReturnBody(capnp::ReturnBody::Builder *rb_builder, ReturnBody &body, - std::vector *saved_uids) { - rb_builder->setDistinct(body.distinct); - rb_builder->setAllIdentifiers(body.all_identifiers); - - ::capnp::List::Builder named_expressions = - rb_builder->initNamedExpressions(body.named_expressions.size()); - for (size_t i = 0; i < body.named_expressions.size(); ++i) { - auto tree_builder = named_expressions[i]; - body.named_expressions[i]->Save(&tree_builder, saved_uids); - } - - ::capnp::List::Builder order_by = - rb_builder->initOrderBy(body.order_by.size()); - for (size_t i = 0; i < body.order_by.size(); ++i) { - auto pair_builder = order_by[i]; - auto ordering = body.order_by[i].first == Ordering::ASC - ? capnp::Ordering::ASC - : capnp::Ordering::DESC; - pair_builder.setOrdering(ordering); - auto tree_builder = pair_builder.getExpression(); - body.order_by[i].second->Save(&tree_builder, saved_uids); - } - - if (body.skip) { - auto skip_builder = rb_builder->getSkip(); - body.skip->Save(&skip_builder, saved_uids); - } - if (body.limit) { - auto limit_builder = rb_builder->getLimit(); - body.limit->Save(&limit_builder, saved_uids); - } -} - -void Return::Save(capnp::Return::Builder *builder, - std::vector *saved_uids) { - auto rb_builder = builder->initReturnBody(); - SaveReturnBody(&rb_builder, body_, saved_uids); -} - -void LoadReturnBody(capnp::ReturnBody::Reader &rb_reader, ReturnBody &body, - AstStorage *storage, std::vector *loaded_uids) { - body.distinct = rb_reader.getDistinct(); - body.all_identifiers = rb_reader.getAllIdentifiers(); - - for (const auto tree_reader : rb_reader.getNamedExpressions()) { - auto tree = storage->Load(tree_reader, loaded_uids); - body.named_expressions.push_back(dynamic_cast(tree)); - } - - for (auto pair_reader : rb_reader.getOrderBy()) { - auto ordering = pair_reader.getOrdering() == capnp::Ordering::ASC - ? Ordering::ASC - : Ordering::DESC; - const auto tree_reader = pair_reader.getExpression(); - // TODO Check if expression is null? - auto tree = - dynamic_cast(storage->Load(tree_reader, loaded_uids)); - body.order_by.push_back(std::make_pair(ordering, tree)); - } - - if (rb_reader.hasSkip()) { - const auto skip_reader = rb_reader.getSkip(); - body.skip = - dynamic_cast(storage->Load(skip_reader, loaded_uids)); - } - if (rb_reader.hasLimit()) { - const auto limit_reader = rb_reader.getLimit(); - body.limit = - dynamic_cast(storage->Load(limit_reader, loaded_uids)); - } -} - -void Return::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getReturn(); - auto rb_reader = reader.getReturnBody(); - LoadReturnBody(rb_reader, body_, storage, loaded_uids); -} - -Return *Return::Construct(const capnp::Return::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// SetLabels. -void SetLabels::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initSetLabels(); - SetLabels::Save(&builder, saved_uids); -} - -void SetLabels::Save(capnp::SetLabels::Builder *builder, - std::vector *saved_uids) { - if (identifier_) { - auto id_builder = builder->getIdentifier(); - identifier_->Save(&id_builder, saved_uids); - } - auto common_builders = builder->initLabels(labels_.size()); - for (size_t i = 0; i < labels_.size(); ++i) { - auto common_builder = common_builders[i]; - storage::Save(labels_[i], &common_builder); - } -} - -void SetLabels::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getSetLabels(); - if (reader.hasIdentifier()) { - const auto id_reader = reader.getIdentifier(); - identifier_ = - dynamic_cast(storage->Load(id_reader, loaded_uids)); - } - for (auto label_reader : reader.getLabels()) { - storage::Label label; - storage::Load(&label, label_reader); - labels_.push_back(label); - } -} - -SetLabels *SetLabels::Construct(const capnp::SetLabels::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// SetProperty. -void SetProperty::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initSetProperty(); - SetProperty::Save(&builder, saved_uids); -} - -void SetProperty::Save(capnp::SetProperty::Builder *builder, - std::vector *saved_uids) { - if (property_lookup_) { - auto pl_builder = builder->getPropertyLookup(); - property_lookup_->Save(&pl_builder, saved_uids); - } - if (expression_) { - auto expr_builder = builder->getExpression(); - expression_->Save(&expr_builder, saved_uids); - } -} - -void SetProperty::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getSetProperty(); - if (reader.hasPropertyLookup()) { - const auto pl_reader = reader.getPropertyLookup(); - property_lookup_ = - dynamic_cast(storage->Load(pl_reader, loaded_uids)); - } - if (reader.hasExpression()) { - const auto expr_reader = reader.getExpression(); - expression_ = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); - } -} - -SetProperty *SetProperty::Construct(const capnp::SetProperty::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// SetProperties. -void SetProperties::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initSetProperties(); - SetProperties::Save(&builder, saved_uids); -} - -void SetProperties::Save(capnp::SetProperties::Builder *builder, - std::vector *saved_uids) { - if (identifier_) { - auto id_builder = builder->getIdentifier(); - identifier_->Save(&id_builder, saved_uids); - } - if (expression_) { - auto expr_builder = builder->getExpression(); - expression_->Save(&expr_builder, saved_uids); - } - builder->setUpdate(update_); -} - -void SetProperties::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getSetProperties(); - if (reader.hasIdentifier()) { - const auto id_reader = reader.getIdentifier(); - identifier_ = - dynamic_cast(storage->Load(id_reader, loaded_uids)); - } - if (reader.hasExpression()) { - const auto expr_reader = reader.getExpression(); - expression_ = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); - } - update_ = reader.getUpdate(); -} - -SetProperties *SetProperties::Construct( - const capnp::SetProperties::Reader &reader, AstStorage *storage) { - return storage->Create(); -} - -// Unwind. -void Unwind::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initUnwind(); - Unwind::Save(&builder, saved_uids); -} - -void Unwind::Save(capnp::Unwind::Builder *builder, - std::vector *saved_uids) { - if (named_expression_) { - auto expr_builder = builder->getNamedExpression(); - named_expression_->Save(&expr_builder, saved_uids); - } -} - -void Unwind::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getUnwind(); - if (reader.hasNamedExpression()) { - const auto expr_reader = reader.getNamedExpression(); - named_expression_ = dynamic_cast( - storage->Load(expr_reader, loaded_uids)); - } -} - -Unwind *Unwind::Construct(const capnp::Unwind::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// With. -void With::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initWith(); - With::Save(&builder, saved_uids); -} - -void With::Save(capnp::With::Builder *builder, std::vector *saved_uids) { - if (where_) { - auto where_builder = builder->getWhere(); - where_->Save(&where_builder, saved_uids); - } - auto rb_builder = builder->initReturnBody(); - SaveReturnBody(&rb_builder, body_, saved_uids); -} - -void With::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getClause().getWith(); - if (reader.hasWhere()) { - const auto where_reader = reader.getWhere(); - where_ = dynamic_cast(storage->Load(where_reader, loaded_uids)); - } - auto rb_reader = reader.getReturnBody(); - LoadReturnBody(rb_reader, body_, storage, loaded_uids); -} - -With *With::Construct(const capnp::With::Reader &reader, AstStorage *storage) { - return storage->Create(); -} - -// AuthQuery. -void AuthQuery::Save(capnp::Clause::Builder *clause_builder, - std::vector *saved_uids) { - Clause::Save(clause_builder, saved_uids); - auto builder = clause_builder->initAuthQuery(); - AuthQuery::Save(&builder, saved_uids); -} - -void AuthQuery::Save(capnp::AuthQuery::Builder *builder, - std::vector *saved_uids) { - switch (action_) { - case Action::CREATE_ROLE: - builder->setAction(capnp::AuthQuery::Action::CREATE_ROLE); - break; - case Action::DROP_ROLE: - builder->setAction(capnp::AuthQuery::Action::DROP_ROLE); - break; - case Action::SHOW_ROLES: - builder->setAction(capnp::AuthQuery::Action::SHOW_ROLES); - break; - case Action::CREATE_USER: - builder->setAction(capnp::AuthQuery::Action::CREATE_USER); - break; - case Action::SET_PASSWORD: - builder->setAction(capnp::AuthQuery::Action::SET_PASSWORD); - break; - case Action::DROP_USER: - builder->setAction(capnp::AuthQuery::Action::DROP_USER); - break; - case Action::SHOW_USERS: - builder->setAction(capnp::AuthQuery::Action::SHOW_USERS); - break; - case Action::SET_ROLE: - builder->setAction(capnp::AuthQuery::Action::SET_ROLE); - break; - case Action::CLEAR_ROLE: - builder->setAction(capnp::AuthQuery::Action::CLEAR_ROLE); - break; - case Action::GRANT_PRIVILEGE: - builder->setAction(capnp::AuthQuery::Action::GRANT_PRIVILEGE); - break; - case Action::DENY_PRIVILEGE: - builder->setAction(capnp::AuthQuery::Action::DENY_PRIVILEGE); - break; - case Action::REVOKE_PRIVILEGE: - builder->setAction(capnp::AuthQuery::Action::REVOKE_PRIVILEGE); - break; - case Action::SHOW_PRIVILEGES: - builder->setAction(capnp::AuthQuery::Action::SHOW_PRIVILEGES); - break; - case Action::SHOW_ROLE_FOR_USER: - builder->setAction(capnp::AuthQuery::Action::SHOW_ROLE_FOR_USER); - break; - case Action::SHOW_USERS_FOR_ROLE: - builder->setAction(capnp::AuthQuery::Action::SHOW_USERS_FOR_ROLE); - break; - } - builder->setUser(user_); - builder->setRole(role_); - builder->setUserOrRole(user_or_role_); - if (password_) { - auto password_builder = builder->initPassword(); - password_->Save(&password_builder, saved_uids); - } - ::capnp::List::Builder privileges_builder = - builder->initPrivileges(privileges_.size()); - for (size_t i = 0; i < privileges_.size(); ++i) { - switch (privileges_[i]) { - case Privilege::CREATE: - privileges_builder.set(i, capnp::AuthQuery::Privilege::CREATE); - break; - case Privilege::DELETE: - privileges_builder.set(i, capnp::AuthQuery::Privilege::DELETE); - break; - case Privilege::MATCH: - privileges_builder.set(i, capnp::AuthQuery::Privilege::MATCH); - break; - case Privilege::MERGE: - privileges_builder.set(i, capnp::AuthQuery::Privilege::MERGE); - break; - case Privilege::SET: - privileges_builder.set(i, capnp::AuthQuery::Privilege::SET); - break; - case Privilege::REMOVE: - privileges_builder.set(i, capnp::AuthQuery::Privilege::REMOVE); - break; - case Privilege::INDEX: - privileges_builder.set(i, capnp::AuthQuery::Privilege::INDEX); - break; - case Privilege::AUTH: - privileges_builder.set(i, capnp::AuthQuery::Privilege::AUTH); - break; - case Privilege::STREAM: - privileges_builder.set(i, capnp::AuthQuery::Privilege::STREAM); - break; - } - } -} - -void AuthQuery::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Clause::Load(base_reader, storage, loaded_uids); - auto auth_reader = base_reader.getClause().getAuthQuery(); - switch (auth_reader.getAction()) { - case capnp::AuthQuery::Action::CREATE_ROLE: - action_ = Action::CREATE_ROLE; - break; - case capnp::AuthQuery::Action::DROP_ROLE: - action_ = Action::DROP_ROLE; - break; - case capnp::AuthQuery::Action::SHOW_ROLES: - action_ = Action::SHOW_ROLES; - break; - case capnp::AuthQuery::Action::CREATE_USER: - action_ = Action::CREATE_USER; - break; - case capnp::AuthQuery::Action::SET_PASSWORD: - action_ = Action::SET_PASSWORD; - break; - case capnp::AuthQuery::Action::DROP_USER: - action_ = Action::DROP_USER; - break; - case capnp::AuthQuery::Action::SHOW_USERS: - action_ = Action::SHOW_USERS; - break; - case capnp::AuthQuery::Action::SET_ROLE: - action_ = Action::SET_ROLE; - break; - case capnp::AuthQuery::Action::CLEAR_ROLE: - action_ = Action::CLEAR_ROLE; - break; - case capnp::AuthQuery::Action::GRANT_PRIVILEGE: - action_ = Action::GRANT_PRIVILEGE; - break; - case capnp::AuthQuery::Action::DENY_PRIVILEGE: - action_ = Action::DENY_PRIVILEGE; - break; - case capnp::AuthQuery::Action::REVOKE_PRIVILEGE: - action_ = Action::REVOKE_PRIVILEGE; - break; - case capnp::AuthQuery::Action::SHOW_PRIVILEGES: - action_ = Action::SHOW_PRIVILEGES; - break; - case capnp::AuthQuery::Action::SHOW_ROLE_FOR_USER: - action_ = Action::SHOW_ROLE_FOR_USER; - break; - case capnp::AuthQuery::Action::SHOW_USERS_FOR_ROLE: - action_ = Action::SHOW_USERS_FOR_ROLE; - break; - } - user_ = auth_reader.getUser(); - role_ = auth_reader.getRole(); - user_or_role_ = auth_reader.getUserOrRole(); - if (auth_reader.hasPassword()) { - const auto password_reader = auth_reader.getPassword(); - password_ = - dynamic_cast(storage->Load(password_reader, loaded_uids)); - } - for (const auto &privilege : auth_reader.getPrivileges()) { - switch (privilege) { - case capnp::AuthQuery::Privilege::CREATE: - privileges_.push_back(Privilege::CREATE); - break; - case capnp::AuthQuery::Privilege::DELETE: - privileges_.push_back(Privilege::DELETE); - break; - case capnp::AuthQuery::Privilege::MATCH: - privileges_.push_back(Privilege::MATCH); - break; - case capnp::AuthQuery::Privilege::MERGE: - privileges_.push_back(Privilege::MERGE); - break; - case capnp::AuthQuery::Privilege::SET: - privileges_.push_back(Privilege::SET); - break; - case capnp::AuthQuery::Privilege::REMOVE: - privileges_.push_back(Privilege::REMOVE); - break; - case capnp::AuthQuery::Privilege::INDEX: - privileges_.push_back(Privilege::INDEX); - break; - case capnp::AuthQuery::Privilege::AUTH: - privileges_.push_back(Privilege::AUTH); - break; - case capnp::AuthQuery::Privilege::STREAM: - privileges_.push_back(Privilege::STREAM); - break; - } - } -} - -AuthQuery *AuthQuery::Construct(const capnp::AuthQuery::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// CypherUnion -void CypherUnion::Save(capnp::Tree::Builder *tree_builder, - std::vector *saved_uids) { - Tree::Save(tree_builder, saved_uids); - if (IsSaved(*saved_uids)) { - return; - } - auto builder = tree_builder->initCypherUnion(); - Save(&builder, saved_uids); - AddToSaved(saved_uids); -} - -void CypherUnion::Save(capnp::CypherUnion::Builder *builder, - std::vector *saved_uids) { - if (single_query_) { - auto sq_builder = builder->initSingleQuery(); - single_query_->Save(&sq_builder, saved_uids); - } - builder->setDistinct(distinct_); - auto symbol_builders = builder->initUnionSymbols(union_symbols_.size()); - for (size_t i = 0; i < union_symbols_.size(); ++i) { - auto symbol_builder = symbol_builders[i]; - query::Save(union_symbols_[i], &symbol_builder); - } -} - -void CypherUnion::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Tree::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getCypherUnion(); - if (reader.hasSingleQuery()) { - const auto sq_reader = reader.getSingleQuery(); - single_query_ = - dynamic_cast(storage->Load(sq_reader, loaded_uids)); - } - distinct_ = reader.getDistinct(); - for (auto symbol_reader : reader.getUnionSymbols()) { - Symbol symbol; - query::Load(&symbol, symbol_reader); - union_symbols_.push_back(symbol); - } -} - -CypherUnion *CypherUnion::Construct(const capnp::CypherUnion::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// NamedExpression -void NamedExpression::Save(capnp::Tree::Builder *tree_builder, - std::vector *saved_uids) { - Tree::Save(tree_builder, saved_uids); - if (IsSaved(*saved_uids)) { - return; - } - auto builder = tree_builder->initNamedExpression(); - Save(&builder, saved_uids); - AddToSaved(saved_uids); -} - -void NamedExpression::Save(capnp::NamedExpression::Builder *builder, - std::vector *saved_uids) { - builder->setName(name_); - builder->setTokenPosition(token_position_); - if (expression_) { - auto expr_builder = builder->getExpression(); - expression_->Save(&expr_builder, saved_uids); - } -} - -void NamedExpression::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Tree::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getNamedExpression(); - name_ = reader.getName().cStr(); - token_position_ = reader.getTokenPosition(); - if (reader.hasExpression()) { - const auto expr_reader = reader.getExpression(); - expression_ = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); - } -} - -NamedExpression *NamedExpression::Construct( - const capnp::NamedExpression::Reader &reader, AstStorage *storage) { - return storage->Create(); -} - -// Pattern -void Pattern::Save(capnp::Tree::Builder *tree_builder, - std::vector *saved_uids) { - Tree::Save(tree_builder, saved_uids); - if (IsSaved(*saved_uids)) { - return; - } - auto builder = tree_builder->initPattern(); - Save(&builder, saved_uids); - AddToSaved(saved_uids); -} - -void Pattern::Save(capnp::Pattern::Builder *builder, - std::vector *saved_uids) { - if (identifier_) { - auto id_builder = builder->getIdentifier(); - identifier_->Save(&id_builder, saved_uids); - } - ::capnp::List::Builder tree_builders = - builder->initAtoms(atoms_.size()); - for (size_t i = 0; i < atoms_.size(); ++i) { - auto tree_builder = tree_builders[i]; - atoms_[i]->Save(&tree_builder, saved_uids); - } -} - -void Pattern::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - Tree::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getPattern(); - if (reader.hasIdentifier()) { - const auto id_reader = reader.getIdentifier(); - identifier_ = - dynamic_cast(storage->Load(id_reader, loaded_uids)); - } - for (const auto tree_reader : reader.getAtoms()) { - auto tree = storage->Load(tree_reader, loaded_uids); - atoms_.push_back(dynamic_cast(tree)); - } -} - -Pattern *Pattern::Construct(const capnp::Pattern::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// PatternAtom. -void PatternAtom::Save(capnp::Tree::Builder *tree_builder, - std::vector *saved_uids) { - Tree::Save(tree_builder, saved_uids); - if (IsSaved(*saved_uids)) { - return; - } - auto pattern_builder = tree_builder->initPatternAtom(); - Save(&pattern_builder, saved_uids); - AddToSaved(saved_uids); -} - -void PatternAtom::Save(capnp::PatternAtom::Builder *builder, - std::vector *saved_uids) { - if (identifier_) { - auto id_builder = builder->getIdentifier(); - identifier_->Save(&id_builder, saved_uids); - } -} - -PatternAtom *PatternAtom::Construct(const capnp::PatternAtom::Reader &reader, - AstStorage *storage) { - switch (reader.which()) { - case capnp::PatternAtom::EDGE_ATOM: { - auto edge_reader = reader.getEdgeAtom(); - return EdgeAtom::Construct(edge_reader, storage); - } - case capnp::PatternAtom::NODE_ATOM: { - auto node_reader = reader.getNodeAtom(); - return NodeAtom::Construct(node_reader, storage); - } - } -} - -void PatternAtom::Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) { - Tree::Load(reader, storage, loaded_uids); - auto pa_reader = reader.getPatternAtom(); - if (pa_reader.hasIdentifier()) { - const auto id_reader = pa_reader.getIdentifier(); - identifier_ = - dynamic_cast(storage->Load(id_reader, loaded_uids)); - } -} - -// NodeAtom -void NodeAtom::Save(capnp::PatternAtom::Builder *pattern_builder, - std::vector *saved_uids) { - PatternAtom::Save(pattern_builder, saved_uids); - auto builder = pattern_builder->initNodeAtom(); - Save(&builder, saved_uids); -} - -void NodeAtom::Save(capnp::NodeAtom::Builder *builder, - std::vector *saved_uids) { - ::capnp::List::Builder map_builder = - builder->initProperties(properties_.size()); - size_t i = 0; - for (auto &entry : properties_) { - auto entry_builder = map_builder[i]; - auto key_builder = entry_builder.getKey(); - key_builder.setFirst(entry.first.first); - auto storage_property_builder = key_builder.getSecond(); - storage::Save(entry.first.second, &storage_property_builder); - auto value_builder = entry_builder.getValue(); - if (entry.second) entry.second->Save(&value_builder, saved_uids); - ++i; - } - auto common_builders = builder->initLabels(labels_.size()); - for (size_t i = 0; i < labels_.size(); ++i) { - auto common_builder = common_builders[i]; - storage::Save(labels_[i], &common_builder); - } -} - -void NodeAtom::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - PatternAtom::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getPatternAtom().getNodeAtom(); - for (auto entry_reader : reader.getProperties()) { - auto key_pair_reader = entry_reader.getKey(); - auto key_first = key_pair_reader.getFirst().cStr(); - auto storage_property_reader = key_pair_reader.getSecond(); - storage::Property property; - storage::Load(&property, storage_property_reader); - const auto value_reader = entry_reader.getValue(); - auto value = storage->Load(value_reader, loaded_uids); - auto key = std::make_pair(key_first, property); - // TODO Maybe check if expression is nullptr? - properties_.emplace(key, dynamic_cast(value)); - } - for (auto label_reader : reader.getLabels()) { - storage::Label label; - storage::Load(&label, label_reader); - labels_.push_back(label); - } -} - -NodeAtom *NodeAtom::Construct(const capnp::NodeAtom::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// EdgeAtom -void EdgeAtom::Save(capnp::PatternAtom::Builder *pattern_builder, - std::vector *saved_uids) { - PatternAtom::Save(pattern_builder, saved_uids); - auto builder = pattern_builder->initEdgeAtom(); - Save(&builder, saved_uids); -} - -void SaveLambda(query::EdgeAtom::Lambda &lambda, - capnp::EdgeAtom::Lambda::Builder *builder, - std::vector *saved_uids) { - if (lambda.inner_edge) { - auto ie_builder = builder->getInnerEdge(); - lambda.inner_edge->Save(&ie_builder, saved_uids); - } - if (lambda.inner_node) { - auto in_builder = builder->getInnerNode(); - lambda.inner_node->Save(&in_builder, saved_uids); - } - if (lambda.expression) { - auto expr_builder = builder->getExpression(); - lambda.expression->Save(&expr_builder, saved_uids); - } -} - -void EdgeAtom::Save(capnp::EdgeAtom::Builder *builder, - std::vector *saved_uids) { - switch (type_) { - case Type::BREADTH_FIRST: - builder->setType(capnp::EdgeAtom::Type::BREADTH_FIRST); - break; - case Type::DEPTH_FIRST: - builder->setType(capnp::EdgeAtom::Type::DEPTH_FIRST); - break; - case Type::SINGLE: - builder->setType(capnp::EdgeAtom::Type::SINGLE); - break; - case Type::WEIGHTED_SHORTEST_PATH: - builder->setType(capnp::EdgeAtom::Type::WEIGHTED_SHORTEST_PATH); - break; - } - - switch (direction_) { - case Direction::BOTH: - builder->setDirection(capnp::EdgeAtom::Direction::BOTH); - break; - case Direction::IN: - builder->setDirection(capnp::EdgeAtom::Direction::IN); - break; - case Direction::OUT: - builder->setDirection(capnp::EdgeAtom::Direction::OUT); - break; - } - - auto common_builders = builder->initEdgeTypes(edge_types_.size()); - for (size_t i = 0; i < edge_types_.size(); ++i) { - auto common_builder = common_builders[i]; - storage::Save(edge_types_[i], &common_builder); - } - - ::capnp::List::Builder map_builder = - builder->initProperties(properties_.size()); - size_t i = 0; - for (auto &entry : properties_) { - auto entry_builder = map_builder[i]; - auto key_builder = entry_builder.getKey(); - key_builder.setFirst(entry.first.first); - auto storage_property_builder = key_builder.getSecond(); - storage::Save(entry.first.second, &storage_property_builder); - auto value_builder = entry_builder.getValue(); - if (entry.second) entry.second->Save(&value_builder, saved_uids); - ++i; - } - - if (lower_bound_) { - auto lb_builder = builder->getLowerBound(); - lower_bound_->Save(&lb_builder, saved_uids); - } - if (upper_bound_) { - auto ub_builder = builder->getUpperBound(); - upper_bound_->Save(&ub_builder, saved_uids); - } - - auto filter_builder = builder->initFilterLambda(); - SaveLambda(filter_lambda_, &filter_builder, saved_uids); - auto weight_builder = builder->initWeightLambda(); - SaveLambda(weight_lambda_, &weight_builder, saved_uids); - - if (total_weight_) { - auto total_weight_builder = builder->getTotalWeight(); - total_weight_->Save(&total_weight_builder, saved_uids); - } -} - -void LoadLambda(capnp::EdgeAtom::Lambda::Reader &reader, - query::EdgeAtom::Lambda &lambda, AstStorage *storage, - std::vector *loaded_uids) { - if (reader.hasInnerEdge()) { - const auto ie_reader = reader.getInnerEdge(); - lambda.inner_edge = - dynamic_cast(storage->Load(ie_reader, loaded_uids)); - } - if (reader.hasInnerNode()) { - const auto in_reader = reader.getInnerNode(); - lambda.inner_node = - dynamic_cast(storage->Load(in_reader, loaded_uids)); - } - if (reader.hasExpression()) { - const auto expr_reader = reader.getExpression(); - lambda.expression = - dynamic_cast(storage->Load(expr_reader, loaded_uids)); - } -} - -void EdgeAtom::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) { - PatternAtom::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getPatternAtom().getEdgeAtom(); - switch (reader.getType()) { - case capnp::EdgeAtom::Type::BREADTH_FIRST: - type_ = Type::BREADTH_FIRST; - break; - case capnp::EdgeAtom::Type::DEPTH_FIRST: - type_ = Type::DEPTH_FIRST; - break; - case capnp::EdgeAtom::Type::SINGLE: - type_ = Type::SINGLE; - break; - case capnp::EdgeAtom::Type::WEIGHTED_SHORTEST_PATH: - type_ = Type::WEIGHTED_SHORTEST_PATH; - break; - } - - switch (reader.getDirection()) { - case capnp::EdgeAtom::Direction::BOTH: - direction_ = Direction::BOTH; - break; - case capnp::EdgeAtom::Direction::IN: - direction_ = Direction::IN; - break; - case capnp::EdgeAtom::Direction::OUT: - direction_ = Direction::OUT; - break; - } - - if (reader.hasTotalWeight()) { - const auto id_reader = reader.getTotalWeight(); - total_weight_ = - dynamic_cast(storage->Load(id_reader, loaded_uids)); - } - if (reader.hasLowerBound()) { - const auto lb_reader = reader.getLowerBound(); - lower_bound_ = - dynamic_cast(storage->Load(lb_reader, loaded_uids)); - } - if (reader.hasUpperBound()) { - const auto ub_reader = reader.getUpperBound(); - upper_bound_ = - dynamic_cast(storage->Load(ub_reader, loaded_uids)); - } - auto filter_reader = reader.getFilterLambda(); - LoadLambda(filter_reader, filter_lambda_, storage, loaded_uids); - auto weight_reader = reader.getWeightLambda(); - LoadLambda(weight_reader, weight_lambda_, storage, loaded_uids); - - for (auto entry_reader : reader.getProperties()) { - auto key_pair_reader = entry_reader.getKey(); - auto key_first = key_pair_reader.getFirst().cStr(); - auto storage_property_reader = key_pair_reader.getSecond(); - storage::Property property; - storage::Load(&property, storage_property_reader); - const auto value_reader = entry_reader.getValue(); - auto value = storage->Load(value_reader, loaded_uids); - auto key = std::make_pair(key_first, property); - // TODO Check if expression is null? - properties_.emplace(key, dynamic_cast(value)); - } - - for (auto edge_type_reader : reader.getEdgeTypes()) { - storage::EdgeType edge_type; - storage::Load(&edge_type, edge_type_reader); - edge_types_.push_back(edge_type); - } -} - -EdgeAtom *EdgeAtom::Construct(const capnp::EdgeAtom::Reader &reader, - AstStorage *storage) { - return storage->Create(); -} - -// Query -void Query::Save(capnp::Tree::Builder *tree_builder, - std::vector *saved_uids) { - Tree::Save(tree_builder, saved_uids); - if (IsSaved(*saved_uids)) { - return; - } - auto builder = tree_builder->initQuery(); - Save(&builder, saved_uids); - AddToSaved(saved_uids); -} - -void Query::Save(capnp::Query::Builder *builder, std::vector *saved_uids) { - builder->setExplain(explain_); - if (single_query_) { - auto sq_builder = builder->initSingleQuery(); - single_query_->Save(&sq_builder, saved_uids); - } - ::capnp::List::Builder tree_builders = - builder->initCypherUnions(cypher_unions_.size()); - for (size_t i = 0; i < cypher_unions_.size(); ++i) { - auto tree_builder = tree_builders[i]; - cypher_unions_[i]->Save(&tree_builder, saved_uids); - } -} - -void Query::Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) { - Tree::Load(reader, storage, loaded_uids); - auto query_reader = reader.getQuery(); - explain_ = query_reader.getExplain(); - if (query_reader.hasSingleQuery()) { - const auto sq_reader = query_reader.getSingleQuery(); - single_query_ = - dynamic_cast(storage->Load(sq_reader, loaded_uids)); - } - for (const auto tree_reader : query_reader.getCypherUnions()) { - auto tree = storage->Load(tree_reader, loaded_uids); - cypher_unions_.push_back(dynamic_cast(tree)); - } -} - -// SingleQuery -void SingleQuery::Save(capnp::Tree::Builder *tree_builder, - std::vector *saved_uids) { - Tree::Save(tree_builder, saved_uids); - if (IsSaved(*saved_uids)) { - return; - } - auto builder = tree_builder->initSingleQuery(); - Save(&builder, saved_uids); - AddToSaved(saved_uids); -} - -void SingleQuery::Save(capnp::SingleQuery::Builder *builder, - std::vector *saved_uids) { - ::capnp::List::Builder tree_builders = - builder->initClauses(clauses_.size()); - for (size_t i = 0; i < clauses_.size(); ++i) { - auto tree_builder = tree_builders[i]; - clauses_[i]->Save(&tree_builder, saved_uids); - } -} - -void SingleQuery::Load(const capnp::Tree::Reader &base_reader, - AstStorage *storage, std::vector *loaded_uids) { - Tree::Load(base_reader, storage, loaded_uids); - auto reader = base_reader.getSingleQuery(); - for (const auto tree_reader : reader.getClauses()) { - auto tree = storage->Load(tree_reader, loaded_uids); - clauses_.push_back(dynamic_cast(tree)); - } -} - -SingleQuery *SingleQuery::Construct(const capnp::SingleQuery::Reader &reader, - AstStorage *storage) { - return storage->Create(); + storage_.clear(); + std::unique_ptr root; + ::query::Load(&root, tree, this, loaded_uids); + root_idx_ = storage_.size(); + storage_.emplace_back(std::move(root)); + return storage_[root_idx_].get(); } } // namespace query diff --git a/src/query/frontend/ast/ast.hpp b/src/query/frontend/ast/ast.hpp deleted file mode 100644 index 1ca0487d4..000000000 --- a/src/query/frontend/ast/ast.hpp +++ /dev/null @@ -1,2644 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "query/frontend/ast/ast_visitor.hpp" -#include "query/frontend/semantic/symbol.hpp" -#include "query/interpret/awesome_memgraph_functions.hpp" -#include "query/typed_value.hpp" -#include "storage/property_value.hpp" -#include "storage/types.hpp" -#include "utils/serialization.hpp" - -#include "ast.capnp.h" - -// Hash function for the key in pattern atom property maps. -namespace std { -template <> -struct hash> { - size_t operator()( - const std::pair &pair) const { - return string_hash(pair.first) ^ property_hash(pair.second); - }; - - private: - std::hash string_hash{}; - std::hash property_hash{}; -}; -} // namespace std - -namespace database { -class GraphDbAccessor; -} - -namespace query { - -#define CLONE_BINARY_EXPRESSION \ - auto Clone(AstStorage &storage) const->std::remove_const< \ - std::remove_pointer::type>::type *override { \ - return storage.Create< \ - std::remove_cv::type>::type>( \ - expression1_->Clone(storage), expression2_->Clone(storage)); \ - } -#define CLONE_UNARY_EXPRESSION \ - auto Clone(AstStorage &storage) const->std::remove_const< \ - std::remove_pointer::type>::type *override { \ - return storage.Create< \ - std::remove_cv::type>::type>( \ - expression_->Clone(storage)); \ - } - -class Context; -class Tree; - -// It would be better to call this AstTree, but we already have a class Tree, -// which could be renamed to Node or AstTreeNode, but we also have a class -// called NodeAtom... -class AstStorage { - public: - AstStorage(); - AstStorage(const AstStorage &) = delete; - AstStorage &operator=(const AstStorage &) = delete; - AstStorage(AstStorage &&) = default; - AstStorage &operator=(AstStorage &&) = default; - - template - T *Create(Args &&... args) { - // Never call create for a Query. Call query() instead. - static_assert(!std::is_same::value, "Call query() instead"); - T *p = new T(next_uid_++, std::forward(args)...); - storage_.emplace_back(p); - return p; - } - - Query *query() const; - - Tree *Load(const capnp::Tree::Reader &tree, std::vector *loaded_uids); - - private: - int next_uid_ = 0; - std::vector> storage_; -}; - -class Tree : public ::utils::Visitable, - ::utils::Visitable> { - friend class AstStorage; - - public: - using ::utils::Visitable::Accept; - using ::utils::Visitable>::Accept; - - int uid() const { return uid_; } - - virtual Tree *Clone(AstStorage &storage) const = 0; - virtual void Save(capnp::Tree::Builder *builder, - std::vector *saved_uids); - - protected: - explicit Tree(int uid) : uid_(uid) {} - - virtual void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids); - bool IsSaved(const std::vector &saved_uids); - void AddToSaved(std::vector *saved_uids); - - private: - int uid_; -}; - -// Expressions - -class Expression : public Tree { - friend class AstStorage; - - public: - Expression *Clone(AstStorage &storage) const override = 0; - static Expression *Construct(const capnp::Expression::Reader &reader, - AstStorage *storage); - - void Save(capnp::Tree::Builder *builder, - std::vector *saved_uids) override; - - protected: - explicit Expression(int uid) : Tree(uid) {} - - virtual void Save(capnp::Expression::Builder *, std::vector *) {} -}; - -class Where : public Tree { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - Where *Clone(AstStorage &storage) const override { - return storage.Create(expression_->Clone(storage)); - } - - static Where *Construct(const capnp::Where::Reader &reader, - AstStorage *storage); - - void Save(capnp::Tree::Builder *builder, - std::vector *saved_uids) override; - - Expression *expression_ = nullptr; - - protected: - explicit Where(int uid) : Tree(uid) {} - Where(int uid, Expression *expression) : Tree(uid), expression_(expression) {} - - virtual void Save(capnp::Where::Builder *, std::vector *saved_uids); - void Load(const capnp::Tree::Reader &tree_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class BinaryOperator : public Expression { - friend class AstStorage; - - public: - Expression *expression1_ = nullptr; - Expression *expression2_ = nullptr; - - BinaryOperator *Clone(AstStorage &storage) const override = 0; - static BinaryOperator *Construct(const capnp::BinaryOperator::Reader &reader, - AstStorage *storage); - - protected: - explicit BinaryOperator(int uid) : Expression(uid) {} - BinaryOperator(int uid, Expression *expression1, Expression *expression2) - : Expression(uid), expression1_(expression1), expression2_(expression2) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - using Expression::Save; - virtual void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class UnaryOperator : public Expression { - friend class AstStorage; - - public: - Expression *expression_ = nullptr; - - UnaryOperator *Clone(AstStorage &storage) const override = 0; - static UnaryOperator *Construct(const capnp::UnaryOperator::Reader &reader, - AstStorage *storage); - - protected: - explicit UnaryOperator(int uid) : Expression(uid) {} - UnaryOperator(int uid, Expression *expression) - : Expression(uid), expression_(expression) {} - - void Save(capnp::Expression::Builder *, - std::vector *saved_uids) override; - using Expression::Save; - virtual void Save(capnp::UnaryOperator::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class OrOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - - static OrOperator *Construct(const capnp::OrOperator::Reader &reader, - AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class XorOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static XorOperator *Construct(const capnp::XorOperator::Reader &reader, - AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class AndOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static AndOperator *Construct(const capnp::AndOperator::Reader &reader, - AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class AdditionOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static AdditionOperator *Construct( - const capnp::AdditionOperator::Reader &reader, AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class SubtractionOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static SubtractionOperator *Construct( - capnp::SubtractionOperator::Reader &reader, AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class MultiplicationOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static MultiplicationOperator *Construct( - capnp::MultiplicationOperator::Reader &reader, AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class DivisionOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static DivisionOperator *Construct( - const capnp::DivisionOperator::Reader &reader, AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class ModOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static ModOperator *Construct(const capnp::ModOperator::Reader &reader, - AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class NotEqualOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static NotEqualOperator *Construct( - const capnp::NotEqualOperator::Reader &reader, AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class EqualOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static EqualOperator *Construct(const capnp::EqualOperator::Reader &reader, - AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class LessOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static LessOperator *Construct(const capnp::LessOperator::Reader &reader, - AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class GreaterOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static GreaterOperator *Construct( - const capnp::GreaterOperator::Reader &reader, AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class LessEqualOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static LessEqualOperator *Construct( - const capnp::LessEqualOperator::Reader &reader, AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class GreaterEqualOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static GreaterEqualOperator *Construct( - const capnp::GreaterEqualOperator::Reader &reader, AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class InListOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static InListOperator *Construct(const capnp::InListOperator::Reader &reader, - AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class SubscriptOperator : public BinaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression1_->Accept(visitor) && expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_BINARY_EXPRESSION; - static SubscriptOperator *Construct(capnp::SubscriptOperator::Reader &reader, - AstStorage *storage); - - protected: - using BinaryOperator::BinaryOperator; - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class ListSlicingOperator : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - bool cont = list_->Accept(visitor); - if (cont && lower_bound_) { - cont = lower_bound_->Accept(visitor); - } - if (cont && upper_bound_) { - upper_bound_->Accept(visitor); - } - } - return visitor.PostVisit(*this); - } - - ListSlicingOperator *Clone(AstStorage &storage) const override { - return storage.Create( - list_->Clone(storage), - lower_bound_ ? lower_bound_->Clone(storage) : nullptr, - upper_bound_ ? upper_bound_->Clone(storage) : nullptr); - } - - static ListSlicingOperator *Construct( - const capnp::ListSlicingOperator::Reader &reader, AstStorage *storage); - - Expression *list_ = nullptr; - Expression *lower_bound_ = nullptr; - Expression *upper_bound_ = nullptr; - - protected: - ListSlicingOperator(int uid, Expression *list, Expression *lower_bound, - Expression *upper_bound) - : Expression(uid), - list_(list), - lower_bound_(lower_bound), - upper_bound_(upper_bound) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - using Expression::Save; - virtual void Save(capnp::ListSlicingOperator::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class IfOperator : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - condition_->Accept(visitor) && then_expression_->Accept(visitor) && - else_expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - IfOperator *Clone(AstStorage &storage) const override { - return storage.Create(condition_->Clone(storage), - then_expression_->Clone(storage), - else_expression_->Clone(storage)); - } - - static IfOperator *Construct(const capnp::IfOperator::Reader &reader, - AstStorage *storage); - // None of the expressions should be nullptrs. If there is no else_expression - // you probably want to make it NULL PrimitiveLiteral. - Expression *condition_; - Expression *then_expression_; - Expression *else_expression_; - - protected: - IfOperator(int uid, Expression *condition, Expression *then_expression, - Expression *else_expression) - : Expression(uid), - condition_(condition), - then_expression_(then_expression), - else_expression_(else_expression) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - using Expression::Save; - virtual void Save(capnp::IfOperator::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class NotOperator : public UnaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_UNARY_EXPRESSION; - static NotOperator *Construct(const capnp::NotOperator::Reader &reader, - AstStorage *storage); - - protected: - using UnaryOperator::UnaryOperator; - void Save(capnp::UnaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class UnaryPlusOperator : public UnaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_UNARY_EXPRESSION; - static UnaryPlusOperator *Construct( - const capnp::UnaryPlusOperator::Reader &reader, AstStorage *storage); - - protected: - using UnaryOperator::UnaryOperator; - void Save(capnp::UnaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class UnaryMinusOperator : public UnaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_UNARY_EXPRESSION; - static UnaryMinusOperator *Construct( - capnp::UnaryMinusOperator::Reader &reader, AstStorage *storage); - - protected: - using UnaryOperator::UnaryOperator; - void Save(capnp::UnaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class IsNullOperator : public UnaryOperator { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - CLONE_UNARY_EXPRESSION; - static IsNullOperator *Construct(const capnp::IsNullOperator::Reader &reader, - AstStorage *storage); - - protected: - using UnaryOperator::UnaryOperator; - void Save(capnp::UnaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class BaseLiteral : public Expression { - friend class AstStorage; - - public: - BaseLiteral *Clone(AstStorage &storage) const override = 0; - static BaseLiteral *Construct(const capnp::BaseLiteral::Reader &reader, - AstStorage *storage); - - protected: - explicit BaseLiteral(int uid) : Expression(uid) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - using Expression::Save; - virtual void Save(capnp::BaseLiteral::Builder *, - std::vector *saved_uids) {} -}; - -class PrimitiveLiteral : public BaseLiteral { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - PrimitiveLiteral *Clone(AstStorage &storage) const override { - return storage.Create(value_, token_position_); - } - - static PrimitiveLiteral *Construct( - const capnp::PrimitiveLiteral::Reader &reader, AstStorage *storage); - - PropertyValue value_; - // This field contains token position of literal used to create - // PrimitiveLiteral object. If PrimitiveLiteral object is not created from - // query leave its value at -1. - int token_position_ = -1; - - protected: - explicit PrimitiveLiteral(int uid) : BaseLiteral(uid) {} - template - PrimitiveLiteral(int uid, T value) : BaseLiteral(uid), value_(value) {} - template - PrimitiveLiteral(int uid, T value, int token_position) - : BaseLiteral(uid), value_(value), token_position_(token_position) {} - - void Save(capnp::BaseLiteral::Builder *builder, - std::vector *saved_uids) override; - void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class ListLiteral : public BaseLiteral { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - for (auto expr_ptr : elements_) - if (!expr_ptr->Accept(visitor)) break; - } - return visitor.PostVisit(*this); - } - - ListLiteral *Clone(AstStorage &storage) const override { - auto *list = storage.Create(); - for (auto *element : elements_) { - list->elements_.push_back(element->Clone(storage)); - } - return list; - } - - static ListLiteral *Construct(const capnp::ListLiteral::Reader &reader, - AstStorage *storage); - - std::vector elements_; - - protected: - explicit ListLiteral(int uid) : BaseLiteral(uid) {} - ListLiteral(int uid, const std::vector &elements) - : BaseLiteral(uid), elements_(elements) {} - - void Save(capnp::BaseLiteral::Builder *builder, - std::vector *saved_uids) override; - void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class MapLiteral : public BaseLiteral { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - for (auto pair : elements_) - if (!pair.second->Accept(visitor)) break; - } - return visitor.PostVisit(*this); - } - - MapLiteral *Clone(AstStorage &storage) const override { - auto *map = storage.Create(); - for (auto pair : elements_) - map->elements_.emplace(pair.first, pair.second->Clone(storage)); - return map; - } - - static MapLiteral *Construct(const capnp::MapLiteral::Reader &reader, - AstStorage *storage); - - // maps (property_name, property) to expressions - std::unordered_map, Expression *> - elements_; - - protected: - explicit MapLiteral(int uid) : BaseLiteral(uid) {} - MapLiteral(int uid, - const std::unordered_map, - Expression *> &elements) - : BaseLiteral(uid), elements_(elements) {} - - void Save(capnp::BaseLiteral::Builder *builder, - std::vector *saved_uids) override; - void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class Identifier : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - Identifier *Clone(AstStorage &storage) const override { - return storage.Create(name_, user_declared_); - } - - static Identifier *Construct(const capnp::Identifier::Reader &reader, - AstStorage *storage); - using Expression::Save; - - std::string name_; - bool user_declared_ = true; - - protected: - Identifier(int uid, const std::string &name) : Expression(uid), name_(name) {} - Identifier(int uid, const std::string &name, bool user_declared) - : Expression(uid), name_(name), user_declared_(user_declared) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::Identifier::Builder *builder, - std::vector *saved_uids); -}; - -class PropertyLookup : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - PropertyLookup *Clone(AstStorage &storage) const override { - return storage.Create(expression_->Clone(storage), - property_name_, property_); - } - - static PropertyLookup *Construct(const capnp::PropertyLookup::Reader &reader, - AstStorage *storage); - using Expression::Save; - - Expression *expression_ = nullptr; - std::string property_name_; - storage::Property property_; - - protected: - PropertyLookup(int uid, Expression *expression, - const std::string &property_name, storage::Property property) - : Expression(uid), - expression_(expression), - property_name_(property_name), - property_(property) {} - PropertyLookup(int uid, Expression *expression, - const std::pair &property) - : Expression(uid), - expression_(expression), - property_name_(property.first), - property_(property.second) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::PropertyLookup::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class LabelsTest : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - LabelsTest *Clone(AstStorage &storage) const override { - return storage.Create(expression_->Clone(storage), labels_); - } - - static LabelsTest *Construct(const capnp::LabelsTest::Reader &reader, - AstStorage *storage); - using Expression::Save; - - Expression *expression_ = nullptr; - std::vector labels_; - - protected: - LabelsTest(int uid, Expression *expression, - const std::vector &labels) - : Expression(uid), expression_(expression), labels_(labels) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::LabelsTest::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &tree_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class Function : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - for (auto *argument : arguments_) { - if (!argument->Accept(visitor)) break; - } - } - return visitor.PostVisit(*this); - } - - Function *Clone(AstStorage &storage) const override { - std::vector arguments; - for (auto *argument : arguments_) { - arguments.push_back(argument->Clone(storage)); - } - return storage.Create(function_name_, arguments); - } - - static Function *Construct(const capnp::Function::Reader &reader, - AstStorage *storage); - - const auto &function() const { return function_; } - const auto &function_name() const { return function_name_; } - std::vector arguments_; - - protected: - explicit Function(int uid) : Expression(uid) {} - - Function(int uid, const std::string &function_name, - const std::vector &arguments) - : Expression(uid), - arguments_(arguments), - function_name_(function_name), - function_(NameToFunction(function_name_)) { - DCHECK(function_) << "Unexpected missing function: " << function_name_; - } - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - using Expression::Save; - virtual void Save(capnp::Function::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &tree_reader, AstStorage *storage, - std::vector *loaded_uids) override; - - private: - std::string function_name_; - std::function - function_; -}; - -class Aggregation : public BinaryOperator { - friend class AstStorage; - - public: - enum class Op { COUNT, MIN, MAX, SUM, AVG, COLLECT_LIST, COLLECT_MAP }; - static const constexpr char *const kCount = "COUNT"; - static const constexpr char *const kMin = "MIN"; - static const constexpr char *const kMax = "MAX"; - static const constexpr char *const kSum = "SUM"; - static const constexpr char *const kAvg = "AVG"; - static const constexpr char *const kCollect = "COLLECT"; - - static std::string OpToString(Op op) { - const char *op_strings[] = {kCount, kMin, kMax, kSum, - kAvg, kCollect, kCollect}; - return op_strings[static_cast(op)]; - } - - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - if (expression1_) expression1_->Accept(visitor); - if (expression2_) expression2_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - Aggregation *Clone(AstStorage &storage) const override { - return storage.Create( - expression1_ ? expression1_->Clone(storage) : nullptr, - expression2_ ? expression2_->Clone(storage) : nullptr, op_); - } - - Op op_; - static Aggregation *Construct(const capnp::Aggregation::Reader &, - AstStorage *storage); - - protected: - // Use only for serialization. - Aggregation(int uid, Op op) : BinaryOperator(uid), op_(op) {} - - /// Aggregation's first expression is the value being aggregated. The second - /// expression is the key used only in COLLECT_MAP. - Aggregation(int uid, Expression *expression1, Expression *expression2, Op op) - : BinaryOperator(uid, expression1, expression2), op_(op) { - // COUNT without expression denotes COUNT(*) in cypher. - DCHECK(expression1 || op == Aggregation::Op::COUNT) - << "All aggregations, except COUNT require expression"; - DCHECK((expression2 == nullptr) ^ (op == Aggregation::Op::COLLECT_MAP)) - << "The second expression is obligatory in COLLECT_MAP and " - "invalid otherwise"; - } - - void Save(capnp::BinaryOperator::Builder *builder, - std::vector *saved_uids) override; -}; - -class Reduce : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - accumulator_->Accept(visitor) && initializer_->Accept(visitor) && - identifier_->Accept(visitor) && list_->Accept(visitor) && - expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - Reduce *Clone(AstStorage &storage) const override { - return storage.Create( - accumulator_->Clone(storage), initializer_->Clone(storage), - identifier_->Clone(storage), list_->Clone(storage), - expression_->Clone(storage)); - } - - static Reduce *Construct(const capnp::Reduce::Reader &reader, - AstStorage *storage); - using Expression::Save; - - // None of these should be nullptr after construction. - - /// Identifier for the accumulating variable - Identifier *accumulator_ = nullptr; - /// Expression which produces the initial accumulator value. - Expression *initializer_ = nullptr; - /// Identifier for the list element. - Identifier *identifier_ = nullptr; - /// Expression which produces a list which will be reduced. - Expression *list_ = nullptr; - /// Expression which does the reduction, i.e. produces the new accumulator - /// value. - Expression *expression_ = nullptr; - - protected: - Reduce(int uid, Identifier *accumulator, Expression *initializer, - Identifier *identifier, Expression *list, Expression *expression) - : Expression(uid), - accumulator_(accumulator), - initializer_(initializer), - identifier_(identifier), - list_(list), - expression_(expression) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::Reduce::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &tree_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class Extract : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - identifier_->Accept(visitor) && list_->Accept(visitor) && - expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - Extract *Clone(AstStorage &storage) const override { - return storage.Create(identifier_->Clone(storage), - list_->Clone(storage), - expression_->Clone(storage)); - } - - static Extract *Construct(const capnp::Extract::Reader &reader, - AstStorage *storage); - using Expression::Save; - - // None of these should be nullptr after construction. - - /// Identifier for the list element. - Identifier *identifier_ = nullptr; - /// Expression which produces a list which will be extracted. - Expression *list_ = nullptr; - /// Expression which produces the new value for list element. - Expression *expression_ = nullptr; - - protected: - Extract(int uid, Identifier *identifier, Expression *list, - Expression *expression) - : Expression(uid), - identifier_(identifier), - list_(list), - expression_(expression) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::Extract::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &tree_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -// TODO: Think about representing All and Any as Reduce. -class All : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - identifier_->Accept(visitor) && list_expression_->Accept(visitor) && - where_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - All *Clone(AstStorage &storage) const override { - return storage.Create(identifier_->Clone(storage), - list_expression_->Clone(storage), - where_->Clone(storage)); - } - - static All *Construct(const capnp::All::Reader &reader, AstStorage *storage); - - // None of these should be nullptr after construction. - Identifier *identifier_ = nullptr; - Expression *list_expression_ = nullptr; - Where *where_ = nullptr; - - protected: - All(int uid, Identifier *identifier, Expression *list_expression, - Where *where) - : Expression(uid), - identifier_(identifier), - list_expression_(list_expression), - where_(where) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - using Expression::Save; - virtual void Save(capnp::All::Builder *builder, std::vector *saved_uids); - void Load(const capnp::Tree::Reader &tree_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -// TODO: This is pretty much copy pasted from All. Consider merging Reduce, -// All, Any and Single into something like a higher-order function call which -// takes a list argument and a function which is applied on list elements. -class Single : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - identifier_->Accept(visitor) && list_expression_->Accept(visitor) && - where_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - Single *Clone(AstStorage &storage) const override { - return storage.Create(identifier_->Clone(storage), - list_expression_->Clone(storage), - where_->Clone(storage)); - } - - static Single *Construct(const capnp::Single::Reader &reader, - AstStorage *storage); - using Expression::Save; - - // None of these should be nullptr after construction. - Identifier *identifier_ = nullptr; - Expression *list_expression_ = nullptr; - Where *where_ = nullptr; - - protected: - Single(int uid, Identifier *identifier, Expression *list_expression, - Where *where) - : Expression(uid), - identifier_(identifier), - list_expression_(list_expression), - where_(where) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::Single::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &tree_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class ParameterLookup : public Expression { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - ParameterLookup *Clone(AstStorage &storage) const override { - return storage.Create(token_position_); - } - - static ParameterLookup *Construct( - const capnp::ParameterLookup::Reader &reader, AstStorage *storage); - using Expression::Save; - - // This field contains token position of *literal* used to create - // ParameterLookup object. If ParameterLookup object is not created from - // a literal leave this value at -1. - int token_position_ = -1; - - protected: - explicit ParameterLookup(int uid) : Expression(uid) {} - ParameterLookup(int uid, int token_position) - : Expression(uid), token_position_(token_position) {} - - void Save(capnp::Expression::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::ParameterLookup::Builder *builder, - std::vector *saved_uids); -}; - -class NamedExpression : public Tree { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - NamedExpression *Clone(AstStorage &storage) const override { - return storage.Create(name_, expression_->Clone(storage), - token_position_); - } - - static NamedExpression *Construct( - const capnp::NamedExpression::Reader &reader, AstStorage *storage); - void Save(capnp::Tree::Builder *builder, - std::vector *saved_uids) override; - - std::string name_; - Expression *expression_ = nullptr; - // This field contains token position of first token in named expression - // used to create name_. If NamedExpression object is not created from - // query or it is aliased leave this value at -1. - int token_position_ = -1; - - protected: - explicit NamedExpression(int uid) : Tree(uid) {} - NamedExpression(int uid, const std::string &name) : Tree(uid), name_(name) {} - NamedExpression(int uid, const std::string &name, Expression *expression) - : Tree(uid), name_(name), expression_(expression) {} - NamedExpression(int uid, const std::string &name, Expression *expression, - int token_position) - : Tree(uid), - name_(name), - expression_(expression), - token_position_(token_position) {} - - virtual void Save(capnp::NamedExpression::Builder *, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -// Pattern atoms - -class PatternAtom : public Tree { - friend class AstStorage; - - public: - Identifier *identifier_ = nullptr; - - PatternAtom *Clone(AstStorage &storage) const override = 0; - - static PatternAtom *Construct(const capnp::PatternAtom::Reader &reader, - AstStorage *storage); - void Save(capnp::Tree::Builder *builder, - std::vector *saved_uids) override; - - protected: - explicit PatternAtom(int uid) : Tree(uid) {} - PatternAtom(int uid, Identifier *identifier) - : Tree(uid), identifier_(identifier) {} - - virtual void Save(capnp::PatternAtom::Builder *, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class NodeAtom : public PatternAtom { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - bool cont = identifier_->Accept(visitor); - for (auto &property : properties_) { - if (cont) { - cont = property.second->Accept(visitor); - } - } - } - return visitor.PostVisit(*this); - } - - NodeAtom *Clone(AstStorage &storage) const override { - auto *node_atom = storage.Create(identifier_->Clone(storage)); - node_atom->labels_ = labels_; - for (auto property : properties_) { - node_atom->properties_[property.first] = property.second->Clone(storage); - } - return node_atom; - } - - static NodeAtom *Construct(const capnp::NodeAtom::Reader &reader, - AstStorage *storage); - using PatternAtom::Save; - - std::vector labels_; - // maps (property_name, property) to an expression - std::unordered_map, Expression *> - properties_; - - protected: - using PatternAtom::PatternAtom; - - void Save(capnp::PatternAtom::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::NodeAtom::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class EdgeAtom : public PatternAtom { - friend class AstStorage; - - template - static TPtr *CloneOpt(TPtr *ptr, AstStorage &storage) { - return ptr ? ptr->Clone(storage) : nullptr; - } - - public: - enum class Type { - SINGLE, - DEPTH_FIRST, - BREADTH_FIRST, - WEIGHTED_SHORTEST_PATH - }; - enum class Direction { IN, OUT, BOTH }; - - /// Lambda for use in filtering or weight calculation during variable - /// expands. - struct Lambda { - /// Argument identifier for the edge currently being traversed. - Identifier *inner_edge = nullptr; - /// Argument identifier for the destination node of the edge. - Identifier *inner_node = nullptr; - /// Evaluates the result of the lambda. - Expression *expression = nullptr; - }; - - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - bool cont = identifier_->Accept(visitor); - for (auto &property : properties_) { - if (cont) { - cont = property.second->Accept(visitor); - } - } - if (cont && lower_bound_) { - cont = lower_bound_->Accept(visitor); - } - if (cont && upper_bound_) { - cont = upper_bound_->Accept(visitor); - } - if (cont && total_weight_) { - total_weight_->Accept(visitor); - } - } - return visitor.PostVisit(*this); - } - - EdgeAtom *Clone(AstStorage &storage) const override { - auto *edge_atom = storage.Create(identifier_->Clone(storage)); - edge_atom->direction_ = direction_; - edge_atom->type_ = type_; - edge_atom->edge_types_ = edge_types_; - for (auto property : properties_) { - edge_atom->properties_[property.first] = property.second->Clone(storage); - } - edge_atom->lower_bound_ = CloneOpt(lower_bound_, storage); - edge_atom->upper_bound_ = CloneOpt(upper_bound_, storage); - auto clone_lambda = [&storage](const auto &lambda) { - return Lambda{CloneOpt(lambda.inner_edge, storage), - CloneOpt(lambda.inner_node, storage), - CloneOpt(lambda.expression, storage)}; - }; - edge_atom->filter_lambda_ = clone_lambda(filter_lambda_); - edge_atom->weight_lambda_ = clone_lambda(weight_lambda_); - edge_atom->total_weight_ = CloneOpt(total_weight_, storage); - return edge_atom; - } - - bool IsVariable() const { - switch (type_) { - case Type::DEPTH_FIRST: - case Type::BREADTH_FIRST: - case Type::WEIGHTED_SHORTEST_PATH: - return true; - case Type::SINGLE: - return false; - } - } - - static EdgeAtom *Construct(const capnp::EdgeAtom::Reader &reader, - AstStorage *storage); - using PatternAtom::Save; - - Type type_ = Type::SINGLE; - Direction direction_ = Direction::BOTH; - std::vector edge_types_; - std::unordered_map, Expression *> - properties_; - - // Members used only in variable length expansions. - - /// Evaluates to lower bound in variable length expands. - Expression *lower_bound_ = nullptr; - /// Evaluated to upper bound in variable length expands. - Expression *upper_bound_ = nullptr; - /// Filter lambda for variable length expands. - /// Can have an empty expression, but identifiers must be valid, because an - /// optimization pass may inline other expressions into this lambda. - Lambda filter_lambda_; - /// Used in weighted shortest path. - /// It must have valid expressions and identifiers. In all other expand - /// types, it is empty. - Lambda weight_lambda_; - /// Variable where the total weight for weighted shortest path will be - /// stored. - Identifier *total_weight_ = nullptr; - - protected: - using PatternAtom::PatternAtom; - EdgeAtom(int uid, Identifier *identifier, Type type, Direction direction) - : PatternAtom(uid, identifier), type_(type), direction_(direction) {} - - // Creates an edge atom for a SINGLE expansion with the given . - EdgeAtom(int uid, Identifier *identifier, Type type, Direction direction, - const std::vector &edge_types) - : PatternAtom(uid, identifier), - type_(type), - direction_(direction), - edge_types_(edge_types) {} - - void Save(capnp::PatternAtom::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::EdgeAtom::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class Pattern : public Tree { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - bool cont = identifier_->Accept(visitor); - for (auto &part : atoms_) { - if (cont) { - cont = part->Accept(visitor); - } - } - } - return visitor.PostVisit(*this); - } - - Pattern *Clone(AstStorage &storage) const override { - auto *pattern = storage.Create(); - pattern->identifier_ = identifier_->Clone(storage); - for (auto *atom : atoms_) { - pattern->atoms_.push_back(atom->Clone(storage)); - } - return pattern; - } - - static Pattern *Construct(const capnp::Pattern::Reader &reader, - AstStorage *storage); - void Save(capnp::Tree::Builder *builder, - std::vector *saved_uids) override; - - Identifier *identifier_ = nullptr; - std::vector atoms_; - - protected: - explicit Pattern(int uid) : Tree(uid) {} - - virtual void Save(capnp::Pattern::Builder *, std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -// Clause - -class Clause : public Tree { - friend class AstStorage; - - public: - explicit Clause(int uid) : Tree(uid) {} - - Clause *Clone(AstStorage &storage) const override = 0; - - static Clause *Construct(const capnp::Clause::Reader &reader, - AstStorage *storage); - - void Save(capnp::Tree::Builder *builder, - std::vector *saved_uids) override; - - protected: - virtual void Save(capnp::Clause::Builder *, std::vector *saved_uids) {} -}; - -// SingleQuery - -class SingleQuery : public Tree { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - for (auto &clause : clauses_) { - if (!clause->Accept(visitor)) break; - } - } - return visitor.PostVisit(*this); - } - - SingleQuery *Clone(AstStorage &storage) const override { - auto *single_query = storage.Create(); - for (auto *clause : clauses_) { - single_query->clauses_.push_back(clause->Clone(storage)); - } - return single_query; - } - - static SingleQuery *Construct(const capnp::SingleQuery::Reader &reader, - AstStorage *storage); - - void Save(capnp::Tree::Builder *builder, - std::vector *saved_uids) override; - - std::vector clauses_; - - protected: - explicit SingleQuery(int uid) : Tree(uid) {} - - virtual void Save(capnp::SingleQuery::Builder *, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -// CypherUnion - -class CypherUnion : public Tree { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - single_query_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - CypherUnion *Clone(AstStorage &storage) const override { - auto cypher_union = storage.Create(distinct_); - cypher_union->single_query_ = single_query_->Clone(storage); - cypher_union->union_symbols_ = union_symbols_; - return cypher_union; - } - - static CypherUnion *Construct(const capnp::CypherUnion::Reader &reader, - AstStorage *storage); - void Save(capnp::Tree::Builder *builder, - std::vector *saved_uids) override; - - SingleQuery *single_query_ = nullptr; - bool distinct_ = false; - /// Holds symbols that are created during symbol generation phase. - /// These symbols are used when UNION/UNION ALL combines single query - /// results. - std::vector union_symbols_; - - protected: - explicit CypherUnion(int uid) : Tree(uid) {} - CypherUnion(int uid, bool distinct) : Tree(uid), distinct_(distinct) {} - CypherUnion(int uid, bool distinct, SingleQuery *single_query, - std::vector union_symbols) - : Tree(uid), - single_query_(single_query), - distinct_(distinct), - union_symbols_(union_symbols) {} - - virtual void Save(capnp::CypherUnion::Builder *, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -// Queries - -class Query : public Tree { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - bool should_continue = single_query_->Accept(visitor); - for (auto *cypher_union : cypher_unions_) { - if (should_continue) { - should_continue = cypher_union->Accept(visitor); - } - } - } - return visitor.PostVisit(*this); - } - - // Creates deep copy of whole ast. - Query *Clone(AstStorage &storage) const override { - auto *query = storage.query(); - query->single_query_ = single_query_->Clone(storage); - for (auto *cypher_union : cypher_unions_) { - query->cypher_unions_.push_back(cypher_union->Clone(storage)); - } - query->explain_ = explain_; - return query; - } - - void Load(const capnp::Tree::Reader &reader, AstStorage *storage, - std::vector *loaded_uids) override; - void Save(capnp::Tree::Builder *builder, - std::vector *saved_uids) override; - - /// True if this is an EXPLAIN query - bool explain_ = false; - /// First and potentially only query - SingleQuery *single_query_ = nullptr; - /// Contains remaining queries that should form a union with `single_query_` - std::vector cypher_unions_; - - protected: - explicit Query(int uid) : Tree(uid) {} - - virtual void Save(capnp::Query::Builder *, std::vector *saved_uids); -}; - -// Clauses - -class Create : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - for (auto &pattern : patterns_) { - if (!pattern->Accept(visitor)) break; - } - } - return visitor.PostVisit(*this); - } - - Create *Clone(AstStorage &storage) const override { - auto *create = storage.Create(); - for (auto *pattern : patterns_) { - create->patterns_.push_back(pattern->Clone(storage)); - } - return create; - } - - static Create *Construct(const capnp::Create::Reader &reader, - AstStorage *storage); - using Clause::Save; - - std::vector patterns_; - - protected: - explicit Create(int uid) : Clause(uid) {} - Create(int uid, std::vector patterns) - : Clause(uid), patterns_(patterns) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::Create::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &tree_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class Match : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - bool cont = true; - for (auto &pattern : patterns_) { - if (!pattern->Accept(visitor)) { - cont = false; - break; - } - } - if (cont && where_) { - where_->Accept(visitor); - } - } - return visitor.PostVisit(*this); - } - - Match *Clone(AstStorage &storage) const override { - auto *match = storage.Create(optional_); - for (auto *pattern : patterns_) { - match->patterns_.push_back(pattern->Clone(storage)); - } - match->where_ = where_ ? where_->Clone(storage) : nullptr; - return match; - } - - using Clause::Save; - static Match *Construct(const capnp::Match::Reader &reader, - AstStorage *storage); - - std::vector patterns_; - Where *where_ = nullptr; - bool optional_ = false; - - protected: - explicit Match(int uid) : Clause(uid) {} - Match(int uid, bool optional) : Clause(uid), optional_(optional) {} - Match(int uid, bool optional, Where *where, std::vector patterns) - : Clause(uid), patterns_(patterns), where_(where), optional_(optional) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::Match::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -/// Defines the order for sorting values (ascending or descending). -enum class Ordering { ASC, DESC }; - -/// Contents common to @c Return and @c With clauses. -struct ReturnBody { - /// True if distinct results should be produced. - bool distinct = false; - /// True if asterisk was found in return body - bool all_identifiers = false; - /// Expressions which are used to produce results. - std::vector named_expressions; - /// Expressions used for ordering the results. - std::vector> order_by; - /// Optional expression on how many results to skip. - Expression *skip = nullptr; - /// Optional expression on how much to limit the results. - Expression *limit = nullptr; -}; - -// Deep copy ReturnBody. -// TODO: Think about turning ReturnBody to class and making this -// function class member. -ReturnBody CloneReturnBody(AstStorage &storage, const ReturnBody &body); - -class Return : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - bool cont = true; - for (auto &expr : body_.named_expressions) { - if (!expr->Accept(visitor)) { - cont = false; - break; - } - } - if (cont) { - for (auto &order_by : body_.order_by) { - if (!order_by.second->Accept(visitor)) { - cont = false; - break; - } - } - } - if (cont && body_.skip) cont = body_.skip->Accept(visitor); - if (cont && body_.limit) cont = body_.limit->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - Return *Clone(AstStorage &storage) const override { - auto *ret = storage.Create(); - ret->body_ = CloneReturnBody(storage, body_); - return ret; - } - - using Clause::Save; - static Return *Construct(const capnp::Return::Reader &reader, - AstStorage *storage); - - ReturnBody body_; - - protected: - explicit Return(int uid) : Clause(uid) {} - Return(int uid, ReturnBody &body) : Clause(uid), body_(body) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::Return::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class With : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - bool cont = true; - for (auto &expr : body_.named_expressions) { - if (!expr->Accept(visitor)) { - cont = false; - break; - } - } - if (cont) { - for (auto &order_by : body_.order_by) { - if (!order_by.second->Accept(visitor)) { - cont = false; - break; - } - } - } - if (cont && where_) cont = where_->Accept(visitor); - if (cont && body_.skip) cont = body_.skip->Accept(visitor); - if (cont && body_.limit) cont = body_.limit->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - With *Clone(AstStorage &storage) const override { - auto *with = storage.Create(); - with->body_ = CloneReturnBody(storage, body_); - with->where_ = where_ ? where_->Clone(storage) : nullptr; - return with; - } - - using Clause::Save; - static With *Construct(const capnp::With::Reader &reader, - AstStorage *storage); - - ReturnBody body_; - Where *where_ = nullptr; - - protected: - explicit With(int uid) : Clause(uid) {} - With(int uid, ReturnBody &body, Where *where) - : Clause(uid), body_(body), where_(where) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::With::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class Delete : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - for (auto &expr : expressions_) { - if (!expr->Accept(visitor)) break; - } - } - return visitor.PostVisit(*this); - } - - Delete *Clone(AstStorage &storage) const override { - auto *del = storage.Create(); - for (auto *expression : expressions_) { - del->expressions_.push_back(expression->Clone(storage)); - } - del->detach_ = detach_; - return del; - } - - using Clause::Save; - static Delete *Construct(const capnp::Delete::Reader &reader, - AstStorage *storage); - - std::vector expressions_; - - bool detach_ = false; - - protected: - explicit Delete(int uid) : Clause(uid) {} - Delete(int uid, bool detach, std::vector expressions) - : Clause(uid), expressions_(expressions), detach_(detach) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::Delete::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class SetProperty : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - property_lookup_->Accept(visitor) && expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - SetProperty *Clone(AstStorage &storage) const override { - return storage.Create(property_lookup_->Clone(storage), - expression_->Clone(storage)); - } - - using Clause::Save; - static SetProperty *Construct(const capnp::SetProperty::Reader &reader, - AstStorage *storage); - - PropertyLookup *property_lookup_ = nullptr; - Expression *expression_ = nullptr; - - protected: - explicit SetProperty(int uid) : Clause(uid) {} - SetProperty(int uid, PropertyLookup *property_lookup, Expression *expression) - : Clause(uid), - property_lookup_(property_lookup), - expression_(expression) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::SetProperty::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class SetProperties : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - identifier_->Accept(visitor) && expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - SetProperties *Clone(AstStorage &storage) const override { - return storage.Create(identifier_->Clone(storage), - expression_->Clone(storage), update_); - } - - using Clause::Save; - static SetProperties *Construct(const capnp::SetProperties::Reader &reader, - AstStorage *storage); - - Identifier *identifier_ = nullptr; - Expression *expression_ = nullptr; - bool update_ = false; - - protected: - explicit SetProperties(int uid) : Clause(uid) {} - SetProperties(int uid, Identifier *identifier, Expression *expression, - bool update = false) - : Clause(uid), - identifier_(identifier), - expression_(expression), - update_(update) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::SetProperties::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class SetLabels : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - identifier_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - SetLabels *Clone(AstStorage &storage) const override { - return storage.Create(identifier_->Clone(storage), labels_); - } - - using Clause::Save; - static SetLabels *Construct(const capnp::SetLabels::Reader &reader, - AstStorage *storage); - - Identifier *identifier_ = nullptr; - std::vector labels_; - - protected: - explicit SetLabels(int uid) : Clause(uid) {} - SetLabels(int uid, Identifier *identifier, - const std::vector &labels) - : Clause(uid), identifier_(identifier), labels_(labels) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::SetLabels::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class RemoveProperty : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - property_lookup_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - RemoveProperty *Clone(AstStorage &storage) const override { - return storage.Create(property_lookup_->Clone(storage)); - } - - using Clause::Save; - static RemoveProperty *Construct(const capnp::RemoveProperty::Reader &reader, - AstStorage *storage); - - PropertyLookup *property_lookup_ = nullptr; - - protected: - explicit RemoveProperty(int uid) : Clause(uid) {} - RemoveProperty(int uid, PropertyLookup *property_lookup) - : Clause(uid), property_lookup_(property_lookup) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::RemoveProperty::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class RemoveLabels : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - identifier_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - RemoveLabels *Clone(AstStorage &storage) const override { - return storage.Create(identifier_->Clone(storage), labels_); - } - - using Clause::Save; - static RemoveLabels *Construct(const capnp::RemoveLabels::Reader &reader, - AstStorage *storage); - - Identifier *identifier_ = nullptr; - std::vector labels_; - - protected: - explicit RemoveLabels(int uid) : Clause(uid) {} - RemoveLabels(int uid, Identifier *identifier, - const std::vector &labels) - : Clause(uid), identifier_(identifier), labels_(labels) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::RemoveLabels::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class Merge : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - bool cont = pattern_->Accept(visitor); - if (cont) { - for (auto &set : on_match_) { - if (!set->Accept(visitor)) { - cont = false; - break; - } - } - } - if (cont) { - for (auto &set : on_create_) { - if (!set->Accept(visitor)) { - cont = false; - break; - } - } - } - } - return visitor.PostVisit(*this); - } - - Merge *Clone(AstStorage &storage) const override { - auto *merge = storage.Create(); - merge->pattern_ = pattern_->Clone(storage); - for (auto *on_match : on_match_) { - merge->on_match_.push_back(on_match->Clone(storage)); - } - for (auto *on_create : on_create_) { - merge->on_create_.push_back(on_create->Clone(storage)); - } - return merge; - } - - using Clause::Save; - static Merge *Construct(const capnp::Merge::Reader &reader, - AstStorage *storage); - - Pattern *pattern_ = nullptr; - std::vector on_match_; - std::vector on_create_; - - protected: - explicit Merge(int uid) : Clause(uid) {} - Merge(int uid, Pattern *pattern, std::vector on_match, - std::vector on_create) - : Clause(uid), - pattern_(pattern), - on_match_(on_match), - on_create_(on_create) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::Merge::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class Unwind : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - bool Accept(HierarchicalTreeVisitor &visitor) override { - if (visitor.PreVisit(*this)) { - named_expression_->Accept(visitor); - } - return visitor.PostVisit(*this); - } - - Unwind *Clone(AstStorage &storage) const override { - return storage.Create(named_expression_->Clone(storage)); - } - - using Clause::Save; - static Unwind *Construct(const capnp::Unwind::Reader &reader, - AstStorage *storage); - - NamedExpression *named_expression_ = nullptr; - - protected: - explicit Unwind(int uid) : Clause(uid) {} - - Unwind(int uid, NamedExpression *named_expression) - : Clause(uid), named_expression_(named_expression) { - DCHECK(named_expression) - << "Unwind cannot take nullptr for named_expression"; - } - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::Unwind::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class CreateIndex : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - CreateIndex *Clone(AstStorage &storage) const override { - return storage.Create(label_, property_); - } - - static CreateIndex *Construct(const capnp::CreateIndex::Reader &reader, - AstStorage *storage); - using Clause::Save; - - storage::Label label_; - storage::Property property_; - - protected: - explicit CreateIndex(int uid) : Clause(uid) {} - CreateIndex(int uid, storage::Label label, storage::Property property) - : Clause(uid), label_(label), property_(property) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::CreateIndex::Builder *builder, - std::vector *saved_uids); -}; - -class AuthQuery : public Clause { - friend class AstStorage; - - public: - enum class Action { - CREATE_ROLE, - DROP_ROLE, - SHOW_ROLES, - CREATE_USER, - SET_PASSWORD, - DROP_USER, - SHOW_USERS, - SET_ROLE, - CLEAR_ROLE, - GRANT_PRIVILEGE, - DENY_PRIVILEGE, - REVOKE_PRIVILEGE, - SHOW_PRIVILEGES, - SHOW_ROLE_FOR_USER, - SHOW_USERS_FOR_ROLE - }; - - // When adding new privileges, please add them to the `kPrivilegesAll` - // constant. - enum class Privilege { - CREATE, - DELETE, - MATCH, - MERGE, - SET, - REMOVE, - INDEX, - AUTH, - STREAM - }; - - Action action_; - std::string user_; - std::string role_; - std::string user_or_role_; - Expression *password_{nullptr}; - std::vector privileges_; - - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - AuthQuery *Clone(AstStorage &storage) const override { - return storage.Create( - action_, user_, role_, user_or_role_, - password_ ? password_->Clone(storage) : nullptr, privileges_); - } - - static AuthQuery *Construct(const capnp::AuthQuery::Reader &reader, - AstStorage *storage); - using Clause::Save; - - protected: - explicit AuthQuery(int uid) : Clause(uid) {} - - explicit AuthQuery(int uid, Action action, std::string user, std::string role, - std::string user_or_role, Expression *password, - std::vector privileges) - : Clause(uid), - action_(action), - user_(user), - role_(role), - user_or_role_(user_or_role), - password_(password), - privileges_(privileges) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::AuthQuery::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -// Constant that holds all available privileges. -const std::vector kPrivilegesAll = { - AuthQuery::Privilege::CREATE, AuthQuery::Privilege::DELETE, - AuthQuery::Privilege::MATCH, AuthQuery::Privilege::MERGE, - AuthQuery::Privilege::SET, AuthQuery::Privilege::REMOVE, - AuthQuery::Privilege::INDEX, AuthQuery::Privilege::AUTH, - AuthQuery::Privilege::STREAM}; - -class CreateStream : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - CreateStream *Clone(AstStorage &storage) const override { - return storage.Create( - stream_name_, stream_uri_->Clone(storage), - stream_topic_->Clone(storage), transform_uri_->Clone(storage), - batch_interval_in_ms_ ? batch_interval_in_ms_->Clone(storage) : nullptr, - batch_size_ ? batch_size_->Clone(storage) : nullptr); - } - - static CreateStream *Construct(const capnp::CreateStream::Reader &reader, - AstStorage *storage); - using Clause::Save; - - std::string stream_name_; - Expression *stream_uri_; - Expression *stream_topic_; - Expression *transform_uri_; - Expression *batch_interval_in_ms_; - Expression *batch_size_; - - protected: - explicit CreateStream(int uid) : Clause(uid) {} - CreateStream(int uid, std::string stream_name, Expression *stream_uri, - Expression *stream_topic, Expression *transform_uri, - Expression *batch_interval_in_ms, Expression *batch_size) - : Clause(uid), - stream_name_(std::move(stream_name)), - stream_uri_(stream_uri), - stream_topic_(stream_topic), - transform_uri_(transform_uri), - batch_interval_in_ms_(batch_interval_in_ms), - batch_size_(batch_size) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::CreateStream::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class DropStream : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - DropStream *Clone(AstStorage &storage) const override { - return storage.Create(stream_name_); - } - - static DropStream *Construct(const capnp::DropStream::Reader &reader, - AstStorage *storage); - using Clause::Save; - - std::string stream_name_; - - protected: - explicit DropStream(int uid) : Clause(uid) {} - DropStream(int uid, std::string stream_name) - : Clause(uid), stream_name_(std::move(stream_name)) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::DropStream::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class ShowStreams : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - ShowStreams *Clone(AstStorage &storage) const override { - return storage.Create(); - } - - static ShowStreams *Construct(const capnp::ShowStreams::Reader &reader, - AstStorage *storage); - using Clause::Save; - - protected: - explicit ShowStreams(int uid) : Clause(uid) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::ShowStreams::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class StartStopStream : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - StartStopStream *Clone(AstStorage &storage) const override { - return storage.Create( - stream_name_, is_start_, - limit_batches_ ? limit_batches_->Clone(storage) : nullptr); - } - - static StartStopStream *Construct( - const capnp::StartStopStream::Reader &reader, AstStorage *storage); - using Clause::Save; - - std::string stream_name_; - bool is_start_; - Expression *limit_batches_; - - protected: - explicit StartStopStream(int uid) : Clause(uid) {} - StartStopStream(int uid, std::string stream_name, bool is_start, - Expression *limit_batches) - : Clause(uid), - stream_name_(std::move(stream_name)), - is_start_(is_start), - limit_batches_(limit_batches) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::StartStopStream::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class StartStopAllStreams : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - StartStopAllStreams *Clone(AstStorage &storage) const override { - return storage.Create(is_start_); - } - - static StartStopAllStreams *Construct( - const capnp::StartStopAllStreams::Reader &reader, AstStorage *storage); - using Clause::Save; - - bool is_start_; - - protected: - explicit StartStopAllStreams(int uid) : Clause(uid) {} - StartStopAllStreams(int uid, bool is_start) - : Clause(uid), is_start_(is_start) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::StartStopAllStreams::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -class TestStream : public Clause { - friend class AstStorage; - - public: - DEFVISITABLE(TreeVisitor); - DEFVISITABLE(HierarchicalTreeVisitor); - - TestStream *Clone(AstStorage &storage) const override { - return storage.Create( - stream_name_, - limit_batches_ ? limit_batches_->Clone(storage) : nullptr); - } - - static TestStream *Construct(const capnp::TestStream::Reader &reader, - AstStorage *storage); - using Clause::Save; - - std::string stream_name_; - Expression *limit_batches_; - - protected: - explicit TestStream(int uid) : Clause(uid) {} - TestStream(int uid, std::string stream_name, Expression *limit_batches) - : Clause(uid), - stream_name_(std::move(stream_name)), - limit_batches_(limit_batches) {} - - void Save(capnp::Clause::Builder *builder, - std::vector *saved_uids) override; - virtual void Save(capnp::TestStream::Builder *builder, - std::vector *saved_uids); - void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage, - std::vector *loaded_uids) override; -}; - -#undef CLONE_BINARY_EXPRESSION -#undef CLONE_UNARY_EXPRESSION - -} // namespace query diff --git a/src/query/frontend/ast/ast.lcp b/src/query/frontend/ast/ast.lcp new file mode 100644 index 000000000..212bc29bb --- /dev/null +++ b/src/query/frontend/ast/ast.lcp @@ -0,0 +1,2507 @@ +#>cpp +#pragma once + +#include +#include +#include + +#include "query/frontend/ast/ast_visitor.hpp" +#include "query/frontend/semantic/symbol.hpp" +#include "query/interpret/awesome_memgraph_functions.hpp" +#include "query/typed_value.hpp" +#include "storage/property_value.hpp" +#include "storage/types.hpp" +#include "utils/serialization.hpp" + +#include "ast.capnp.h" + +// Hash function for the key in pattern atom property maps. +namespace std { +template <> +struct hash> { + size_t operator()( + const std::pair &pair) const { + return string_hash(pair.first) ^ property_hash(pair.second); + }; + + private: + std::hash string_hash{}; + std::hash property_hash{}; +}; +} // namespace std + +namespace database { +class GraphDbAccessor; +} + +cpp<# +(lcp:in-impl + #>cpp + #include "storage/serialization.hpp" + cpp<#) + +(lcp:namespace query) +(lcp:capnp-namespace "query") + +(lcp:capnp-import 'storage "/storage/serialization.capnp") +(lcp:capnp-import 'symbol "/query/frontend/semantic/symbol.capnp") +(lcp:capnp-import 'utils "/utils/serialization.capnp") + +(lcp:capnp-type-conversion "PropertyValue" "Storage.PropertyValue") +(lcp:capnp-type-conversion "storage::Label" "Storage.Common") +(lcp:capnp-type-conversion "storage::EdgeType" "Storage.Common") +(lcp:capnp-type-conversion "storage::Property" "Storage.Common") +(lcp:capnp-type-conversion "Symbol" "Symbol.Symbol") + +(defun save-ast-pointer (builder member capnp-name) + #>cpp + if (${member}) { + auto ${capnp-name}_builder = ${builder}->init${capnp-name}(); + Save(*${member}, &${capnp-name}_builder, saved_uids); + } + cpp<#) + +(defun load-ast-pointer (type) + (lambda (reader member capnp-name) + (let ((cpp-type (lcp::cpp-type-name type))) + #>cpp + if (${reader}.has${capnp-name}()) { + std::unique_ptr<${cpp-type}> tmp; + Load(&tmp, ${reader}.get${capnp-name}(), storage, loaded_uids); + ${member} = storage->Take(std::move(tmp)); + } else { + ${member} = nullptr; + } + cpp<#))) + +(defun save-ast-vector (type) + (lcp:capnp-save-vector "capnp::Tree" type + "[saved_uids](auto *builder, const auto &val) { + Save(*val, builder, saved_uids); + }")) + +(defun load-ast-vector (type) + (lcp:capnp-load-vector "capnp::Tree" type + (format + nil + "[storage, loaded_uids](const auto &reader) { + std::unique_ptr<~A> tmp; + Load(&tmp, reader, storage, loaded_uids); + return storage->Take(std::move(tmp)); + }" + (remove #\* type)))) + +(defun save-property-map (builder member capnp-name) + #>cpp + auto entries_builder = ${builder}.initEntries(${member}.size()); + size_t i = 0; + for (const auto &entry : ${member}) { + auto key_builder = entries_builder[i].initKey(); + key_builder.setFirst(entry.first.first); + auto prop_id_builder = key_builder.initSecond(); + storage::Save(entry.first.second, &prop_id_builder); + auto value_builder = entries_builder[i].initValue(); + Save(*entry.second, &value_builder, saved_uids); + ++i; + } + cpp<#) + +(defun load-property-map (reader member capnp-name) + #>cpp + for (const auto &entry : ${reader}.getEntries()) { + std::unique_ptr value; + Load(&value, entry.getValue(), storage, loaded_uids); + std::string prop_name = entry.getKey().getFirst(); + storage::Property prop_id; + storage::Load(&prop_id, entry.getKey().getSecond()); + ${member}.emplace(std::make_pair(prop_name, prop_id), + storage->Take(std::move(value))); + } + cpp<#) + +#>cpp +#define CLONE_BINARY_EXPRESSION \ + auto Clone(AstStorage &storage) const->std::remove_const< \ + std::remove_pointer::type>::type *override { \ + return storage.Create< \ + std::remove_cv::type>::type>( \ + expression1_->Clone(storage), expression2_->Clone(storage)); \ + } +#define CLONE_UNARY_EXPRESSION \ + auto Clone(AstStorage &storage) const->std::remove_const< \ + std::remove_pointer::type>::type *override { \ + return storage.Create< \ + std::remove_cv::type>::type>( \ + expression_->Clone(storage)); \ + } + +class Context; +class Tree; + +// It would be better to call this AstTree, but we already have a class Tree, +// which could be renamed to Node or AstTreeNode, but we also have a class +// called NodeAtom... +class AstStorage { + public: + AstStorage(); + AstStorage(const AstStorage &) = delete; + AstStorage &operator=(const AstStorage &) = delete; + AstStorage(AstStorage &&) = default; + AstStorage &operator=(AstStorage &&) = default; + + template + T *Create(Args &&... args) { + // Never call create for a Query. Call query() instead. + static_assert(!std::is_same::value, "Call query() instead"); + T *ptr = new T(next_uid_++, std::forward(args)...); + std::unique_ptr tmp(ptr); + storage_.emplace_back(std::move(tmp)); + return ptr; + } + + template + T *Take(std::unique_ptr &&node) { + T *ret = node.get(); + storage_.emplace_back(std::move(node)); + return ret; + } + + Query *query() const; + + Tree *Load(const capnp::Tree::Reader &tree, std::vector *loaded_uids); + + private: + int next_uid_ = 0; + size_t root_idx_; + std::vector> storage_; +}; +cpp<# + +(lcp:define-class tree ("::utils::Visitable" + "::utils::Visitable>") + ((uid :int32_t :scope :public)) + (:abstractp t) + (:public + #>cpp + Tree() = default; + + using ::utils::Visitable::Accept; + using ::utils::Visitable>::Accept; + + virtual Tree *Clone(AstStorage &storage) const = 0; + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:protected + #>cpp + explicit Tree(int uid) : uid_(uid) {} + cpp<#) + (:serialize :capnp :base t + :save-args '((saved-uids "std::vector *")) + :load-args '((storage "AstStorage *") + (loaded-uids "std::vector *")))) + +(lcp:define-class expression (tree) + () + (:abstractp t) + (:public + #>cpp + Expression() = default; + + Expression *Clone(AstStorage &storage) const override = 0; + cpp<#) + (:protected + #>cpp + explicit Expression(int uid) : Tree(uid) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class where (tree) + ((expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression"))) + (:public + #>cpp + Where() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + Where *Clone(AstStorage &storage) const override { + return storage.Create(expression_->Clone(storage)); + } + cpp<#) + (:protected + #>cpp + explicit Where(int uid) : Tree(uid) {} + Where(int uid, Expression *expression) : Tree(uid), expression_(expression) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class binary-operator (expression) + ((expression1 "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (expression2 "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression"))) + (:abstractp t) + (:public + #>cpp + BinaryOperator() = default; + + BinaryOperator *Clone(AstStorage &storage) const override = 0; + cpp<#) + (:protected + #>cpp + explicit BinaryOperator(int uid) : Expression(uid) {} + BinaryOperator(int uid, Expression *expression1, Expression *expression2) + : Expression(uid), expression1_(expression1), expression2_(expression2) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class unary-operator (expression) + ((expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression"))) + (:abstractp t) + (:public + #>cpp + UnaryOperator() = default; + + UnaryOperator *Clone(AstStorage &storage) const override = 0; + cpp<#) + (:protected + #>cpp + explicit UnaryOperator(int uid) : Expression(uid) {} + UnaryOperator(int uid, Expression *expression) + : Expression(uid), expression_(expression) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(macrolet ((define-binary-operators () + `(lcp:cpp-list + ,@(loop for op in + '(or-operator xor-operator and-operator addition-operator + subtraction-operator multiplication-operator division-operator + mod-operator not-equal-operator equal-operator less-operator + greater-operator less-equal-operator greater-equal-operator + in-list-operator subscript-operator) + collecting + `(lcp:define-class ,op (binary-operator) + () + (:public + (let ((cpp-name (lcp::cpp-type-name ',op))) + #>cpp + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + CLONE_BINARY_EXPRESSION; + cpp<#)) + (:protected + #>cpp + using BinaryOperator::BinaryOperator; + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)))))) + (define-binary-operators)) + +(macrolet ((define-unary-operators () + `(lcp:cpp-list + ,@(loop for op in + '(not-operator unary-plus-operator + unary-minus-operator is-null-operator) + collecting + `(lcp:define-class ,op (unary-operator) + () + (:public + (let ((cpp-name (lcp::cpp-type-name ',op))) + #>cpp + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + CLONE_UNARY_EXPRESSION; + cpp<#)) + (:protected + #>cpp + using UnaryOperator::UnaryOperator; + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)))))) + (define-unary-operators)) + +(lcp:define-class aggregation (binary-operator) + ((op "Op" :scope :public)) + (:public + (lcp:define-enum op + (count min max sum avg collect-list collect-map) + (:serialize :capnp)) + #>cpp + Aggregation() = default; + + static const constexpr char *const kCount = "COUNT"; + static const constexpr char *const kMin = "MIN"; + static const constexpr char *const kMax = "MAX"; + static const constexpr char *const kSum = "SUM"; + static const constexpr char *const kAvg = "AVG"; + static const constexpr char *const kCollect = "COLLECT"; + + static std::string OpToString(Op op) { + const char *op_strings[] = {kCount, kMin, kMax, kSum, + kAvg, kCollect, kCollect}; + return op_strings[static_cast(op)]; + } + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + if (expression1_) expression1_->Accept(visitor); + if (expression2_) expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + Aggregation *Clone(AstStorage &storage) const override { + return storage.Create( + expression1_ ? expression1_->Clone(storage) : nullptr, + expression2_ ? expression2_->Clone(storage) : nullptr, op_); + } + cpp<#) + (:protected + #>cpp + // Use only for serialization. + Aggregation(int uid, Op op) : BinaryOperator(uid), op_(op) {} + + /// Aggregation's first expression is the value being aggregated. The second + /// expression is the key used only in COLLECT_MAP. + Aggregation(int uid, Expression *expression1, Expression *expression2, Op op) + : BinaryOperator(uid, expression1, expression2), op_(op) { + // COUNT without expression denotes COUNT(*) in cypher. + DCHECK(expression1 || op == Aggregation::Op::COUNT) + << "All aggregations, except COUNT require expression"; + DCHECK((expression2 == nullptr) ^ (op == Aggregation::Op::COLLECT_MAP)) + << "The second expression is obligatory in COLLECT_MAP and " + "invalid otherwise"; + } + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class list-slicing-operator (expression) + ((list "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (lower-bound "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (upper-bound "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression"))) + (:public + #>cpp + ListSlicingOperator() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = list_->Accept(visitor); + if (cont && lower_bound_) { + cont = lower_bound_->Accept(visitor); + } + if (cont && upper_bound_) { + upper_bound_->Accept(visitor); + } + } + return visitor.PostVisit(*this); + } + + ListSlicingOperator *Clone(AstStorage &storage) const override { + return storage.Create( + list_->Clone(storage), + lower_bound_ ? lower_bound_->Clone(storage) : nullptr, + upper_bound_ ? upper_bound_->Clone(storage) : nullptr); + } + cpp<#) + (:protected + #>cpp + ListSlicingOperator(int uid, Expression *list, Expression *lower_bound, + Expression *upper_bound) + : Expression(uid), + list_(list), + lower_bound_(lower_bound), + upper_bound_(upper_bound) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class if-operator (expression) + ((condition "Expression *" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "None of the expressions should be nullptr. If there is no else_expression, you should make it null PrimitiveLiteral.") + (then-expression "Expression *" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (else-expression "Expression *" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression"))) + (:public + #>cpp + IfOperator() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + condition_->Accept(visitor) && then_expression_->Accept(visitor) && + else_expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + IfOperator *Clone(AstStorage &storage) const override { + return storage.Create(condition_->Clone(storage), + then_expression_->Clone(storage), + else_expression_->Clone(storage)); + } + cpp<#) + (:protected + #>cpp + IfOperator(int uid, Expression *condition, Expression *then_expression, + Expression *else_expression) + : Expression(uid), + condition_(condition), + then_expression_(then_expression), + else_expression_(else_expression) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class base-literal (expression) + () + (:abstractp t) + (:public + #>cpp + BaseLiteral() = default; + + BaseLiteral *Clone(AstStorage &storage) const override = 0; + cpp<#) + (:protected + #>cpp + explicit BaseLiteral(int uid) : Expression(uid) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class primitive-literal (base-literal) + ((value "PropertyValue" :scope :public + :capnp-save (lambda (builder member capnp-name) + #>cpp + storage::SaveCapnpPropertyValue(${member}, &${builder}); + cpp<#) + :capnp-load (lambda (reader member capnp-name) + #>cpp + storage::LoadCapnpPropertyValue(${reader}, &${member}); + cpp<#)) + (token-position :int32_t :scope :public :initval -1 + :documentation "This field contains token position of literal used to create PrimitiveLiteral object. If PrimitiveLiteral object is not created from query, leave its value at -1.")) + (:public + #>cpp + PrimitiveLiteral() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + PrimitiveLiteral *Clone(AstStorage &storage) const override { + return storage.Create(value_, token_position_); + } + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:protected + #>cpp + explicit PrimitiveLiteral(int uid) : BaseLiteral(uid) {} + template + PrimitiveLiteral(int uid, T value) : BaseLiteral(uid), value_(value) {} + template + PrimitiveLiteral(int uid, T value, int token_position) + : BaseLiteral(uid), value_(value), token_position_(token_position) {} + cpp<#) + (:serialize :capnp)) + +(lcp:define-class list-literal (base-literal) + ((elements "std::vector" + :scope :public + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "Expression *") + :capnp-load (load-ast-vector "Expression *"))) + (:public + #>cpp + ListLiteral() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto expr_ptr : elements_) + if (!expr_ptr->Accept(visitor)) break; + } + return visitor.PostVisit(*this); + } + + ListLiteral *Clone(AstStorage &storage) const override { + auto *list = storage.Create(); + for (auto *element : elements_) { + list->elements_.push_back(element->Clone(storage)); + } + return list; + } + cpp<#) + (:protected + #>cpp + explicit ListLiteral(int uid) : BaseLiteral(uid) {} + ListLiteral(int uid, const std::vector &elements) + : BaseLiteral(uid), elements_(elements) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class map-literal (base-literal) + ((elements "std::unordered_map, Expression *>" + :capnp-type "Utils.Map(Utils.Pair(Text, Storage.Common), Tree)" + :capnp-save #'save-property-map + :capnp-load #'load-property-map + :scope :public)) + (:public + #>cpp + MapLiteral() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto pair : elements_) + if (!pair.second->Accept(visitor)) break; + } + return visitor.PostVisit(*this); + } + + MapLiteral *Clone(AstStorage &storage) const override { + auto *map = storage.Create(); + for (auto pair : elements_) + map->elements_.emplace(pair.first, pair.second->Clone(storage)); + return map; + } + cpp<#) + (:protected + #>cpp + explicit MapLiteral(int uid) : BaseLiteral(uid) {} + MapLiteral(int uid, + const std::unordered_map, + Expression *> &elements) + : BaseLiteral(uid), elements_(elements) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class identifier (expression) + ((name "std::string" :scope :public) + (user-declared :bool :initval "true" :scope :public)) + (:public + #>cpp + Identifier() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + Identifier *Clone(AstStorage &storage) const override { + return storage.Create(name_, user_declared_); + } + cpp<#) + (:protected + #>cpp + Identifier(int uid, const std::string &name) : Expression(uid), name_(name) {} + Identifier(int uid, const std::string &name, bool user_declared) + : Expression(uid), name_(name), user_declared_(user_declared) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class property-lookup (expression) + ((expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (property-name "std::string" :scope :public) + (property "storage::Property" :scope :public)) + (:public + #>cpp + PropertyLookup() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + PropertyLookup *Clone(AstStorage &storage) const override { + return storage.Create(expression_->Clone(storage), + property_name_, property_); + } + cpp<#) + (:protected + #>cpp + PropertyLookup(int uid, Expression *expression, + const std::string &property_name, storage::Property property) + : Expression(uid), + expression_(expression), + property_name_(property_name), + property_(property) {} + PropertyLookup(int uid, Expression *expression, + const std::pair &property) + : Expression(uid), + expression_(expression), + property_name_(property.first), + property_(property.second) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class labels-test (expression) + ((expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (labels "std::vector" :scope :public + :capnp-save (lcp:capnp-save-vector + "storage::capnp::Common" + "storage::Label") + :capnp-load (lcp:capnp-load-vector + "storage::capnp::Common" + "storage::Label"))) + (:public + #>cpp + LabelsTest() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + LabelsTest *Clone(AstStorage &storage) const override { + return storage.Create(expression_->Clone(storage), labels_); + } + cpp<#) + (:protected + #>cpp + LabelsTest(int uid, Expression *expression, + const std::vector &labels) + : Expression(uid), expression_(expression), labels_(labels) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class function (expression) + ((arguments "std::vector" + :scope :public + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "Expression *") + :capnp-load (load-ast-vector "Expression *")) + (function-name "std::string" :scope :public) + (function "std::function" + :scope :public :capnp-init nil + :capnp-save :dont-save + :capnp-load (lambda (reader member capnp-name) + #>cpp + ${member} = NameToFunction(self->get()->function_name_); + cpp<#))) + (:public + #>cpp + Function() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto *argument : arguments_) { + if (!argument->Accept(visitor)) break; + } + } + return visitor.PostVisit(*this); + } + + Function *Clone(AstStorage &storage) const override { + std::vector arguments; + for (auto *argument : arguments_) { + arguments.push_back(argument->Clone(storage)); + } + return storage.Create(function_name_, arguments); + } + cpp<#) + (:protected + #>cpp + explicit Function(int uid) : Expression(uid) {} + + Function(int uid, const std::string &function_name, + const std::vector &arguments) + : Expression(uid), + arguments_(arguments), + function_name_(function_name), + function_(NameToFunction(function_name_)) { + DCHECK(function_) << "Unexpected missing function: " << function_name_; + } + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class reduce (expression) + ((accumulator "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier") + :documentation "Identifier for the accumulating variable") + (initializer "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "Expression which produces the initial accumulator value.") + (identifier "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier") + :documentation "Identifier for the list element.") + (list "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "Expression which produces a list to be reduced.") + (expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "Expression which does the reduction, i.e. produces the new accumulator value.")) + (:public + #>cpp + Reduce() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + accumulator_->Accept(visitor) && initializer_->Accept(visitor) && + identifier_->Accept(visitor) && list_->Accept(visitor) && + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + Reduce *Clone(AstStorage &storage) const override { + return storage.Create( + accumulator_->Clone(storage), initializer_->Clone(storage), + identifier_->Clone(storage), list_->Clone(storage), + expression_->Clone(storage)); + } + cpp<#) + (:protected + #>cpp + Reduce(int uid, Identifier *accumulator, Expression *initializer, + Identifier *identifier, Expression *list, Expression *expression) + : Expression(uid), + accumulator_(accumulator), + initializer_(initializer), + identifier_(identifier), + list_(list), + expression_(expression) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class extract (expression) + ((identifier "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier") + :documentation "Identifier for the list element.") + (list "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "Expression which produces a list which will be extracted.") + (expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "Expression which produces the new value for list element.")) + (:public + #>cpp + Extract() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor) && list_->Accept(visitor) && + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + Extract *Clone(AstStorage &storage) const override { + return storage.Create(identifier_->Clone(storage), + list_->Clone(storage), + expression_->Clone(storage)); + } + cpp<#) + (:protected + #>cpp + Extract(int uid, Identifier *identifier, Expression *list, + Expression *expression) + : Expression(uid), + identifier_(identifier), + list_(list), + expression_(expression) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class all (expression) + ((identifier "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier")) + (list-expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (where "Where *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Where"))) + (:public + #>cpp + All() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor) && list_expression_->Accept(visitor) && + where_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + All *Clone(AstStorage &storage) const override { + return storage.Create(identifier_->Clone(storage), + list_expression_->Clone(storage), + where_->Clone(storage)); + } + cpp<#) + (:protected + #>cpp + All(int uid, Identifier *identifier, Expression *list_expression, + Where *where) + : Expression(uid), + identifier_(identifier), + list_expression_(list_expression), + where_(where) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +;;;; TODO: This is pretty much copy pasted from All. Consider merging Reduce, +;;;; All, Any and Single into something like a higher-order function call which +;;;; takes a list argument and a function which is applied on list elements. +(lcp:define-class single (expression) + ((identifier "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier")) + (list-expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (where "Where *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Where"))) + (:public + #>cpp + Single() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor) && list_expression_->Accept(visitor) && + where_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + Single *Clone(AstStorage &storage) const override { + return storage.Create(identifier_->Clone(storage), + list_expression_->Clone(storage), + where_->Clone(storage)); + } + cpp<#) + (:protected + #>cpp + Single(int uid, Identifier *identifier, Expression *list_expression, + Where *where) + : Expression(uid), + identifier_(identifier), + list_expression_(list_expression), + where_(where) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class parameter-lookup (expression) + ((token-position :int32_t :initval -1 :scope :public + :documentation "This field contains token position of *literal* used to create ParameterLookup object. If ParameterLookup object is not created from a literal leave this value at -1.")) + (:public + #>cpp + ParameterLookup() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + ParameterLookup *Clone(AstStorage &storage) const override { + return storage.Create(token_position_); + } + cpp<#) + (:protected + #>cpp + explicit ParameterLookup(int uid) : Expression(uid) {} + ParameterLookup(int uid, int token_position) + : Expression(uid), token_position_(token_position) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class named-expression (tree) + ((name "std::string" :scope :public) + (expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (token-position :int32_t :initval -1 :scope :public + :documentation "This field contains token position of first token in named expression used to create name_. If NamedExpression object is not created from query or it is aliased leave this value at -1.")) + (:public + #>cpp + NamedExpression() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + NamedExpression *Clone(AstStorage &storage) const override { + return storage.Create(name_, expression_->Clone(storage), + token_position_); + } + cpp<#) + (:protected + #>cpp + explicit NamedExpression(int uid) : Tree(uid) {} + NamedExpression(int uid, const std::string &name) : Tree(uid), name_(name) {} + NamedExpression(int uid, const std::string &name, Expression *expression) + : Tree(uid), name_(name), expression_(expression) {} + NamedExpression(int uid, const std::string &name, Expression *expression, + int token_position) + : Tree(uid), + name_(name), + expression_(expression), + token_position_(token_position) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class pattern-atom (tree) + ((identifier "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier"))) + (:abstractp t) + (:public + #>cpp + PatternAtom() = default; + + PatternAtom *Clone(AstStorage &storage) const override = 0; + cpp<#) + (:protected + #>cpp + explicit PatternAtom(int uid) : Tree(uid) {} + PatternAtom(int uid, Identifier *identifier) + : Tree(uid), identifier_(identifier) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class node-atom (pattern-atom) + ((labels "std::vector" :scope :public + :capnp-save (lcp:capnp-save-vector + "storage::capnp::Common" + "storage::Label") + :capnp-load (lcp:capnp-load-vector + "storage::capnp::Common" + "storage::Label")) + (properties "std::unordered_map, Expression *>" + :capnp-type "Utils.Map(Utils.Pair(Text, Storage.Common), Tree)" + :capnp-save #'save-property-map + :capnp-load #'load-property-map + :scope :public)) + (:public + #>cpp + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = identifier_->Accept(visitor); + for (auto &property : properties_) { + if (cont) { + cont = property.second->Accept(visitor); + } + } + } + return visitor.PostVisit(*this); + } + + NodeAtom *Clone(AstStorage &storage) const override { + auto *node_atom = storage.Create(identifier_->Clone(storage)); + node_atom->labels_ = labels_; + for (auto property : properties_) { + node_atom->properties_[property.first] = property.second->Clone(storage); + } + return node_atom; + } + cpp<#) + (:protected + #>cpp + using PatternAtom::PatternAtom; + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class edge-atom (pattern-atom) + ((type "Type" :initval "Type::SINGLE" :scope :public) + (direction "Direction" :initval "Direction::BOTH" :scope :public) + (edge-types "std::vector" :scope :public + :capnp-save (lcp:capnp-save-vector + "storage::capnp::Common" + "storage::EdgeType") + :capnp-load (lcp:capnp-load-vector + "storage::capnp::Common" + "storage::EdgeType")) + (properties "std::unordered_map, Expression *>" + :scope :public + :capnp-type "Utils.Map(Utils.Pair(Text, Storage.Common), Tree)" + :capnp-save #'save-property-map + :capnp-load #'load-property-map) + (lower-bound "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "Evaluates to lower bound in variable length expands.") + (upper-bound "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "Evaluated to upper bound in variable length expands.") + (filter-lambda "Lambda" :scope :public + :documentation "Filter lambda for variable length expands. Can have an empty expression, but identifiers must be valid, because an optimization pass may inline other expressions into this lambda.") + (weight-lambda "Lambda" :scope :public + :documentation "Used in weighted shortest path. It must have valid expressions and identifiers. In all other expand types, it is empty.") + (total-weight "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier") + :documentation "Variable where the total weight for weighted shortest path will be stored.")) + (:public + (lcp:define-enum type + (single depth-first breadth-first weighted-shortest-path) + (:serialize :capnp)) + (lcp:define-enum direction + (in out both) + (:serialize :capnp)) + (lcp:define-struct lambda () + ((inner-edge "Identifier *" :initval "nullptr" + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier") + :documentation "Argument identifier for the edge currently being traversed.") + (inner-node "Identifier *" :initval "nullptr" + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier") + :documentation "Argument identifier for the destination node of the edge.") + (expression "Expression *" :initval "nullptr" + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "Evaluates the result of the lambda.")) + (:documentation "Lambda for use in filtering or weight calculation during variable expand.") + (:serialize :capnp + :save-args '((saved-uids "std::vector *")) + :load-args '((storage "AstStorage *") + (loaded-uids "std::vector *")))) + #>cpp + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = identifier_->Accept(visitor); + for (auto &property : properties_) { + if (cont) { + cont = property.second->Accept(visitor); + } + } + if (cont && lower_bound_) { + cont = lower_bound_->Accept(visitor); + } + if (cont && upper_bound_) { + cont = upper_bound_->Accept(visitor); + } + if (cont && total_weight_) { + total_weight_->Accept(visitor); + } + } + return visitor.PostVisit(*this); + } + + EdgeAtom *Clone(AstStorage &storage) const override { + auto *edge_atom = storage.Create(identifier_->Clone(storage)); + edge_atom->direction_ = direction_; + edge_atom->type_ = type_; + edge_atom->edge_types_ = edge_types_; + for (auto property : properties_) { + edge_atom->properties_[property.first] = property.second->Clone(storage); + } + edge_atom->lower_bound_ = CloneOpt(lower_bound_, storage); + edge_atom->upper_bound_ = CloneOpt(upper_bound_, storage); + auto clone_lambda = [&storage](const auto &lambda) { + return Lambda{CloneOpt(lambda.inner_edge, storage), + CloneOpt(lambda.inner_node, storage), + CloneOpt(lambda.expression, storage)}; + }; + edge_atom->filter_lambda_ = clone_lambda(filter_lambda_); + edge_atom->weight_lambda_ = clone_lambda(weight_lambda_); + edge_atom->total_weight_ = CloneOpt(total_weight_, storage); + return edge_atom; + } + + bool IsVariable() const { + switch (type_) { + case Type::DEPTH_FIRST: + case Type::BREADTH_FIRST: + case Type::WEIGHTED_SHORTEST_PATH: + return true; + case Type::SINGLE: + return false; + } + } + cpp<#) + (:protected + #>cpp + using PatternAtom::PatternAtom; + EdgeAtom(int uid, Identifier *identifier, Type type, Direction direction) + : PatternAtom(uid, identifier), type_(type), direction_(direction) {} + + // Creates an edge atom for a SINGLE expansion with the given . + EdgeAtom(int uid, Identifier *identifier, Type type, Direction direction, + const std::vector &edge_types) + : PatternAtom(uid, identifier), + type_(type), + direction_(direction), + edge_types_(edge_types) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + + template + static TPtr *CloneOpt(TPtr *ptr, AstStorage &storage) { + return ptr ? ptr->Clone(storage) : nullptr; + } + cpp<#) + (:serialize :capnp)) + +(lcp:define-class pattern (tree) + ((identifier "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier")) + (atoms "std::vector" + :scope :public + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "PatternAtom *") + :capnp-load (load-ast-vector "PatternAtom *"))) + (:public + #>cpp + Pattern() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = identifier_->Accept(visitor); + for (auto &part : atoms_) { + if (cont) { + cont = part->Accept(visitor); + } + } + } + return visitor.PostVisit(*this); + } + + Pattern *Clone(AstStorage &storage) const override { + auto *pattern = storage.Create(); + pattern->identifier_ = identifier_->Clone(storage); + for (auto *atom : atoms_) { + pattern->atoms_.push_back(atom->Clone(storage)); + } + return pattern; + } + cpp<#) + (:protected + #>cpp + explicit Pattern(int uid) : Tree(uid) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class clause (tree) + () + (:abstractp t) + (:public + #>cpp + Clause() = default; + + Clause *Clone(AstStorage &storage) const override = 0; + cpp<#) + (:protected + #>cpp + explicit Clause(int uid) : Tree(uid) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class single-query (tree) + ((clauses "std::vector" + :scope :public + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "Clause *") + :capnp-load (load-ast-vector "Clause *"))) + (:public + #>cpp + SingleQuery() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto &clause : clauses_) { + if (!clause->Accept(visitor)) break; + } + } + return visitor.PostVisit(*this); + } + + SingleQuery *Clone(AstStorage &storage) const override { + auto *single_query = storage.Create(); + for (auto *clause : clauses_) { + single_query->clauses_.push_back(clause->Clone(storage)); + } + return single_query; + } + cpp<#) + (:protected + #>cpp + explicit SingleQuery(int uid) : Tree(uid) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class cypher-union (tree) + ((single-query "SingleQuery *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "SingleQuery")) + (distinct :bool :initval "false" :scope :public) + (union-symbols "std::vector" :scope :public + :documentation "Holds symbols that are created during symbol generation phase. These symbols are used when UNION/UNION ALL combines single query results.")) + (:public + #>cpp + CypherUnion() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + single_query_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + CypherUnion *Clone(AstStorage &storage) const override { + auto cypher_union = storage.Create(distinct_); + cypher_union->single_query_ = single_query_->Clone(storage); + cypher_union->union_symbols_ = union_symbols_; + return cypher_union; + } + cpp<#) + (:protected + #>cpp + explicit CypherUnion(int uid) : Tree(uid) {} + CypherUnion(int uid, bool distinct) : Tree(uid), distinct_(distinct) {} + CypherUnion(int uid, bool distinct, SingleQuery *single_query, + std::vector union_symbols) + : Tree(uid), + single_query_(single_query), + distinct_(distinct), + union_symbols_(union_symbols) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class query (tree) + ((explain :bool :initval "false" :scope :public + :documentation "True if this is an EXPLAIN query.") + (single-query "SingleQuery *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "SingleQuery") + :documentation "First and potentially only query.") + (cypher-unions "std::vector" + :scope :public + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "CypherUnion *") + :capnp-load (load-ast-vector "CypherUnion *") + :documentation "Contains remaining queries that should form and union with `single_query_`.")) + (:public + #>cpp + Query() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool should_continue = single_query_->Accept(visitor); + for (auto *cypher_union : cypher_unions_) { + if (should_continue) { + should_continue = cypher_union->Accept(visitor); + } + } + } + return visitor.PostVisit(*this); + } + + // Creates deep copy of whole ast. + Query *Clone(AstStorage &storage) const override { + auto *query = storage.query(); + query->single_query_ = single_query_->Clone(storage); + for (auto *cypher_union : cypher_unions_) { + query->cypher_unions_.push_back(cypher_union->Clone(storage)); + } + query->explain_ = explain_; + return query; + } + cpp<#) + (:protected + #>cpp + explicit Query(int uid) : Tree(uid) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class create (clause) + ((patterns "std::vector" + :scope :public + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "Pattern *") + :capnp-load (load-ast-vector "Pattern *"))) + (:public + #>cpp + Create() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto &pattern : patterns_) { + if (!pattern->Accept(visitor)) break; + } + } + return visitor.PostVisit(*this); + } + + Create *Clone(AstStorage &storage) const override { + auto *create = storage.Create(); + for (auto *pattern : patterns_) { + create->patterns_.push_back(pattern->Clone(storage)); + } + return create; + } + cpp<#) + (:protected + #>cpp + explicit Create(int uid) : Clause(uid) {} + Create(int uid, std::vector patterns) + : Clause(uid), patterns_(patterns) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class match (clause) + ((patterns "std::vector" + :scope :public + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "Pattern *") + :capnp-load (load-ast-vector "Pattern *")) + (where "Where *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Where")) + (optional :bool :initval "false" :scope :public)) + (:public + #>cpp + Match() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = true; + for (auto &pattern : patterns_) { + if (!pattern->Accept(visitor)) { + cont = false; + break; + } + } + if (cont && where_) { + where_->Accept(visitor); + } + } + return visitor.PostVisit(*this); + } + + Match *Clone(AstStorage &storage) const override { + auto *match = storage.Create(optional_); + for (auto *pattern : patterns_) { + match->patterns_.push_back(pattern->Clone(storage)); + } + match->where_ = where_ ? where_->Clone(storage) : nullptr; + return match; + } + cpp<#) + (:protected + #>cpp + explicit Match(int uid) : Clause(uid) {} + Match(int uid, bool optional) : Clause(uid), optional_(optional) {} + Match(int uid, bool optional, Where *where, std::vector patterns) + : Clause(uid), patterns_(patterns), where_(where), optional_(optional) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-enum ordering + (asc desc) + (:documentation "Defines the order for sorting values (ascending or descending).") + (:serialize :capnp)) + +(lcp:define-struct sort-item () + ((ordering "Ordering") + (expression "Expression *" + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression"))) + (:serialize :capnp + :save-args '((saved-uids "std::vector *")) + :load-args '((storage "AstStorage *") + (loaded-uids "std::vector *")))) + +(lcp:define-struct return-body () + ((distinct :bool :initval "false" + :documentation "True if distinct results should be produced." + ) + (all-identifiers :bool :initval "false" + :documentation "True if asterisk was found in the return body.") + (named-expressions "std::vector" + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "NamedExpression *") + :capnp-load (load-ast-vector "NamedExpression *") + :documentation "Expressions which are used to produce results.") + (order-by "std::vector" + :capnp-save (lcp:capnp-save-vector + "capnp::SortItem" + "SortItem" + "[saved_uids](auto *builder, const auto &val) { + Save(val, builder, saved_uids); + }") + :capnp-load (lcp:capnp-load-vector + "capnp::SortItem" + "SortItem" + "[storage, loaded_uids](const auto &reader) { + SortItem val; + Load(&val, reader, storage, loaded_uids); + return val; + }") + :documentation "Expressions used for ordering the results.") + (skip "Expression *" :initval "nullptr" + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "Optional expression on how many results to skip.") + (limit "Expression *" :initval "nullptr" + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression") + :documentation "Optional expression on how many results to produce.")) + (:documentation "Contents common to @c Return and @c With clauses.") + (:serialize :capnp + :save-args '((saved-uids "std::vector *")) + :load-args '((storage "AstStorage *") + (loaded-uids "std::vector *")))) + +#>cpp +// Deep copy ReturnBody. +// TODO: Think about turning ReturnBody to class and making this +// function class member. +ReturnBody CloneReturnBody(AstStorage &storage, const ReturnBody &body); +cpp<# + +(lcp:define-class return (clause) + ((body "ReturnBody" :scope :public)) + (:public + #>cpp + Return() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = true; + for (auto &expr : body_.named_expressions) { + if (!expr->Accept(visitor)) { + cont = false; + break; + } + } + if (cont) { + for (auto &order_by : body_.order_by) { + if (!order_by.expression->Accept(visitor)) { + cont = false; + break; + } + } + } + if (cont && body_.skip) cont = body_.skip->Accept(visitor); + if (cont && body_.limit) cont = body_.limit->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + Return *Clone(AstStorage &storage) const override { + auto *ret = storage.Create(); + ret->body_ = CloneReturnBody(storage, body_); + return ret; + } + cpp<#) + (:protected + #>cpp + explicit Return(int uid) : Clause(uid) {} + Return(int uid, ReturnBody &body) : Clause(uid), body_(body) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class with (clause) + ((body "ReturnBody" :scope :public) + (where "Where *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Where"))) + (:public + #>cpp + With() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = true; + for (auto &expr : body_.named_expressions) { + if (!expr->Accept(visitor)) { + cont = false; + break; + } + } + if (cont) { + for (auto &order_by : body_.order_by) { + if (!order_by.expression->Accept(visitor)) { + cont = false; + break; + } + } + } + if (cont && where_) cont = where_->Accept(visitor); + if (cont && body_.skip) cont = body_.skip->Accept(visitor); + if (cont && body_.limit) cont = body_.limit->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + With *Clone(AstStorage &storage) const override { + auto *with = storage.Create(); + with->body_ = CloneReturnBody(storage, body_); + with->where_ = where_ ? where_->Clone(storage) : nullptr; + return with; + } + cpp<#) + (:protected + #>cpp + explicit With(int uid) : Clause(uid) {} + With(int uid, ReturnBody &body, Where *where) + : Clause(uid), body_(body), where_(where) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class delete (clause) + ((expressions "std::vector" + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "Expression *") + :capnp-load (load-ast-vector "Expression *") + :scope :public) + (detach :bool :initval "false" :scope :public)) + (:public + #>cpp + Delete() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto &expr : expressions_) { + if (!expr->Accept(visitor)) break; + } + } + return visitor.PostVisit(*this); + } + + Delete *Clone(AstStorage &storage) const override { + auto *del = storage.Create(); + for (auto *expression : expressions_) { + del->expressions_.push_back(expression->Clone(storage)); + } + del->detach_ = detach_; + return del; + } + cpp<#) + (:protected + #>cpp + explicit Delete(int uid) : Clause(uid) {} + Delete(int uid, bool detach, std::vector expressions) + : Clause(uid), expressions_(expressions), detach_(detach) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class set-property (clause) + ((property-lookup "PropertyLookup *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "PropertyLookup")) + (expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression"))) + (:public + #>cpp + SetProperty() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + property_lookup_->Accept(visitor) && expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + SetProperty *Clone(AstStorage &storage) const override { + return storage.Create(property_lookup_->Clone(storage), + expression_->Clone(storage)); + } + cpp<#) + (:protected + #>cpp + explicit SetProperty(int uid) : Clause(uid) {} + SetProperty(int uid, PropertyLookup *property_lookup, Expression *expression) + : Clause(uid), + property_lookup_(property_lookup), + expression_(expression) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class set-properties (clause) + ((identifier "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier")) + (expression "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (update :bool :initval "false" :scope :public)) + (:public + #>cpp + SetProperties() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor) && expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + SetProperties *Clone(AstStorage &storage) const override { + return storage.Create(identifier_->Clone(storage), + expression_->Clone(storage), update_); + } + cpp<#) + (:protected + #>cpp + explicit SetProperties(int uid) : Clause(uid) {} + SetProperties(int uid, Identifier *identifier, Expression *expression, + bool update = false) + : Clause(uid), + identifier_(identifier), + expression_(expression), + update_(update) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class set-labels (clause) + ((identifier "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier")) + (labels "std::vector" :scope :public + :capnp-save (lcp:capnp-save-vector + "storage::capnp::Common" + "storage::Label") + :capnp-load (lcp:capnp-load-vector + "storage::capnp::Common" + "storage::Label"))) + (:public + #>cpp + SetLabels() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + SetLabels *Clone(AstStorage &storage) const override { + return storage.Create(identifier_->Clone(storage), labels_); + } + cpp<#) + (:protected + #>cpp + explicit SetLabels(int uid) : Clause(uid) {} + SetLabels(int uid, Identifier *identifier, + const std::vector &labels) + : Clause(uid), identifier_(identifier), labels_(labels) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class remove-property (clause) + ((property-lookup "PropertyLookup *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "PropertyLookup"))) + (:public + #>cpp + RemoveProperty() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + property_lookup_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + RemoveProperty *Clone(AstStorage &storage) const override { + return storage.Create(property_lookup_->Clone(storage)); + } + cpp<#) + (:protected + #>cpp + explicit RemoveProperty(int uid) : Clause(uid) {} + RemoveProperty(int uid, PropertyLookup *property_lookup) + : Clause(uid), property_lookup_(property_lookup) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class remove-labels (clause) + ((identifier "Identifier *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Identifier")) + (labels "std::vector" :scope :public + :capnp-save (lcp:capnp-save-vector + "storage::capnp::Common" + "storage::Label") + :capnp-load (lcp:capnp-load-vector + "storage::capnp::Common" + "storage::Label"))) + (:public + #>cpp + RemoveLabels() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + RemoveLabels *Clone(AstStorage &storage) const override { + return storage.Create(identifier_->Clone(storage), labels_); + } + cpp<#) + (:protected + #>cpp + explicit RemoveLabels(int uid) : Clause(uid) {} + RemoveLabels(int uid, Identifier *identifier, + const std::vector &labels) + : Clause(uid), identifier_(identifier), labels_(labels) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class merge (clause) + ((pattern "Pattern *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Pattern")) + (on-match "std::vector" + :scope :public + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "Clause *") + :capnp-load (load-ast-vector "Clause *")) + (on-create "std::vector" + :scope :public + :capnp-type "List(Tree)" + :capnp-save (save-ast-vector "Clause *") + :capnp-load (load-ast-vector "Clause *"))) + (:public + #>cpp + Merge() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = pattern_->Accept(visitor); + if (cont) { + for (auto &set : on_match_) { + if (!set->Accept(visitor)) { + cont = false; + break; + } + } + } + if (cont) { + for (auto &set : on_create_) { + if (!set->Accept(visitor)) { + cont = false; + break; + } + } + } + } + return visitor.PostVisit(*this); + } + + Merge *Clone(AstStorage &storage) const override { + auto *merge = storage.Create(); + merge->pattern_ = pattern_->Clone(storage); + for (auto *on_match : on_match_) { + merge->on_match_.push_back(on_match->Clone(storage)); + } + for (auto *on_create : on_create_) { + merge->on_create_.push_back(on_create->Clone(storage)); + } + return merge; + } + cpp<#) + (:protected + #>cpp + explicit Merge(int uid) : Clause(uid) {} + Merge(int uid, Pattern *pattern, std::vector on_match, + std::vector on_create) + : Clause(uid), + pattern_(pattern), + on_match_(on_match), + on_create_(on_create) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class unwind (clause) + ((named-expression "NamedExpression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "NamedExpression"))) + (:public + #>cpp + Unwind() = default; + + DEFVISITABLE(TreeVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + named_expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + Unwind *Clone(AstStorage &storage) const override { + return storage.Create(named_expression_->Clone(storage)); + } + cpp<#) + (:protected + #>cpp + explicit Unwind(int uid) : Clause(uid) {} + + Unwind(int uid, NamedExpression *named_expression) + : Clause(uid), named_expression_(named_expression) { + DCHECK(named_expression) + << "Unwind cannot take nullptr for named_expression"; + } + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class create-index (clause) + ((label "storage::Label" :scope :public) + (property "storage::Property" :scope :public)) + (:public + #>cpp + CreateIndex() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + CreateIndex *Clone(AstStorage &storage) const override { + return storage.Create(label_, property_); + } + cpp<#) + (:protected + #>cpp + explicit CreateIndex(int uid) : Clause(uid) {} + CreateIndex(int uid, storage::Label label, storage::Property property) + : Clause(uid), label_(label), property_(property) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class auth-query (clause) + ((action "Action" :scope :public) + (user "std::string" :scope :public) + (role "std::string" :scope :public) + (user-or-role "std::string" :scope :public) + (password "Expression *" :initval "nullptr" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (privileges "std::vector" :scope :public + :capnp-save (lambda (builder member capnp-name) + #>cpp + for (size_t i = 0; i < ${member}.size(); ++i) { + switch (${member}[i]) { + case AuthQuery::Privilege::CREATE: + ${builder}.set(i, capnp::AuthQuery::Privilege::CREATE); + break; + case AuthQuery::Privilege::DELETE: + ${builder}.set(i, capnp::AuthQuery::Privilege::DELETE); + break; + case AuthQuery::Privilege::MATCH: + ${builder}.set(i, capnp::AuthQuery::Privilege::MATCH); + break; + case AuthQuery::Privilege::MERGE: + ${builder}.set(i, capnp::AuthQuery::Privilege::MERGE); + break; + case AuthQuery::Privilege::SET: + ${builder}.set(i, capnp::AuthQuery::Privilege::SET); + break; + case AuthQuery::Privilege::REMOVE: + ${builder}.set(i, capnp::AuthQuery::Privilege::REMOVE); + break; + case AuthQuery::Privilege::INDEX: + ${builder}.set(i, capnp::AuthQuery::Privilege::INDEX); + break; + case AuthQuery::Privilege::AUTH: + ${builder}.set(i, capnp::AuthQuery::Privilege::AUTH); + break; + case AuthQuery::Privilege::STREAM: + ${builder}.set(i, capnp::AuthQuery::Privilege::STREAM); + break; + } + } + cpp<#) + :capnp-load (lambda (reader member capnp-name) + #>cpp + ${member}.resize(${reader}.size()); + size_t i = 0; + for (const auto &val : ${reader}) { + switch (val) { + case capnp::AuthQuery::Privilege::CREATE: + ${member}[i] = AuthQuery::Privilege::CREATE; + break; + case capnp::AuthQuery::Privilege::DELETE: + ${member}[i] = AuthQuery::Privilege::DELETE; + break; + case capnp::AuthQuery::Privilege::MATCH: + ${member}[i] = AuthQuery::Privilege::MATCH; + break; + case capnp::AuthQuery::Privilege::MERGE: + ${member}[i] = AuthQuery::Privilege::MERGE; + break; + case capnp::AuthQuery::Privilege::SET: + ${member}[i] = AuthQuery::Privilege::SET; + break; + case capnp::AuthQuery::Privilege::REMOVE: + ${member}[i] = AuthQuery::Privilege::REMOVE; + break; + case capnp::AuthQuery::Privilege::INDEX: + ${member}[i] = AuthQuery::Privilege::INDEX; + break; + case capnp::AuthQuery::Privilege::AUTH: + ${member}[i] = AuthQuery::Privilege::AUTH; + break; + case capnp::AuthQuery::Privilege::STREAM: + ${member}[i] = AuthQuery::Privilege::STREAM; + break; + } + ++i; + } + cpp<#))) + (:public + (lcp:define-enum action + (create-role drop-role show-roles create-user + set-password drop-user show-users set-role + clear-role grant-privilege deny-privilege + revoke-privilege show-privileges + show-role-for-user show-users-for-role) + (:serialize :capnp)) + (lcp:define-enum privilege + (create delete match merge set remove index auth stream) + (:serialize :capnp)) + #>cpp + AuthQuery() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + AuthQuery *Clone(AstStorage &storage) const override { + return storage.Create( + action_, user_, role_, user_or_role_, + password_ ? password_->Clone(storage) : nullptr, privileges_); + } + cpp<#) + (:protected + #>cpp + explicit AuthQuery(int uid) : Clause(uid) {} + + explicit AuthQuery(int uid, Action action, std::string user, std::string role, + std::string user_or_role, Expression *password, + std::vector privileges) + : Clause(uid), + action_(action), + user_(user), + role_(role), + user_or_role_(user_or_role), + password_(password), + privileges_(privileges) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +#>cpp +// Constant that holds all available privileges. +const std::vector kPrivilegesAll = { + AuthQuery::Privilege::CREATE, AuthQuery::Privilege::DELETE, + AuthQuery::Privilege::MATCH, AuthQuery::Privilege::MERGE, + AuthQuery::Privilege::SET, AuthQuery::Privilege::REMOVE, + AuthQuery::Privilege::INDEX, AuthQuery::Privilege::AUTH, + AuthQuery::Privilege::STREAM}; +cpp<# + +(lcp:define-class create-stream (clause) + ((stream-name "std::string" :scope :public) + (stream-uri "Expression *" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (stream-topic "Expression *" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (transform-uri "Expression *" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (batch-interval-in-ms "Expression *" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression")) + (batch-size "Expression *" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression"))) + (:public + #>cpp + CreateStream() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + CreateStream *Clone(AstStorage &storage) const override { + return storage.Create( + stream_name_, stream_uri_->Clone(storage), + stream_topic_->Clone(storage), transform_uri_->Clone(storage), + batch_interval_in_ms_ ? batch_interval_in_ms_->Clone(storage) : nullptr, + batch_size_ ? batch_size_->Clone(storage) : nullptr); + } + cpp<#) + (:protected + #>cpp + explicit CreateStream(int uid) : Clause(uid) {} + CreateStream(int uid, std::string stream_name, Expression *stream_uri, + Expression *stream_topic, Expression *transform_uri, + Expression *batch_interval_in_ms, Expression *batch_size) + : Clause(uid), + stream_name_(std::move(stream_name)), + stream_uri_(stream_uri), + stream_topic_(stream_topic), + transform_uri_(transform_uri), + batch_interval_in_ms_(batch_interval_in_ms), + batch_size_(batch_size) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class drop-stream (clause) + ((stream-name "std::string" :scope :public)) + (:public + #>cpp + DropStream() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + DropStream *Clone(AstStorage &storage) const override { + return storage.Create(stream_name_); + } + cpp<#) + (:protected + #>cpp + explicit DropStream(int uid) : Clause(uid) {} + DropStream(int uid, std::string stream_name) + : Clause(uid), stream_name_(std::move(stream_name)) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class show-streams (clause) + () + (:public + #>cpp + ShowStreams() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + ShowStreams *Clone(AstStorage &storage) const override { + return storage.Create(); + } + cpp<#) + (:protected + #>cpp + explicit ShowStreams(int uid) : Clause(uid) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class start-stop-stream (clause) + ((stream-name "std::string" :scope :public) + (is-start :bool :scope :public) + (limit-batches "Expression *" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression"))) + (:public + #>cpp + StartStopStream() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + StartStopStream *Clone(AstStorage &storage) const override { + return storage.Create( + stream_name_, is_start_, + limit_batches_ ? limit_batches_->Clone(storage) : nullptr); + } + cpp<#) + (:protected + #>cpp + explicit StartStopStream(int uid) : Clause(uid) {} + StartStopStream(int uid, std::string stream_name, bool is_start, + Expression *limit_batches) + : Clause(uid), + stream_name_(std::move(stream_name)), + is_start_(is_start), + limit_batches_(limit_batches) {} + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class start-stop-all-streams (clause) + ((is-start :bool :scope :public)) + (:public + #>cpp + StartStopAllStreams() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + StartStopAllStreams *Clone(AstStorage &storage) const override { + return storage.Create(is_start_); + } + cpp<#) + (:protected + #>cpp + explicit StartStopAllStreams(int uid) : Clause(uid) {} + StartStopAllStreams(int uid, bool is_start) + : Clause(uid), is_start_(is_start) {} + + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +(lcp:define-class test-stream (clause) + ((stream-name "std::string" :scope :public) + (limit-batches "Expression *" :scope :public + :capnp-type "Tree" :capnp-init nil + :capnp-save #'save-ast-pointer + :capnp-load (load-ast-pointer "Expression"))) + (:public + #>cpp + TestStream() = default; + + DEFVISITABLE(TreeVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + TestStream *Clone(AstStorage &storage) const override { + return storage.Create( + stream_name_, + limit_batches_ ? limit_batches_->Clone(storage) : nullptr); + } + + cpp<#) + (:protected + #>cpp + explicit TestStream(int uid) : Clause(uid) {} + TestStream(int uid, std::string stream_name, Expression *limit_batches) + : Clause(uid), + stream_name_(std::move(stream_name)), + limit_batches_(limit_batches) {} + + cpp<#) + (:private + #>cpp + friend class AstStorage; + cpp<#) + (:serialize :capnp)) + +#>cpp +#undef CLONE_BINARY_EXPRESSION +#undef CLONE_UNARY_EXPRESSION +cpp<# + +(lcp:pop-namespace) ; namespace query diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp index c90070cf6..fdf695149 100644 --- a/src/query/frontend/ast/cypher_main_visitor.cpp +++ b/src/query/frontend/ast/cypher_main_visitor.cpp @@ -638,9 +638,7 @@ antlrcpp::Any CypherMainVisitor::visitReturnBody( MemgraphCypher::ReturnBodyContext *ctx) { ReturnBody body; if (ctx->order()) { - body.order_by = ctx->order() - ->accept(this) - .as>>(); + body.order_by = ctx->order()->accept(this).as>(); } if (ctx->skip()) { body.skip = static_cast(ctx->skip()->accept(this)); @@ -684,7 +682,7 @@ antlrcpp::Any CypherMainVisitor::visitReturnItem( } antlrcpp::Any CypherMainVisitor::visitOrder(MemgraphCypher::OrderContext *ctx) { - std::vector> order_by; + std::vector order_by; for (auto *sort_item : ctx->sortItem()) { order_by.push_back(sort_item->accept(this)); } @@ -693,9 +691,9 @@ antlrcpp::Any CypherMainVisitor::visitOrder(MemgraphCypher::OrderContext *ctx) { antlrcpp::Any CypherMainVisitor::visitSortItem( MemgraphCypher::SortItemContext *ctx) { - return std::pair( + return SortItem{ ctx->DESC() || ctx->DESCENDING() ? Ordering::DESC : Ordering::ASC, - ctx->expression()->accept(this)); + ctx->expression()->accept(this)}; } antlrcpp::Any CypherMainVisitor::visitNodePattern( diff --git a/src/query/frontend/ast/cypher_main_visitor.hpp b/src/query/frontend/ast/cypher_main_visitor.hpp index dd6685747..53b960d4c 100644 --- a/src/query/frontend/ast/cypher_main_visitor.hpp +++ b/src/query/frontend/ast/cypher_main_visitor.hpp @@ -358,12 +358,12 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor { MemgraphCypher::ReturnItemContext *ctx) override; /** - * @return vector> + * @return vector */ antlrcpp::Any visitOrder(MemgraphCypher::OrderContext *ctx) override; /** - * @return pair + * @return SortItem */ antlrcpp::Any visitSortItem(MemgraphCypher::SortItemContext *ctx) override; diff --git a/src/query/frontend/semantic/symbol_generator.cpp b/src/query/frontend/semantic/symbol_generator.cpp index 724de43cf..dd38fd3d6 100644 --- a/src/query/frontend/semantic/symbol_generator.cpp +++ b/src/query/frontend/semantic/symbol_generator.cpp @@ -84,7 +84,7 @@ void SymbolGenerator::VisitReturnBody(ReturnBody &body, Where *where) { } scope_.in_order_by = true; for (const auto &order_pair : body.order_by) { - order_pair.second->Accept(*this); + order_pair.expression->Accept(*this); } scope_.in_order_by = false; if (body.skip) { @@ -318,7 +318,7 @@ bool SymbolGenerator::PreVisit(Aggregation &aggr) { // Create a virtual symbol for aggregation result. // Currently, we only have aggregation operators which return numbers. auto aggr_name = - Aggregation::OpToString(aggr.op_) + std::to_string(aggr.uid()); + Aggregation::OpToString(aggr.op_) + std::to_string(aggr.uid_); symbol_table_[aggr] = symbol_table_.CreateSymbol(aggr_name, false, Symbol::Type::Number); scope_.in_aggregation = true; diff --git a/src/query/frontend/semantic/symbol_table.hpp b/src/query/frontend/semantic/symbol_table.hpp index f5b08cd6b..8dc1130da 100644 --- a/src/query/frontend/semantic/symbol_table.hpp +++ b/src/query/frontend/semantic/symbol_table.hpp @@ -19,10 +19,10 @@ class SymbolTable final { return Symbol(name, position, user_declared, type, token_position); } - auto &operator[](const Tree &tree) { return table_[tree.uid()]; } + auto &operator[](const Tree &tree) { return table_[tree.uid_]; } - Symbol &at(const Tree &tree) { return table_.at(tree.uid()); } - const Symbol &at(const Tree &tree) const { return table_.at(tree.uid()); } + Symbol &at(const Tree &tree) { return table_.at(tree.uid_); } + const Symbol &at(const Tree &tree) const { return table_.at(tree.uid_); } // TODO: Remove these since members are public int max_position() const { return position_; } diff --git a/src/query/interpret/eval.hpp b/src/query/interpret/eval.hpp index 3351a202c..1ec7a5e14 100644 --- a/src/query/interpret/eval.hpp +++ b/src/query/interpret/eval.hpp @@ -377,16 +377,16 @@ class ExpressionEvaluator : public TreeVisitor { for (size_t i = 0; i < function.arguments_.size(); ++i) { arguments[i] = function.arguments_[i]->Accept(*this); } - return function.function()(arguments, function.arguments_.size(), *ctx_, - dba_); + return function.function_(arguments, function.arguments_.size(), *ctx_, + dba_); } else { std::vector arguments; arguments.reserve(function.arguments_.size()); for (const auto &argument : function.arguments_) { arguments.emplace_back(argument->Accept(*this)); } - return function.function()(arguments.data(), arguments.size(), *ctx_, - dba_); + return function.function_(arguments.data(), arguments.size(), *ctx_, + dba_); } } diff --git a/src/query/plan/distributed.cpp b/src/query/plan/distributed.cpp index 75a2f4ab9..56154f4ad 100644 --- a/src/query/plan/distributed.cpp +++ b/src/query/plan/distributed.cpp @@ -1214,11 +1214,11 @@ class DistributedPlanner : public HierarchicalLogicalOperatorVisitor { } // Create a copy of OrderBy but with added symbols used in expressions, so // that they can be pulled. - std::vector> ordering; + std::vector ordering; ordering.reserve(order_by.order_by_.size()); for (int i = 0; i < order_by.order_by_.size(); ++i) { - ordering.emplace_back(order_by.compare_.ordering()[i], - order_by.order_by_[i]); + ordering.emplace_back( + SortItem{order_by.compare_.ordering()[i], order_by.order_by_[i]}); } auto worker_plan = std::make_shared( order_by.input(), ordering, @@ -1328,7 +1328,7 @@ class DistributedPlanner : public HierarchicalLogicalOperatorVisitor { auto make_merge_aggregation = [&](auto op, const auto &worker_sym) { auto *worker_ident = make_ident(worker_sym); auto merge_name = Aggregation::OpToString(op) + - std::to_string(worker_ident->uid()) + "<-" + + std::to_string(worker_ident->uid_) + "<-" + worker_sym.name(); auto merge_sym = distributed_plan_.symbol_table.CreateSymbol( merge_name, false, Symbol::Type::Number); diff --git a/src/query/plan/distributed_ops.cpp b/src/query/plan/distributed_ops.cpp index afd265ae5..fdfed37fe 100644 --- a/src/query/plan/distributed_ops.cpp +++ b/src/query/plan/distributed_ops.cpp @@ -81,8 +81,7 @@ bool Synchronize::Accept(HierarchicalLogicalOperatorVisitor &visitor) { PullRemoteOrderBy::PullRemoteOrderBy( const std::shared_ptr &input, int64_t plan_id, - const std::vector> &order_by, - const std::vector &symbols) + const std::vector &order_by, const std::vector &symbols) : input_(input), plan_id_(plan_id), symbols_(symbols) { CHECK(input_ != nullptr) << "PullRemoteOrderBy should always be constructed with input!"; @@ -90,8 +89,8 @@ PullRemoteOrderBy::PullRemoteOrderBy( ordering.reserve(order_by.size()); order_by_.reserve(order_by.size()); for (const auto &ordering_expression_pair : order_by) { - ordering.emplace_back(ordering_expression_pair.first); - order_by_.emplace_back(ordering_expression_pair.second); + ordering.emplace_back(ordering_expression_pair.ordering); + order_by_.emplace_back(ordering_expression_pair.expression); } compare_ = TypedValueVectorCompare(ordering); } diff --git a/src/query/plan/distributed_ops.lcp b/src/query/plan/distributed_ops.lcp index 965e321c0..b42b6a1c0 100644 --- a/src/query/plan/distributed_ops.lcp +++ b/src/query/plan/distributed_ops.lcp @@ -172,8 +172,7 @@ by having only one result from each worker.") PullRemoteOrderBy() {} PullRemoteOrderBy( const std::shared_ptr &input, int64_t plan_id, - const std::vector> &order_by, - const std::vector &symbols); + const std::vector &order_by, const std::vector &symbols); bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; std::unique_ptr MakeCursor( database::GraphDbAccessor &db) const override; diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp index f24e4e568..68e596d7d 100644 --- a/src/query/plan/operator.cpp +++ b/src/query/plan/operator.cpp @@ -2658,7 +2658,7 @@ void Limit::LimitCursor::Reset() { } OrderBy::OrderBy(const std::shared_ptr &input, - const std::vector> &order_by, + const std::vector &order_by, const std::vector &output_symbols) : input_(input), output_symbols_(output_symbols) { // split the order_by vector into two vectors of orderings and expressions @@ -2666,8 +2666,8 @@ OrderBy::OrderBy(const std::shared_ptr &input, ordering.reserve(order_by.size()); order_by_.reserve(order_by.size()); for (const auto &ordering_expression_pair : order_by) { - ordering.emplace_back(ordering_expression_pair.first); - order_by_.emplace_back(ordering_expression_pair.second); + ordering.emplace_back(ordering_expression_pair.ordering); + order_by_.emplace_back(ordering_expression_pair.expression); } compare_ = TypedValueVectorCompare(ordering); } diff --git a/src/query/plan/operator.lcp b/src/query/plan/operator.lcp index c912317dd..38125ea06 100644 --- a/src/query/plan/operator.lcp +++ b/src/query/plan/operator.lcp @@ -151,6 +151,7 @@ cpp<# (lcp:define-class logical-operator ("::utils::Visitable") () + (:abstractp t) (:documentation "Base class for logical operators. @@ -238,23 +239,27 @@ can serve as inputs to others and thus a sequence of operations is formed.") #>cpp if (${member}) { auto ${capnp-name}_builder = ${builder}->init${capnp-name}(); - ${member}->Save(&${capnp-name}_builder, &helper->saved_ast_uids); + Save(*${member}, &${capnp-name}_builder, &helper->saved_ast_uids); } cpp<#) (defun load-ast-pointer (ast-type) (lambda (reader member capnp-name) - #>cpp - if (${reader}.has${capnp-name}()) - ${member} = static_cast<${ast-type}>(helper->ast_storage.Load(${reader}.get${capnp-name}(), &helper->loaded_ast_uids)); - else - ${member} = nullptr; - cpp<#)) + (let ((cpp-type (remove #\* ast-type))) + #>cpp + if (${reader}.has${capnp-name}()) { + std::unique_ptr<${cpp-type}> tmp; + Load(&tmp, ${reader}.get${capnp-name}(), &helper->ast_storage, &helper->loaded_ast_uids); + ${member} = helper->ast_storage.Take(std::move(tmp)); + } else { + ${member} = nullptr; + } + cpp<#))) (defun save-ast-vector (ast-type) (lcp:capnp-save-vector "::query::capnp::Tree" ast-type "[helper](auto *builder, const auto &val) { - val->Save(builder, &helper->saved_ast_uids); + Save(*val, builder, &helper->saved_ast_uids); }")) (defun load-ast-vector (ast-type) @@ -262,9 +267,11 @@ can serve as inputs to others and thus a sequence of operations is formed.") (format nil "[helper](const auto &reader) { - // We expect the unsafe downcast via static_cast to work. - return static_cast<~A>(helper->ast_storage.Load(reader, &helper->loaded_ast_uids)); - }" ast-type))) + std::unique_ptr<~A> tmp; + Load(&tmp, reader, &helper->ast_storage, &helper->loaded_ast_uids); + return helper->ast_storage.Take(std::move(tmp)); + }" + (remove #\* ast-type)))) (defun save-operator-pointer (builder member-name capnp-name) (declare (ignore capnp-name)) @@ -547,7 +554,7 @@ given label. ::utils::capnp::Bound<::query::capnp::Tree>::Type::INCLUSIVE : ::utils::capnp::Bound<::query::capnp::Tree>::Type::EXCLUSIVE); auto value_builder = builder->initValue(); - bound.value()->Save(&value_builder, &helper->saved_ast_uids); + Save(*bound.value(), &value_builder, &helper->saved_ast_uids); }")) (funcall (lcp:capnp-save-optional "::utils::capnp::Bound<::query::capnp::Tree>" "utils::Bound" @@ -559,7 +566,9 @@ given label. "[helper](const auto &reader) { auto type = reader.getType() == ::utils::capnp::Bound<::query::capnp::Tree>::Type::INCLUSIVE ? utils::BoundType::INCLUSIVE : utils::BoundType::EXCLUSIVE; - auto *value = static_cast(helper->ast_storage.Load(reader.getValue(), &helper->loaded_ast_uids)); + std::unique_ptr tmp; + Load(&tmp, reader.getValue(), &helper->ast_storage, &helper->loaded_ast_uids); + auto *value = static_cast(helper->ast_storage.Take(std::move(tmp))); return utils::Bound(value, type); }")) (funcall (lcp:capnp-load-optional "::utils::capnp::Bound<::query::capnp::Tree>" @@ -818,16 +827,16 @@ pulled.") :capnp-save (lambda (builder member capnp-name) #>cpp if (${member}) { - auto expression_builder = ${builder}->initExpression(); - ${member}->Save(&expression_builder, saved_ast_uids); + auto ${capnp-name}_builder = ${builder}->init${capnp-name}(); + Save(*${member}, &${capnp-name}_builder, saved_ast_uids); } cpp<#) :capnp-load (lambda (reader member capnp-name) #>cpp if (${reader}.hasExpression()) { - ${member} = static_cast( - ast_storage->Load(${reader}.getExpression(), - loaded_ast_uids)); + std::unique_ptr tmp; + Load(&tmp, ${reader}.getExpression(), ast_storage, loaded_ast_uids); + ${member} = ast_storage->Take(std::move(tmp)); } else { ${member} = nullptr; } @@ -854,7 +863,7 @@ pulled.") :capnp-type "Ast.Tree" :capnp-init nil :capnp-save #'save-ast-pointer :capnp-load (load-ast-pointer "Expression *") :documentation "Optional upper bound of the variable length expansion, defaults are (1, inf)") - (filter-lambda "ExpansionLambda" + (filter-lambda "ExpansionLambda" :scope :public :capnp-save (lambda (builder member capnp-name) #>cpp @@ -867,12 +876,12 @@ pulled.") (weight-lambda "std::experimental::optional" :scope :public :capnp-save (lcp:capnp-save-optional "capnp::ExpansionLambda" "ExpansionLambda" - "[helper](auto *builder, const auto &val) { - Save(val, builder, &helper->saved_ast_uids); + "[helper](auto *builder, const auto &val) { + Save(val, builder, &helper->saved_ast_uids); }") :capnp-load (lcp:capnp-load-optional "capnp::ExpansionLambda" "ExpansionLambda" - "[helper](const auto &reader) { + "[helper](const auto &reader) { ExpansionLambda val; Load(&val, reader, &helper->ast_storage, &helper->loaded_ast_uids); return val; @@ -1832,7 +1841,7 @@ are valid for usage after the OrderBy operator.") OrderBy() {} OrderBy(const std::shared_ptr &input, - const std::vector> &order_by, + const std::vector &order_by, const std::vector &output_symbols); bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; std::unique_ptr MakeCursor( diff --git a/src/query/plan/rule_based_planner.cpp b/src/query/plan/rule_based_planner.cpp index 826bfb81d..41a0903d6 100644 --- a/src/query/plan/rule_based_planner.cpp +++ b/src/query/plan/rule_based_planner.cpp @@ -132,7 +132,7 @@ class ReturnBodyContext : public HierarchicalTreeVisitor { // about collecting used_symbols. Also, semantic analysis should // have prevented any aggregations from appearing here. for (const auto &order_pair : body.order_by) { - order_pair.second->Accept(*this); + order_pair.expression->Accept(*this); } if (where) { where->Accept(*this); diff --git a/src/storage/serialization.capnp b/src/storage/serialization.capnp index 7eb6f310b..604b9ac37 100644 --- a/src/storage/serialization.capnp +++ b/src/storage/serialization.capnp @@ -39,7 +39,7 @@ struct PropertyValue { struct PropertyValueStore { properties @0 :List(Entry); - + struct Entry { id @0 :Common; value @1 :PropertyValue; diff --git a/tests/unit/cypher_main_visitor.cpp b/tests/unit/cypher_main_visitor.cpp index 8f2699c8a..7c220b280 100644 --- a/tests/unit/cypher_main_visitor.cpp +++ b/tests/unit/cypher_main_visitor.cpp @@ -158,7 +158,7 @@ class CapnpAstGenerator : public Base { query::capnp::Tree::Builder builder = message.initRoot(); std::vector saved_uids; - visitor.query()->Save(&builder, &saved_uids); + Save(*visitor.query(), &builder, &saved_uids); } AstStorage new_ast; @@ -332,8 +332,8 @@ TYPED_TEST(CypherMainVisitorTest, ReturnOrderBy) { ASSERT_EQ(return_clause->body_.order_by.size(), 3U); std::vector> ordering; for (const auto &sort_item : return_clause->body_.order_by) { - auto *identifier = dynamic_cast(sort_item.second); - ordering.emplace_back(sort_item.first, identifier->name_); + auto *identifier = dynamic_cast(sort_item.expression); + ordering.emplace_back(sort_item.ordering, identifier->name_); } ASSERT_THAT(ordering, UnorderedElementsAre(Pair(Ordering::ASC, "z"), Pair(Ordering::ASC, "x"), @@ -762,7 +762,7 @@ TYPED_TEST(CypherMainVisitorTest, Function) { auto *function = dynamic_cast( return_clause->body_.named_expressions[0]->expression_); ASSERT_TRUE(function); - ASSERT_TRUE(function->function()); + ASSERT_TRUE(function->function_); } TYPED_TEST(CypherMainVisitorTest, StringLiteralDoubleQuotes) { diff --git a/tests/unit/distributed_query_plan.cpp b/tests/unit/distributed_query_plan.cpp index f5c0f742d..0bc1daf2a 100644 --- a/tests/unit/distributed_query_plan.cpp +++ b/tests/unit/distributed_query_plan.cpp @@ -329,16 +329,14 @@ TEST_F(DistributedQueryPlan, PullRemoteOrderBy) { auto n_p = PROPERTY_LOOKUP("n", prop); ctx.symbol_table_[*n_p->expression_] = n.sym_; auto order_by = std::make_shared( - n.op_, - std::vector>{{Ordering::ASC, n_p}}, + n.op_, std::vector{{Ordering::ASC, n_p}}, std::vector{n.sym_}); const int plan_id = 42; master().plan_dispatcher().DispatchPlan(plan_id, order_by, ctx.symbol_table_); auto pull_remote_order_by = std::make_shared( - order_by, plan_id, - std::vector>{{Ordering::ASC, n_p}}, + order_by, plan_id, std::vector{{Ordering::ASC, n_p}}, std::vector{n.sym_}); auto n_p_ne = NEXPR("n.prop", n_p); diff --git a/tests/unit/query_common.hpp b/tests/unit/query_common.hpp index 9461a7477..d1ff40751 100644 --- a/tests/unit/query_common.hpp +++ b/tests/unit/query_common.hpp @@ -57,7 +57,7 @@ auto ToMap(const TypedValue &t) { // Custom types for ORDER BY, SKIP, LIMIT, ON MATCH and ON CREATE expressions, // so that they can be used to resolve function calls. struct OrderBy { - std::vector> expressions; + std::vector expressions; }; struct Skip { Expression *expression = nullptr; @@ -75,7 +75,7 @@ struct OnCreate { // Helper functions for filling the OrderBy with expressions. auto FillOrderBy(OrderBy &order_by, Expression *expression, Ordering ordering = Ordering::ASC) { - order_by.expressions.emplace_back(ordering, expression); + order_by.expressions.push_back({ordering, expression}); } template auto FillOrderBy(OrderBy &order_by, Expression *expression, Ordering ordering, diff --git a/tests/unit/query_plan_bag_semantics.cpp b/tests/unit/query_plan_bag_semantics.cpp index 44d3cc96f..eb67caacf 100644 --- a/tests/unit/query_plan_bag_semantics.cpp +++ b/tests/unit/query_plan_bag_semantics.cpp @@ -151,9 +151,7 @@ TEST(QueryPlan, OrderBy) { auto n_p = PROPERTY_LOOKUP("n", prop); symbol_table[*n_p->expression_] = n.sym_; auto order_by = std::make_shared( - n.op_, - std::vector>{ - {order_value_pair.first, n_p}}, + n.op_, std::vector{{order_value_pair.first, n_p}}, std::vector{n.sym_}); auto n_p_ne = NEXPR("n.p", n_p); symbol_table[*n_p_ne] = symbol_table.CreateSymbol("n.p", true); @@ -201,13 +199,12 @@ TEST(QueryPlan, OrderByMultiple) { // (p1: 0, p2: N-2) // ... // (p1: N-1, p2:0) - auto order_by = std::make_shared( - n.op_, - std::vector>{ - {Ordering::ASC, n_p1}, - {Ordering::DESC, n_p2}, - }, - std::vector{n.sym_}); + auto order_by = std::make_shared(n.op_, + std::vector{ + {Ordering::ASC, n_p1}, + {Ordering::DESC, n_p2}, + }, + std::vector{n.sym_}); auto n_p1_ne = NEXPR("n.p1", n_p1); symbol_table[*n_p1_ne] = symbol_table.CreateSymbol("n.p1", true); auto n_p2_ne = NEXPR("n.p2", n_p2); @@ -262,8 +259,7 @@ TEST(QueryPlan, OrderByExceptions) { auto n_p = PROPERTY_LOOKUP("n", prop); symbol_table[*n_p->expression_] = n.sym_; auto order_by = std::make_shared( - n.op_, - std::vector>{{Ordering::ASC, n_p}}, + n.op_, std::vector{{Ordering::ASC, n_p}}, std::vector{}); EXPECT_THROW(PullAll(order_by, dba, symbol_table), QueryRuntimeException); } diff --git a/tests/unit/query_planner.cpp b/tests/unit/query_planner.cpp index deb1e57a6..7b6730e41 100644 --- a/tests/unit/query_planner.cpp +++ b/tests/unit/query_planner.cpp @@ -3201,7 +3201,7 @@ TEST(CapnpSerial, PullRemoteOrderBy) { AstStorage storage; std::vector symbols{ Symbol("my_symbol", 2, true, Symbol::Type::Vertex, 3)}; - std::vector> order_by{ + std::vector order_by{ {query::Ordering::ASC, IDENT("my_symbol")}}; auto pull_remote_order_by = std::make_unique(once, 42, order_by, symbols);