Adding a new query to Memgraph is not hard but it consists of multiple steps that affect different parts of code. Using a small example of adding a FREE MEMORY query we will go through all the necessary steps while the additional functionalities like adding a query with a variable can be deduced by looking at the similar queries. The point of this tutorial is to only show you all the places you need to change to add a completely functional new query.

Modifying the grammar

First step is adding the new keywords, if any, to the Memgraph's grammar.

For our query, we have two keywords: FREE and MEMORY.

We go to the src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 file and check if the keywords are already defined. We see that MEMORY is actually defined but FREE is missing.

Next we go to the src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 file which contains Memgraph specific keywords. We also see that FREE is not present so we add it here:

import CypherLexer ;

ALTER          : A L T E R ; 
ASYNC          : A S Y N C ; 
AUTH           : A U T H ; 
BAD            : B A D ; 
CLEAR          : C L E A R ; 
CSV            : C S V ; 
DATA           : D A T A ; 
DELIMITER      : D E L I M I T E R ; 
DATABASE       : D A T A B A S E ; 
DENY           : D E N Y ; 
DIRECTORY      : D I R E C T O R Y ; 
DROP           : D R O P ; 
DUMP           : D U M P ; 
FOR            : F O R ; 
FREE           : F R E E ; 
FROM           : F R O M ; 
GRANT          : G R A N T ; 
GRANTS         : G R A N T S ; 
HEADER         : H E A D E R ; 
IDENTIFIED     : I D E N T I F I E D ; 
IGNORE         : I G N O R E ; 
LOAD           : L O A D ; 
LOCK           : L O C K ; 
MAIN           : M A I N ; 
MODE           : M O D E ; 
NO             : N O ; 
PASSWORD       : P A S S W O R D ; 
PORT           : P O R T ; 
PRIVILEGES     : P R I V I L E G E S ; 
REGISTER       : R E G I S T E R ; 
REPLICA        : R E P L I C A ; 
REPLICAS       : R E P L I C A S ; 
REPLICATION    : R E P L I C A T I O N ; 
REVOKE         : R E V O K E ; 
ROLE           : R O L E ; 
ROLES          : R O L E S ; 
QUOTE          : Q U O T E ; 
STATS          : S T A T S ; 
SYNC           : S Y N C ; 
TIMEOUT        : T I M E O U T ; 
TO             : T O ; 
UNLOCK         : U N L O C K ; 
USER           : U S E R ; 
USERS          : U S E R S ;

After that, we read the comment at the beginning of the file and notice that we need to add the new keyword to the kKeywords in src/query/frontend/stripped_lexer_constants.hpp :

const trie::Trie kKeywords = {
      "union",  "all",        "optional",  "match",   "unwind",     "as",       "merge",    "on",    "create",
      "set",    "detach",     "delete",    "remove",  "with",       "distinct", "return",   "order", "by",
      "skip",   "limit",      "ascending", "asc",     "descending", "desc",     "where",    "or",    "xor",
      "and",    "not",        "in",        "starts",  "ends",       "contains", "is",       "null",  "case",
      "when",   "then",       "else",      "end",     "count",      "filter",   "extract",  "any",   "none",
      "single", "true",       "false",     "reduce",  "coalesce",   "user",     "password", "alter", "drop",
      "show",   "stats",      "unique",    "explain", "profile",    "storage",  "index",    "info",  "exists",
      "assert", "constraint", "node",      "key",     "dump",       "database", "call",     "yield", "memory",
      "mb",     "kb",         "unlimited", "free"};

Defining a new query

We added all the new keywords to Memgraph's grammar now we can define how our query actually looks like.

We go to the src/query/frontend/opencypher/grammar/MemgraphCypher.g4 and define our new query. Again, we need to add the new FREE keyword:

memgraphCypherKeyword : cypherKeyword
                      | ALTER
                      | ASYNC
                      | AUTH
                      | BAD
                      | CLEAR
                      | CSV
                      | DATA
                      | DELIMITER
                      | DATABASE
                      | DENY
                      | DROP
                      | DUMP
                      | FOR
                      | FREE
                      | FROM
                      | GRANT
                      | HEADER
                      | IDENTIFIED
                      | LOAD
                      | LOCK
                      | MAIN
                      | MODE
                      | NO
                      | PASSWORD
                      | PORT
                      | PRIVILEGES
                      | REGISTER
                      | REPLICA
                      | REPLICAS
                      | REPLICATION
                      | REVOKE
                      | ROLE
                      | ROLES
                      | QUOTE
                      | STATS
                      | SYNC
                      | TIMEOUT
                      | TO
                      | UNLOCK
                      | USER
                      | USERS
                      ;

Then we define the name of our query. In this case it will be freeMemoryQuery and we add it to the query :

query : cypherQuery
      | indexQuery
      | explainQuery
      | profileQuery
      | infoQuery
      | constraintQuery
      | authQuery
      | dumpQuery
      | replicationQuery
      | lockPathQuery
      | freeMemoryQuery
      ;

Add the end of the file, we simply define the query:

freeMemoryQuery : FREE MEMORY ;

You can take a look at the replication and authentication queries in the same file to see how to define more complex queries.

Parsing the query

After we defined the query we now need to add the logic for it. First, we need to define the class which can be accessed by the visitor. By doing so, we can add a more complex parsing logic for our queries.